diff --git a/.gitignore b/.gitignore index 0d20b648..e2270029 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.pyc +/.project diff --git a/extensions/fablabchemnitz/fablabchemnitz_apollon.py b/extensions/fablabchemnitz/apollonian/fablabchemnitz_apollon.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_apollon.py rename to extensions/fablabchemnitz/apollonian/fablabchemnitz_apollon.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_apollonian.inx b/extensions/fablabchemnitz/apollonian/fablabchemnitz_apollonian.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_apollonian.inx rename to extensions/fablabchemnitz/apollonian/fablabchemnitz_apollonian.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_apollonian.py b/extensions/fablabchemnitz/apollonian/fablabchemnitz_apollonian.py similarity index 98% rename from extensions/fablabchemnitz/fablabchemnitz_apollonian.py rename to extensions/fablabchemnitz/apollonian/fablabchemnitz_apollonian.py index ebdb80b1..b771a6fe 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_apollonian.py +++ b/extensions/fablabchemnitz/apollonian/fablabchemnitz_apollonian.py @@ -92,4 +92,5 @@ class Gasket(inkex.Effect): # choose a better name cx, cy, r = scale_factor*cx , scale_factor*cy, scale_factor*r draw_SVG_circle(topgroup,r,cx,cy,'apo') -Gasket().run() \ No newline at end of file +if __name__ == '__main__': + Gasket().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_apolloniangasket_func.py b/extensions/fablabchemnitz/apollonian/fablabchemnitz_apolloniangasket_func.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_apolloniangasket_func.py rename to extensions/fablabchemnitz/apollonian/fablabchemnitz_apolloniangasket_func.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_gen_box.inx b/extensions/fablabchemnitz/boxmaker_generic/fablabchemnitz_gen_box.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_gen_box.inx rename to extensions/fablabchemnitz/boxmaker_generic/fablabchemnitz_gen_box.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_gen_box.py b/extensions/fablabchemnitz/boxmaker_generic/fablabchemnitz_gen_box.py similarity index 99% rename from extensions/fablabchemnitz/fablabchemnitz_gen_box.py rename to extensions/fablabchemnitz/boxmaker_generic/fablabchemnitz_gen_box.py index aaa4c2e0..97045ee9 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_gen_box.py +++ b/extensions/fablabchemnitz/boxmaker_generic/fablabchemnitz_gen_box.py @@ -3052,6 +3052,5 @@ class GenericBox(inkex.Effect): CloseDebugFile() -# Create effect instance and apply it. -effect = GenericBox() -effect.run() +if __name__ == '__main__': + GenericBox().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_inkscape_path.py b/extensions/fablabchemnitz/boxmaker_generic/fablabchemnitz_inkscape_path.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_inkscape_path.py rename to extensions/fablabchemnitz/boxmaker_generic/fablabchemnitz_inkscape_path.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxmaker.inx b/extensions/fablabchemnitz/boxmaker_tabbed/fablabchemnitz_boxmaker.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_boxmaker.inx rename to extensions/fablabchemnitz/boxmaker_tabbed/fablabchemnitz_boxmaker.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxmaker.py b/extensions/fablabchemnitz/boxmaker_tabbed/fablabchemnitz_boxmaker.py similarity index 99% rename from extensions/fablabchemnitz/fablabchemnitz_boxmaker.py rename to extensions/fablabchemnitz/boxmaker_tabbed/fablabchemnitz_boxmaker.py index 55f60371..50d825f4 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_boxmaker.py +++ b/extensions/fablabchemnitz/boxmaker_tabbed/fablabchemnitz_boxmaker.py @@ -636,4 +636,5 @@ class BoxMaker(inkex.Effect): side(group,(x+dx,y+dy),(-b,-c),(d,-c),keydivwalls*ctabs*(thickness if c else -thickness),dx,(-1,0),c,1,0,0) # side c side(group,(x,y+dy),(d,-c),(d,a),keydivfloor*dtabs*(-thickness if d else thickness),dy,(0,-1),d,1,0,0) # side d -BoxMaker().run() +if __name__ == '__main__': + BoxMaker().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_schroffmaker.inx b/extensions/fablabchemnitz/boxmaker_tabbed/fablabchemnitz_schroffmaker.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_schroffmaker.inx rename to extensions/fablabchemnitz/boxmaker_tabbed/fablabchemnitz_schroffmaker.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_contour_scanner.inx b/extensions/fablabchemnitz/contourscanner/fablabchemnitz_contour_scanner.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_contour_scanner.inx rename to extensions/fablabchemnitz/contourscanner/fablabchemnitz_contour_scanner.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_contour_scanner.py b/extensions/fablabchemnitz/contourscanner/fablabchemnitz_contour_scanner.py similarity index 99% rename from extensions/fablabchemnitz/fablabchemnitz_contour_scanner.py rename to extensions/fablabchemnitz/contourscanner/fablabchemnitz_contour_scanner.py index 43d086cc..33775f94 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_contour_scanner.py +++ b/extensions/fablabchemnitz/contourscanner/fablabchemnitz_contour_scanner.py @@ -199,4 +199,5 @@ class ContourScanner(inkex.Effect): for id, item in self.svg.selected.items(): self.scanContours(item) -ContourScanner().run() \ No newline at end of file +if __name__ == '__main__': + ContourScanner().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_poly_point_isect.py b/extensions/fablabchemnitz/contourscanner/fablabchemnitz_poly_point_isect.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_poly_point_isect.py rename to extensions/fablabchemnitz/contourscanner/fablabchemnitz_poly_point_isect.py diff --git a/extensions/fablabchemnitz/cutcraft/README.md b/extensions/fablabchemnitz/cutcraft/cutcraft/README.md similarity index 100% rename from extensions/fablabchemnitz/cutcraft/README.md rename to extensions/fablabchemnitz/cutcraft/cutcraft/README.md diff --git a/extensions/fablabchemnitz/cutcraft/__init__.py b/extensions/fablabchemnitz/cutcraft/cutcraft/__init__.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/__init__.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/__init__.py diff --git a/extensions/fablabchemnitz/cutcraft/core/__init__.py b/extensions/fablabchemnitz/cutcraft/cutcraft/core/__init__.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/core/__init__.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/core/__init__.py diff --git a/extensions/fablabchemnitz/cutcraft/core/circle.py b/extensions/fablabchemnitz/cutcraft/cutcraft/core/circle.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/core/circle.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/core/circle.py diff --git a/extensions/fablabchemnitz/cutcraft/core/fingerjoint.py b/extensions/fablabchemnitz/cutcraft/cutcraft/core/fingerjoint.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/core/fingerjoint.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/core/fingerjoint.py diff --git a/extensions/fablabchemnitz/cutcraft/core/line.py b/extensions/fablabchemnitz/cutcraft/cutcraft/core/line.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/core/line.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/core/line.py diff --git a/extensions/fablabchemnitz/cutcraft/core/neopixel.py b/extensions/fablabchemnitz/cutcraft/cutcraft/core/neopixel.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/core/neopixel.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/core/neopixel.py diff --git a/extensions/fablabchemnitz/cutcraft/core/part.py b/extensions/fablabchemnitz/cutcraft/cutcraft/core/part.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/core/part.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/core/part.py diff --git a/extensions/fablabchemnitz/cutcraft/core/point.py b/extensions/fablabchemnitz/cutcraft/cutcraft/core/point.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/core/point.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/core/point.py diff --git a/extensions/fablabchemnitz/cutcraft/core/rectangle.py b/extensions/fablabchemnitz/cutcraft/cutcraft/core/rectangle.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/core/rectangle.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/core/rectangle.py diff --git a/extensions/fablabchemnitz/cutcraft/core/trace.py b/extensions/fablabchemnitz/cutcraft/cutcraft/core/trace.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/core/trace.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/core/trace.py diff --git a/extensions/fablabchemnitz/cutcraft/platforms/__init__.py b/extensions/fablabchemnitz/cutcraft/cutcraft/platforms/__init__.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/platforms/__init__.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/platforms/__init__.py diff --git a/extensions/fablabchemnitz/cutcraft/platforms/circular.py b/extensions/fablabchemnitz/cutcraft/cutcraft/platforms/circular.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/platforms/circular.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/platforms/circular.py diff --git a/extensions/fablabchemnitz/cutcraft/platforms/platform.py b/extensions/fablabchemnitz/cutcraft/cutcraft/platforms/platform.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/platforms/platform.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/platforms/platform.py diff --git a/extensions/fablabchemnitz/cutcraft/platforms/rollerframe.py b/extensions/fablabchemnitz/cutcraft/cutcraft/platforms/rollerframe.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/platforms/rollerframe.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/platforms/rollerframe.py diff --git a/extensions/fablabchemnitz/cutcraft/shapes/__init__.py b/extensions/fablabchemnitz/cutcraft/cutcraft/shapes/__init__.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/shapes/__init__.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/shapes/__init__.py diff --git a/extensions/fablabchemnitz/cutcraft/shapes/box.py b/extensions/fablabchemnitz/cutcraft/cutcraft/shapes/box.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/shapes/box.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/shapes/box.py diff --git a/extensions/fablabchemnitz/cutcraft/shapes/cone.py b/extensions/fablabchemnitz/cutcraft/cutcraft/shapes/cone.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/shapes/cone.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/shapes/cone.py diff --git a/extensions/fablabchemnitz/cutcraft/shapes/cylinder.py b/extensions/fablabchemnitz/cutcraft/cutcraft/shapes/cylinder.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/shapes/cylinder.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/shapes/cylinder.py diff --git a/extensions/fablabchemnitz/cutcraft/shapes/rollerbot.py b/extensions/fablabchemnitz/cutcraft/cutcraft/shapes/rollerbot.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/shapes/rollerbot.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/shapes/rollerbot.py diff --git a/extensions/fablabchemnitz/cutcraft/shapes/shape.py b/extensions/fablabchemnitz/cutcraft/cutcraft/shapes/shape.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/shapes/shape.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/shapes/shape.py diff --git a/extensions/fablabchemnitz/cutcraft/shapes/sphere.py b/extensions/fablabchemnitz/cutcraft/cutcraft/shapes/sphere.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/shapes/sphere.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/shapes/sphere.py diff --git a/extensions/fablabchemnitz/cutcraft/supports/__init__.py b/extensions/fablabchemnitz/cutcraft/cutcraft/supports/__init__.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/supports/__init__.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/supports/__init__.py diff --git a/extensions/fablabchemnitz/cutcraft/supports/pier.py b/extensions/fablabchemnitz/cutcraft/cutcraft/supports/pier.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/supports/pier.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/supports/pier.py diff --git a/extensions/fablabchemnitz/cutcraft/supports/support.py b/extensions/fablabchemnitz/cutcraft/cutcraft/supports/support.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/supports/support.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/supports/support.py diff --git a/extensions/fablabchemnitz/cutcraft/util.py b/extensions/fablabchemnitz/cutcraft/cutcraft/util.py similarity index 100% rename from extensions/fablabchemnitz/cutcraft/util.py rename to extensions/fablabchemnitz/cutcraft/cutcraft/util.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_cutcraftbox.inx b/extensions/fablabchemnitz/cutcraft/fablabchemnitz_cutcraftbox.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_cutcraftbox.inx rename to extensions/fablabchemnitz/cutcraft/fablabchemnitz_cutcraftbox.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_cutcraftbox.py b/extensions/fablabchemnitz/cutcraft/fablabchemnitz_cutcraftbox.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_cutcraftbox.py rename to extensions/fablabchemnitz/cutcraft/fablabchemnitz_cutcraftbox.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_cutcraftcylinder.inx b/extensions/fablabchemnitz/cutcraft/fablabchemnitz_cutcraftcylinder.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_cutcraftcylinder.inx rename to extensions/fablabchemnitz/cutcraft/fablabchemnitz_cutcraftcylinder.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_cutcraftcylinder.py b/extensions/fablabchemnitz/cutcraft/fablabchemnitz_cutcraftcylinder.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_cutcraftcylinder.py rename to extensions/fablabchemnitz/cutcraft/fablabchemnitz_cutcraftcylinder.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_cutcraftrollerbot.inx b/extensions/fablabchemnitz/cutcraft/fablabchemnitz_cutcraftrollerbot.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_cutcraftrollerbot.inx rename to extensions/fablabchemnitz/cutcraft/fablabchemnitz_cutcraftrollerbot.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_cutcraftrollerbot.py b/extensions/fablabchemnitz/cutcraft/fablabchemnitz_cutcraftrollerbot.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_cutcraftrollerbot.py rename to extensions/fablabchemnitz/cutcraft/fablabchemnitz_cutcraftrollerbot.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_cutcraftshape.py b/extensions/fablabchemnitz/cutcraft/fablabchemnitz_cutcraftshape.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_cutcraftshape.py rename to extensions/fablabchemnitz/cutcraft/fablabchemnitz_cutcraftshape.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_cutoptim/linux/CutOptim b/extensions/fablabchemnitz/cutoptim/linux/CutOptim similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_cutoptim/linux/CutOptim rename to extensions/fablabchemnitz/cutoptim/linux/CutOptim diff --git a/extensions/fablabchemnitz/fablabchemnitz_cutoptim/linux/fablabchemnitz_cutoptim.inx b/extensions/fablabchemnitz/cutoptim/linux/fablabchemnitz_cutoptim.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_cutoptim/linux/fablabchemnitz_cutoptim.inx rename to extensions/fablabchemnitz/cutoptim/linux/fablabchemnitz_cutoptim.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_cutoptim/windows/CutOptim.exe b/extensions/fablabchemnitz/cutoptim/windows/CutOptim.exe similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_cutoptim/windows/CutOptim.exe rename to extensions/fablabchemnitz/cutoptim/windows/CutOptim.exe diff --git a/extensions/fablabchemnitz/fablabchemnitz_cutoptim/windows/fablabchemnitz_cutoptim.inx b/extensions/fablabchemnitz/cutoptim/windows/fablabchemnitz_cutoptim.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_cutoptim/windows/fablabchemnitz_cutoptim.inx rename to extensions/fablabchemnitz/cutoptim/windows/fablabchemnitz_cutoptim.inx diff --git a/extensions/fablabchemnitz/dxfdwgimporter/.zip b/extensions/fablabchemnitz/dxfdwgimporter/.zip new file mode 100644 index 00000000..ac8a3eaf Binary files /dev/null and b/extensions/fablabchemnitz/dxfdwgimporter/.zip differ diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/dxfdwgimporter.inx b/extensions/fablabchemnitz/dxfdwgimporter/dxfdwgimporter.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/dxfdwgimporter.inx rename to extensions/fablabchemnitz/dxfdwgimporter/dxfdwgimporter.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/dxfdwgimporter.py b/extensions/fablabchemnitz/dxfdwgimporter/dxfdwgimporter.py similarity index 99% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/dxfdwgimporter.py rename to extensions/fablabchemnitz/dxfdwgimporter/dxfdwgimporter.py index 1d372d49..dc8e075f 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/dxfdwgimporter.py +++ b/extensions/fablabchemnitz/dxfdwgimporter/dxfdwgimporter.py @@ -377,4 +377,5 @@ class DXFDWGImport(inkex.Effect): root.set('width', bbox.width + 2 * offset) root.set('height', bbox.height + 2 * offset) -DXFDWGImport().run() +if __name__ == '__main__': + DXFDWGImport().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node.exe b/extensions/fablabchemnitz/dxfdwgimporter/node.exe similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node.exe rename to extensions/fablabchemnitz/dxfdwgimporter/node.exe diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/.eslintrc.json b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/.eslintrc.json similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/.eslintrc.json rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/.eslintrc.json diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/.travis.yml b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/.travis.yml similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/.travis.yml rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/.travis.yml diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/LICENSE b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/LICENSE similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/LICENSE rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/LICENSE diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/README.md b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/README.md similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/README.md rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/README.md diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/RELEASE.md b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/RELEASE.md similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/RELEASE.md rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/RELEASE.md diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/dist/dxf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/dist/dxf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/dist/dxf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/dist/dxf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/examples/dxf.html b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/examples/dxf.html similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/examples/dxf.html rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/examples/dxf.html diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/examples/example.es5.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/examples/example.es5.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/examples/example.es5.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/examples/example.es5.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/examples/example.es6.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/examples/example.es6.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/examples/example.es6.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/examples/example.es6.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/Helper.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/Helper.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/Helper.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/Helper.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/applyTransforms.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/applyTransforms.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/applyTransforms.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/applyTransforms.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/cli.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/cli.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/cli.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/cli.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/config.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/config.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/config.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/config.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/constants.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/constants.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/constants.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/constants.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/denormalise.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/denormalise.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/denormalise.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/denormalise.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/entityToPolyline.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/entityToPolyline.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/entityToPolyline.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/entityToPolyline.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/getRGBForEntity.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/getRGBForEntity.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/getRGBForEntity.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/getRGBForEntity.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/groupEntitiesByLayer.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/groupEntitiesByLayer.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/groupEntitiesByLayer.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/groupEntitiesByLayer.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/blocks.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/blocks.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/blocks.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/blocks.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entities.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entities.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entities.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entities.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/arc.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/arc.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/arc.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/arc.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/circle.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/circle.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/circle.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/circle.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/common.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/common.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/common.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/common.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/ellipse.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/ellipse.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/ellipse.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/ellipse.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/insert.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/insert.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/insert.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/insert.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/line.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/line.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/line.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/line.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/lwpolyline.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/lwpolyline.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/lwpolyline.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/lwpolyline.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/mtext.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/mtext.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/mtext.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/mtext.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/point.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/point.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/point.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/point.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/polyline.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/polyline.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/polyline.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/polyline.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/solid.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/solid.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/solid.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/solid.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/spline.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/spline.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/spline.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/spline.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/threeDFace.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/threeDFace.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/threeDFace.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/threeDFace.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/vertex.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/vertex.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/entity/vertex.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/entity/vertex.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/header.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/header.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/header.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/header.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/tables.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/tables.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/handlers/tables.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/handlers/tables.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/index.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/index.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/index.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/index.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/parseString.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/parseString.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/parseString.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/parseString.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/toPolylines.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/toPolylines.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/toPolylines.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/toPolylines.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/toSVG.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/toSVG.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/toSVG.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/toSVG.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/bSpline.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/bSpline.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/bSpline.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/bSpline.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/colors.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/colors.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/colors.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/colors.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/createArcForLWPolyline.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/createArcForLWPolyline.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/createArcForLWPolyline.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/createArcForLWPolyline.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/insertKnot.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/insertKnot.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/insertKnot.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/insertKnot.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/logger.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/logger.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/logger.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/logger.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/rgbToColorAttribute.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/rgbToColorAttribute.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/rgbToColorAttribute.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/rgbToColorAttribute.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/rotate.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/rotate.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/rotate.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/rotate.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/toPiecewiseBezier.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/toPiecewiseBezier.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/toPiecewiseBezier.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/toPiecewiseBezier.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/transformBoundingBoxAndElement.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/transformBoundingBoxAndElement.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/lib/util/transformBoundingBoxAndElement.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/lib/util/transformBoundingBoxAndElement.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/commander/CHANGELOG.md b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/commander/CHANGELOG.md similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/commander/CHANGELOG.md rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/commander/CHANGELOG.md diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/commander/LICENSE b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/commander/LICENSE similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/commander/LICENSE rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/commander/LICENSE diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/commander/Readme.md b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/commander/Readme.md similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/commander/Readme.md rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/commander/Readme.md diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/commander/index.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/commander/index.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/commander/index.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/commander/index.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/commander/package.json b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/commander/package.json similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/commander/package.json rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/commander/package.json diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/commander/typings/index.d.ts b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/commander/typings/index.d.ts similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/commander/typings/index.d.ts rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/commander/typings/index.d.ts diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/LICENSE b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/LICENSE similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/LICENSE rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/LICENSE diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/README.md b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/README.md similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/README.md rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/README.md diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_DataView.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_DataView.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_DataView.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_DataView.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Hash.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Hash.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Hash.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Hash.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_LazyWrapper.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_LazyWrapper.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_LazyWrapper.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_LazyWrapper.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_ListCache.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_ListCache.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_ListCache.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_ListCache.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_LodashWrapper.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_LodashWrapper.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_LodashWrapper.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_LodashWrapper.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Map.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Map.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Map.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Map.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_MapCache.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_MapCache.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_MapCache.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_MapCache.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Promise.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Promise.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Promise.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Promise.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Set.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Set.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Set.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Set.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_SetCache.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_SetCache.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_SetCache.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_SetCache.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Stack.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Stack.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Stack.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Stack.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Symbol.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Symbol.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Symbol.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Symbol.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Uint8Array.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Uint8Array.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Uint8Array.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_Uint8Array.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_WeakMap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_WeakMap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_WeakMap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_WeakMap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_apply.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_apply.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_apply.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_apply.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayAggregator.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayAggregator.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayAggregator.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayAggregator.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayEach.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayEach.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayEach.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayEach.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayEachRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayEachRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayEachRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayEachRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayEvery.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayEvery.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayEvery.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayEvery.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayFilter.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayFilter.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayFilter.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayFilter.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayIncludes.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayIncludes.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayIncludes.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayIncludes.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayIncludesWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayIncludesWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayIncludesWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayIncludesWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayLikeKeys.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayLikeKeys.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayLikeKeys.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayLikeKeys.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayMap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayMap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayMap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayMap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayPush.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayPush.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayPush.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayPush.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayReduce.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayReduce.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayReduce.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayReduce.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayReduceRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayReduceRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayReduceRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayReduceRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arraySample.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arraySample.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arraySample.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arraySample.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arraySampleSize.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arraySampleSize.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arraySampleSize.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arraySampleSize.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayShuffle.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayShuffle.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayShuffle.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arrayShuffle.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arraySome.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arraySome.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arraySome.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_arraySome.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_asciiSize.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_asciiSize.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_asciiSize.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_asciiSize.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_asciiToArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_asciiToArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_asciiToArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_asciiToArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_asciiWords.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_asciiWords.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_asciiWords.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_asciiWords.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_assignMergeValue.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_assignMergeValue.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_assignMergeValue.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_assignMergeValue.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_assignValue.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_assignValue.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_assignValue.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_assignValue.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_assocIndexOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_assocIndexOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_assocIndexOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_assocIndexOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAggregator.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAggregator.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAggregator.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAggregator.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAssign.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAssign.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAssign.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAssign.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAssignIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAssignIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAssignIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAssignIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAssignValue.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAssignValue.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAssignValue.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAssignValue.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseAt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseClamp.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseClamp.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseClamp.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseClamp.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseClone.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseClone.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseClone.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseClone.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseConforms.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseConforms.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseConforms.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseConforms.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseConformsTo.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseConformsTo.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseConformsTo.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseConformsTo.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseCreate.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseCreate.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseCreate.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseCreate.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseDelay.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseDelay.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseDelay.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseDelay.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseDifference.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseDifference.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseDifference.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseDifference.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseEach.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseEach.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseEach.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseEach.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseEachRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseEachRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseEachRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseEachRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseEvery.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseEvery.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseEvery.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseEvery.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseExtremum.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseExtremum.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseExtremum.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseExtremum.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFill.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFill.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFill.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFill.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFilter.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFilter.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFilter.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFilter.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFindIndex.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFindIndex.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFindIndex.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFindIndex.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFindKey.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFindKey.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFindKey.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFindKey.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFlatten.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFlatten.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFlatten.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFlatten.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFor.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFor.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFor.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFor.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseForOwn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseForOwn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseForOwn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseForOwn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseForOwnRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseForOwnRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseForOwnRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseForOwnRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseForRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseForRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseForRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseForRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFunctions.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFunctions.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFunctions.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseFunctions.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseGet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseGet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseGet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseGet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseGetAllKeys.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseGetAllKeys.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseGetAllKeys.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseGetAllKeys.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseGetTag.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseGetTag.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseGetTag.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseGetTag.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseGt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseGt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseGt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseGt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseHas.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseHas.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseHas.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseHas.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseHasIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseHasIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseHasIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseHasIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseInRange.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseInRange.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseInRange.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseInRange.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIndexOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIndexOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIndexOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIndexOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIndexOfWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIndexOfWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIndexOfWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIndexOfWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIntersection.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIntersection.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIntersection.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIntersection.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseInverter.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseInverter.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseInverter.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseInverter.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseInvoke.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseInvoke.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseInvoke.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseInvoke.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsArguments.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsArguments.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsArguments.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsArguments.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsArrayBuffer.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsArrayBuffer.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsArrayBuffer.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsArrayBuffer.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsDate.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsDate.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsDate.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsDate.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsEqual.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsEqual.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsEqual.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsEqual.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsEqualDeep.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsEqualDeep.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsEqualDeep.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsEqualDeep.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsMap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsMap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsMap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsMap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsMatch.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsMatch.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsMatch.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsMatch.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsNaN.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsNaN.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsNaN.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsNaN.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsNative.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsNative.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsNative.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsNative.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsRegExp.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsRegExp.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsRegExp.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsRegExp.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsSet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsSet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsSet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsSet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsTypedArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsTypedArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsTypedArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIsTypedArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIteratee.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIteratee.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIteratee.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseIteratee.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseKeys.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseKeys.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseKeys.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseKeys.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseKeysIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseKeysIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseKeysIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseKeysIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseLodash.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseLodash.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseLodash.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseLodash.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseLt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseLt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseLt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseLt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMatches.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMatches.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMatches.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMatches.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMatchesProperty.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMatchesProperty.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMatchesProperty.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMatchesProperty.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMean.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMean.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMean.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMean.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMerge.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMerge.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMerge.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMerge.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMergeDeep.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMergeDeep.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMergeDeep.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseMergeDeep.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseNth.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseNth.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseNth.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseNth.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseOrderBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseOrderBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseOrderBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseOrderBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePick.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePick.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePick.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePick.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePickBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePickBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePickBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePickBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseProperty.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseProperty.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseProperty.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseProperty.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePropertyDeep.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePropertyDeep.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePropertyDeep.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePropertyDeep.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePropertyOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePropertyOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePropertyOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePropertyOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePullAll.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePullAll.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePullAll.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePullAll.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePullAt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePullAt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePullAt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_basePullAt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseRandom.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseRandom.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseRandom.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseRandom.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseRange.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseRange.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseRange.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseRange.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseReduce.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseReduce.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseReduce.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseReduce.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseRepeat.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseRepeat.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseRepeat.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseRepeat.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseRest.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseRest.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseRest.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseRest.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSample.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSample.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSample.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSample.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSampleSize.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSampleSize.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSampleSize.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSampleSize.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSetData.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSetData.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSetData.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSetData.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSetToString.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSetToString.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSetToString.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSetToString.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseShuffle.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseShuffle.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseShuffle.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseShuffle.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSlice.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSlice.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSlice.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSlice.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSome.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSome.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSome.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSome.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSortBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSortBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSortBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSortBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSortedIndex.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSortedIndex.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSortedIndex.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSortedIndex.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSortedIndexBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSortedIndexBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSortedIndexBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSortedIndexBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSortedUniq.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSortedUniq.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSortedUniq.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSortedUniq.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSum.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSum.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSum.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseSum.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseTimes.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseTimes.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseTimes.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseTimes.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseToNumber.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseToNumber.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseToNumber.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseToNumber.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseToPairs.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseToPairs.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseToPairs.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseToPairs.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseToString.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseToString.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseToString.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseToString.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseUnary.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseUnary.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseUnary.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseUnary.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseUniq.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseUniq.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseUniq.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseUniq.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseUnset.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseUnset.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseUnset.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseUnset.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseUpdate.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseUpdate.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseUpdate.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseUpdate.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseValues.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseValues.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseValues.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseValues.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseWhile.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseWhile.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseWhile.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseWhile.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseWrapperValue.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseWrapperValue.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseWrapperValue.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseWrapperValue.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseXor.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseXor.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseXor.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseXor.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseZipObject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseZipObject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseZipObject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_baseZipObject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cacheHas.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cacheHas.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cacheHas.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cacheHas.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castArrayLikeObject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castArrayLikeObject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castArrayLikeObject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castArrayLikeObject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castFunction.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castFunction.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castFunction.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castFunction.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castPath.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castPath.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castPath.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castPath.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castRest.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castRest.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castRest.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castRest.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castSlice.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castSlice.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castSlice.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_castSlice.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_charsEndIndex.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_charsEndIndex.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_charsEndIndex.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_charsEndIndex.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_charsStartIndex.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_charsStartIndex.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_charsStartIndex.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_charsStartIndex.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneArrayBuffer.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneArrayBuffer.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneArrayBuffer.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneArrayBuffer.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneBuffer.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneBuffer.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneBuffer.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneBuffer.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneDataView.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneDataView.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneDataView.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneDataView.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneRegExp.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneRegExp.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneRegExp.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneRegExp.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneSymbol.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneSymbol.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneSymbol.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneSymbol.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneTypedArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneTypedArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneTypedArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_cloneTypedArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_compareAscending.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_compareAscending.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_compareAscending.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_compareAscending.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_compareMultiple.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_compareMultiple.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_compareMultiple.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_compareMultiple.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_composeArgs.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_composeArgs.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_composeArgs.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_composeArgs.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_composeArgsRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_composeArgsRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_composeArgsRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_composeArgsRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_copyArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_copyArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_copyArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_copyArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_copyObject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_copyObject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_copyObject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_copyObject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_copySymbols.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_copySymbols.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_copySymbols.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_copySymbols.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_copySymbolsIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_copySymbolsIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_copySymbolsIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_copySymbolsIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_coreJsData.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_coreJsData.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_coreJsData.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_coreJsData.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_countHolders.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_countHolders.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_countHolders.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_countHolders.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createAggregator.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createAggregator.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createAggregator.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createAggregator.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createAssigner.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createAssigner.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createAssigner.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createAssigner.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createBaseEach.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createBaseEach.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createBaseEach.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createBaseEach.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createBaseFor.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createBaseFor.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createBaseFor.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createBaseFor.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createBind.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createBind.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createBind.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createBind.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createCaseFirst.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createCaseFirst.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createCaseFirst.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createCaseFirst.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createCompounder.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createCompounder.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createCompounder.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createCompounder.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createCtor.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createCtor.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createCtor.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createCtor.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createCurry.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createCurry.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createCurry.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createCurry.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createFind.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createFind.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createFind.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createFind.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createFlow.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createFlow.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createFlow.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createFlow.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createHybrid.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createHybrid.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createHybrid.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createHybrid.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createInverter.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createInverter.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createInverter.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createInverter.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createMathOperation.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createMathOperation.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createMathOperation.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createMathOperation.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createOver.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createOver.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createOver.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createOver.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createPadding.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createPadding.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createPadding.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createPadding.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createPartial.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createPartial.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createPartial.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createPartial.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createRange.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createRange.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createRange.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createRange.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createRecurry.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createRecurry.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createRecurry.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createRecurry.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createRelationalOperation.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createRelationalOperation.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createRelationalOperation.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createRelationalOperation.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createRound.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createRound.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createRound.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createRound.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createSet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createSet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createSet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createSet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createToPairs.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createToPairs.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createToPairs.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createToPairs.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createWrap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createWrap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createWrap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_createWrap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_customDefaultsAssignIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_customDefaultsAssignIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_customDefaultsAssignIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_customDefaultsAssignIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_customDefaultsMerge.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_customDefaultsMerge.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_customDefaultsMerge.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_customDefaultsMerge.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_customOmitClone.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_customOmitClone.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_customOmitClone.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_customOmitClone.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_deburrLetter.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_deburrLetter.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_deburrLetter.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_deburrLetter.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_defineProperty.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_defineProperty.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_defineProperty.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_defineProperty.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_equalArrays.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_equalArrays.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_equalArrays.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_equalArrays.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_equalByTag.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_equalByTag.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_equalByTag.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_equalByTag.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_equalObjects.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_equalObjects.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_equalObjects.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_equalObjects.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_escapeHtmlChar.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_escapeHtmlChar.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_escapeHtmlChar.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_escapeHtmlChar.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_escapeStringChar.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_escapeStringChar.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_escapeStringChar.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_escapeStringChar.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_flatRest.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_flatRest.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_flatRest.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_flatRest.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_freeGlobal.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_freeGlobal.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_freeGlobal.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_freeGlobal.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getAllKeys.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getAllKeys.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getAllKeys.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getAllKeys.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getAllKeysIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getAllKeysIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getAllKeysIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getAllKeysIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getData.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getData.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getData.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getData.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getFuncName.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getFuncName.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getFuncName.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getFuncName.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getHolder.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getHolder.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getHolder.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getHolder.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getMapData.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getMapData.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getMapData.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getMapData.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getMatchData.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getMatchData.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getMatchData.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getMatchData.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getNative.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getNative.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getNative.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getNative.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getPrototype.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getPrototype.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getPrototype.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getPrototype.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getRawTag.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getRawTag.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getRawTag.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getRawTag.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getSymbols.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getSymbols.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getSymbols.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getSymbols.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getSymbolsIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getSymbolsIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getSymbolsIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getSymbolsIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getTag.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getTag.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getTag.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getTag.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getValue.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getValue.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getValue.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getValue.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getView.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getView.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getView.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getView.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getWrapDetails.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getWrapDetails.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getWrapDetails.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_getWrapDetails.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hasPath.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hasPath.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hasPath.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hasPath.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hasUnicode.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hasUnicode.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hasUnicode.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hasUnicode.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hasUnicodeWord.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hasUnicodeWord.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hasUnicodeWord.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hasUnicodeWord.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashClear.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashClear.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashClear.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashClear.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashDelete.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashDelete.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashDelete.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashDelete.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashGet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashGet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashGet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashGet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashHas.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashHas.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashHas.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashHas.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashSet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashSet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashSet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_hashSet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_initCloneArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_initCloneArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_initCloneArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_initCloneArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_initCloneByTag.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_initCloneByTag.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_initCloneByTag.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_initCloneByTag.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_initCloneObject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_initCloneObject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_initCloneObject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_initCloneObject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_insertWrapDetails.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_insertWrapDetails.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_insertWrapDetails.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_insertWrapDetails.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isFlattenable.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isFlattenable.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isFlattenable.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isFlattenable.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isIndex.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isIndex.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isIndex.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isIndex.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isIterateeCall.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isIterateeCall.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isIterateeCall.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isIterateeCall.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isKey.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isKey.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isKey.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isKey.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isKeyable.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isKeyable.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isKeyable.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isKeyable.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isLaziable.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isLaziable.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isLaziable.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isLaziable.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isMaskable.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isMaskable.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isMaskable.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isMaskable.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isMasked.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isMasked.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isMasked.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isMasked.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isPrototype.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isPrototype.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isPrototype.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isPrototype.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isStrictComparable.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isStrictComparable.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isStrictComparable.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_isStrictComparable.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_iteratorToArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_iteratorToArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_iteratorToArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_iteratorToArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_lazyClone.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_lazyClone.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_lazyClone.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_lazyClone.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_lazyReverse.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_lazyReverse.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_lazyReverse.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_lazyReverse.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_lazyValue.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_lazyValue.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_lazyValue.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_lazyValue.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheClear.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheClear.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheClear.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheClear.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheDelete.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheDelete.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheDelete.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheDelete.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheGet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheGet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheGet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheGet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheHas.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheHas.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheHas.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheHas.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheSet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheSet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheSet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_listCacheSet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheClear.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheClear.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheClear.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheClear.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheDelete.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheDelete.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheDelete.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheDelete.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheGet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheGet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheGet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheGet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheHas.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheHas.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheHas.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheHas.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheSet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheSet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheSet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapCacheSet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapToArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapToArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapToArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mapToArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_matchesStrictComparable.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_matchesStrictComparable.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_matchesStrictComparable.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_matchesStrictComparable.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_memoizeCapped.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_memoizeCapped.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_memoizeCapped.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_memoizeCapped.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mergeData.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mergeData.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mergeData.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_mergeData.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_metaMap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_metaMap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_metaMap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_metaMap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_nativeCreate.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_nativeCreate.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_nativeCreate.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_nativeCreate.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_nativeKeys.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_nativeKeys.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_nativeKeys.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_nativeKeys.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_nativeKeysIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_nativeKeysIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_nativeKeysIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_nativeKeysIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_nodeUtil.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_nodeUtil.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_nodeUtil.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_nodeUtil.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_objectToString.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_objectToString.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_objectToString.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_objectToString.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_overArg.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_overArg.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_overArg.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_overArg.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_overRest.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_overRest.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_overRest.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_overRest.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_parent.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_parent.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_parent.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_parent.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_reEscape.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_reEscape.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_reEscape.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_reEscape.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_reEvaluate.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_reEvaluate.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_reEvaluate.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_reEvaluate.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_reInterpolate.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_reInterpolate.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_reInterpolate.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_reInterpolate.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_realNames.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_realNames.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_realNames.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_realNames.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_reorder.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_reorder.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_reorder.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_reorder.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_replaceHolders.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_replaceHolders.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_replaceHolders.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_replaceHolders.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_root.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_root.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_root.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_root.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_safeGet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_safeGet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_safeGet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_safeGet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setCacheAdd.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setCacheAdd.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setCacheAdd.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setCacheAdd.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setCacheHas.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setCacheHas.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setCacheHas.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setCacheHas.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setData.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setData.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setData.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setData.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setToArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setToArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setToArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setToArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setToPairs.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setToPairs.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setToPairs.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setToPairs.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setToString.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setToString.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setToString.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setToString.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setWrapToString.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setWrapToString.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setWrapToString.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_setWrapToString.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_shortOut.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_shortOut.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_shortOut.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_shortOut.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_shuffleSelf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_shuffleSelf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_shuffleSelf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_shuffleSelf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackClear.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackClear.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackClear.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackClear.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackDelete.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackDelete.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackDelete.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackDelete.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackGet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackGet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackGet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackGet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackHas.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackHas.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackHas.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackHas.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackSet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackSet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackSet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stackSet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_strictIndexOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_strictIndexOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_strictIndexOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_strictIndexOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_strictLastIndexOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_strictLastIndexOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_strictLastIndexOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_strictLastIndexOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stringSize.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stringSize.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stringSize.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stringSize.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stringToArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stringToArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stringToArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stringToArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stringToPath.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stringToPath.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stringToPath.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_stringToPath.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_toKey.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_toKey.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_toKey.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_toKey.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_toSource.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_toSource.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_toSource.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_toSource.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_unescapeHtmlChar.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_unescapeHtmlChar.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_unescapeHtmlChar.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_unescapeHtmlChar.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_unicodeSize.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_unicodeSize.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_unicodeSize.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_unicodeSize.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_unicodeToArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_unicodeToArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_unicodeToArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_unicodeToArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_unicodeWords.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_unicodeWords.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_unicodeWords.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_unicodeWords.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_updateWrapDetails.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_updateWrapDetails.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_updateWrapDetails.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_updateWrapDetails.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_wrapperClone.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_wrapperClone.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/_wrapperClone.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/_wrapperClone.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/add.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/add.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/add.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/add.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/after.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/after.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/after.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/after.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/array.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/array.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/array.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/array.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/ary.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/ary.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/ary.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/ary.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/assign.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/assign.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/assign.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/assign.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/assignIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/assignIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/assignIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/assignIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/assignInWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/assignInWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/assignInWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/assignInWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/assignWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/assignWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/assignWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/assignWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/at.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/at.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/at.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/at.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/attempt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/attempt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/attempt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/attempt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/before.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/before.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/before.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/before.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/bind.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/bind.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/bind.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/bind.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/bindAll.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/bindAll.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/bindAll.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/bindAll.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/bindKey.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/bindKey.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/bindKey.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/bindKey.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/camelCase.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/camelCase.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/camelCase.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/camelCase.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/capitalize.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/capitalize.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/capitalize.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/capitalize.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/castArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/castArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/castArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/castArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/ceil.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/ceil.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/ceil.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/ceil.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/chain.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/chain.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/chain.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/chain.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/chunk.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/chunk.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/chunk.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/chunk.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/clamp.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/clamp.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/clamp.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/clamp.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/clone.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/clone.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/clone.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/clone.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/cloneDeep.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/cloneDeep.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/cloneDeep.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/cloneDeep.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/cloneDeepWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/cloneDeepWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/cloneDeepWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/cloneDeepWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/cloneWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/cloneWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/cloneWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/cloneWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/collection.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/collection.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/collection.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/collection.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/commit.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/commit.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/commit.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/commit.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/compact.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/compact.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/compact.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/compact.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/concat.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/concat.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/concat.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/concat.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/cond.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/cond.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/cond.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/cond.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/conforms.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/conforms.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/conforms.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/conforms.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/conformsTo.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/conformsTo.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/conformsTo.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/conformsTo.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/constant.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/constant.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/constant.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/constant.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/core.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/core.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/core.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/core.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/core.min.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/core.min.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/core.min.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/core.min.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/countBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/countBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/countBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/countBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/create.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/create.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/create.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/create.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/curry.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/curry.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/curry.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/curry.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/curryRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/curryRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/curryRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/curryRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/date.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/date.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/date.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/date.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/debounce.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/debounce.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/debounce.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/debounce.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/deburr.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/deburr.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/deburr.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/deburr.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/defaultTo.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/defaultTo.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/defaultTo.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/defaultTo.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/defaults.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/defaults.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/defaults.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/defaults.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/defaultsDeep.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/defaultsDeep.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/defaultsDeep.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/defaultsDeep.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/defer.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/defer.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/defer.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/defer.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/delay.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/delay.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/delay.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/delay.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/difference.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/difference.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/difference.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/difference.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/differenceBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/differenceBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/differenceBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/differenceBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/differenceWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/differenceWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/differenceWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/differenceWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/divide.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/divide.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/divide.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/divide.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/drop.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/drop.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/drop.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/drop.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/dropRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/dropRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/dropRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/dropRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/dropRightWhile.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/dropRightWhile.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/dropRightWhile.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/dropRightWhile.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/dropWhile.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/dropWhile.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/dropWhile.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/dropWhile.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/each.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/each.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/each.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/each.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/eachRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/eachRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/eachRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/eachRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/endsWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/endsWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/endsWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/endsWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/entries.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/entries.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/entries.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/entries.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/entriesIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/entriesIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/entriesIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/entriesIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/eq.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/eq.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/eq.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/eq.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/escape.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/escape.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/escape.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/escape.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/escapeRegExp.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/escapeRegExp.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/escapeRegExp.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/escapeRegExp.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/every.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/every.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/every.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/every.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/extend.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/extend.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/extend.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/extend.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/extendWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/extendWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/extendWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/extendWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fill.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fill.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fill.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fill.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/filter.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/filter.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/filter.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/filter.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/find.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/find.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/find.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/find.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/findIndex.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/findIndex.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/findIndex.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/findIndex.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/findKey.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/findKey.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/findKey.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/findKey.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/findLast.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/findLast.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/findLast.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/findLast.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/findLastIndex.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/findLastIndex.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/findLastIndex.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/findLastIndex.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/findLastKey.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/findLastKey.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/findLastKey.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/findLastKey.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/first.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/first.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/first.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/first.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flatMap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flatMap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flatMap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flatMap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flatMapDeep.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flatMapDeep.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flatMapDeep.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flatMapDeep.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flatMapDepth.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flatMapDepth.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flatMapDepth.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flatMapDepth.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flatten.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flatten.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flatten.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flatten.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flattenDeep.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flattenDeep.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flattenDeep.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flattenDeep.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flattenDepth.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flattenDepth.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flattenDepth.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flattenDepth.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flip.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flip.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flip.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flip.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/floor.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/floor.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/floor.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/floor.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flow.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flow.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flow.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flow.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flowRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flowRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/flowRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/flowRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/forEach.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/forEach.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/forEach.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/forEach.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/forEachRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/forEachRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/forEachRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/forEachRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/forIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/forIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/forIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/forIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/forInRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/forInRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/forInRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/forInRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/forOwn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/forOwn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/forOwn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/forOwn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/forOwnRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/forOwnRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/forOwnRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/forOwnRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/F.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/F.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/F.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/F.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/T.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/T.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/T.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/T.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/__.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/__.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/__.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/__.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_baseConvert.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_baseConvert.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_baseConvert.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_baseConvert.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_convertBrowser.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_convertBrowser.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_convertBrowser.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_convertBrowser.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_falseOptions.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_falseOptions.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_falseOptions.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_falseOptions.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_mapping.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_mapping.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_mapping.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_mapping.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_util.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_util.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_util.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/_util.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/add.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/add.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/add.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/add.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/after.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/after.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/after.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/after.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/all.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/all.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/all.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/all.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/allPass.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/allPass.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/allPass.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/allPass.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/always.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/always.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/always.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/always.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/any.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/any.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/any.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/any.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/anyPass.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/anyPass.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/anyPass.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/anyPass.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/apply.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/apply.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/apply.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/apply.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/array.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/array.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/array.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/array.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/ary.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/ary.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/ary.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/ary.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assign.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assign.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assign.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assign.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignAll.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignAll.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignAll.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignAll.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignAllWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignAllWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignAllWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignAllWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignInAll.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignInAll.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignInAll.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignInAll.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignInAllWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignInAllWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignInAllWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignInAllWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignInWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignInWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignInWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignInWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assignWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assoc.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assoc.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assoc.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assoc.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assocPath.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assocPath.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assocPath.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/assocPath.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/at.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/at.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/at.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/at.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/attempt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/attempt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/attempt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/attempt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/before.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/before.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/before.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/before.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/bind.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/bind.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/bind.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/bind.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/bindAll.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/bindAll.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/bindAll.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/bindAll.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/bindKey.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/bindKey.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/bindKey.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/bindKey.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/camelCase.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/camelCase.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/camelCase.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/camelCase.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/capitalize.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/capitalize.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/capitalize.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/capitalize.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/castArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/castArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/castArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/castArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/ceil.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/ceil.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/ceil.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/ceil.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/chain.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/chain.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/chain.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/chain.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/chunk.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/chunk.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/chunk.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/chunk.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/clamp.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/clamp.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/clamp.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/clamp.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/clone.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/clone.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/clone.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/clone.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/cloneDeep.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/cloneDeep.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/cloneDeep.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/cloneDeep.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/cloneDeepWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/cloneDeepWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/cloneDeepWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/cloneDeepWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/cloneWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/cloneWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/cloneWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/cloneWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/collection.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/collection.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/collection.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/collection.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/commit.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/commit.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/commit.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/commit.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/compact.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/compact.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/compact.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/compact.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/complement.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/complement.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/complement.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/complement.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/compose.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/compose.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/compose.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/compose.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/concat.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/concat.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/concat.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/concat.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/cond.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/cond.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/cond.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/cond.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/conforms.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/conforms.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/conforms.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/conforms.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/conformsTo.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/conformsTo.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/conformsTo.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/conformsTo.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/constant.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/constant.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/constant.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/constant.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/contains.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/contains.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/contains.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/contains.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/convert.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/convert.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/convert.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/convert.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/countBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/countBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/countBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/countBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/create.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/create.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/create.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/create.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/curry.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/curry.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/curry.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/curry.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/curryN.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/curryN.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/curryN.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/curryN.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/curryRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/curryRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/curryRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/curryRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/curryRightN.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/curryRightN.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/curryRightN.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/curryRightN.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/date.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/date.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/date.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/date.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/debounce.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/debounce.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/debounce.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/debounce.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/deburr.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/deburr.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/deburr.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/deburr.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaultTo.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaultTo.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaultTo.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaultTo.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaults.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaults.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaults.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaults.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaultsAll.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaultsAll.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaultsAll.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaultsAll.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaultsDeep.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaultsDeep.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaultsDeep.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaultsDeep.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaultsDeepAll.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaultsDeepAll.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaultsDeepAll.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defaultsDeepAll.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defer.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defer.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defer.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/defer.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/delay.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/delay.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/delay.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/delay.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/difference.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/difference.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/difference.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/difference.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/differenceBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/differenceBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/differenceBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/differenceBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/differenceWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/differenceWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/differenceWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/differenceWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dissoc.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dissoc.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dissoc.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dissoc.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dissocPath.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dissocPath.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dissocPath.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dissocPath.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/divide.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/divide.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/divide.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/divide.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/drop.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/drop.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/drop.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/drop.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropLast.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropLast.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropLast.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropLast.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropLastWhile.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropLastWhile.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropLastWhile.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropLastWhile.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropRightWhile.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropRightWhile.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropRightWhile.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropRightWhile.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropWhile.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropWhile.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropWhile.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/dropWhile.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/each.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/each.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/each.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/each.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/eachRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/eachRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/eachRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/eachRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/endsWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/endsWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/endsWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/endsWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/entries.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/entries.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/entries.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/entries.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/entriesIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/entriesIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/entriesIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/entriesIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/eq.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/eq.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/eq.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/eq.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/equals.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/equals.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/equals.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/equals.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/escape.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/escape.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/escape.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/escape.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/escapeRegExp.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/escapeRegExp.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/escapeRegExp.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/escapeRegExp.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/every.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/every.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/every.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/every.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/extend.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/extend.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/extend.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/extend.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/extendAll.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/extendAll.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/extendAll.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/extendAll.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/extendAllWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/extendAllWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/extendAllWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/extendAllWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/extendWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/extendWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/extendWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/extendWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/fill.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/fill.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/fill.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/fill.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/filter.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/filter.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/filter.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/filter.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/find.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/find.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/find.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/find.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findFrom.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findFrom.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findFrom.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findFrom.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findIndex.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findIndex.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findIndex.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findIndex.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findIndexFrom.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findIndexFrom.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findIndexFrom.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findIndexFrom.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findKey.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findKey.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findKey.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findKey.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLast.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLast.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLast.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLast.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLastFrom.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLastFrom.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLastFrom.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLastFrom.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLastIndex.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLastIndex.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLastIndex.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLastIndex.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLastIndexFrom.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLastIndexFrom.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLastIndexFrom.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLastIndexFrom.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLastKey.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLastKey.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLastKey.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/findLastKey.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/first.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/first.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/first.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/first.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flatMap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flatMap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flatMap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flatMap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flatMapDeep.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flatMapDeep.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flatMapDeep.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flatMapDeep.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flatMapDepth.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flatMapDepth.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flatMapDepth.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flatMapDepth.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flatten.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flatten.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flatten.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flatten.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flattenDeep.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flattenDeep.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flattenDeep.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flattenDeep.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flattenDepth.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flattenDepth.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flattenDepth.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flattenDepth.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flip.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flip.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flip.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flip.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/floor.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/floor.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/floor.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/floor.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flow.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flow.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flow.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flow.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flowRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flowRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flowRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/flowRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forEach.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forEach.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forEach.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forEach.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forEachRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forEachRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forEachRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forEachRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forInRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forInRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forInRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forInRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forOwn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forOwn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forOwn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forOwn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forOwnRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forOwnRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forOwnRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/forOwnRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/fromPairs.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/fromPairs.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/fromPairs.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/fromPairs.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/function.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/function.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/function.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/function.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/functions.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/functions.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/functions.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/functions.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/functionsIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/functionsIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/functionsIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/functionsIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/get.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/get.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/get.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/get.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/getOr.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/getOr.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/getOr.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/getOr.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/groupBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/groupBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/groupBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/groupBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/gt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/gt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/gt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/gt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/gte.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/gte.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/gte.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/gte.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/has.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/has.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/has.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/has.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/hasIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/hasIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/hasIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/hasIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/head.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/head.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/head.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/head.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/identical.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/identical.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/identical.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/identical.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/identity.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/identity.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/identity.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/identity.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/inRange.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/inRange.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/inRange.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/inRange.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/includes.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/includes.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/includes.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/includes.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/includesFrom.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/includesFrom.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/includesFrom.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/includesFrom.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/indexBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/indexBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/indexBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/indexBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/indexOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/indexOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/indexOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/indexOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/indexOfFrom.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/indexOfFrom.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/indexOfFrom.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/indexOfFrom.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/init.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/init.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/init.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/init.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/initial.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/initial.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/initial.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/initial.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/intersection.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/intersection.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/intersection.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/intersection.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/intersectionBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/intersectionBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/intersectionBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/intersectionBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/intersectionWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/intersectionWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/intersectionWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/intersectionWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invert.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invert.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invert.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invert.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invertBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invertBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invertBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invertBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invertObj.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invertObj.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invertObj.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invertObj.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invoke.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invoke.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invoke.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invoke.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invokeArgs.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invokeArgs.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invokeArgs.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invokeArgs.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invokeArgsMap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invokeArgsMap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invokeArgsMap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invokeArgsMap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invokeMap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invokeMap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invokeMap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/invokeMap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArguments.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArguments.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArguments.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArguments.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArrayBuffer.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArrayBuffer.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArrayBuffer.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArrayBuffer.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArrayLike.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArrayLike.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArrayLike.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArrayLike.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArrayLikeObject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArrayLikeObject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArrayLikeObject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isArrayLikeObject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isBoolean.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isBoolean.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isBoolean.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isBoolean.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isBuffer.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isBuffer.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isBuffer.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isBuffer.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isDate.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isDate.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isDate.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isDate.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isElement.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isElement.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isElement.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isElement.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isEmpty.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isEmpty.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isEmpty.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isEmpty.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isEqual.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isEqual.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isEqual.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isEqual.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isEqualWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isEqualWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isEqualWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isEqualWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isError.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isError.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isError.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isError.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isFinite.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isFinite.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isFinite.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isFinite.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isFunction.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isFunction.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isFunction.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isFunction.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isInteger.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isInteger.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isInteger.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isInteger.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isLength.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isLength.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isLength.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isLength.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isMap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isMap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isMap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isMap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isMatch.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isMatch.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isMatch.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isMatch.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isMatchWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isMatchWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isMatchWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isMatchWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNaN.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNaN.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNaN.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNaN.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNative.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNative.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNative.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNative.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNil.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNil.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNil.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNil.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNull.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNull.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNull.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNull.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNumber.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNumber.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNumber.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isNumber.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isObject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isObject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isObject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isObject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isObjectLike.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isObjectLike.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isObjectLike.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isObjectLike.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isPlainObject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isPlainObject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isPlainObject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isPlainObject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isRegExp.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isRegExp.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isRegExp.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isRegExp.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isSafeInteger.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isSafeInteger.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isSafeInteger.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isSafeInteger.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isSet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isSet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isSet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isSet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isString.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isString.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isString.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isString.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isSymbol.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isSymbol.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isSymbol.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isSymbol.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isTypedArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isTypedArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isTypedArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isTypedArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isUndefined.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isUndefined.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isUndefined.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isUndefined.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isWeakMap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isWeakMap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isWeakMap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isWeakMap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isWeakSet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isWeakSet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isWeakSet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/isWeakSet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/iteratee.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/iteratee.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/iteratee.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/iteratee.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/join.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/join.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/join.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/join.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/juxt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/juxt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/juxt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/juxt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/kebabCase.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/kebabCase.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/kebabCase.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/kebabCase.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/keyBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/keyBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/keyBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/keyBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/keys.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/keys.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/keys.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/keys.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/keysIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/keysIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/keysIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/keysIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lang.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lang.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lang.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lang.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/last.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/last.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/last.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/last.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lastIndexOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lastIndexOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lastIndexOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lastIndexOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lastIndexOfFrom.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lastIndexOfFrom.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lastIndexOfFrom.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lastIndexOfFrom.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lowerCase.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lowerCase.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lowerCase.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lowerCase.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lowerFirst.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lowerFirst.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lowerFirst.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lowerFirst.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lte.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lte.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lte.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/lte.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/map.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/map.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/map.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/map.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mapKeys.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mapKeys.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mapKeys.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mapKeys.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mapValues.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mapValues.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mapValues.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mapValues.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/matches.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/matches.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/matches.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/matches.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/matchesProperty.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/matchesProperty.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/matchesProperty.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/matchesProperty.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/math.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/math.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/math.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/math.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/max.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/max.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/max.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/max.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/maxBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/maxBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/maxBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/maxBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mean.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mean.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mean.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mean.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/meanBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/meanBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/meanBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/meanBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/memoize.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/memoize.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/memoize.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/memoize.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/merge.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/merge.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/merge.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/merge.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mergeAll.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mergeAll.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mergeAll.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mergeAll.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mergeAllWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mergeAllWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mergeAllWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mergeAllWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mergeWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mergeWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mergeWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mergeWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/method.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/method.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/method.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/method.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/methodOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/methodOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/methodOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/methodOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/min.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/min.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/min.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/min.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/minBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/minBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/minBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/minBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mixin.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mixin.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mixin.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/mixin.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/multiply.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/multiply.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/multiply.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/multiply.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/nAry.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/nAry.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/nAry.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/nAry.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/negate.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/negate.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/negate.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/negate.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/next.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/next.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/next.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/next.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/noop.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/noop.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/noop.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/noop.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/now.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/now.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/now.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/now.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/nth.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/nth.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/nth.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/nth.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/nthArg.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/nthArg.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/nthArg.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/nthArg.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/number.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/number.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/number.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/number.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/object.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/object.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/object.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/object.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/omit.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/omit.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/omit.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/omit.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/omitAll.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/omitAll.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/omitAll.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/omitAll.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/omitBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/omitBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/omitBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/omitBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/once.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/once.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/once.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/once.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/orderBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/orderBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/orderBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/orderBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/over.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/over.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/over.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/over.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/overArgs.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/overArgs.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/overArgs.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/overArgs.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/overEvery.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/overEvery.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/overEvery.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/overEvery.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/overSome.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/overSome.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/overSome.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/overSome.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pad.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pad.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pad.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pad.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padChars.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padChars.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padChars.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padChars.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padCharsEnd.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padCharsEnd.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padCharsEnd.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padCharsEnd.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padCharsStart.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padCharsStart.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padCharsStart.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padCharsStart.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padEnd.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padEnd.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padEnd.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padEnd.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padStart.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padStart.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padStart.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/padStart.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/parseInt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/parseInt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/parseInt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/parseInt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/partial.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/partial.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/partial.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/partial.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/partialRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/partialRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/partialRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/partialRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/partition.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/partition.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/partition.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/partition.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/path.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/path.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/path.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/path.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pathEq.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pathEq.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pathEq.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pathEq.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pathOr.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pathOr.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pathOr.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pathOr.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/paths.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/paths.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/paths.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/paths.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pick.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pick.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pick.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pick.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pickAll.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pickAll.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pickAll.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pickAll.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pickBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pickBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pickBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pickBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pipe.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pipe.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pipe.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pipe.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/placeholder.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/placeholder.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/placeholder.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/placeholder.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/plant.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/plant.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/plant.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/plant.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pluck.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pluck.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pluck.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pluck.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/prop.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/prop.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/prop.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/prop.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/propEq.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/propEq.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/propEq.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/propEq.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/propOr.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/propOr.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/propOr.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/propOr.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/property.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/property.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/property.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/property.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/propertyOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/propertyOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/propertyOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/propertyOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/props.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/props.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/props.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/props.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pull.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pull.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pull.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pull.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pullAll.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pullAll.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pullAll.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pullAll.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pullAllBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pullAllBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pullAllBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pullAllBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pullAllWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pullAllWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pullAllWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pullAllWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pullAt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pullAt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pullAt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/pullAt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/random.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/random.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/random.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/random.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/range.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/range.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/range.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/range.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rangeRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rangeRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rangeRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rangeRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rangeStep.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rangeStep.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rangeStep.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rangeStep.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rangeStepRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rangeStepRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rangeStepRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rangeStepRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rearg.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rearg.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rearg.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rearg.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/reduce.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/reduce.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/reduce.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/reduce.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/reduceRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/reduceRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/reduceRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/reduceRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/reject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/reject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/reject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/reject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/remove.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/remove.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/remove.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/remove.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/repeat.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/repeat.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/repeat.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/repeat.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/replace.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/replace.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/replace.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/replace.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rest.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rest.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rest.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/rest.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/restFrom.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/restFrom.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/restFrom.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/restFrom.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/result.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/result.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/result.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/result.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/reverse.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/reverse.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/reverse.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/reverse.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/round.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/round.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/round.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/round.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sample.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sample.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sample.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sample.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sampleSize.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sampleSize.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sampleSize.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sampleSize.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/seq.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/seq.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/seq.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/seq.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/set.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/set.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/set.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/set.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/setWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/setWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/setWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/setWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/shuffle.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/shuffle.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/shuffle.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/shuffle.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/size.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/size.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/size.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/size.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/slice.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/slice.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/slice.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/slice.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/snakeCase.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/snakeCase.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/snakeCase.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/snakeCase.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/some.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/some.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/some.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/some.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedIndex.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedIndex.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedIndex.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedIndex.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedIndexBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedIndexBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedIndexBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedIndexBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedIndexOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedIndexOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedIndexOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedIndexOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedLastIndex.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedLastIndex.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedLastIndex.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedLastIndex.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedLastIndexBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedLastIndexBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedLastIndexBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedLastIndexBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedLastIndexOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedLastIndexOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedLastIndexOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedLastIndexOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedUniq.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedUniq.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedUniq.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedUniq.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedUniqBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedUniqBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedUniqBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sortedUniqBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/split.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/split.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/split.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/split.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/spread.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/spread.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/spread.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/spread.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/spreadFrom.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/spreadFrom.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/spreadFrom.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/spreadFrom.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/startCase.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/startCase.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/startCase.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/startCase.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/startsWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/startsWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/startsWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/startsWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/string.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/string.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/string.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/string.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubFalse.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubFalse.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubFalse.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubFalse.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubObject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubObject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubObject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubObject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubString.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubString.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubString.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubString.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubTrue.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubTrue.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubTrue.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/stubTrue.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/subtract.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/subtract.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/subtract.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/subtract.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sum.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sum.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sum.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sum.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sumBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sumBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sumBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/sumBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/symmetricDifference.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/symmetricDifference.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/symmetricDifference.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/symmetricDifference.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/symmetricDifferenceBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/symmetricDifferenceBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/symmetricDifferenceBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/symmetricDifferenceBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/symmetricDifferenceWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/symmetricDifferenceWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/symmetricDifferenceWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/symmetricDifferenceWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/tail.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/tail.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/tail.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/tail.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/take.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/take.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/take.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/take.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeLast.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeLast.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeLast.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeLast.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeLastWhile.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeLastWhile.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeLastWhile.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeLastWhile.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeRightWhile.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeRightWhile.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeRightWhile.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeRightWhile.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeWhile.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeWhile.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeWhile.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/takeWhile.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/tap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/tap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/tap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/tap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/template.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/template.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/template.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/template.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/templateSettings.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/templateSettings.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/templateSettings.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/templateSettings.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/throttle.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/throttle.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/throttle.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/throttle.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/thru.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/thru.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/thru.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/thru.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/times.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/times.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/times.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/times.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toFinite.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toFinite.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toFinite.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toFinite.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toInteger.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toInteger.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toInteger.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toInteger.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toIterator.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toIterator.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toIterator.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toIterator.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toJSON.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toJSON.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toJSON.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toJSON.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toLength.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toLength.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toLength.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toLength.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toLower.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toLower.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toLower.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toLower.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toNumber.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toNumber.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toNumber.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toNumber.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toPairs.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toPairs.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toPairs.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toPairs.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toPairsIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toPairsIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toPairsIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toPairsIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toPath.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toPath.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toPath.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toPath.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toPlainObject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toPlainObject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toPlainObject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toPlainObject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toSafeInteger.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toSafeInteger.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toSafeInteger.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toSafeInteger.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toString.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toString.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toString.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toString.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toUpper.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toUpper.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toUpper.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/toUpper.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/transform.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/transform.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/transform.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/transform.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trim.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trim.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trim.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trim.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimChars.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimChars.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimChars.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimChars.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimCharsEnd.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimCharsEnd.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimCharsEnd.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimCharsEnd.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimCharsStart.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimCharsStart.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimCharsStart.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimCharsStart.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimEnd.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimEnd.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimEnd.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimEnd.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimStart.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimStart.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimStart.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/trimStart.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/truncate.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/truncate.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/truncate.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/truncate.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unapply.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unapply.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unapply.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unapply.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unary.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unary.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unary.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unary.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unescape.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unescape.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unescape.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unescape.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/union.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/union.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/union.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/union.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unionBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unionBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unionBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unionBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unionWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unionWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unionWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unionWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/uniq.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/uniq.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/uniq.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/uniq.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/uniqBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/uniqBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/uniqBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/uniqBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/uniqWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/uniqWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/uniqWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/uniqWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/uniqueId.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/uniqueId.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/uniqueId.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/uniqueId.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unnest.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unnest.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unnest.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unnest.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unset.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unset.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unset.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unset.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unzip.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unzip.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unzip.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unzip.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unzipWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unzipWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unzipWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/unzipWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/update.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/update.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/update.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/update.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/updateWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/updateWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/updateWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/updateWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/upperCase.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/upperCase.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/upperCase.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/upperCase.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/upperFirst.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/upperFirst.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/upperFirst.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/upperFirst.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/useWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/useWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/useWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/useWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/util.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/util.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/util.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/util.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/value.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/value.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/value.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/value.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/valueOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/valueOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/valueOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/valueOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/values.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/values.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/values.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/values.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/valuesIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/valuesIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/valuesIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/valuesIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/where.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/where.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/where.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/where.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/whereEq.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/whereEq.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/whereEq.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/whereEq.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/without.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/without.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/without.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/without.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/words.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/words.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/words.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/words.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperAt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperAt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperAt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperAt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperChain.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperChain.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperChain.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperChain.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperLodash.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperLodash.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperLodash.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperLodash.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperReverse.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperReverse.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperReverse.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperReverse.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperValue.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperValue.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperValue.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/wrapperValue.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/xor.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/xor.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/xor.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/xor.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/xorBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/xorBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/xorBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/xorBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/xorWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/xorWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/xorWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/xorWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zip.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zip.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zip.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zip.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipAll.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipAll.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipAll.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipAll.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipObj.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipObj.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipObj.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipObj.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipObject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipObject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipObject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipObject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipObjectDeep.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipObjectDeep.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipObjectDeep.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipObjectDeep.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fp/zipWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fromPairs.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fromPairs.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/fromPairs.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/fromPairs.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/function.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/function.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/function.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/function.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/functions.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/functions.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/functions.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/functions.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/functionsIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/functionsIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/functionsIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/functionsIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/get.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/get.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/get.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/get.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/groupBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/groupBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/groupBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/groupBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/gt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/gt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/gt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/gt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/gte.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/gte.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/gte.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/gte.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/has.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/has.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/has.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/has.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/hasIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/hasIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/hasIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/hasIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/head.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/head.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/head.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/head.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/identity.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/identity.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/identity.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/identity.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/inRange.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/inRange.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/inRange.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/inRange.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/includes.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/includes.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/includes.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/includes.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/index.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/index.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/index.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/index.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/indexOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/indexOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/indexOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/indexOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/initial.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/initial.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/initial.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/initial.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/intersection.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/intersection.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/intersection.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/intersection.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/intersectionBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/intersectionBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/intersectionBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/intersectionBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/intersectionWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/intersectionWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/intersectionWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/intersectionWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/invert.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/invert.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/invert.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/invert.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/invertBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/invertBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/invertBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/invertBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/invoke.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/invoke.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/invoke.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/invoke.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/invokeMap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/invokeMap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/invokeMap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/invokeMap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArguments.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArguments.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArguments.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArguments.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArrayBuffer.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArrayBuffer.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArrayBuffer.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArrayBuffer.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArrayLike.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArrayLike.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArrayLike.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArrayLike.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArrayLikeObject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArrayLikeObject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArrayLikeObject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isArrayLikeObject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isBoolean.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isBoolean.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isBoolean.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isBoolean.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isBuffer.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isBuffer.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isBuffer.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isBuffer.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isDate.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isDate.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isDate.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isDate.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isElement.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isElement.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isElement.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isElement.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isEmpty.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isEmpty.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isEmpty.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isEmpty.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isEqual.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isEqual.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isEqual.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isEqual.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isEqualWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isEqualWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isEqualWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isEqualWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isError.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isError.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isError.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isError.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isFinite.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isFinite.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isFinite.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isFinite.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isFunction.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isFunction.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isFunction.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isFunction.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isInteger.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isInteger.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isInteger.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isInteger.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isLength.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isLength.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isLength.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isLength.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isMap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isMap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isMap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isMap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isMatch.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isMatch.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isMatch.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isMatch.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isMatchWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isMatchWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isMatchWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isMatchWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNaN.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNaN.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNaN.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNaN.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNative.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNative.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNative.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNative.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNil.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNil.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNil.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNil.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNull.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNull.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNull.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNull.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNumber.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNumber.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNumber.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isNumber.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isObject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isObject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isObject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isObject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isObjectLike.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isObjectLike.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isObjectLike.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isObjectLike.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isPlainObject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isPlainObject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isPlainObject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isPlainObject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isRegExp.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isRegExp.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isRegExp.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isRegExp.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isSafeInteger.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isSafeInteger.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isSafeInteger.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isSafeInteger.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isSet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isSet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isSet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isSet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isString.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isString.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isString.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isString.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isSymbol.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isSymbol.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isSymbol.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isSymbol.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isTypedArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isTypedArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isTypedArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isTypedArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isUndefined.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isUndefined.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isUndefined.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isUndefined.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isWeakMap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isWeakMap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isWeakMap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isWeakMap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isWeakSet.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isWeakSet.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/isWeakSet.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/isWeakSet.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/iteratee.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/iteratee.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/iteratee.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/iteratee.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/join.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/join.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/join.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/join.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/kebabCase.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/kebabCase.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/kebabCase.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/kebabCase.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/keyBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/keyBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/keyBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/keyBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/keys.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/keys.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/keys.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/keys.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/keysIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/keysIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/keysIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/keysIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/lang.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/lang.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/lang.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/lang.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/last.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/last.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/last.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/last.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/lastIndexOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/lastIndexOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/lastIndexOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/lastIndexOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/lodash.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/lodash.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/lodash.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/lodash.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/lodash.min.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/lodash.min.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/lodash.min.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/lodash.min.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/lowerCase.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/lowerCase.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/lowerCase.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/lowerCase.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/lowerFirst.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/lowerFirst.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/lowerFirst.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/lowerFirst.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/lt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/lt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/lt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/lt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/lte.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/lte.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/lte.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/lte.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/map.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/map.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/map.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/map.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/mapKeys.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/mapKeys.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/mapKeys.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/mapKeys.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/mapValues.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/mapValues.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/mapValues.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/mapValues.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/matches.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/matches.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/matches.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/matches.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/matchesProperty.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/matchesProperty.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/matchesProperty.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/matchesProperty.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/math.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/math.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/math.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/math.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/max.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/max.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/max.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/max.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/maxBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/maxBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/maxBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/maxBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/mean.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/mean.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/mean.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/mean.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/meanBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/meanBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/meanBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/meanBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/memoize.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/memoize.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/memoize.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/memoize.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/merge.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/merge.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/merge.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/merge.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/mergeWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/mergeWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/mergeWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/mergeWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/method.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/method.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/method.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/method.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/methodOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/methodOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/methodOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/methodOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/min.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/min.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/min.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/min.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/minBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/minBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/minBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/minBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/mixin.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/mixin.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/mixin.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/mixin.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/multiply.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/multiply.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/multiply.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/multiply.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/negate.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/negate.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/negate.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/negate.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/next.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/next.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/next.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/next.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/noop.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/noop.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/noop.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/noop.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/now.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/now.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/now.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/now.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/nth.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/nth.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/nth.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/nth.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/nthArg.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/nthArg.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/nthArg.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/nthArg.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/number.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/number.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/number.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/number.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/object.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/object.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/object.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/object.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/omit.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/omit.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/omit.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/omit.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/omitBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/omitBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/omitBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/omitBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/once.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/once.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/once.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/once.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/orderBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/orderBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/orderBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/orderBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/over.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/over.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/over.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/over.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/overArgs.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/overArgs.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/overArgs.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/overArgs.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/overEvery.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/overEvery.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/overEvery.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/overEvery.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/overSome.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/overSome.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/overSome.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/overSome.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/package.json b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/package.json similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/package.json rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/package.json diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/pad.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/pad.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/pad.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/pad.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/padEnd.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/padEnd.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/padEnd.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/padEnd.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/padStart.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/padStart.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/padStart.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/padStart.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/parseInt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/parseInt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/parseInt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/parseInt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/partial.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/partial.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/partial.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/partial.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/partialRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/partialRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/partialRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/partialRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/partition.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/partition.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/partition.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/partition.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/pick.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/pick.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/pick.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/pick.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/pickBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/pickBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/pickBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/pickBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/plant.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/plant.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/plant.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/plant.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/property.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/property.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/property.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/property.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/propertyOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/propertyOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/propertyOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/propertyOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/pull.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/pull.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/pull.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/pull.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/pullAll.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/pullAll.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/pullAll.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/pullAll.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/pullAllBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/pullAllBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/pullAllBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/pullAllBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/pullAllWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/pullAllWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/pullAllWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/pullAllWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/pullAt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/pullAt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/pullAt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/pullAt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/random.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/random.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/random.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/random.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/range.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/range.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/range.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/range.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/rangeRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/rangeRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/rangeRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/rangeRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/rearg.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/rearg.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/rearg.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/rearg.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/reduce.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/reduce.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/reduce.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/reduce.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/reduceRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/reduceRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/reduceRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/reduceRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/reject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/reject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/reject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/reject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/remove.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/remove.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/remove.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/remove.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/repeat.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/repeat.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/repeat.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/repeat.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/replace.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/replace.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/replace.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/replace.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/rest.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/rest.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/rest.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/rest.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/result.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/result.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/result.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/result.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/reverse.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/reverse.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/reverse.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/reverse.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/round.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/round.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/round.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/round.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sample.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sample.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sample.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sample.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sampleSize.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sampleSize.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sampleSize.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sampleSize.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/seq.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/seq.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/seq.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/seq.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/set.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/set.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/set.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/set.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/setWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/setWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/setWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/setWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/shuffle.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/shuffle.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/shuffle.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/shuffle.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/size.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/size.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/size.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/size.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/slice.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/slice.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/slice.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/slice.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/snakeCase.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/snakeCase.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/snakeCase.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/snakeCase.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/some.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/some.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/some.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/some.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedIndex.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedIndex.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedIndex.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedIndex.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedIndexBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedIndexBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedIndexBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedIndexBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedIndexOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedIndexOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedIndexOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedIndexOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedLastIndex.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedLastIndex.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedLastIndex.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedLastIndex.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedLastIndexBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedLastIndexBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedLastIndexBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedLastIndexBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedLastIndexOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedLastIndexOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedLastIndexOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedLastIndexOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedUniq.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedUniq.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedUniq.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedUniq.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedUniqBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedUniqBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedUniqBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sortedUniqBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/split.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/split.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/split.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/split.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/spread.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/spread.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/spread.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/spread.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/startCase.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/startCase.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/startCase.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/startCase.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/startsWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/startsWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/startsWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/startsWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/string.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/string.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/string.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/string.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubFalse.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubFalse.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubFalse.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubFalse.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubObject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubObject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubObject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubObject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubString.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubString.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubString.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubString.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubTrue.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubTrue.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubTrue.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/stubTrue.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/subtract.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/subtract.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/subtract.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/subtract.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sum.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sum.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sum.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sum.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sumBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sumBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/sumBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/sumBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/tail.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/tail.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/tail.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/tail.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/take.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/take.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/take.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/take.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/takeRight.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/takeRight.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/takeRight.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/takeRight.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/takeRightWhile.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/takeRightWhile.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/takeRightWhile.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/takeRightWhile.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/takeWhile.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/takeWhile.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/takeWhile.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/takeWhile.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/tap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/tap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/tap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/tap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/template.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/template.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/template.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/template.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/templateSettings.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/templateSettings.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/templateSettings.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/templateSettings.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/throttle.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/throttle.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/throttle.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/throttle.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/thru.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/thru.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/thru.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/thru.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/times.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/times.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/times.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/times.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toArray.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toArray.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toArray.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toArray.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toFinite.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toFinite.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toFinite.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toFinite.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toInteger.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toInteger.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toInteger.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toInteger.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toIterator.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toIterator.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toIterator.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toIterator.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toJSON.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toJSON.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toJSON.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toJSON.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toLength.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toLength.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toLength.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toLength.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toLower.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toLower.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toLower.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toLower.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toNumber.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toNumber.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toNumber.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toNumber.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toPairs.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toPairs.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toPairs.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toPairs.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toPairsIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toPairsIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toPairsIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toPairsIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toPath.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toPath.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toPath.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toPath.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toPlainObject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toPlainObject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toPlainObject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toPlainObject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toSafeInteger.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toSafeInteger.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toSafeInteger.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toSafeInteger.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toString.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toString.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toString.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toString.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toUpper.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toUpper.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/toUpper.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/toUpper.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/transform.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/transform.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/transform.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/transform.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/trim.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/trim.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/trim.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/trim.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/trimEnd.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/trimEnd.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/trimEnd.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/trimEnd.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/trimStart.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/trimStart.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/trimStart.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/trimStart.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/truncate.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/truncate.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/truncate.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/truncate.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/unary.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/unary.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/unary.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/unary.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/unescape.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/unescape.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/unescape.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/unescape.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/union.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/union.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/union.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/union.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/unionBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/unionBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/unionBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/unionBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/unionWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/unionWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/unionWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/unionWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/uniq.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/uniq.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/uniq.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/uniq.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/uniqBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/uniqBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/uniqBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/uniqBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/uniqWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/uniqWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/uniqWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/uniqWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/uniqueId.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/uniqueId.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/uniqueId.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/uniqueId.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/unset.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/unset.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/unset.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/unset.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/unzip.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/unzip.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/unzip.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/unzip.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/unzipWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/unzipWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/unzipWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/unzipWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/update.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/update.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/update.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/update.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/updateWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/updateWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/updateWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/updateWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/upperCase.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/upperCase.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/upperCase.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/upperCase.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/upperFirst.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/upperFirst.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/upperFirst.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/upperFirst.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/util.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/util.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/util.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/util.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/value.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/value.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/value.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/value.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/valueOf.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/valueOf.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/valueOf.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/valueOf.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/values.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/values.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/values.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/values.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/valuesIn.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/valuesIn.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/valuesIn.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/valuesIn.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/without.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/without.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/without.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/without.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/words.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/words.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/words.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/words.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrap.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrap.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrap.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrap.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperAt.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperAt.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperAt.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperAt.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperChain.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperChain.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperChain.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperChain.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperLodash.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperLodash.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperLodash.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperLodash.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperReverse.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperReverse.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperReverse.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperReverse.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperValue.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperValue.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperValue.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/wrapperValue.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/xor.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/xor.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/xor.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/xor.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/xorBy.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/xorBy.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/xorBy.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/xorBy.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/xorWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/xorWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/xorWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/xorWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/zip.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/zip.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/zip.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/zip.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/zipObject.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/zipObject.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/zipObject.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/zipObject.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/zipObjectDeep.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/zipObjectDeep.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/zipObjectDeep.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/zipObjectDeep.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/zipWith.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/zipWith.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/lodash/zipWith.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/lodash/zipWith.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/README.md b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/README.md similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/README.md rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/README.md diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/package.json b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/package.json similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/package.json rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/package.json diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/pretty-data.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/pretty-data.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/pretty-data.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/pretty-data.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/test/test_css.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/test/test_css.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/test/test_css.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/test/test_css.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/test/test_json.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/test/test_json.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/test/test_json.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/test/test_json.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/test/test_sql.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/test/test_sql.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/test/test_sql.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/test/test_sql.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/test/test_xml.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/test/test_xml.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/test/test_xml.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/pretty-data/test/test_xml.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/round10/.npmignore b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/round10/.npmignore similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/round10/.npmignore rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/round10/.npmignore diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/round10/README.md b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/round10/README.md similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/round10/README.md rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/round10/README.md diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/round10/package.json b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/round10/package.json similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/round10/package.json rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/round10/package.json diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/round10/round10.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/round10/round10.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/round10/round10.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/round10/round10.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/round10/test/test.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/round10/test/test.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/round10/test/test.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/round10/test/test.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/.eslintrc.json b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/.eslintrc.json similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/.eslintrc.json rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/.eslintrc.json diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/.travis.yml b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/.travis.yml similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/.travis.yml rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/.travis.yml diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/README.md b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/README.md similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/README.md rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/README.md diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Box2.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Box2.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Box2.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Box2.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Box3.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Box3.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Box3.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Box3.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Line2.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Line2.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Line2.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Line2.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Line3.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Line3.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Line3.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Line3.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Plane3.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Plane3.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Plane3.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Plane3.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Quaternion.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Quaternion.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Quaternion.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/Quaternion.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/V2.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/V2.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/V2.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/V2.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/V3.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/V3.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/V3.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/V3.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/index.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/index.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/index.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/lib/index.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/package.json b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/package.json similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/package.json rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/package.json diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Box2.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Box2.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Box2.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Box2.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Box3.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Box3.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Box3.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Box3.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Line2.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Line2.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Line2.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Line2.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Line3.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Line3.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Line3.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Line3.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Plane3.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Plane3.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Plane3.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Plane3.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Quaternion.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Quaternion.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Quaternion.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/Quaternion.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/V2.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/V2.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/V2.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/V2.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/V3.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/V3.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/V3.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/V3.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/index.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/index.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/index.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/node_modules/vecks/src/index.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/package.json b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/package.json similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/package.json rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/package.json diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/Helper.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/Helper.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/Helper.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/Helper.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/applyTransforms.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/applyTransforms.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/applyTransforms.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/applyTransforms.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/cli.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/cli.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/cli.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/cli.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/config.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/config.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/config.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/config.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/constants.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/constants.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/constants.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/constants.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/denormalise.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/denormalise.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/denormalise.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/denormalise.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/entityToPolyline.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/entityToPolyline.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/entityToPolyline.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/entityToPolyline.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/getRGBForEntity.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/getRGBForEntity.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/getRGBForEntity.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/getRGBForEntity.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/groupEntitiesByLayer.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/groupEntitiesByLayer.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/groupEntitiesByLayer.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/groupEntitiesByLayer.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/blocks.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/blocks.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/blocks.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/blocks.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entities.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entities.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entities.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entities.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/arc.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/arc.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/arc.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/arc.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/circle.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/circle.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/circle.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/circle.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/common.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/common.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/common.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/common.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/ellipse.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/ellipse.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/ellipse.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/ellipse.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/insert.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/insert.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/insert.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/insert.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/line.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/line.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/line.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/line.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/lwpolyline.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/lwpolyline.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/lwpolyline.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/lwpolyline.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/mtext.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/mtext.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/mtext.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/mtext.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/point.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/point.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/point.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/point.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/polyline.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/polyline.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/polyline.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/polyline.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/solid.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/solid.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/solid.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/solid.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/spline.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/spline.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/spline.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/spline.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/threeDFace.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/threeDFace.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/threeDFace.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/threeDFace.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/vertex.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/vertex.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/entity/vertex.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/entity/vertex.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/header.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/header.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/header.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/header.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/tables.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/tables.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/handlers/tables.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/handlers/tables.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/index.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/index.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/index.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/index.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/parseString.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/parseString.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/parseString.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/parseString.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/toPolylines.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/toPolylines.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/toPolylines.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/toPolylines.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/toSVG.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/toSVG.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/toSVG.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/toSVG.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/bSpline.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/bSpline.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/bSpline.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/bSpline.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/colors.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/colors.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/colors.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/colors.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/createArcForLWPolyline.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/createArcForLWPolyline.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/createArcForLWPolyline.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/createArcForLWPolyline.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/diagram.png b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/diagram.png similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/diagram.png rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/diagram.png diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/insertKnot.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/insertKnot.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/insertKnot.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/insertKnot.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/logger.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/logger.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/logger.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/logger.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/rgbToColorAttribute.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/rgbToColorAttribute.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/rgbToColorAttribute.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/rgbToColorAttribute.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/rotate.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/rotate.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/rotate.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/rotate.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/toPiecewiseBezier.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/toPiecewiseBezier.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/toPiecewiseBezier.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/toPiecewiseBezier.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/transformBoundingBoxAndElement.js b/extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/transformBoundingBoxAndElement.js similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_dxfdwgimporter/node_modules/dxf/src/util/transformBoundingBoxAndElement.js rename to extensions/fablabchemnitz/dxfdwgimporter/node_modules/dxf/src/util/transformBoundingBoxAndElement.js diff --git a/extensions/fablabchemnitz/fablabchemnitz_airplanetypelinearcase.inx b/extensions/fablabchemnitz/estucheria/fablabchemnitz_airplanetypelinearcase.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_airplanetypelinearcase.inx rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_airplanetypelinearcase.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_airplanetypelinearcase.py b/extensions/fablabchemnitz/estucheria/fablabchemnitz_airplanetypelinearcase.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_airplanetypelinearcase.py rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_airplanetypelinearcase.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_airplanetypelinearcase.svg b/extensions/fablabchemnitz/estucheria/fablabchemnitz_airplanetypelinearcase.svg similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_airplanetypelinearcase.svg rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_airplanetypelinearcase.svg diff --git a/extensions/fablabchemnitz/fablabchemnitz_automaticbottomcase.inx b/extensions/fablabchemnitz/estucheria/fablabchemnitz_automaticbottomcase.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_automaticbottomcase.inx rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_automaticbottomcase.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_automaticbottomcase.py b/extensions/fablabchemnitz/estucheria/fablabchemnitz_automaticbottomcase.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_automaticbottomcase.py rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_automaticbottomcase.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_automaticbottomcase.svg b/extensions/fablabchemnitz/estucheria/fablabchemnitz_automaticbottomcase.svg similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_automaticbottomcase.svg rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_automaticbottomcase.svg diff --git a/extensions/fablabchemnitz/fablabchemnitz_box4p.inx b/extensions/fablabchemnitz/estucheria/fablabchemnitz_box4p.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_box4p.inx rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_box4p.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_box4p.py b/extensions/fablabchemnitz/estucheria/fablabchemnitz_box4p.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_box4p.py rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_box4p.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_box4p.svg b/extensions/fablabchemnitz/estucheria/fablabchemnitz_box4p.svg similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_box4p.svg rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_box4p.svg diff --git a/extensions/fablabchemnitz/fablabchemnitz_doublerailingcase.inx b/extensions/fablabchemnitz/estucheria/fablabchemnitz_doublerailingcase.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_doublerailingcase.inx rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_doublerailingcase.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_doublerailingcase.py b/extensions/fablabchemnitz/estucheria/fablabchemnitz_doublerailingcase.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_doublerailingcase.py rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_doublerailingcase.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_doublerailingcase.svg b/extensions/fablabchemnitz/estucheria/fablabchemnitz_doublerailingcase.svg similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_doublerailingcase.svg rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_doublerailingcase.svg diff --git a/extensions/fablabchemnitz/fablabchemnitz_girdle.inx b/extensions/fablabchemnitz/estucheria/fablabchemnitz_girdle.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_girdle.inx rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_girdle.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_girdle.py b/extensions/fablabchemnitz/estucheria/fablabchemnitz_girdle.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_girdle.py rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_girdle.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_girdle.svg b/extensions/fablabchemnitz/estucheria/fablabchemnitz_girdle.svg similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_girdle.svg rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_girdle.svg diff --git a/extensions/fablabchemnitz/fablabchemnitz_linearcase.inx b/extensions/fablabchemnitz/estucheria/fablabchemnitz_linearcase.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_linearcase.inx rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_linearcase.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_linearcase.py b/extensions/fablabchemnitz/estucheria/fablabchemnitz_linearcase.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_linearcase.py rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_linearcase.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_linearcase.svg b/extensions/fablabchemnitz/estucheria/fablabchemnitz_linearcase.svg similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_linearcase.svg rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_linearcase.svg diff --git a/extensions/fablabchemnitz/fablabchemnitz_swissbottomcase.inx b/extensions/fablabchemnitz/estucheria/fablabchemnitz_swissbottomcase.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_swissbottomcase.inx rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_swissbottomcase.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_swissbottomcase.py b/extensions/fablabchemnitz/estucheria/fablabchemnitz_swissbottomcase.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_swissbottomcase.py rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_swissbottomcase.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_swissbottomcase.svg b/extensions/fablabchemnitz/estucheria/fablabchemnitz_swissbottomcase.svg similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_swissbottomcase.svg rename to extensions/fablabchemnitz/estucheria/fablabchemnitz_swissbottomcase.svg diff --git a/extensions/fablabchemnitz/fablabchemnitz_RemoveDuplicateGuides.py b/extensions/fablabchemnitz/fablabchemnitz_RemoveDuplicateGuides.py index ff08f198..a94af0f9 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_RemoveDuplicateGuides.py +++ b/extensions/fablabchemnitz/fablabchemnitz_RemoveDuplicateGuides.py @@ -129,5 +129,4 @@ class RemoveDuplicateGuidesEffect(inkex.Effect): guide.node.getparent().remove(guide.node) if __name__ == '__main__': - effect = RemoveDuplicateGuidesEffect() - effect.run() \ No newline at end of file + effect = RemoveDuplicateGuidesEffect().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_affine_spirals.py b/extensions/fablabchemnitz/fablabchemnitz_affine_spirals.py index b46530bb..46e996ca 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_affine_spirals.py +++ b/extensions/fablabchemnitz/fablabchemnitz_affine_spirals.py @@ -95,4 +95,5 @@ class AffineTorus(inkex.Effect): # choose a better name curve_attribs = { 'style': styles[0], 'd': payload} etree.SubElement(topgroup, inkex.addNS('path','svg'), curve_attribs) -AffineTorus().run() \ No newline at end of file +if __name__ == '__main__': + AffineTorus().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_anotherperspective.py b/extensions/fablabchemnitz/fablabchemnitz_anotherperspective.py index 55826039..b881e9e2 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_anotherperspective.py +++ b/extensions/fablabchemnitz/fablabchemnitz_anotherperspective.py @@ -309,4 +309,5 @@ class AnotherPerspective(inkex.Effect): inkex.errormsg("The first selected object is not a path.\nTry using the procedure Path->Object to Path.") exit() -AnotherPerspective().run() +if __name__ == '__main__': + AnotherPerspective().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_arakne_xy.py b/extensions/fablabchemnitz/fablabchemnitz_arakne_xy.py deleted file mode 100644 index 56b2a37e..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_arakne_xy.py +++ /dev/null @@ -1,292 +0,0 @@ -#!/usr/bin/env python3 -''' -shapes.py - -Copyright (C) 2015 Paco Garcia, www.arakne.es - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - ------------------------ - -''' -# standard library -import locale, os, sys, tempfile, webbrowser, math -import inkex, simplestyle, simpletransform - -def info(s, newLine="\n"): - sys.stderr.write(s.encode("UTF-8") + newLine) - -def tern(condition,val1,val2): - return val1 if condition else val2 - -class XY: - """A class for creating Inkscape SVG Effects""" - def __init__(self, *args, **kwargs): - self.co=[0.0,0.0] - lArgs=len(args) - if lArgs>0: - if lArgs==1: - if type(args[0]==XY): - self.co=args[0].co - else: - self.co=[args[0],args[0]] - if lArgs>1: - self.co=[args[0],args[1]] - def __add__(self,xy): - co=[self.co[0] + xy.co[0],self.co[1] + xy.co[1]] - self.co = co - return self - def __sub__(self,xy): - self.co=[self.co[0] - xy.co[0], self.co[1] - xy.co[1]] - return self - def __eq__(self,xy): - return (self.co[0] == xy.x and self.co[1] == xy.y) - - def sub(self,xy): - #self.co=[self.co[0] - xy.co[0],self.co[1] - xy.co[1]] - self.__sub__(xy) - return self - def mul(self,xy): - if type(xy)==XY: - co=[self.co[0] * xy.co[0],self.co[1] * xy.co[1]] - else: - co=[self.co[0] * xy,self.co[1] * xy] - self.co = co - return self - def div(self,xy): - if type(xy)==XY: - co=[self.co[0] / xy.co[0],self.co[1] / xy.co[1]] - else: - co=[self.co[0] / xy, self.co[1] / xy] - self.co = co - return self - def vlength(self): - return math.sqrt((self.co[0]*self.co[0])+(self.co[1]*self.co[1])) - - def rot(self,ang): - x,y,sa,ca= (self.co[0], self.co[1], math.sin(ang), math.cos(ang)) - self.co=[ca * x - sa * y, sa * x + ca * y] - return self - - def Rot(self,p,r): - self.co=[math.cos(r)*p,math.sin(r)*p] - return self - - def rotate(self,rot,cX=0.0,cY=0.0): - px = cX + (self.x-cX) * math.cos(rot) - (self.y-cY)*math.sin(rot) - py = cY + (self.x-cX) * math.sin(rot) + (self.y-cY)*math.cos(rot) - self.co = [px,py] - return self - def rotateD(self,rot,cX=0.0,cY=0.0): - self.rotate(math.radians(rot),cX,cY) - return self - def VDist(self,V2): - tmp = XY(self.co[0],self.co[1]) - tmp = tmp.sub(V2) - return tmp.vlength() - def st(self): - return str(self.co[0])+','+str(self.co[1]) - @property - def x(self): - return self.co[0] - @property - def y(self): - return self.co[1] - def hipo(self,xy): - return math.sqrt( math.pow(self.x-xy.x,2) + math.pow(self.y-xy.y,2) ) - def angBetween2Lines(self,p1,p2): # pC punto comun - return math.atan2(self.y - p1.y, self.x - p1.x) - math.atan2(self.y - p2.y, self.x - p2.x) - def getAngle(self,b): - return math.atan2(b.y - self.y, b.x - self.x) - def getAngleD(self,b): - return math.degrees(math.atan2(b.y - self.y, b.x - self.x)) - -# ________________________________________________________________ -# ________________________________________________________________ -# ________________________________________________________________ -class bezpnt(object): - def __init__(self,pfixed=None,pprev=None,pnext=None): - if isinstance(pfixed, list): - self.fixed = XY(pfixed[0],pfixed[1]) - else: - self.fixed = pfixed - if isinstance(pprev, list): - self.prev = XY(pprev[0],pprev[1]) - else: - self.prev = pprev - if isinstance(pnext, list): - self.next = XY(pnext[0],pnext[1]) - else: - self.next = pnext - return - - def translate(self,x,y): - self.fixed + XY(x,y) - if self.prev!=None:self.prev + XY(x,y) - if self.next!=None:self.next + XY(x,y) - return self - def scale(self,x=1.0,y=1.0): - self.fixed.scale(x,y) - if self.prev!=None:self.prev.scale(x,y) - if self.next!=None:self.next.scale(x,y) - return self - def rotate(self,rot,cX=0.0,cY=0.0): - self.fixed.rotate(rot,cX,cY) - if self.prev!=None:self.prev.rotate(rot,cX,cY) - if self.next!=None:self.next.rotate(rot,cX,cY) - return self - def skew(self,rotx,roty,cX=0.0,cY=0.0): - self.fixed.skew(rotx,roty,cX,cY) - if self.prev!=None:self.prev.skew(rotx,roty,cX,cY) - if self.next!=None:self.next.skew(rotx,roty,cX,cY) - return self - def copy(self,bez2): - try: - self.fixed=XY().copy(bez2.fixed) - self.prev = None if bez2.prev == None else XY().copy(bez2.prev) - self.next = None if bez2.next == None else XY().copy(bez2.next) - except Exception as e: - gimp.message(str(e)) - return self - def arrXY(self): - pts=[] - if self.prev == None: - pts+=self.fixed.arrXY(1) - else: - pts+=self.prev.arrXY(1) - pts+=self.fixed.arrXY(1) - if self.next==None: - pts+=self.fixed.arrXY(1) - else: - pts+=self.next.arrXY(1) - return pts - def Prev(self): - p = self.prev - if p==None: p=self.fixed - return p - def Next(self): - p = self.next - if p==None: p=self.fixed - return p - def Fixed(self): - return self.fixed - def flip(self): - p=self.prev - n=self.next - self.prev=n - self.next=p - -def createSmallArcBez(r, a1, a2,rot): - a = (a2 - a1) * 0.5 - p4 = XY(r * math.cos(a), r * math.sin(a)) - p1 = XY(p4.x, -p4.y) - k = 0.5522847498 - f = k * math.tan(a) - p2 = XY(p1.x + f * p4.y, p1.y + f * p4.x) - p3 = XY(p2.x,-p2.y) - ar = a + a1 - P1 = XY(r * math.cos(a1), r * math.sin(a1)).rotate(rot) - P2 = XY(p2.x, p2.y).rotate(ar).rotate(rot) - P3 = XY(p3.x, p3.y).rotate(ar).rotate(rot) - P4 = XY(r * math.cos(a2),r * math.sin(a2)).rotate(rot) - B1=bezpnt(P1,None,P2) - B2=bezpnt(P4,P3) - return [B1,B2] - -def createArcBez(rad, sAng, eAng): - EPSILON = 0.0000000001 - bezs =[] - if eAng < sAng: - eAng += 360.0 - sAng = math.radians(sAng) - eAng = math.radians(eAng) - rot = sAng - sAng = math.radians(0) - eAng = eAng - rot - pi2 = math.pi * 2 - sAng, eAng = (sAng % pi2, eAng % pi2) - pi_2 = math.pi * 0.5 - sign = 1 if (sAng < eAng) else -1 - a1 = sAng - totAng = min(math.pi * 2, abs(eAng - sAng)) - while (totAng > EPSILON): - a2 = a1 + sign * min(totAng, pi_2) - bezs.extend(createSmallArcBez(rad, a1, a2,rot)) - totAng = totAng - abs(a2 - a1) - a1 = a2 - return bezs - -def bezs2XYList(arc1,transform = None): - pnts=[] - bezs=[] - for aa in arc1: - if aa.prev != None: - bezs.append(XY(aa.prev)) - bezs.append(XY(aa.fixed)) - if aa.next!=None: - bezs.append(XY(aa.next)) - for i in range(len(bezs)): - v = bezs[i] - if transform: - v = v + transform - if i == 0: - pnts.append(v) - else: - v2=pnts[-1] - if (v2.x != v.x or v2.y != v.y): - pnts.append(XY(v)) - a=len(pnts) - return pnts - -def XYList(lst, rot = 0.0, add = None): - verts=[] - for nn in range(len(lst)): - v = lst[nn] - if rot != 0.0: v = v.rotate(rot) - if add: v = v + add - verts.append([v.x,v.y]) - return verts - -def XYListSt(lst, rot = 0.0, add = None): - D2 = "" - for nn in range(len(lst)): - v = lst[nn] - if rot != 0.0: v = v.rotate(rot) - if add: v = v + add - D2 += "%s%s " % (tern(nn==1,"C",""), v.st()) - return D2 - -# circle by quadrants, A: 0>90, B: 90>180, C: 180>270, D: 270>360 -def circQ(p,r,abcd="ABCD",inverse=0,xtra=None): - aa = r * 0.551915024494 - parts={ - 'A':[XY(0,-r),XY(aa,-r), XY(r, -aa),XY(r,0)], - 'B':[XY(r,0), XY(r, aa), XY(aa, r),XY(0,r)], - 'C':[XY(0,r), XY(-aa,r), XY(-r, aa),XY(-r,0)], - 'D':[XY(-r,0),XY(-r,-aa),XY(-aa,-r),XY(0,-r)]} - #pA = parts[abcd[0]] - pA = [XY(p)+N for N in parts[abcd[0]]] - for aa in abcd[1:]: - pA = pA + [XY(p)+N for N in parts[aa][1:]] - if inverse==1: pA.reverse() - listA = XYList(pA) - if xtra: - for n in xtra: - listA[n].extend(xtra[n]) - return listA - -def circleInCircle(c1,r1,c2,r2): - d = c1.hipo(c2) - return tern((r1 > (d + r2)),True,False) \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_archimedesspiral.py b/extensions/fablabchemnitz/fablabchemnitz_archimedesspiral.py index f52b9c73..7f925478 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_archimedesspiral.py +++ b/extensions/fablabchemnitz/fablabchemnitz_archimedesspiral.py @@ -84,4 +84,5 @@ class Archimedes(inkex.Effect): else: break return i -Archimedes().run() \ No newline at end of file +if __name__ == '__main__': + Archimedes().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_attributes_editor.py b/extensions/fablabchemnitz/fablabchemnitz_attributes_editor.py index 0798aea2..c4481ff2 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_attributes_editor.py +++ b/extensions/fablabchemnitz/fablabchemnitz_attributes_editor.py @@ -34,4 +34,5 @@ class AttribEditor(inkex.Effect): else: inkex.errormsg("Invalid mode: " + self.options.mode) -AttribEditor().run() \ No newline at end of file +if __name__ == '__main__': + AttribEditor().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_attributes_import.py b/extensions/fablabchemnitz/fablabchemnitz_attributes_import.py index 9a0d9f04..d2935696 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_attributes_import.py +++ b/extensions/fablabchemnitz/fablabchemnitz_attributes_import.py @@ -26,5 +26,6 @@ class AttribImport(inkex.Effect): inkex.utils.debug("Unknown Attribute") except AttributeError: inkex.utils.debug("element with id '" + id + "' not found in current selection.") + if __name__ == '__main__': AttribImport().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_bezierenvelope.py b/extensions/fablabchemnitz/fablabchemnitz_bezierenvelope.py index 198daa60..fc36a722 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_bezierenvelope.py +++ b/extensions/fablabchemnitz/fablabchemnitz_bezierenvelope.py @@ -391,5 +391,5 @@ def rotateTransform( a ): def scale_transform( sx, sy ): return [[sx,0,0],[0,sy,0]] - -BezierEnvelope().run() \ No newline at end of file +if __name__ == '__main__': + BezierEnvelope().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_blobs.py b/extensions/fablabchemnitz/fablabchemnitz_blobs.py index ac2a6980..7c64e3e3 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_blobs.py +++ b/extensions/fablabchemnitz/fablabchemnitz_blobs.py @@ -31,8 +31,8 @@ result in loopy splines. global cave if self.options.pgsizep: svg = self.document.getroot() - rx = self.svg.unittouu(svg.get('width')) - ry = self.svg.unittouu(svg.attrib['height']) + rx = int(self.svg.unittouu(svg.get('width'))) + ry = int(self.svg.unittouu(svg.attrib['height'])) else: rx = self.options.rx ry = self.options.ry @@ -167,5 +167,5 @@ def findall(a, f): r.append(j) return r -# Create effect instance and apply it. -blobsEffect().run() \ No newline at end of file +if __name__ == '__main__': + blobsEffect().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_blueprint_maker.py b/extensions/fablabchemnitz/fablabchemnitz_blueprint_maker.py index ff92899f..d04a9d60 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_blueprint_maker.py +++ b/extensions/fablabchemnitz/fablabchemnitz_blueprint_maker.py @@ -114,5 +114,4 @@ class bluePrintMaker(inkex.Effect): return None if __name__ == '__main__': - program=bluePrintMaker() -program.run() \ No newline at end of file + program=bluePrintMaker().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_boundingbox.py b/extensions/fablabchemnitz/fablabchemnitz_boundingbox.py index d362b0ad..fe5c497c 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_boundingbox.py +++ b/extensions/fablabchemnitz/fablabchemnitz_boundingbox.py @@ -39,6 +39,8 @@ class DrawBBoxes(inkex.Effect): for id, item in self.svg.selected.items(): self.drawBBox(item.bounding_box()) else: - self.drawBBox(self.svg.selection.bounding_box()) + self.drawBBox(self.svg.get_selected_bbox()) #works for InkScape (1:1.0+devel+202008292235+eff2292935) @ Linux and for Windows (but with deprecation) + #self.drawBBox(self.svg.selection.bounding_box()): #works for InkScape 1.1dev (9b1fc87, 2020-08-27)) @ Windows -DrawBBoxes().run() \ No newline at end of file +if __name__ == '__main__': + DrawBBoxes().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_bouwkamp_code.py b/extensions/fablabchemnitz/fablabchemnitz_bouwkamp_code.py index a95bc91f..0fed41b3 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_bouwkamp_code.py +++ b/extensions/fablabchemnitz/fablabchemnitz_bouwkamp_code.py @@ -160,4 +160,5 @@ class BouwkampCodeExtension(inkex.Effect): etree.SubElement(parent, inkex.addNS('rect', 'svg'), rectangle_attributes) -BouwkampCodeExtension().run() \ No newline at end of file +if __name__ == '__main__': + BouwkampCodeExtension().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes deleted file mode 100644 index 7ad985c6..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/python3 -# EASY-INSTALL-SCRIPT: 'boxes==0.9','boxes' -__requires__ = 'boxes==0.9' -__import__('pkg_resources').run_script('boxes==0.9', 'boxes') diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.AllEdges.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.AllEdges.inx deleted file mode 100644 index 8e699126..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.AllEdges.inx +++ /dev/null @@ -1,101 +0,0 @@ - - - AllEdges - info.festi.boxes.py.AllEdges - - alledges - - - - 100 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - 0 - false - 0.5 - - - - - 2 - 0 - 1 - - - - 90.0 - true - - - - - - - - - - - 2.0 - 1.0 - 3.0 - 0.05 - 2.0 - 1.0 - - - - 5 - 0.1 - 3.0 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.AngledBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.AngledBox.inx deleted file mode 100644 index a0f14087..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.AngledBox.inx +++ /dev/null @@ -1,63 +0,0 @@ - - - AngledBox - info.festi.boxes.py.AngledBox - - angledbox - - - - 100.0 - 100.0 - 100.0 - true - - - - - - - 5 - - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.AngledCutJig.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.AngledCutJig.inx deleted file mode 100644 index cca2349b..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.AngledCutJig.inx +++ /dev/null @@ -1,49 +0,0 @@ - - - AngledCutJig - info.festi.boxes.py.AngledCutJig - - angledcutjig - - - - 50 - 100 - 45.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Arcade.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Arcade.inx deleted file mode 100644 index bd7902af..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Arcade.inx +++ /dev/null @@ -1,49 +0,0 @@ - - - Arcade - info.festi.boxes.py.Arcade - - arcade - - - - 450.0 - 350.0 - 150.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Atreus21.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Atreus21.inx deleted file mode 100644 index 18831be7..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Atreus21.inx +++ /dev/null @@ -1,49 +0,0 @@ - - - Atreus21 - info.festi.boxes.py.Atreus21 - - atreus21 - - - - 1.5 - false - 1.5 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.BasedBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.BasedBox.inx deleted file mode 100644 index c2da020b..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.BasedBox.inx +++ /dev/null @@ -1,50 +0,0 @@ - - - BasedBox - info.festi.boxes.py.BasedBox - - basedbox - - - - 100.0 - 100.0 - 100.0 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.BayonetBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.BayonetBox.inx deleted file mode 100644 index 7b61bdf8..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.BayonetBox.inx +++ /dev/null @@ -1,35 +0,0 @@ - - - BayonetBox - info.festi.boxes.py.BayonetBox - - bayonetbox - - - - 50.0 - 10 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.BinTray.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.BinTray.inx deleted file mode 100644 index 6c3700e9..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.BinTray.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - BinTray - info.festi.boxes.py.BinTray - - bintray - - - - 50*3 - 50*3 - 100.0 - true - 0.4 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.BottleStack.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.BottleStack.inx deleted file mode 100644 index 4295697c..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.BottleStack.inx +++ /dev/null @@ -1,36 +0,0 @@ - - - BottleStack - info.festi.boxes.py.BottleStack - - bottlestack - - - - 80 - 3 - 80 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.BurnTest.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.BurnTest.inx deleted file mode 100644 index eec7e10c..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.BurnTest.inx +++ /dev/null @@ -1,49 +0,0 @@ - - - BurnTest - info.festi.boxes.py.BurnTest - - burntest - - - - 100 - 0.01 - 2 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.CardBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.CardBox.inx deleted file mode 100644 index c163c95b..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.CardBox.inx +++ /dev/null @@ -1,50 +0,0 @@ - - - CardBox - info.festi.boxes.py.CardBox - - cardbox - - - - 30 - 65 - 90 - 2 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Castle.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Castle.inx deleted file mode 100644 index 6b9a8b12..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Castle.inx +++ /dev/null @@ -1,46 +0,0 @@ - - - Castle - info.festi.boxes.py.Castle - - castle - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.ClosedBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.ClosedBox.inx deleted file mode 100644 index ac371003..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.ClosedBox.inx +++ /dev/null @@ -1,50 +0,0 @@ - - - ClosedBox - info.festi.boxes.py.ClosedBox - - closedbox - - - - 100.0 - 100.0 - 100.0 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.ConcaveKnob.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.ConcaveKnob.inx deleted file mode 100644 index fa218087..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.ConcaveKnob.inx +++ /dev/null @@ -1,39 +0,0 @@ - - - ConcaveKnob - info.festi.boxes.py.ConcaveKnob - - concaveknob - - - - 50.0 - 3 - 0.2 - 70.0 - 6.0 - 1.0 - 10.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Console.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Console.inx deleted file mode 100644 index e461f672..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Console.inx +++ /dev/null @@ -1,58 +0,0 @@ - - - Console - info.festi.boxes.py.Console - - console - - - - 100 - 100 - 100 - 30 - 50 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Console2.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Console2.inx deleted file mode 100644 index 10d38853..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Console2.inx +++ /dev/null @@ -1,67 +0,0 @@ - - - Console2 - info.festi.boxes.py.Console2 - - console2 - - - - 100 - 100 - 100 - - - - - - - 30 - 50 - true - true - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DinRailBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DinRailBox.inx deleted file mode 100644 index 0df30dc3..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DinRailBox.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - DinRailBox - info.festi.boxes.py.DinRailBox - - dinrailbox - - - - 70 - 90 - 60 - 35.0 - 0.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.8 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DiscRack.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DiscRack.inx deleted file mode 100644 index eb9d20ab..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DiscRack.inx +++ /dev/null @@ -1,53 +0,0 @@ - - - DiscRack - info.festi.boxes.py.DiscRack - - discrack - - - - 20*10 - 150.0 - 5.0 - 0.75 - 0.75 - 3.0 - 18 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Display.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Display.inx deleted file mode 100644 index c7b09bad..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Display.inx +++ /dev/null @@ -1,36 +0,0 @@ - - - Display - info.festi.boxes.py.Display - - display - - - - 150.0 - 200.0 - 5.0 - 0.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DisplayCase.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DisplayCase.inx deleted file mode 100644 index b9668316..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DisplayCase.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - DisplayCase - info.festi.boxes.py.DisplayCase - - displaycase - - - - 100.0 - 100.0 - 100.0 - true - 2 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DisplayShelf.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DisplayShelf.inx deleted file mode 100644 index a4ad36db..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DisplayShelf.inx +++ /dev/null @@ -1,53 +0,0 @@ - - - DisplayShelf - info.festi.boxes.py.DisplayShelf - - displayshelf - - - - 400 - 100 - 300 - true - 3 - 20.0 - 30.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DividerTray.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DividerTray.inx deleted file mode 100644 index 9ebfd856..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DividerTray.inx +++ /dev/null @@ -1,61 +0,0 @@ - - - DividerTray - info.festi.boxes.py.DividerTray - - dividertray - - - - 50*3 - 50*3 - 100.0 - true - 20 - 0 - 2 - 0.2 - 0 - 1 - 8 - 15 - true - true - false - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DrillBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DrillBox.inx deleted file mode 100644 index 5121a34f..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.DrillBox.inx +++ /dev/null @@ -1,46 +0,0 @@ - - - DrillBox - info.festi.boxes.py.DrillBox - - drillbox - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.ElectronicsBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.ElectronicsBox.inx deleted file mode 100644 index 411a8928..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.ElectronicsBox.inx +++ /dev/null @@ -1,56 +0,0 @@ - - - ElectronicsBox - info.festi.boxes.py.ElectronicsBox - - electronicsbox - - - - 100.0 - 100.0 - 100.0 - true - 25.0 - 2.0 - 3.0 - 3.0 - true - 7.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.EuroRackSkiff.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.EuroRackSkiff.inx deleted file mode 100644 index db8e6328..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.EuroRackSkiff.inx +++ /dev/null @@ -1,48 +0,0 @@ - - - EuroRackSkiff - info.festi.boxes.py.EuroRackSkiff - - eurorackskiff - - - - 100.0 - 84 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexBox.inx deleted file mode 100644 index 5eab85be..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexBox.inx +++ /dev/null @@ -1,59 +0,0 @@ - - - FlexBox - info.festi.boxes.py.FlexBox - - flexbox - - - - 100.0 - 100.0 - 100.0 - true - 15 - 8 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexBox2.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexBox2.inx deleted file mode 100644 index 60f1fc2a..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexBox2.inx +++ /dev/null @@ -1,59 +0,0 @@ - - - FlexBox2 - info.festi.boxes.py.FlexBox2 - - flexbox2 - - - - 100.0 - 100.0 - 100.0 - true - 15 - 8 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexBox3.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexBox3.inx deleted file mode 100644 index 378a6b33..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexBox3.inx +++ /dev/null @@ -1,60 +0,0 @@ - - - FlexBox3 - info.festi.boxes.py.FlexBox3 - - flexbox3 - - - - 100.0 - 100.0 - true - 100.0 - 10.0 - 10.0 - 1.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexBox4.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexBox4.inx deleted file mode 100644 index 4b4fa59c..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexBox4.inx +++ /dev/null @@ -1,59 +0,0 @@ - - - FlexBox4 - info.festi.boxes.py.FlexBox4 - - flexbox4 - - - - 100.0 - 100.0 - 100.0 - true - 15 - 8 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexBox5.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexBox5.inx deleted file mode 100644 index 56de7128..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexBox5.inx +++ /dev/null @@ -1,59 +0,0 @@ - - - FlexBox5 - info.festi.boxes.py.FlexBox5 - - flexbox5 - - - - 100.0 - 100.0 - true - 60 - 60 - 8 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexTest.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexTest.inx deleted file mode 100644 index c7d38e52..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexTest.inx +++ /dev/null @@ -1,41 +0,0 @@ - - - FlexTest - info.festi.boxes.py.FlexTest - - flextest - - - - 100.0 - 100.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexTest2.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexTest2.inx deleted file mode 100644 index 9ca8593c..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.FlexTest2.inx +++ /dev/null @@ -1,35 +0,0 @@ - - - FlexTest2 - info.festi.boxes.py.FlexTest2 - - flextest2 - - - - 100.0 - 100.0 - 1 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Folder.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Folder.inx deleted file mode 100644 index cd1d7d18..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Folder.inx +++ /dev/null @@ -1,50 +0,0 @@ - - - Folder - info.festi.boxes.py.Folder - - folder - - - - 100.0 - 100.0 - 20 - 10.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.GearBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.GearBox.inx deleted file mode 100644 index a72e3e8a..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.GearBox.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - GearBox - info.festi.boxes.py.GearBox - - gearbox - - - - 8 - 20 - 3 - 6.0 - 4 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Gears.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Gears.inx deleted file mode 100644 index 435fbf58..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Gears.inx +++ /dev/null @@ -1,41 +0,0 @@ - - - Gears - info.festi.boxes.py.Gears - - gears - - - - 12 - 6.0 - 75 - 32 - 0.0 - 0 - 5 - 20 - 20 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.HeartBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.HeartBox.inx deleted file mode 100644 index c3b51331..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.HeartBox.inx +++ /dev/null @@ -1,60 +0,0 @@ - - - HeartBox - info.festi.boxes.py.HeartBox - - heartbox - - - - 150 - 50 - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 1.0 - 0.0 - 1.0 - 1.0 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.HingeBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.HingeBox.inx deleted file mode 100644 index 585884a2..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.HingeBox.inx +++ /dev/null @@ -1,65 +0,0 @@ - - - HingeBox - info.festi.boxes.py.HingeBox - - hingebox - - - - 100.0 - 100.0 - 100.0 - true - 20.0 - 0.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 3.2 - 5 - 2 - - - - - 1.5 - 0.05 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Hook.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Hook.inx deleted file mode 100644 index 31ca260f..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Hook.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - Hook - info.festi.boxes.py.Hook - - hook - - - - 40.0 - 40.0 - 40.0 - 20.0 - 45.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.IntegratedHingeBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.IntegratedHingeBox.inx deleted file mode 100644 index c4df579a..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.IntegratedHingeBox.inx +++ /dev/null @@ -1,57 +0,0 @@ - - - IntegratedHingeBox - info.festi.boxes.py.IntegratedHingeBox - - integratedhingebox - - - - 100.0 - 100.0 - 100.0 - true - 20.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 1.0 - 2.0 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Keypad.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Keypad.inx deleted file mode 100644 index 9f88e22e..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Keypad.inx +++ /dev/null @@ -1,52 +0,0 @@ - - - Keypad - info.festi.boxes.py.Keypad - - keypad - - - - 30 - 3 - 4 - 1.5 - false - 1.5 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.LBeam.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.LBeam.inx deleted file mode 100644 index 9ea54987..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.LBeam.inx +++ /dev/null @@ -1,50 +0,0 @@ - - - LBeam - info.festi.boxes.py.LBeam - - lbeam - - - - 100.0 - 100.0 - 100.0 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.LaserClamp.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.LaserClamp.inx deleted file mode 100644 index 5ba86d7a..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.LaserClamp.inx +++ /dev/null @@ -1,49 +0,0 @@ - - - LaserClamp - info.festi.boxes.py.LaserClamp - - laserclamp - - - - 25.0 - 50.0 - 0.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.LaserHoldfast.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.LaserHoldfast.inx deleted file mode 100644 index 4ce190ed..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.LaserHoldfast.inx +++ /dev/null @@ -1,36 +0,0 @@ - - - LaserHoldfast - info.festi.boxes.py.LaserHoldfast - - laserholdfast - - - - 25 - 40 - 5.0 - 5.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.MagazinFile.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.MagazinFile.inx deleted file mode 100644 index 1b56d9f6..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.MagazinFile.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - MagazinFile - info.festi.boxes.py.MagazinFile - - magazinfile - - - - 100.0 - 100.0 - 100.0 - 0.0 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.MakitaPowerSupply.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.MakitaPowerSupply.inx deleted file mode 100644 index 4fc2ea85..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.MakitaPowerSupply.inx +++ /dev/null @@ -1,48 +0,0 @@ - - - MakitaPowerSupply - info.festi.boxes.py.MakitaPowerSupply - - makitapowersupply - - - - 8.0 - 6.3 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.NemaMount.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.NemaMount.inx deleted file mode 100644 index c3a1a07e..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.NemaMount.inx +++ /dev/null @@ -1,57 +0,0 @@ - - - NemaMount - info.festi.boxes.py.NemaMount - - nemamount - - - - - - - - - - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.NotesHolder.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.NotesHolder.inx deleted file mode 100644 index c7cc6dba..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.NotesHolder.inx +++ /dev/null @@ -1,63 +0,0 @@ - - - NotesHolder - info.festi.boxes.py.NotesHolder - - notesholder - - - - 78 - 78 - 35 - - - - - - - 40 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.OpenBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.OpenBox.inx deleted file mode 100644 index cdbbce8a..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.OpenBox.inx +++ /dev/null @@ -1,50 +0,0 @@ - - - OpenBox - info.festi.boxes.py.OpenBox - - openbox - - - - 100.0 - 100.0 - 100.0 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.OrganPipe.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.OrganPipe.inx deleted file mode 100644 index 312ccf55..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.OrganPipe.inx +++ /dev/null @@ -1,73 +0,0 @@ - - - OrganPipe - info.festi.boxes.py.OrganPipe - - organpipe - - - - - - - - - - - - - - - - - - 2 - 2.0 - 0.25 - 0.3 - 0 - 588.4 - - - - - - - false - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1.0 - 1.0 - 3.0 - 0.0 - 3.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.OttoBody.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.OttoBody.inx deleted file mode 100644 index e55ccb4b..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.OttoBody.inx +++ /dev/null @@ -1,52 +0,0 @@ - - - OttoBody - info.festi.boxes.py.OttoBody - - ottobody - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 1.0 - 2.0 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.OttoLegs.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.OttoLegs.inx deleted file mode 100644 index 6806dfdd..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.OttoLegs.inx +++ /dev/null @@ -1,49 +0,0 @@ - - - OttoLegs - info.festi.boxes.py.OttoLegs - - ottolegs - - - - 3.0 - 2.6 - 34.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1.0 - 1.0 - 1.0 - 0.0 - 1.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.OttoSoles.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.OttoSoles.inx deleted file mode 100644 index b7d7084e..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.OttoSoles.inx +++ /dev/null @@ -1,37 +0,0 @@ - - - OttoSoles - info.festi.boxes.py.OttoSoles - - ottosoles - - - - 56.0 - 36.0 - 4.0 - 5.0 - 2 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.PaintStorage.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.PaintStorage.inx deleted file mode 100644 index 34a4917e..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.PaintStorage.inx +++ /dev/null @@ -1,59 +0,0 @@ - - - PaintStorage - info.festi.boxes.py.PaintStorage - - paintstorage - - - - 100 - 300 - 50 - 30 - 10 - false - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Planetary.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Planetary.inx deleted file mode 100644 index ca025360..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Planetary.inx +++ /dev/null @@ -1,38 +0,0 @@ - - - Planetary - info.festi.boxes.py.Planetary - - planetary - - - - 8 - 20 - 0 - 0 - 3 - 6.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Planetary2.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Planetary2.inx deleted file mode 100644 index 2115c0ea..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Planetary2.inx +++ /dev/null @@ -1,68 +0,0 @@ - - - Planetary2 - info.festi.boxes.py.Planetary2 - - planetary2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 20 - 20 - 0 - 1 - 3 - 6.0 - 2.4 - 4.0 - 3.1 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.PoleHook.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.PoleHook.inx deleted file mode 100644 index d11518fc..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.PoleHook.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - PoleHook - info.festi.boxes.py.PoleHook - - polehook - - - - 50.0 - 7.8 - 13.0 - 5.5 - 4.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Pulley.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Pulley.inx deleted file mode 100644 index 00199c9e..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Pulley.inx +++ /dev/null @@ -1,53 +0,0 @@ - - - Pulley - info.festi.boxes.py.Pulley - - pulley - - - - 6.0 - - - - - - - - - - - - - - - - - 20 - 5 - false - 0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Rack10Box.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Rack10Box.inx deleted file mode 100644 index 1439d660..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Rack10Box.inx +++ /dev/null @@ -1,68 +0,0 @@ - - - Rack10Box - info.festi.boxes.py.Rack10Box - - rack10box - - - - 100.0 - - - - - - - - - - - - - - - - - - - 25.0 - 2.0 - 3.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Rack19Box.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Rack19Box.inx deleted file mode 100644 index 38c54a0f..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Rack19Box.inx +++ /dev/null @@ -1,68 +0,0 @@ - - - Rack19Box - info.festi.boxes.py.Rack19Box - - rack19box - - - - 100.0 - - - - - - - - - - - - - - - - - - - 25.0 - 2.0 - 3.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Rack19HalfWidth.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Rack19HalfWidth.inx deleted file mode 100644 index 46fc334f..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Rack19HalfWidth.inx +++ /dev/null @@ -1,36 +0,0 @@ - - - Rack19HalfWidth - info.festi.boxes.py.Rack19HalfWidth - - rack19halfwidth - - - - 1 - xxmpwx - 20 - 124 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RackBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RackBox.inx deleted file mode 100644 index 8d35c55b..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RackBox.inx +++ /dev/null @@ -1,55 +0,0 @@ - - - RackBox - info.festi.boxes.py.RackBox - - rackbox - - - - 100.0 - 100.0 - 100.0 - true - 25.0 - 2.0 - 3.0 - 4.0 - 7.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1.2 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RectangularWall.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RectangularWall.inx deleted file mode 100644 index a05b3ca2..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RectangularWall.inx +++ /dev/null @@ -1,281 +0,0 @@ - - - RectangularWall - info.festi.boxes.py.RectangularWall - - rectangularwall - - - - 100 - 100 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 3.2 - 5 - 2 - - - - - 1.5 - 0.05 - 2.0 - - - - 5 - 0.1 - 3.0 - - - - 50 - 1.5 - 0.2 - 3 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 20.0 - 0.0 - 3.0 - 20.0 - - - - true - - - - - 0.3 - - - - 0 - false - 0.5 - - - - - 2 - 0 - 1 - - - - 1.0 - 2.0 - 0.1 - - - - 90.0 - true - - - - - - - - - - - 2.0 - 1.0 - 3.0 - 0.05 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - all - - - - - - - - \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RegularBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RegularBox.inx deleted file mode 100644 index 119a0f31..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RegularBox.inx +++ /dev/null @@ -1,59 +0,0 @@ - - - RegularBox - info.festi.boxes.py.RegularBox - - regularbox - - - - 100.0 - true - 50.0 - 5 - - - - - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RobotArm.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RobotArm.inx deleted file mode 100644 index ce92ca40..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RobotArm.inx +++ /dev/null @@ -1,121 +0,0 @@ - - - RobotArm - info.festi.boxes.py.RobotArm - - robotarm - - - - - - - - - - - - - - - - - - 50.0 - - - - - - - - - - - - - - - 50.0 - - - - - - - - - - - - - - - 50.0 - - - - - - - - - - - - - - - 50.0 - - - - - - - - - - - - - - - 50.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Rotary.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Rotary.inx deleted file mode 100644 index dd0b2f3c..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Rotary.inx +++ /dev/null @@ -1,52 +0,0 @@ - - - Rotary - info.festi.boxes.py.Rotary - - rotary - - - - 72.0 - 5.0 - 6.0 - 8.0 - 32.0 - 7.1 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RoundedBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RoundedBox.inx deleted file mode 100644 index dd7c4371..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RoundedBox.inx +++ /dev/null @@ -1,67 +0,0 @@ - - - RoundedBox - info.festi.boxes.py.RoundedBox - - roundedbox - - - - 100.0 - 100.0 - 100.0 - true - 15 - - - - - - - - - - - - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RoyalGame.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RoyalGame.inx deleted file mode 100644 index 3bf6cf18..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.RoyalGame.inx +++ /dev/null @@ -1,47 +0,0 @@ - - - RoyalGame - info.festi.boxes.py.RoyalGame - - royalgame - - - - 200 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SBCMicroRack.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SBCMicroRack.inx deleted file mode 100644 index f836b07e..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SBCMicroRack.inx +++ /dev/null @@ -1,67 +0,0 @@ - - - SBCMicroRack - info.festi.boxes.py.SBCMicroRack - - sbcmicrorack - - - - 56 - 85 - 5 - 3 - 3 - 28 - 3.5 - 58 - 49 - 2.75 - 18 - 53 - false - false - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.ShutterBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.ShutterBox.inx deleted file mode 100644 index ff5ad7d3..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.ShutterBox.inx +++ /dev/null @@ -1,61 +0,0 @@ - - - ShutterBox - info.festi.boxes.py.ShutterBox - - shutterbox - - - - 150 - 100 - 100 - 40.0 - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 1.05 - 2.0 - 0.75 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SideDoorHousing.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SideDoorHousing.inx deleted file mode 100644 index 41aee708..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SideDoorHousing.inx +++ /dev/null @@ -1,63 +0,0 @@ - - - SideDoorHousing - info.festi.boxes.py.SideDoorHousing - - sidedoorhousing - - - - 100 - 100 - 100 - - - - - - - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Silverware.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Silverware.inx deleted file mode 100644 index cefba99e..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Silverware.inx +++ /dev/null @@ -1,38 +0,0 @@ - - - Silverware - info.festi.boxes.py.Silverware - - silverware - - - - 250 - 154 - 120 - 30 - 150 - 120 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallCaliper.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallCaliper.inx deleted file mode 100644 index 1aea808d..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallCaliper.inx +++ /dev/null @@ -1,60 +0,0 @@ - - - SlatwallCaliper - info.festi.boxes.py.SlatwallCaliper - - slatwallcaliper - - - - 100 - 18.0 - 6.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallChiselHolder.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallChiselHolder.inx deleted file mode 100644 index 39c59a6c..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallChiselHolder.inx +++ /dev/null @@ -1,68 +0,0 @@ - - - SlatwallChiselHolder - info.festi.boxes.py.SlatwallChiselHolder - - slatwallchiselholder - - - - 120 - 30.0 - 30.0 - 5.0 - 5.0 - 6 - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallConsole.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallConsole.inx deleted file mode 100644 index 50cd1e2b..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallConsole.inx +++ /dev/null @@ -1,62 +0,0 @@ - - - SlatwallConsole - info.festi.boxes.py.SlatwallConsole - - slatwallconsole - - - - 100 - 100 - true - 50 - 35 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallDrillBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallDrillBox.inx deleted file mode 100644 index d6b5b478..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallDrillBox.inx +++ /dev/null @@ -1,61 +0,0 @@ - - - SlatwallDrillBox - info.festi.boxes.py.SlatwallDrillBox - - slatwalldrillbox - - - - 25*6 - 10:20:30 - 25:40:60 - 15.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallEdges.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallEdges.inx deleted file mode 100644 index 94d0af0b..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallEdges.inx +++ /dev/null @@ -1,58 +0,0 @@ - - - SlatwallEdges - info.festi.boxes.py.SlatwallEdges - - slatwalledges - - - - 120 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallPlaneHolder.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallPlaneHolder.inx deleted file mode 100644 index fa0e20b8..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallPlaneHolder.inx +++ /dev/null @@ -1,61 +0,0 @@ - - - SlatwallPlaneHolder - info.festi.boxes.py.SlatwallPlaneHolder - - slatwallplaneholder - - - - 80 - 250 - 30 - 80 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallPliersHolder.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallPliersHolder.inx deleted file mode 100644 index d04d106d..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallPliersHolder.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - SlatwallPliersHolder - info.festi.boxes.py.SlatwallPliersHolder - - slatwallpliersholder - - - - 100*3 - 50 - 50 - true - 45 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallSlottedHolder.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallSlottedHolder.inx deleted file mode 100644 index 2579281f..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallSlottedHolder.inx +++ /dev/null @@ -1,69 +0,0 @@ - - - SlatwallSlottedHolder - info.festi.boxes.py.SlatwallSlottedHolder - - slatwallslottedholder - - - - 120 - 50.0 - 50.0 - 5.0 - 35.0 - 5.0 - 6 - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallTypeTray.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallTypeTray.inx deleted file mode 100644 index 21ac6ba5..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallTypeTray.inx +++ /dev/null @@ -1,77 +0,0 @@ - - - SlatwallTypeTray - info.festi.boxes.py.SlatwallTypeTray - - slatwalltypetray - - - - 50*3 - 50*3 - 100.0 - 0.0 - true - - - - - - - 0.0 - 0.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallWrenchHolder.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallWrenchHolder.inx deleted file mode 100644 index 4757ed37..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SlatwallWrenchHolder.inx +++ /dev/null @@ -1,65 +0,0 @@ - - - SlatwallWrenchHolder - info.festi.boxes.py.SlatwallWrenchHolder - - slatwallwrenchholder - - - - 100 - 30.0 - 11 - 8.0 - 25.0 - 3.0 - 5.0 - 0.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SpicesRack.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SpicesRack.inx deleted file mode 100644 index 59421274..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.SpicesRack.inx +++ /dev/null @@ -1,53 +0,0 @@ - - - SpicesRack - info.festi.boxes.py.SpicesRack - - spicesrack - - - - 55.0 - 60.0 - 10.0 - 5 - 6 - false - false - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Stachel.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Stachel.inx deleted file mode 100644 index 2a7aa8ed..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.Stachel.inx +++ /dev/null @@ -1,35 +0,0 @@ - - - Stachel - info.festi.boxes.py.Stachel - - stachel - - - - 115.0 - 25.0 - 7.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.StorageRack.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.StorageRack.inx deleted file mode 100644 index 386be240..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.StorageRack.inx +++ /dev/null @@ -1,69 +0,0 @@ - - - StorageRack - info.festi.boxes.py.StorageRack - - storagerack - - - - 200 - 30 - 100.0 - 50*3 - true - - - - - - - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.StorageShelf.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.StorageShelf.inx deleted file mode 100644 index d2a02d77..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.StorageShelf.inx +++ /dev/null @@ -1,138 +0,0 @@ - - - StorageShelf - info.festi.boxes.py.StorageShelf - - storageshelf - - - - 100.0 - 50*3 - 50*3 - true - - - - - - - - - - - - - - - - - - - - 0.0 - false - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - 0 - false - 0.5 - - - - - 2 - 0 - 1 - - - - 3.2 - 5 - 2 - - - - - 1.5 - 0.05 - 2.0 - - - - 90.0 - true - - - - - - - - - - - 2.0 - 1.0 - 3.0 - 0.05 - 2.0 - 1.0 - - - - 5 - 0.1 - 3.0 - - - - 150.0 - 2.0 - 30.0 - 1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.TrafficLight.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.TrafficLight.inx deleted file mode 100644 index 656ba478..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.TrafficLight.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - TrafficLight - info.festi.boxes.py.TrafficLight - - trafficlight - - - - 100.0 - 100 - 50 - 3 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.TrayInsert.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.TrayInsert.inx deleted file mode 100644 index 3f819042..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.TrayInsert.inx +++ /dev/null @@ -1,36 +0,0 @@ - - - TrayInsert - info.festi.boxes.py.TrayInsert - - trayinsert - - - - 50*3 - 50*3 - 100.0 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.TriangleLamp.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.TriangleLamp.inx deleted file mode 100644 index a367d3e6..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.TriangleLamp.inx +++ /dev/null @@ -1,52 +0,0 @@ - - - TriangleLamp - info.festi.boxes.py.TriangleLamp - - trianglelamp - - - - 250 - 40 - 30 - 4 - 2 - false - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 3.0 - 0.0 - 3.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.TwoPiece.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.TwoPiece.inx deleted file mode 100644 index 09c13e6f..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.TwoPiece.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - TwoPiece - info.festi.boxes.py.TwoPiece - - twopiece - - - - 100.0 - 100.0 - 100.0 - true - 0.05 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.TypeTray.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.TypeTray.inx deleted file mode 100644 index 2174b76c..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.TypeTray.inx +++ /dev/null @@ -1,139 +0,0 @@ - - - TypeTray - info.festi.boxes.py.TypeTray - - typetray - - - - 50*3 - 50*3 - 100.0 - 0.0 - true - - - - - - - - - - - - - - - - - - - - 30 - 70 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - 0 - false - 0.5 - - - - - 2 - 0 - 1 - - - - 3.2 - 5 - 2 - - - - - 1.5 - 0.05 - 2.0 - - - - 90.0 - true - - - - - - - - - - - 2.0 - 1.0 - 3.0 - 0.05 - 2.0 - 1.0 - - - - 5 - 0.1 - 3.0 - - - - 150.0 - 2.0 - 30.0 - 1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.UBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.UBox.inx deleted file mode 100644 index 31d798a7..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.UBox.inx +++ /dev/null @@ -1,142 +0,0 @@ - - - UBox - info.festi.boxes.py.UBox - - ubox - - - - - - - - - - - - - - - - - 100.0 - 100.0 - 100.0 - 30.0 - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - 0 - false - 0.5 - - - - - 2 - 0 - 1 - - - - 3.2 - 5 - 2 - - - - - 1.5 - 0.05 - 2.0 - - - - 90.0 - true - - - - - - - - - - - 2.0 - 1.0 - 3.0 - 0.05 - 2.0 - 1.0 - - - - 5 - 0.1 - 3.0 - - - - 150.0 - 2.0 - 30.0 - 0.0 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.UnevenHeightBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.UnevenHeightBox.inx deleted file mode 100644 index 72b77cea..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.UnevenHeightBox.inx +++ /dev/null @@ -1,60 +0,0 @@ - - - UnevenHeightBox - info.festi.boxes.py.UnevenHeightBox - - unevenheightbox - - - - - - - - - - 100.0 - 100.0 - true - 50 - 50 - 100 - 100 - false - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.UniversalBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.UniversalBox.inx deleted file mode 100644 index 5408ff9e..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.UniversalBox.inx +++ /dev/null @@ -1,148 +0,0 @@ - - - UniversalBox - info.festi.boxes.py.UniversalBox - - universalbox - - - - - - - - - - - - - - - - - - - - - - - 100.0 - 100.0 - 100.0 - true - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - 0 - true - 0.5 - - - - - 2 - 0 - 1 - - - - 3.2 - 5 - 2 - - - - - 1.5 - 0.05 - 2.0 - - - - 90.0 - true - - - - - - - - - - - 2.0 - 1.0 - 3.0 - 0.05 - 2.0 - 1.0 - - - - 5 - 0.1 - 3.0 - - - - 150.0 - 2.0 - 30.0 - 1 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.WaivyKnob.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.WaivyKnob.inx deleted file mode 100644 index 554567a6..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.WaivyKnob.inx +++ /dev/null @@ -1,38 +0,0 @@ - - - WaivyKnob - info.festi.boxes.py.WaivyKnob - - waivyknob - - - - 50.0 - 20 - 45.0 - 6.0 - 1.0 - 10.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.WineRack.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.WineRack.inx deleted file mode 100644 index 9e38ac63..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/linux/boxes.py.WineRack.inx +++ /dev/null @@ -1,55 +0,0 @@ - - - WineRack - info.festi.boxes.py.WineRack - - winerack - - - - 400 - 300 - 210 - 46.0 - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.exe b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.exe deleted file mode 100644 index 01ecba08..00000000 Binary files a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.exe and /dev/null differ diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.AllEdges.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.AllEdges.inx deleted file mode 100644 index 1e4c4fae..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.AllEdges.inx +++ /dev/null @@ -1,101 +0,0 @@ - - - AllEdges - info.festi.boxes.py.AllEdges - - alledges - - - - 100 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - 0 - false - 0.5 - - - - - 2 - 0 - 1 - - - - 90.0 - true - - - - - - - - - - - 2.0 - 1.0 - 3.0 - 0.05 - 2.0 - 1.0 - - - - 5 - 0.1 - 3.0 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.AngledBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.AngledBox.inx deleted file mode 100644 index 7eaf6a0b..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.AngledBox.inx +++ /dev/null @@ -1,63 +0,0 @@ - - - AngledBox - info.festi.boxes.py.AngledBox - - angledbox - - - - 100.0 - 100.0 - 100.0 - true - - - - - - - 5 - - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.AngledCutJig.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.AngledCutJig.inx deleted file mode 100644 index 833a8003..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.AngledCutJig.inx +++ /dev/null @@ -1,49 +0,0 @@ - - - AngledCutJig - info.festi.boxes.py.AngledCutJig - - angledcutjig - - - - 50 - 100 - 45.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Arcade.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Arcade.inx deleted file mode 100644 index a16623bf..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Arcade.inx +++ /dev/null @@ -1,49 +0,0 @@ - - - Arcade - info.festi.boxes.py.Arcade - - arcade - - - - 450.0 - 350.0 - 150.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Atreus21.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Atreus21.inx deleted file mode 100644 index 6dab7edc..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Atreus21.inx +++ /dev/null @@ -1,49 +0,0 @@ - - - Atreus21 - info.festi.boxes.py.Atreus21 - - atreus21 - - - - 1.5 - false - 1.5 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.BasedBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.BasedBox.inx deleted file mode 100644 index 4c8ff713..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.BasedBox.inx +++ /dev/null @@ -1,50 +0,0 @@ - - - BasedBox - info.festi.boxes.py.BasedBox - - basedbox - - - - 100.0 - 100.0 - 100.0 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.BayonetBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.BayonetBox.inx deleted file mode 100644 index 2fee9524..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.BayonetBox.inx +++ /dev/null @@ -1,35 +0,0 @@ - - - BayonetBox - info.festi.boxes.py.BayonetBox - - bayonetbox - - - - 50.0 - 10 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.BinTray.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.BinTray.inx deleted file mode 100644 index 3de6bfbf..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.BinTray.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - BinTray - info.festi.boxes.py.BinTray - - bintray - - - - 50*3 - 50*3 - 100.0 - true - 0.4 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.BottleStack.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.BottleStack.inx deleted file mode 100644 index 8aeb5f73..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.BottleStack.inx +++ /dev/null @@ -1,36 +0,0 @@ - - - BottleStack - info.festi.boxes.py.BottleStack - - bottlestack - - - - 80 - 3 - 80 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.BurnTest.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.BurnTest.inx deleted file mode 100644 index 4ebb6093..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.BurnTest.inx +++ /dev/null @@ -1,49 +0,0 @@ - - - BurnTest - info.festi.boxes.py.BurnTest - - burntest - - - - 100 - 0.01 - 2 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.CardBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.CardBox.inx deleted file mode 100644 index caf6b234..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.CardBox.inx +++ /dev/null @@ -1,50 +0,0 @@ - - - CardBox - info.festi.boxes.py.CardBox - - cardbox - - - - 30 - 65 - 90 - 2 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Castle.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Castle.inx deleted file mode 100644 index 5aef567a..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Castle.inx +++ /dev/null @@ -1,46 +0,0 @@ - - - Castle - info.festi.boxes.py.Castle - - castle - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.ClosedBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.ClosedBox.inx deleted file mode 100644 index ac9d292b..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.ClosedBox.inx +++ /dev/null @@ -1,50 +0,0 @@ - - - ClosedBox - info.festi.boxes.py.ClosedBox - - closedbox - - - - 100.0 - 100.0 - 100.0 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.ConcaveKnob.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.ConcaveKnob.inx deleted file mode 100644 index 5a5658e6..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.ConcaveKnob.inx +++ /dev/null @@ -1,39 +0,0 @@ - - - ConcaveKnob - info.festi.boxes.py.ConcaveKnob - - concaveknob - - - - 50.0 - 3 - 0.2 - 70.0 - 6.0 - 1.0 - 10.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Console.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Console.inx deleted file mode 100644 index ec9cdffd..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Console.inx +++ /dev/null @@ -1,58 +0,0 @@ - - - Console - info.festi.boxes.py.Console - - console - - - - 100 - 100 - 100 - 30 - 50 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Console2.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Console2.inx deleted file mode 100644 index baacc62a..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Console2.inx +++ /dev/null @@ -1,67 +0,0 @@ - - - Console2 - info.festi.boxes.py.Console2 - - console2 - - - - 100 - 100 - 100 - - - - - - - 30 - 50 - true - true - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DinRailBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DinRailBox.inx deleted file mode 100644 index 9546b6d4..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DinRailBox.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - DinRailBox - info.festi.boxes.py.DinRailBox - - dinrailbox - - - - 70 - 90 - 60 - 35.0 - 0.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.8 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DiscRack.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DiscRack.inx deleted file mode 100644 index 8f645259..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DiscRack.inx +++ /dev/null @@ -1,53 +0,0 @@ - - - DiscRack - info.festi.boxes.py.DiscRack - - discrack - - - - 20*10 - 150.0 - 5.0 - 0.75 - 0.75 - 3.0 - 18 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Display.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Display.inx deleted file mode 100644 index 1bea908a..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Display.inx +++ /dev/null @@ -1,36 +0,0 @@ - - - Display - info.festi.boxes.py.Display - - display - - - - 150.0 - 200.0 - 5.0 - 0.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DisplayCase.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DisplayCase.inx deleted file mode 100644 index e0fbf612..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DisplayCase.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - DisplayCase - info.festi.boxes.py.DisplayCase - - displaycase - - - - 100.0 - 100.0 - 100.0 - true - 2 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DisplayShelf.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DisplayShelf.inx deleted file mode 100644 index 3d4253a6..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DisplayShelf.inx +++ /dev/null @@ -1,53 +0,0 @@ - - - DisplayShelf - info.festi.boxes.py.DisplayShelf - - displayshelf - - - - 400 - 100 - 300 - true - 3 - 20.0 - 30.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DividerTray.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DividerTray.inx deleted file mode 100644 index bcc2dc5a..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DividerTray.inx +++ /dev/null @@ -1,61 +0,0 @@ - - - DividerTray - info.festi.boxes.py.DividerTray - - dividertray - - - - 50*3 - 50*3 - 100.0 - true - 20 - 0 - 2 - 0.2 - 0 - 1 - 8 - 15 - true - true - false - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DrillBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DrillBox.inx deleted file mode 100644 index 9e9641c5..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.DrillBox.inx +++ /dev/null @@ -1,46 +0,0 @@ - - - DrillBox - info.festi.boxes.py.DrillBox - - drillbox - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.ElectronicsBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.ElectronicsBox.inx deleted file mode 100644 index b7fbb9f0..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.ElectronicsBox.inx +++ /dev/null @@ -1,56 +0,0 @@ - - - ElectronicsBox - info.festi.boxes.py.ElectronicsBox - - electronicsbox - - - - 100.0 - 100.0 - 100.0 - true - 25.0 - 2.0 - 3.0 - 3.0 - true - 7.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.EuroRackSkiff.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.EuroRackSkiff.inx deleted file mode 100644 index 6fa6b456..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.EuroRackSkiff.inx +++ /dev/null @@ -1,48 +0,0 @@ - - - EuroRackSkiff - info.festi.boxes.py.EuroRackSkiff - - eurorackskiff - - - - 100.0 - 84 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexBox.inx deleted file mode 100644 index 92582b09..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexBox.inx +++ /dev/null @@ -1,59 +0,0 @@ - - - FlexBox - info.festi.boxes.py.FlexBox - - flexbox - - - - 100.0 - 100.0 - 100.0 - true - 15 - 8 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexBox2.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexBox2.inx deleted file mode 100644 index 0bde43aa..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexBox2.inx +++ /dev/null @@ -1,59 +0,0 @@ - - - FlexBox2 - info.festi.boxes.py.FlexBox2 - - flexbox2 - - - - 100.0 - 100.0 - 100.0 - true - 15 - 8 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexBox3.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexBox3.inx deleted file mode 100644 index 52a995fa..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexBox3.inx +++ /dev/null @@ -1,60 +0,0 @@ - - - FlexBox3 - info.festi.boxes.py.FlexBox3 - - flexbox3 - - - - 100.0 - 100.0 - true - 100.0 - 10.0 - 10.0 - 1.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexBox4.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexBox4.inx deleted file mode 100644 index 5237d1a1..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexBox4.inx +++ /dev/null @@ -1,59 +0,0 @@ - - - FlexBox4 - info.festi.boxes.py.FlexBox4 - - flexbox4 - - - - 100.0 - 100.0 - 100.0 - true - 15 - 8 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexBox5.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexBox5.inx deleted file mode 100644 index ba29f1d7..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexBox5.inx +++ /dev/null @@ -1,59 +0,0 @@ - - - FlexBox5 - info.festi.boxes.py.FlexBox5 - - flexbox5 - - - - 100.0 - 100.0 - true - 60 - 60 - 8 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexTest.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexTest.inx deleted file mode 100644 index f8c53cab..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexTest.inx +++ /dev/null @@ -1,41 +0,0 @@ - - - FlexTest - info.festi.boxes.py.FlexTest - - flextest - - - - 100.0 - 100.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexTest2.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexTest2.inx deleted file mode 100644 index 9bb3d86a..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.FlexTest2.inx +++ /dev/null @@ -1,35 +0,0 @@ - - - FlexTest2 - info.festi.boxes.py.FlexTest2 - - flextest2 - - - - 100.0 - 100.0 - 1 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Folder.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Folder.inx deleted file mode 100644 index 655452be..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Folder.inx +++ /dev/null @@ -1,50 +0,0 @@ - - - Folder - info.festi.boxes.py.Folder - - folder - - - - 100.0 - 100.0 - 20 - 10.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.GearBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.GearBox.inx deleted file mode 100644 index 0e875882..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.GearBox.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - GearBox - info.festi.boxes.py.GearBox - - gearbox - - - - 8 - 20 - 3 - 6.0 - 4 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Gears.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Gears.inx deleted file mode 100644 index ddc46b52..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Gears.inx +++ /dev/null @@ -1,41 +0,0 @@ - - - Gears - info.festi.boxes.py.Gears - - gears - - - - 12 - 6.0 - 75 - 32 - 0.0 - 0 - 5 - 20 - 20 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.HeartBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.HeartBox.inx deleted file mode 100644 index 4fc9f87e..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.HeartBox.inx +++ /dev/null @@ -1,60 +0,0 @@ - - - HeartBox - info.festi.boxes.py.HeartBox - - heartbox - - - - 150 - 50 - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 1.0 - 0.0 - 1.0 - 1.0 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.HingeBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.HingeBox.inx deleted file mode 100644 index 8d9dcc13..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.HingeBox.inx +++ /dev/null @@ -1,65 +0,0 @@ - - - HingeBox - info.festi.boxes.py.HingeBox - - hingebox - - - - 100.0 - 100.0 - 100.0 - true - 20.0 - 0.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 3.2 - 5 - 2 - - - - - 1.5 - 0.05 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Hook.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Hook.inx deleted file mode 100644 index f7a6cb12..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Hook.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - Hook - info.festi.boxes.py.Hook - - hook - - - - 40.0 - 40.0 - 40.0 - 20.0 - 45.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.IntegratedHingeBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.IntegratedHingeBox.inx deleted file mode 100644 index 8da6fa03..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.IntegratedHingeBox.inx +++ /dev/null @@ -1,57 +0,0 @@ - - - IntegratedHingeBox - info.festi.boxes.py.IntegratedHingeBox - - integratedhingebox - - - - 100.0 - 100.0 - 100.0 - true - 20.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 1.0 - 2.0 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Keypad.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Keypad.inx deleted file mode 100644 index 67c5c843..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Keypad.inx +++ /dev/null @@ -1,52 +0,0 @@ - - - Keypad - info.festi.boxes.py.Keypad - - keypad - - - - 30 - 3 - 4 - 1.5 - false - 1.5 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.LBeam.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.LBeam.inx deleted file mode 100644 index d4a96d8e..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.LBeam.inx +++ /dev/null @@ -1,50 +0,0 @@ - - - LBeam - info.festi.boxes.py.LBeam - - lbeam - - - - 100.0 - 100.0 - 100.0 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.LaserClamp.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.LaserClamp.inx deleted file mode 100644 index d517327d..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.LaserClamp.inx +++ /dev/null @@ -1,49 +0,0 @@ - - - LaserClamp - info.festi.boxes.py.LaserClamp - - laserclamp - - - - 25.0 - 50.0 - 0.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.LaserHoldfast.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.LaserHoldfast.inx deleted file mode 100644 index 31ed2993..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.LaserHoldfast.inx +++ /dev/null @@ -1,36 +0,0 @@ - - - LaserHoldfast - info.festi.boxes.py.LaserHoldfast - - laserholdfast - - - - 25 - 40 - 5.0 - 5.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.MagazinFile.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.MagazinFile.inx deleted file mode 100644 index 25cf1be3..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.MagazinFile.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - MagazinFile - info.festi.boxes.py.MagazinFile - - magazinfile - - - - 100.0 - 100.0 - 100.0 - 0.0 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.MakitaPowerSupply.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.MakitaPowerSupply.inx deleted file mode 100644 index 4e5cb85a..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.MakitaPowerSupply.inx +++ /dev/null @@ -1,48 +0,0 @@ - - - MakitaPowerSupply - info.festi.boxes.py.MakitaPowerSupply - - makitapowersupply - - - - 8.0 - 6.3 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.NemaMount.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.NemaMount.inx deleted file mode 100644 index 433bb055..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.NemaMount.inx +++ /dev/null @@ -1,57 +0,0 @@ - - - NemaMount - info.festi.boxes.py.NemaMount - - nemamount - - - - - - - - - - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.NotesHolder.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.NotesHolder.inx deleted file mode 100644 index 591345b6..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.NotesHolder.inx +++ /dev/null @@ -1,63 +0,0 @@ - - - NotesHolder - info.festi.boxes.py.NotesHolder - - notesholder - - - - 78 - 78 - 35 - - - - - - - 40 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.OpenBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.OpenBox.inx deleted file mode 100644 index de025048..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.OpenBox.inx +++ /dev/null @@ -1,50 +0,0 @@ - - - OpenBox - info.festi.boxes.py.OpenBox - - openbox - - - - 100.0 - 100.0 - 100.0 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.OrganPipe.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.OrganPipe.inx deleted file mode 100644 index ed5622f8..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.OrganPipe.inx +++ /dev/null @@ -1,73 +0,0 @@ - - - OrganPipe - info.festi.boxes.py.OrganPipe - - organpipe - - - - - - - - - - - - - - - - - - 2 - 2.0 - 0.25 - 0.3 - 0 - 588.4 - - - - - - - false - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1.0 - 1.0 - 3.0 - 0.0 - 3.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.OttoBody.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.OttoBody.inx deleted file mode 100644 index 5c332662..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.OttoBody.inx +++ /dev/null @@ -1,52 +0,0 @@ - - - OttoBody - info.festi.boxes.py.OttoBody - - ottobody - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 1.0 - 2.0 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.OttoLegs.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.OttoLegs.inx deleted file mode 100644 index 9766deaf..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.OttoLegs.inx +++ /dev/null @@ -1,49 +0,0 @@ - - - OttoLegs - info.festi.boxes.py.OttoLegs - - ottolegs - - - - 3.0 - 2.6 - 34.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1.0 - 1.0 - 1.0 - 0.0 - 1.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.OttoSoles.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.OttoSoles.inx deleted file mode 100644 index 0ea59d5d..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.OttoSoles.inx +++ /dev/null @@ -1,37 +0,0 @@ - - - OttoSoles - info.festi.boxes.py.OttoSoles - - ottosoles - - - - 56.0 - 36.0 - 4.0 - 5.0 - 2 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.PaintStorage.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.PaintStorage.inx deleted file mode 100644 index 6ba74986..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.PaintStorage.inx +++ /dev/null @@ -1,59 +0,0 @@ - - - PaintStorage - info.festi.boxes.py.PaintStorage - - paintstorage - - - - 100 - 300 - 50 - 30 - 10 - false - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Planetary.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Planetary.inx deleted file mode 100644 index 26dcd60d..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Planetary.inx +++ /dev/null @@ -1,38 +0,0 @@ - - - Planetary - info.festi.boxes.py.Planetary - - planetary - - - - 8 - 20 - 0 - 0 - 3 - 6.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Planetary2.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Planetary2.inx deleted file mode 100644 index 471ee006..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Planetary2.inx +++ /dev/null @@ -1,68 +0,0 @@ - - - Planetary2 - info.festi.boxes.py.Planetary2 - - planetary2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 20 - 20 - 0 - 1 - 3 - 6.0 - 2.4 - 4.0 - 3.1 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.PoleHook.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.PoleHook.inx deleted file mode 100644 index 35ba0a0b..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.PoleHook.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - PoleHook - info.festi.boxes.py.PoleHook - - polehook - - - - 50.0 - 7.8 - 13.0 - 5.5 - 4.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Pulley.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Pulley.inx deleted file mode 100644 index 66ad0ca2..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Pulley.inx +++ /dev/null @@ -1,53 +0,0 @@ - - - Pulley - info.festi.boxes.py.Pulley - - pulley - - - - 6.0 - - - - - - - - - - - - - - - - - 20 - 5 - false - 0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Rack10Box.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Rack10Box.inx deleted file mode 100644 index fab8e03a..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Rack10Box.inx +++ /dev/null @@ -1,68 +0,0 @@ - - - Rack10Box - info.festi.boxes.py.Rack10Box - - rack10box - - - - 100.0 - - - - - - - - - - - - - - - - - - - 25.0 - 2.0 - 3.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Rack19Box.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Rack19Box.inx deleted file mode 100644 index ac31e345..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Rack19Box.inx +++ /dev/null @@ -1,68 +0,0 @@ - - - Rack19Box - info.festi.boxes.py.Rack19Box - - rack19box - - - - 100.0 - - - - - - - - - - - - - - - - - - - 25.0 - 2.0 - 3.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Rack19HalfWidth.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Rack19HalfWidth.inx deleted file mode 100644 index 4c21edc0..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Rack19HalfWidth.inx +++ /dev/null @@ -1,36 +0,0 @@ - - - Rack19HalfWidth - info.festi.boxes.py.Rack19HalfWidth - - rack19halfwidth - - - - 1 - xxmpwx - 20 - 124 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RackBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RackBox.inx deleted file mode 100644 index a497c041..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RackBox.inx +++ /dev/null @@ -1,55 +0,0 @@ - - - RackBox - info.festi.boxes.py.RackBox - - rackbox - - - - 100.0 - 100.0 - 100.0 - true - 25.0 - 2.0 - 3.0 - 4.0 - 7.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1.2 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RectangularWall.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RectangularWall.inx deleted file mode 100644 index 8b7ec6ff..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RectangularWall.inx +++ /dev/null @@ -1,281 +0,0 @@ - - - RectangularWall - info.festi.boxes.py.RectangularWall - - rectangularwall - - - - 100 - 100 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 3.2 - 5 - 2 - - - - - 1.5 - 0.05 - 2.0 - - - - 5 - 0.1 - 3.0 - - - - 50 - 1.5 - 0.2 - 3 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 20.0 - 0.0 - 3.0 - 20.0 - - - - true - - - - - 0.3 - - - - 0 - false - 0.5 - - - - - 2 - 0 - 1 - - - - 1.0 - 2.0 - 0.1 - - - - 90.0 - true - - - - - - - - - - - 2.0 - 1.0 - 3.0 - 0.05 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - all - - - - - - - - \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RegularBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RegularBox.inx deleted file mode 100644 index 6b22b54e..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RegularBox.inx +++ /dev/null @@ -1,59 +0,0 @@ - - - RegularBox - info.festi.boxes.py.RegularBox - - regularbox - - - - 100.0 - true - 50.0 - 5 - - - - - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RobotArm.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RobotArm.inx deleted file mode 100644 index 90637f3d..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RobotArm.inx +++ /dev/null @@ -1,121 +0,0 @@ - - - RobotArm - info.festi.boxes.py.RobotArm - - robotarm - - - - - - - - - - - - - - - - - - 50.0 - - - - - - - - - - - - - - - 50.0 - - - - - - - - - - - - - - - 50.0 - - - - - - - - - - - - - - - 50.0 - - - - - - - - - - - - - - - 50.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Rotary.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Rotary.inx deleted file mode 100644 index 469dac62..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Rotary.inx +++ /dev/null @@ -1,52 +0,0 @@ - - - Rotary - info.festi.boxes.py.Rotary - - rotary - - - - 72.0 - 5.0 - 6.0 - 8.0 - 32.0 - 7.1 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RoundedBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RoundedBox.inx deleted file mode 100644 index 627d6343..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RoundedBox.inx +++ /dev/null @@ -1,67 +0,0 @@ - - - RoundedBox - info.festi.boxes.py.RoundedBox - - roundedbox - - - - 100.0 - 100.0 - 100.0 - true - 15 - - - - - - - - - - - - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RoyalGame.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RoyalGame.inx deleted file mode 100644 index afce34f7..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.RoyalGame.inx +++ /dev/null @@ -1,47 +0,0 @@ - - - RoyalGame - info.festi.boxes.py.RoyalGame - - royalgame - - - - 200 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SBCMicroRack.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SBCMicroRack.inx deleted file mode 100644 index df5bb9f3..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SBCMicroRack.inx +++ /dev/null @@ -1,67 +0,0 @@ - - - SBCMicroRack - info.festi.boxes.py.SBCMicroRack - - sbcmicrorack - - - - 56 - 85 - 5 - 3 - 3 - 28 - 3.5 - 58 - 49 - 2.75 - 18 - 53 - false - false - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.ShutterBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.ShutterBox.inx deleted file mode 100644 index caf54fb3..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.ShutterBox.inx +++ /dev/null @@ -1,61 +0,0 @@ - - - ShutterBox - info.festi.boxes.py.ShutterBox - - shutterbox - - - - 150 - 100 - 100 - 40.0 - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 1.05 - 2.0 - 0.75 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SideDoorHousing.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SideDoorHousing.inx deleted file mode 100644 index 08520d12..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SideDoorHousing.inx +++ /dev/null @@ -1,63 +0,0 @@ - - - SideDoorHousing - info.festi.boxes.py.SideDoorHousing - - sidedoorhousing - - - - 100 - 100 - 100 - - - - - - - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Silverware.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Silverware.inx deleted file mode 100644 index 97669683..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Silverware.inx +++ /dev/null @@ -1,38 +0,0 @@ - - - Silverware - info.festi.boxes.py.Silverware - - silverware - - - - 250 - 154 - 120 - 30 - 150 - 120 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallCaliper.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallCaliper.inx deleted file mode 100644 index 70ab115c..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallCaliper.inx +++ /dev/null @@ -1,60 +0,0 @@ - - - SlatwallCaliper - info.festi.boxes.py.SlatwallCaliper - - slatwallcaliper - - - - 100 - 18.0 - 6.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallChiselHolder.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallChiselHolder.inx deleted file mode 100644 index b9a7eeec..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallChiselHolder.inx +++ /dev/null @@ -1,68 +0,0 @@ - - - SlatwallChiselHolder - info.festi.boxes.py.SlatwallChiselHolder - - slatwallchiselholder - - - - 120 - 30.0 - 30.0 - 5.0 - 5.0 - 6 - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallConsole.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallConsole.inx deleted file mode 100644 index 2018e39d..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallConsole.inx +++ /dev/null @@ -1,62 +0,0 @@ - - - SlatwallConsole - info.festi.boxes.py.SlatwallConsole - - slatwallconsole - - - - 100 - 100 - true - 50 - 35 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallDrillBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallDrillBox.inx deleted file mode 100644 index bcff3cc4..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallDrillBox.inx +++ /dev/null @@ -1,61 +0,0 @@ - - - SlatwallDrillBox - info.festi.boxes.py.SlatwallDrillBox - - slatwalldrillbox - - - - 25*6 - 10:20:30 - 25:40:60 - 15.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallEdges.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallEdges.inx deleted file mode 100644 index bb1b373d..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallEdges.inx +++ /dev/null @@ -1,58 +0,0 @@ - - - SlatwallEdges - info.festi.boxes.py.SlatwallEdges - - slatwalledges - - - - 120 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallPlaneHolder.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallPlaneHolder.inx deleted file mode 100644 index ec086716..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallPlaneHolder.inx +++ /dev/null @@ -1,61 +0,0 @@ - - - SlatwallPlaneHolder - info.festi.boxes.py.SlatwallPlaneHolder - - slatwallplaneholder - - - - 80 - 250 - 30 - 80 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallPliersHolder.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallPliersHolder.inx deleted file mode 100644 index 5abaec6f..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallPliersHolder.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - SlatwallPliersHolder - info.festi.boxes.py.SlatwallPliersHolder - - slatwallpliersholder - - - - 100*3 - 50 - 50 - true - 45 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallSlottedHolder.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallSlottedHolder.inx deleted file mode 100644 index 89aeea16..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallSlottedHolder.inx +++ /dev/null @@ -1,69 +0,0 @@ - - - SlatwallSlottedHolder - info.festi.boxes.py.SlatwallSlottedHolder - - slatwallslottedholder - - - - 120 - 50.0 - 50.0 - 5.0 - 35.0 - 5.0 - 6 - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallTypeTray.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallTypeTray.inx deleted file mode 100644 index 2f16e427..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallTypeTray.inx +++ /dev/null @@ -1,77 +0,0 @@ - - - SlatwallTypeTray - info.festi.boxes.py.SlatwallTypeTray - - slatwalltypetray - - - - 50*3 - 50*3 - 100.0 - 0.0 - true - - - - - - - 0.0 - 0.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallWrenchHolder.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallWrenchHolder.inx deleted file mode 100644 index ce82d5df..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SlatwallWrenchHolder.inx +++ /dev/null @@ -1,65 +0,0 @@ - - - SlatwallWrenchHolder - info.festi.boxes.py.SlatwallWrenchHolder - - slatwallwrenchholder - - - - 100 - 30.0 - 11 - 8.0 - 25.0 - 3.0 - 5.0 - 0.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - - - - - - 1.0 - 2.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SpicesRack.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SpicesRack.inx deleted file mode 100644 index dd608114..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.SpicesRack.inx +++ /dev/null @@ -1,53 +0,0 @@ - - - SpicesRack - info.festi.boxes.py.SpicesRack - - spicesrack - - - - 55.0 - 60.0 - 10.0 - 5 - 6 - false - false - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 1.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Stachel.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Stachel.inx deleted file mode 100644 index d4636b9a..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.Stachel.inx +++ /dev/null @@ -1,35 +0,0 @@ - - - Stachel - info.festi.boxes.py.Stachel - - stachel - - - - 115.0 - 25.0 - 7.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.StorageRack.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.StorageRack.inx deleted file mode 100644 index c6f90032..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.StorageRack.inx +++ /dev/null @@ -1,69 +0,0 @@ - - - StorageRack - info.festi.boxes.py.StorageRack - - storagerack - - - - 200 - 30 - 100.0 - 50*3 - true - - - - - - - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.StorageShelf.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.StorageShelf.inx deleted file mode 100644 index 807253a7..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.StorageShelf.inx +++ /dev/null @@ -1,138 +0,0 @@ - - - StorageShelf - info.festi.boxes.py.StorageShelf - - storageshelf - - - - 100.0 - 50*3 - 50*3 - true - - - - - - - - - - - - - - - - - - - - 0.0 - false - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - 0 - false - 0.5 - - - - - 2 - 0 - 1 - - - - 3.2 - 5 - 2 - - - - - 1.5 - 0.05 - 2.0 - - - - 90.0 - true - - - - - - - - - - - 2.0 - 1.0 - 3.0 - 0.05 - 2.0 - 1.0 - - - - 5 - 0.1 - 3.0 - - - - 150.0 - 2.0 - 30.0 - 1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.TrafficLight.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.TrafficLight.inx deleted file mode 100644 index 0b5ed86f..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.TrafficLight.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - TrafficLight - info.festi.boxes.py.TrafficLight - - trafficlight - - - - 100.0 - 100 - 50 - 3 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.TrayInsert.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.TrayInsert.inx deleted file mode 100644 index 57dd4805..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.TrayInsert.inx +++ /dev/null @@ -1,36 +0,0 @@ - - - TrayInsert - info.festi.boxes.py.TrayInsert - - trayinsert - - - - 50*3 - 50*3 - 100.0 - true - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.TriangleLamp.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.TriangleLamp.inx deleted file mode 100644 index a31bf923..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.TriangleLamp.inx +++ /dev/null @@ -1,52 +0,0 @@ - - - TriangleLamp - info.festi.boxes.py.TriangleLamp - - trianglelamp - - - - 250 - 40 - 30 - 4 - 2 - false - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 3.0 - 0.0 - 3.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.TwoPiece.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.TwoPiece.inx deleted file mode 100644 index 48995990..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.TwoPiece.inx +++ /dev/null @@ -1,51 +0,0 @@ - - - TwoPiece - info.festi.boxes.py.TwoPiece - - twopiece - - - - 100.0 - 100.0 - 100.0 - true - 0.05 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.TypeTray.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.TypeTray.inx deleted file mode 100644 index 6ba27fcc..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.TypeTray.inx +++ /dev/null @@ -1,139 +0,0 @@ - - - TypeTray - info.festi.boxes.py.TypeTray - - typetray - - - - 50*3 - 50*3 - 100.0 - 0.0 - true - - - - - - - - - - - - - - - - - - - - 30 - 70 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 0.5 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - 0 - false - 0.5 - - - - - 2 - 0 - 1 - - - - 3.2 - 5 - 2 - - - - - 1.5 - 0.05 - 2.0 - - - - 90.0 - true - - - - - - - - - - - 2.0 - 1.0 - 3.0 - 0.05 - 2.0 - 1.0 - - - - 5 - 0.1 - 3.0 - - - - 150.0 - 2.0 - 30.0 - 1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.UBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.UBox.inx deleted file mode 100644 index 385b1d41..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.UBox.inx +++ /dev/null @@ -1,142 +0,0 @@ - - - UBox - info.festi.boxes.py.UBox - - ubox - - - - - - - - - - - - - - - - - 100.0 - 100.0 - 100.0 - 30.0 - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - 0 - false - 0.5 - - - - - 2 - 0 - 1 - - - - 3.2 - 5 - 2 - - - - - 1.5 - 0.05 - 2.0 - - - - 90.0 - true - - - - - - - - - - - 2.0 - 1.0 - 3.0 - 0.05 - 2.0 - 1.0 - - - - 5 - 0.1 - 3.0 - - - - 150.0 - 2.0 - 30.0 - 0.0 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.UnevenHeightBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.UnevenHeightBox.inx deleted file mode 100644 index 56c8b30d..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.UnevenHeightBox.inx +++ /dev/null @@ -1,60 +0,0 @@ - - - UnevenHeightBox - info.festi.boxes.py.UnevenHeightBox - - unevenheightbox - - - - - - - - - - 100.0 - 100.0 - true - 50 - 50 - 100 - 100 - false - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.UniversalBox.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.UniversalBox.inx deleted file mode 100644 index 35d86105..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.UniversalBox.inx +++ /dev/null @@ -1,148 +0,0 @@ - - - UniversalBox - info.festi.boxes.py.UniversalBox - - universalbox - - - - - - - - - - - - - - - - - - - - - - - 100.0 - 100.0 - 100.0 - true - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - 60 - 2.0 - 1.0 - 4.0 - - - - 0 - true - 0.5 - - - - - 2 - 0 - 1 - - - - 3.2 - 5 - 2 - - - - - 1.5 - 0.05 - 2.0 - - - - 90.0 - true - - - - - - - - - - - 2.0 - 1.0 - 3.0 - 0.05 - 2.0 - 1.0 - - - - 5 - 0.1 - 3.0 - - - - 150.0 - 2.0 - 30.0 - 1 - - - - 1.05 - 1.0 - 0.5 - 5.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.WaivyKnob.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.WaivyKnob.inx deleted file mode 100644 index 27b6a60d..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.WaivyKnob.inx +++ /dev/null @@ -1,38 +0,0 @@ - - - WaivyKnob - info.festi.boxes.py.WaivyKnob - - waivyknob - - - - 50.0 - 20 - 45.0 - 6.0 - 1.0 - 10.0 - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.WineRack.inx b/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.WineRack.inx deleted file mode 100644 index 4b0098e2..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_boxes/windows/boxes.py.WineRack.inx +++ /dev/null @@ -1,55 +0,0 @@ - - - WineRack - info.festi.boxes.py.WineRack - - winerack - - - - 400 - 300 - 210 - 46.0 - - - - - - - - - 3.0 - 0.0 - false - 100 - 0.1 - - - - 90.0 - - - - - 2.0 - 1.0 - 2.0 - 0.0 - 2.0 - 1.0 - - - - - all - - - - - - - - diff --git a/extensions/fablabchemnitz/fablabchemnitz_can_generator.py b/extensions/fablabchemnitz/fablabchemnitz_can_generator.py index fe045a06..92ccc5ec 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_can_generator.py +++ b/extensions/fablabchemnitz/fablabchemnitz_can_generator.py @@ -367,4 +367,5 @@ class Dose(inkex.Effect): branding_line = etree.SubElement(textgroup, inkex.addNS('text','svg'), einschnitt_line_attribs) branding_line.text = 'Die Einschnitte nur zu 70 Prozent in das Material lasern' -Dose().run() \ No newline at end of file +if __name__ == '__main__': + Dose().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_chain_paths.py b/extensions/fablabchemnitz/fablabchemnitz_chain_paths.py index c8c751cf..eb031fde 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_chain_paths.py +++ b/extensions/fablabchemnitz/fablabchemnitz_chain_paths.py @@ -279,4 +279,5 @@ class ChainPaths(inkex.Effect): if debug: inkex.utils.debug("min_missed_distance: "+str(math.sqrt(float(self.min_missed_distance_sq))/self.unit_factor)+'>'+str(self.chain_epsilon)+str(self.options.units)) if debug: inkex.utils.debug("Successful link operations: "+str(self.chained_count)) -ChainPaths().run() \ No newline at end of file +if __name__ == '__main__': + ChainPaths().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_checkerboard.py b/extensions/fablabchemnitz/fablabchemnitz_checkerboard.py index 1e9fcbba..4996bcab 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_checkerboard.py +++ b/extensions/fablabchemnitz/fablabchemnitz_checkerboard.py @@ -89,4 +89,5 @@ class Checkerboard(inkex.Effect): x, y = self.svg.namedview.center[0] - cols * size / 2, self.svg.namedview.center[1] - rows * size / 2 draw_grid(x, y, rows, cols, size, color1, color2, group) -Checkerboard().run() +if __name__ == '__main__': + Checkerboard().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_chipScratches.py b/extensions/fablabchemnitz/fablabchemnitz_chipScratches.py index 2d6c47b7..2b14a5da 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_chipScratches.py +++ b/extensions/fablabchemnitz/fablabchemnitz_chipScratches.py @@ -780,5 +780,5 @@ def addparms( p ) : s += parm + ' ' return s -# Create effect instance and apply it. -noiseEffect().run() \ No newline at end of file +if __name__ == '__main__': + noiseEffect().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_cleangroups.py b/extensions/fablabchemnitz/fablabchemnitz_cleangroups.py index 207324f7..51f231a1 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_cleangroups.py +++ b/extensions/fablabchemnitz/fablabchemnitz_cleangroups.py @@ -33,5 +33,7 @@ class CleanGroups(inkex.Effect): continue #we found minimum of one element to delete. so we should run another cycle to check if the parent of this group is empty after deletion newLen = len(self.document.xpath('//svg:g',namespaces=inkex.NSS)) if newLen == oldLen: #found no more empty groups. Leaving the loop - break -CleanGroups().run() \ No newline at end of file + break + +if __name__ == '__main__': + CleanGroups().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_cleanup.py b/extensions/fablabchemnitz/fablabchemnitz_cleanup.py index f1009889..99697fab 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_cleanup.py +++ b/extensions/fablabchemnitz/fablabchemnitz_cleanup.py @@ -58,4 +58,5 @@ class Cleanup(inkex.Effect): declarations[i] = prop + ':' + new_val node.set('style', ';'.join(declarations)) -Cleanup().run() \ No newline at end of file +if __name__ == '__main__': + Cleanup().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_clonesperspective.py b/extensions/fablabchemnitz/fablabchemnitz_clonesperspective.py index 24492c54..92b2f386 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_clonesperspective.py +++ b/extensions/fablabchemnitz/fablabchemnitz_clonesperspective.py @@ -62,4 +62,5 @@ class clonesPerspectiveEffect(inkex.Effect): } parent.insert(j, etree.Element('use', att)) -clonesPerspectiveEffect().run() +if __name__ == '__main__': + clonesPerspectiveEffect().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_close_paths.py b/extensions/fablabchemnitz/fablabchemnitz_close_paths.py index f4f2cbba..57708223 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_close_paths.py +++ b/extensions/fablabchemnitz/fablabchemnitz_close_paths.py @@ -39,4 +39,6 @@ class CloseCurves(inkex.Effect): d = re.sub(r'(?i)(m[^mz]+)',r'\1 Z ',d) d = re.sub(r'(?i)\s*z\s*z\s*',r' Z ',d) node.set('d', d) -CloseCurves().run() \ No newline at end of file + +if __name__ == '__main__': + CloseCurves().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_color_alpha_replace.py b/extensions/fablabchemnitz/fablabchemnitz_color_alpha_replace.py index e653677a..e1ccab69 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_color_alpha_replace.py +++ b/extensions/fablabchemnitz/fablabchemnitz_color_alpha_replace.py @@ -76,4 +76,6 @@ class ReplaceColorAlpha(inkex.Effect): style = style + ";stroke-opacity:" + alphaTo element.set('style',style) sys.stdout = saveout -ReplaceColorAlpha().run() \ No newline at end of file + +if __name__ == '__main__': + ReplaceColorAlpha().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_coloreffect.py b/extensions/fablabchemnitz/fablabchemnitz_coloreffect.py deleted file mode 100644 index 37b179d2..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_coloreffect.py +++ /dev/null @@ -1,209 +0,0 @@ -#!/usr/bin/env python3 -''' -Copyright (C) 2006 Jos Hirth, kaioa.com -Copyright (C) 2007 Aaron C. Spike -Copyright (C) 2009 Monash University - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -''' -import sys, copy, inkex -import random -from inkex import colors - -color_props_fill = ('fill', 'stop-color', 'flood-color', 'lighting-color') -color_props_stroke = ('stroke',) -opacity_props = ('opacity',) #'stop-opacity', 'fill-opacity', 'stroke-opacity' don't work with clones -color_props = color_props_fill + color_props_stroke - - -class ColorEffect(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.visited = [] - - def effect(self): - if len(self.selected)==0: - self.getAttribs(self.document.getroot()) - else: - for id,node in self.selected.items(): - self.getAttribs(node) - - def getAttribs(self,node): - self.changeStyle(node) - for child in node: - self.getAttribs(child) - - def changeStyle(self,node): - for attr in color_props: - val = node.get(attr) - if val: - new_val = self.process_prop(val) - if new_val != val: - node.set(attr, new_val) - - if 'style' in node.attrib: - # References for style attribute: - # http://www.w3.org/TR/SVG11/styling.html#StyleAttribute, - # http://www.w3.org/TR/CSS21/syndata.html - # - # The SVG spec is ambiguous as to how style attributes should be parsed. - # For example, it isn't clear whether semicolons are allowed to appear - # within strings or comments, or indeed whether comments are allowed to - # appear at all. - # - # The processing here is just something simple that should usually work, - # without trying too hard to get everything right. - # (Won't work for the pathological case that someone escapes a property - # name, probably does the wrong thing if colon or semicolon is used inside - # a comment or string value.) - style = node.get('style') # fixme: this will break for presentation attributes! - if style: - #inkex.utils.debug('old style:'+style) - declarations = style.split(';') - opacity_in_style = False - for i,decl in enumerate(declarations): - parts = decl.split(':', 2) - if len(parts) == 2: - (prop, val) = parts - prop = prop.strip().lower() - if prop in color_props: - val = val.strip() - new_val = self.process_prop(val) - if new_val != val: - declarations[i] = prop + ':' + new_val - elif prop in opacity_props: - opacity_in_style = True - val = val.strip() - new_val = self.process_prop(val) - if new_val != val: - declarations[i] = prop + ':' + new_val - if not opacity_in_style: - new_val = self.process_prop("1") - declarations.append('opacity' + ':' + new_val) - #inkex.utils.debug('new style:'+';'.join(declarations)) - node.set('style', ';'.join(declarations)) - - def process_prop(self, col): - #inkex.utils.debug('got:'+col+str(type(col))) - if colors.isColor(col): - c=colors.parseColor(col) - col='#'+self.colmod(c[0], c[1], c[2]) - #inkex.utils.debug('made:'+col) - elif col.startswith('url(#'): - id = col[len('url(#'):col.find(')')] - newid = '%s-%d' % (id, int(random.random() * 1000)) - #inkex.utils.debug('ID:' + id ) - path = '//*[@id="%s"]' % id - for node in self.document.xpath(path, namespaces=inkex.NSS): - self.process_gradient(node, newid) - col = 'url(#%s)' % newid - # what remains should be opacity - else: - col = self.opacmod(col) - - #inkex.utils.debug('col:'+str(col)) - return col - - def process_gradient(self, node, newid): - #if node.hasAttributes(): - #this_id=node.getAttribute('id') - #if this_id in self.visited: - ## prevent multiple processing of the same gradient if it is used by more than one selected object - ##inkex.utils.debug("already had: " + this_id) - #return - #self.visited.append(this_id) - #inkex.utils.debug("visited: " + str(self.visited)) - newnode = copy.deepcopy(node) - newnode.set('id', newid) - node.getparent().append(newnode) - self.changeStyle(newnode) - for child in newnode: - self.changeStyle(child) - xlink = inkex.addNS('href','xlink') - if xlink in newnode.attrib: - href=newnode.get(xlink) - if href.startswith('#'): - id = href[len('#'):len(href)] - #inkex.utils.debug('ID:' + id ) - newhref = '%s-%d' % (id, int(random.random() * 1000)) - newnode.set(xlink, '#%s' % newhref) - path = '//*[@id="%s"]' % id - for node in self.document.xpath(path, namespaces=inkex.NSS): - self.process_gradient(node, newhref) - - def colmod(self,r,g,b): - pass - - def opacmod(self, opacity): - return opacity - - def rgb_to_hsl(self,r, g, b): - rgb_max = max (max (r, g), b) - rgb_min = min (min (r, g), b) - delta = rgb_max - rgb_min - hsl = [0.0, 0.0, 0.0] - hsl[2] = (rgb_max + rgb_min)/2.0 - if delta == 0: - hsl[0] = 0.0 - hsl[1] = 0.0 - else: - if hsl[2] <= 0.5: - hsl[1] = delta / (rgb_max + rgb_min) - else: - hsl[1] = delta / (2 - rgb_max - rgb_min) - if r == rgb_max: - hsl[0] = (g - b) / delta - else: - if g == rgb_max: - hsl[0] = 2.0 + (b - r) / delta - else: - if b == rgb_max: - hsl[0] = 4.0 + (r - g) / delta - hsl[0] = hsl[0] / 6.0 - if hsl[0] < 0: - hsl[0] = hsl[0] + 1 - if hsl[0] > 1: - hsl[0] = hsl[0] - 1 - return hsl - - def hue_2_rgb (self, v1, v2, h): - if h < 0: - h += 6.0 - if h > 6: - h -= 6.0 - if h < 1: - return v1 + (v2 - v1) * h - if h < 3: - return v2 - if h < 4: - return v1 + (v2 - v1) * (4 - h) - return v1 - - def hsl_to_rgb (self,h, s, l): - rgb = [0, 0, 0] - if s == 0: - rgb[0] = l - rgb[1] = l - rgb[2] = l - else: - if l < 0.5: - v2 = l * (1 + s) - else: - v2 = l + s - l*s - v1 = 2*l - v2 - rgb[0] = self.hue_2_rgb (v1, v2, h*6 + 2.0) - rgb[1] = self.hue_2_rgb (v1, v2, h*6) - rgb[2] = self.hue_2_rgb (v1, v2, h*6 - 2.0) - return rgb \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_conic_box.py b/extensions/fablabchemnitz/fablabchemnitz_conic_box.py index 7aa93935..7d5105e6 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_conic_box.py +++ b/extensions/fablabchemnitz/fablabchemnitz_conic_box.py @@ -349,5 +349,5 @@ class ConicalBox(inkex.Effect): #puis pour le petit cercle gen_cercle(d1, nombre_pas, thickness, -xmax - d1/2 + xOffset + 10, d1/2 + yOffset - ymin + 10, layer) -# Create effect instance and apply it. -ConicalBox().run() \ No newline at end of file +if __name__ == '__main__': + ConicalBox().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_convexhull.py b/extensions/fablabchemnitz/fablabchemnitz_convexhull.py index d7dbebc1..c4a07711 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_convexhull.py +++ b/extensions/fablabchemnitz/fablabchemnitz_convexhull.py @@ -115,4 +115,5 @@ class ConvexHull(inkex.Effect): paths_clone_transform = None self.joinWithNode(path, pdata, makeGroup, paths_clone_transform ) -ConvexHull().run() \ No newline at end of file +if __name__ == '__main__': + ConvexHull().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_cutoptim.inx b/extensions/fablabchemnitz/fablabchemnitz_cutoptim.inx deleted file mode 100644 index 51770605..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_cutoptim.inx +++ /dev/null @@ -1,47 +0,0 @@ - - - Cutting Optimizer (Nesting) - fablabchemnitz.de.cutoptim - - - - - - - - - - - - - 2.0 - 1000 - 1 - false - - - - - - - - - - - - true - 0 - true - true - - all - - - - - - - - \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_destructiveclip.py b/extensions/fablabchemnitz/fablabchemnitz_destructiveclip.py index f7c73adb..4363f56a 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_destructiveclip.py +++ b/extensions/fablabchemnitz/fablabchemnitz_destructiveclip.py @@ -216,4 +216,5 @@ class DestructiveClip(inkex.Effect): for error in self.error_messages: inkex.errormsg(error) -DestructiveClip().run() +if __name__ == '__main__': + DestructiveClip().run() diff --git a/extensions/fablabchemnitz/fablabchemnitz_dots2pathpoints.py b/extensions/fablabchemnitz/fablabchemnitz_dots2pathpoints.py index 35c7a450..8f58e7f4 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_dots2pathpoints.py +++ b/extensions/fablabchemnitz/fablabchemnitz_dots2pathpoints.py @@ -71,4 +71,5 @@ class Pathpoints2Dots(inkex.Effect): clone.set('y',point.y-bb.center.y) group.add(clone) -Pathpoints2Dots().run() +if __name__ == '__main__': + Pathpoints2Dots().run() diff --git a/extensions/fablabchemnitz/fablabchemnitz_drawdirections.inx b/extensions/fablabchemnitz/fablabchemnitz_drawdirections.inx index 9dc03427..0dd17c67 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_drawdirections.inx +++ b/extensions/fablabchemnitz/fablabchemnitz_drawdirections.inx @@ -5,7 +5,9 @@ path - + + + - \ No newline at end of file + diff --git a/extensions/fablabchemnitz/fablabchemnitz_gpx2svg.py b/extensions/fablabchemnitz/fablabchemnitz_gpx_input.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_gpx2svg.py rename to extensions/fablabchemnitz/fablabchemnitz_gpx_input.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_gridstrip_creator.py b/extensions/fablabchemnitz/fablabchemnitz_gridstrip_creator.py index 4bd6547b..67480c50 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_gridstrip_creator.py +++ b/extensions/fablabchemnitz/fablabchemnitz_gridstrip_creator.py @@ -342,4 +342,5 @@ class GridStrip_Creator(inkex.Effect): 'd':pathstring} etree.SubElement(grp, inkex.addNS('path','svg'), strip_attribs ) -GridStrip_Creator().run() \ No newline at end of file +if __name__ == '__main__': + GridStrip_Creator().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_group_to_layer.py b/extensions/fablabchemnitz/fablabchemnitz_group_to_layer.py index d22e0c0b..8c3df98e 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_group_to_layer.py +++ b/extensions/fablabchemnitz/fablabchemnitz_group_to_layer.py @@ -44,4 +44,5 @@ class GroupToLayerEffect(inkex.Effect): for child in node: self.convert_group(child, depth - 1) -GroupToLayerEffect().run() \ No newline at end of file +if __name__ == '__main__': + GroupToLayerEffect().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_guillotine_plus.py b/extensions/fablabchemnitz/fablabchemnitz_guillotine_plus.py index 34aa3463..0694d65c 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_guillotine_plus.py +++ b/extensions/fablabchemnitz/fablabchemnitz_guillotine_plus.py @@ -179,4 +179,5 @@ class Guillotine(inkex.EffectExtension): def effect(self): self.export_slices(self.get_slices()) -Guillotine().run() +if __name__ == '__main__': + Guillotine().run() diff --git a/extensions/fablabchemnitz/fablabchemnitz_hexmap.py b/extensions/fablabchemnitz/fablabchemnitz_hexmap.py index 53d2f97b..e4ca17ef 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_hexmap.py +++ b/extensions/fablabchemnitz/fablabchemnitz_hexmap.py @@ -416,4 +416,5 @@ class HexmapEffect(inkex.Effect): for c in svg.iterchildren()]: svg.append(layer) -HexmapEffect().run() \ No newline at end of file +if __name__ == '__main__': + HexmapEffect().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_ids_to_text.py b/extensions/fablabchemnitz/fablabchemnitz_ids_to_text.py index d952bbcd..95e29088 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_ids_to_text.py +++ b/extensions/fablabchemnitz/fablabchemnitz_ids_to_text.py @@ -47,4 +47,5 @@ class IdsToText(inkex.Effect): node.set('y', str(ty)) node.set('transform', 'rotate(%s, %s, %s)' % (-int(self.options.angle), tx, ty)) -IdsToText().run() \ No newline at end of file +if __name__ == '__main__': + IdsToText().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_isometric_projection.py b/extensions/fablabchemnitz/fablabchemnitz_isometric_projection.py index 24aa7e78..1f603140 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_isometric_projection.py +++ b/extensions/fablabchemnitz/fablabchemnitz_isometric_projection.py @@ -158,5 +158,5 @@ class IsometricProjectionTools(inkex.Effect): # Adjust the transformation center. self.moveTransformationCenter(node, midpoint, center_new) -# Create effect instance and apply it. -IsometricProjectionTools().run() \ No newline at end of file +if __name__ == '__main__': + IsometricProjectionTools().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_join_paths_optimized.py b/extensions/fablabchemnitz/fablabchemnitz_join_paths_optimized.py index f1617ebe..2bd5ebba 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_join_paths_optimized.py +++ b/extensions/fablabchemnitz/fablabchemnitz_join_paths_optimized.py @@ -160,4 +160,5 @@ class JoinPathsOptimEffect(inkex.Effect): newElem.set('id', oldId + '_joined') parent.insert(idx, newElem) -JoinPathsOptimEffect().run() \ No newline at end of file +if __name__ == '__main__': + JoinPathsOptimEffect().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_jpegexport.py b/extensions/fablabchemnitz/fablabchemnitz_jpegexport.py index 32c4a816..1469d5b8 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_jpegexport.py +++ b/extensions/fablabchemnitz/fablabchemnitz_jpegexport.py @@ -22,13 +22,13 @@ from distutils.spawn import find_executable import subprocess import math import inkex +import shutil inkex.localization.localize class JPEGExport(inkex.Effect): def __init__(self): - """Init the effect library and get options from gui.""" inkex.Effect.__init__(self) self.arg_parser.add_argument("--path", default="") @@ -57,7 +57,9 @@ class JPEGExport(inkex.Effect): exit() outfile=self.options.path - curfile = self.options.input_file + + shutil.copy(self.options.input_file, self.options.input_file + ".svg") #make a file copy with file ending to suppress import warnings + curfile = self.options.input_file + ".svg" #inkex.utils.debug("curfile:" + curfile) # Test if color is valid @@ -186,4 +188,5 @@ class JPEGExport(inkex.Effect): else: return '/tmp/' -JPEGExport().run() +if __name__ == '__main__': + JPEGExport().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_label_color.py b/extensions/fablabchemnitz/fablabchemnitz_label_color.py index 2ceb6101..8bfaad62 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_label_color.py +++ b/extensions/fablabchemnitz/fablabchemnitz_label_color.py @@ -141,4 +141,5 @@ class LabelColour(inkex.Effect): return nodeX, nodeY, nodeWidth, nodeHeight -LabelColour().run() \ No newline at end of file +if __name__ == '__main__': + LabelColour().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_lasercut_sequence.py b/extensions/fablabchemnitz/fablabchemnitz_lasercut_sequence.py index 6734349b..f65e2a85 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_lasercut_sequence.py +++ b/extensions/fablabchemnitz/fablabchemnitz_lasercut_sequence.py @@ -38,4 +38,5 @@ class LaserSort(inkex.Effect): newpathstring = "z ".join(sections) + nonClosedSection el.set('d', newpathstring) -LaserSort().run() +if __name__ == '__main__': + LaserSort().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_leathercase.py b/extensions/fablabchemnitz/fablabchemnitz_leathercase.py index 8473cf24..b30cee3c 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_leathercase.py +++ b/extensions/fablabchemnitz/fablabchemnitz_leathercase.py @@ -156,4 +156,5 @@ class LeatherCase1(inkex.Effect): fourthPiece = etree.SubElement(parent, inkex.addNS('path','svg'), fourthPiece_attribs ) -LeatherCase1().run() \ No newline at end of file +if __name__ == '__main__': + LeatherCase1().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_living_hinge.py b/extensions/fablabchemnitz/fablabchemnitz_living_hinge.py index ba006af9..4b1ddfa1 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_living_hinge.py +++ b/extensions/fablabchemnitz/fablabchemnitz_living_hinge.py @@ -260,5 +260,5 @@ class HingeCuts(inkex.Effect): return (ret, l, d, dd) -# Create effect instance and apply it. -HingeCuts().run() \ No newline at end of file +if __name__ == '__main__': + HingeCuts().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_living_hinge2.py b/extensions/fablabchemnitz/fablabchemnitz_living_hinge2.py index 362bf45a..4fa166b2 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_living_hinge2.py +++ b/extensions/fablabchemnitz/fablabchemnitz_living_hinge2.py @@ -509,5 +509,5 @@ class LivingHinge(inkex.Effect): self.livingHinge4(x+(Z/2), y, x+(Z/2)+EllipseCircumference(X/2, Z/2)/4, y + (dy/2) + thickness, True, 0, hingeThick) #Add thickness as a cheat so design 4 doesn't have to know if it's a short or long variant self.livingHinge4(x+(Z/2), y + (dy/2) - thickness, (x+(Z/2)+(EllipseCircumference(X/2, Z/2)/4)), y + dy, True, 1, hingeThick) -# Create effect instance and apply it. -LivingHinge().run() \ No newline at end of file +if __name__ == '__main__': + LivingHinge().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_living_hinge3.py b/extensions/fablabchemnitz/fablabchemnitz_living_hinge3.py index 677aca4a..30de8cbf 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_living_hinge3.py +++ b/extensions/fablabchemnitz/fablabchemnitz_living_hinge3.py @@ -78,4 +78,5 @@ class BendWoodCutsPattern(inkex.Effect): self.draw_SVG_line(x * horizontalLineSeparation, y0, x * horizontalLineSeparation, y1, parent) -BendWoodCutsPattern().run() \ No newline at end of file +if __name__ == '__main__': + BendWoodCutsPattern().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_longest_continuous_paths.py b/extensions/fablabchemnitz/fablabchemnitz_longest_continuous_paths.py index 214ff54d..42edec93 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_longest_continuous_paths.py +++ b/extensions/fablabchemnitz/fablabchemnitz_longest_continuous_paths.py @@ -613,4 +613,5 @@ class OptimizePaths(inkex.GenerateExtension): self.log("Total duration: {:.0f} sec ({:.1f} min)".format(totalDuration, totalDuration / 60)) return group -OptimizePaths().run() +if __name__ == '__main__': + OptimizePaths().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_low_poly_2.py b/extensions/fablabchemnitz/fablabchemnitz_low_poly_2.py index a74ba293..d326a1bb 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_low_poly_2.py +++ b/extensions/fablabchemnitz/fablabchemnitz_low_poly_2.py @@ -290,11 +290,12 @@ class Voronoi2svg(inkex.Effect): middleX=(p1.x+p2.x+p3.x)/3.0 middleY=(p1.y+p2.y+p3.y)/3.0 if width>middleX and height>middleY and middleX>=0 and middleY>=0: - r,g,b = img.getpixel((middleX,middleY)) - facestyle["fill"]=str(inkex.Color((r, g, b))) + pixelColor = img.getpixel((middleX,middleY)) + facestyle["fill"]=str(inkex.Color((pixelColor[0], pixelColor[1], pixelColor[2]))) else: facestyle["fill"]="black" path.set('style', str(inkex.Style(facestyle))) groupDelaunay.append(path) -Voronoi2svg().run() \ No newline at end of file +if __name__ == '__main__': + Voronoi2svg().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_migrategroups.inx b/extensions/fablabchemnitz/fablabchemnitz_migrategroups.inx index 181fcfdf..c6ebb4ec 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_migrategroups.inx +++ b/extensions/fablabchemnitz/fablabchemnitz_migrategroups.inx @@ -2,8 +2,8 @@ Ungrouper And Element Migrator/Filter fablabchemnitz.de.migrategroups - - + + @@ -39,19 +39,26 @@ + + true true true true true - true true - true - false + + + + + + true false + false + true diff --git a/extensions/fablabchemnitz/fablabchemnitz_migrategroups.py b/extensions/fablabchemnitz/fablabchemnitz_migrategroups.py index d00fa20b..b6cd4bde 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_migrategroups.py +++ b/extensions/fablabchemnitz/fablabchemnitz_migrategroups.py @@ -8,7 +8,7 @@ This extension parses the selection and will put all elements into one single gr Author: Mario Voigt / FabLab Chemnitz Mail: mario.voigt@stadtfabrikanten.org Date: 13.08.2020 -Last Patch: 29.08.2020 +Last Patch: 31.08.2020 License: GNU GPL v3 """ @@ -18,43 +18,49 @@ from lxml import etree class MigrateGroups(inkex.Effect): allElements = [] #list of all (sub)elements to process within selection - allGroups = [] #list of all groups (svg:g and svg:svg items) to delete - allNonMigrates = [] #list of all other elements except svg:g and svg:svg to drop while migrating + allGroups = [] #list of all groups (svg:g and svg:svg items) to delete for cleanup (for ungrouping) + allDrops = [] #list of all other elements except svg:g and svg:svg to drop while migrating (for filtering) def __init__(self): inkex.Effect.__init__(self) - self.arg_parser.add_argument("--allitems", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--droponly", type=inkex.Boolean, default=False) + self.arg_parser.add_argument("--ignorecustomselection", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--operationmode", default=False) + self.arg_parser.add_argument("--parsechildren", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--cleanup", type=inkex.Boolean, default = True, help = "Decimal tolerance") self.arg_parser.add_argument("--showdroplist", type=inkex.Boolean, default=False) - self.arg_parser.add_argument("--circle", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--clipPath", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--defs", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--ellipse", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--image", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--line", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--path", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--polyline", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--polygon", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--rect", type=inkex.Boolean, default=True) - #self.arg_parser.add_argument("--sodipodi", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--svg", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--text", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--tspan", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--shownewgroupname", type=inkex.Boolean, default=False) + + #self.arg_parser.add_argument("--sodipodi", type=inkex.Boolean, default=True) + #self.arg_parser.add_argument("--svg", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--circle", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--clipPath", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--defs", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--ellipse", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--image", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--line", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--path", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--polyline", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--polygon", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--rect", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--text", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--tspan", type=inkex.Boolean, default=True) self.arg_parser.add_argument("--linearGradient", type=inkex.Boolean, default=True) self.arg_parser.add_argument("--radialGradient", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--meshGradient", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--meshRow", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--meshPatch", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--metadata", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--script", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--stop", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--use", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--flowRoot", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--flowRegion", type=inkex.Boolean, default=True) - self.arg_parser.add_argument("--flowPara", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--meshGradient", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--meshRow", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--meshPatch", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--metadata", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--script", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--stop", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--use", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--flowRoot", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--flowRegion", type=inkex.Boolean, default=True) + self.arg_parser.add_argument("--flowPara", type=inkex.Boolean, default=True) def effect(self): - namespace = [] + namespace = [] #a list of selected types we are going to process for filtering (dropping items) + #namespace.append("{http://www.w3.org/2000/svg}sodipodi") if self.options.sodipodi else "" #do not do this. it will crash InkScape + #namespace.append("{http://www.w3.org/2000/svg}svg") if self.options.svg else "" #we handle svg:svg the same type like svg:g namespace.append("{http://www.w3.org/2000/svg}circle") if self.options.circle else "" namespace.append("{http://www.w3.org/2000/svg}clipPath") if self.options.clipPath else "" namespace.append("{http://www.w3.org/2000/svg}defs") if self.options.defs else "" @@ -65,8 +71,6 @@ class MigrateGroups(inkex.Effect): namespace.append("{http://www.w3.org/2000/svg}path") if self.options.path else "" namespace.append("{http://www.w3.org/2000/svg}polyline") if self.options.polyline else "" namespace.append("{http://www.w3.org/2000/svg}rect") if self.options.rect else "" - #namespace.append("{http://www.w3.org/2000/svg}sodipodi") if self.options.sodipodi else "" #do not do this. it will crash InkScape - #namespace.append("{http://www.w3.org/2000/svg}svg") if self.options.svg else "" namespace.append("{http://www.w3.org/2000/svg}text") if self.options.text else "" namespace.append("{http://www.w3.org/2000/svg}tspan") if self.options.tspan else "" namespace.append("{http://www.w3.org/2000/svg}linearGradient") if self.options.linearGradient else "" @@ -81,85 +85,113 @@ class MigrateGroups(inkex.Effect): namespace.append("{http://www.w3.org/2000/svg}flowRoot") if self.options.flowRoot else "" namespace.append("{http://www.w3.org/2000/svg}flowRegion") if self.options.flowRegion else "" namespace.append("{http://www.w3.org/2000/svg}flowPara") if self.options.flowPara else "" - #inkex.utils.debug(namespace) + #in case the user made a manual selection instead of whole document parsing, we need to collect all required elements first + def parseChildren(element): + if element not in selected: + selected.append(element) + if self.options.parsechildren == True: + children = element.getchildren() + if children is not None: + for child in children: + if child not in selected: + selected.append(child) + parseChildren(child) #go deeper and deeper + + #check the element for it's type and put it into the according list (either re-group or delete or just nothing) + def parseElement(self, element): + #if we only want to ungroup (flatten) the elements we just collect all elements in a list and put them in a new single group later + if self.options.operationmode == "ungroup_only": + if element not in self.allElements: + if element.tag != inkex.addNS('g','svg') and element.tag != inkex.addNS('svg','svg') and element.tag != inkex.addNS('namedview','sodipodi'): + self.allElements.append(element) + #if we dont want to ungroup but filter out elements, or ungroup and filter, we need to divide the elements with respect to the namespace (user selection) + elif self.options.operationmode == "filter_only" or self.options.operationmode == "ungroup_and_filter": + #inkex.utils.debug(element.tag) + if element.tag in namespace: #if the element is in namespace and no group type we will regroup the item. so we will not remove it + if element not in self.allElements: + self.allElements.append(element) + else: #we add all remaining items (except svg:g and svg:svg) into the list for deletion + #inkex.utils.debug(element.tag) + if element.tag != inkex.addNS('g','svg') and element.tag != inkex.addNS('svg','svg') and element.tag != inkex.addNS('namedview','sodipodi'): + if element not in self.allDrops: + self.allDrops.append(element) + #finally the groups we want to get rid off are put into a another list. They will be deleted (depending on the mode) after parsing the element tree + if self.options.operationmode == "ungroup_only" or self.options.operationmode == "ungroup_and_filter": + if element.tag == inkex.addNS('g','svg') or element.tag == inkex.addNS('svg','svg'): + if element not in self.allGroups: + self.allGroups.append(element) + #check if we have selected elements or if we should parse the whole document instead - selected = [] #list of elements to parse + selected = [] #total list of elements to parse if len(self.svg.selected) == 0: for element in self.document.getroot().iter(tag=etree.Element): if element != self.document.getroot(): selected.append(element) else: - selected = self.svg.get_selected() - - #check the element for it's type and put it into the the according list (either re-group or delete) - def parseElement(self, element): - if self.options.allitems: - if element not in self.allElements: - if element.tag != inkex.addNS('g','svg') and element.tag != inkex.addNS('svg','svg') and element.tag != inkex.addNS('namedview','sodipodi'): - self.allElements.append(element) - else: - #inkex.utils.debug(element.tag) - if element.tag in namespace: - if element not in self.allElements: - self.allElements.append(element) - else: - #inkex.utils.debug(element.tag) - if element.tag != inkex.addNS('g','svg') and element.tag != inkex.addNS('svg','svg') and element.tag != inkex.addNS('namedview','sodipodi'): - if element not in self.allNonMigrates: - self.allNonMigrates.append(element) - - if element.tag == inkex.addNS('g','svg') or element.tag == inkex.addNS('svg','svg'): - if element not in self.allGroups: - self.allGroups.append(element) - groups = element.getchildren() - if groups is not None: - for group in groups: - parseElement(self, group) - if group not in self.allGroups: - self.allGroups.append(group) - - #get all elements from the selection. Remove all groups from the selection and form a new single group of it. We also handle svg:svg because it behaves like a group container too + for id, element in self.svg.selected.items(): + parseChildren(element) + + #get all elements from the selection. for element in selected: parseElement(self, element) - - #copy all element into the new group - if len(self.allElements) > 0: - newGroup = self.document.getroot().add(inkex.Group()) #make a new group at root level - for oldElement in self.allElements: - #oldElementId = oldElement.get('id') - newElement = oldElement.copy() - #newElement.set('id', oldElementId) - newGroup.add(newElement) - if self.options.droponly: - if oldElement.getparent() is not None: - oldElement.getparent().remove(oldElement) - - #show a list with items to delete - if self.options.showdroplist: - self.msg(str(len(self.allNonMigrates)) + " elements were removed during nodes while migration:") - for i in self.allNonMigrates: - if i.get('id') is not None: - self.msg(i.tag.replace("{http://www.w3.org/2000/svg}","svg:") + " id:" + i.get('id')) + + #some debugging block + #check output + #inkex.utils.debug("--- Selected items (with or without children) ---") + #inkex.utils.debug(selected) + #inkex.utils.debug("--- All elements (except groups)---") + #inkex.utils.debug(len(self.allElements)) + #inkex.utils.debug(self.allElements) + #inkex.utils.debug("--- All groups ---") + #inkex.utils.debug(len(self.allGroups)) + #inkex.utils.debug(self.allGroups) + #inkex.utils.debug("--- All dropouts ---") + #inkex.utils.debug(len(self.allDrops)) + #inkex.utils.debug(self.allDrops) + + # show a list with items to delete. For ungroup mode it does not apply because we are not going to remove anything + if self.options.operationmode == "filter_only" or self.options.operationmode == "ungroup_and_filter": + if self.options.showdroplist: + self.msg(str(len(self.allDrops)) + " elements were removed during nodes while migration:") + for i in self.allDrops: + if i.get('id') is not None: + self.msg(i.tag.replace("{http://www.w3.org/2000/svg}","svg:") + " id:" + i.get('id')) - # #now remove the stuff with nonMigrates list. this has to be done before we drop the groups where they are located - # if len(self.allNonMigrates) > 0: - # for nonMigrate in self.allNonMigrates: - # if nonMigrate.getparent() is not None: - # nonMigrate.getparent().remove(nonMigrate) + # remove all groups from the selection and form a new single group of it by copying with old IDs. + if self.options.operationmode == "ungroup_only" or self.options.operationmode == "ungroup_and_filter": + if len(self.allElements) > 0: + newGroup = self.document.getroot().add(inkex.Group()) #make a new group at root level + newGroup.set('id', self.svg.get_unique_id('migrate-')) #generate some known ID with the prefix 'migrate-' + if self.options.shownewgroupname == True: + inkex.utils.debug("The migrated elements are now in group with ID " + str(newGroup.get('id'))) + index = 0 + for element in self.allElements: #we have a list of elements which does not cotain any other elements like svg:g or svg:svg + newGroup.insert(index, element) #we do not copy any elements. we just rearrange them by moving to another place (group index) + index += 1 #we must count up the index or we would overwrite each previous element + + # remove the stuff from drop list list. this has to be done before we drop the groups where they are located in + if self.options.operationmode == "filter_only" or self.options.operationmode == "ungroup_and_filter": + if len(self.allDrops) > 0: + for dropElement in self.allDrops: + if dropElement.getparent() is not None: + dropElement.getparent().remove(dropElement) - #now remove all the obsolete groups - if self.options.droponly == False: + # remove all the obsolete groups which are left over from ungrouping (flattening) + if self.options.operationmode == "ungroup_only" or self.options.operationmode == "ungroup_and_filter": if len(self.allGroups) > 0: for group in self.allGroups: if group.getparent() is not None: group.getparent().remove(group) - - #remove the selected, now empty group (if it's the case) - this applies not if there is no user selection at all so some dangling group(s) might be left over - if len(self.svg.selected) > 0 and len(self.allElements) > 0: - if self.svg.get_first_selected().tag == inkex.addNS('g','svg') or self.svg.get_first_selected().tag == inkex.addNS('svg','svg'): - if self.svg.get_first_selected().getparent() is not None: - self.svg.get_first_selected().getparent().remove(self.svg.get_first_selected()) + + # finally removed dangling empty groups using external extension (if installed) + if self.options.cleanup == True: + try: + import fablabchemnitz_cleangroups + fablabchemnitz_cleangroups.CleanGroups.effect(self) + except: + inkex.utils.debug("Calling 'Remove Empty Groups' extension failed. Maybe the extension is not installed. You can download it from official InkScape Gallery.") -MigrateGroups().run() +if __name__ == '__main__': + MigrateGroups().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_netting.py b/extensions/fablabchemnitz/fablabchemnitz_netting.py index d62ee7b4..f5a1dba9 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_netting.py +++ b/extensions/fablabchemnitz/fablabchemnitz_netting.py @@ -56,4 +56,5 @@ class RadiusRandomize(inkex.Effect): my_path.set('d', " ".join(net_strings)) self.svg.get_current_layer().append( my_path ) -RadiusRandomize().run() \ No newline at end of file +if __name__ == '__main__': + RadiusRandomize().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_ofsplot.py b/extensions/fablabchemnitz/fablabchemnitz_ofsplot.py index 26184782..6cb9ad44 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_ofsplot.py +++ b/extensions/fablabchemnitz/fablabchemnitz_ofsplot.py @@ -81,4 +81,5 @@ class ofsplot(inkex.Effect): path.set('d',CubicSuperPath(new)) -ofsplot().run() +if __name__ == '__main__': + ofsplot().run() diff --git a/extensions/fablabchemnitz/fablabchemnitz_paste_length.py b/extensions/fablabchemnitz/fablabchemnitz_paste_length.py index 26eaf473..29ae1cc2 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_paste_length.py +++ b/extensions/fablabchemnitz/fablabchemnitz_paste_length.py @@ -108,4 +108,5 @@ class PasteLengthEffect(inkex.Effect): length is to be copied at the top. You may have to convert the shape \ to path with path->Object to Path.") -PasteLengthEffect().run() +if __name__ == '__main__': + PasteLengthEffect().run() diff --git a/extensions/fablabchemnitz/fablabchemnitz_paths2openscad.py b/extensions/fablabchemnitz/fablabchemnitz_paths2openscad.py index 402345b4..a64baeb1 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_paths2openscad.py +++ b/extensions/fablabchemnitz/fablabchemnitz_paths2openscad.py @@ -1490,4 +1490,5 @@ module chamfer_sphere(rad=chamfer, res=chamfer_fn) stdout.close() stderr.close() -OpenSCAD().run() +if __name__ == '__main__': + OpenSCAD().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_pianoscale.py b/extensions/fablabchemnitz/fablabchemnitz_pianoscale.py index cb72b0aa..9b978e52 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_pianoscale.py +++ b/extensions/fablabchemnitz/fablabchemnitz_pianoscale.py @@ -328,4 +328,5 @@ class SVGPianoScale (inkex.Effect): self.createPiano(group) self.createMarkersFromIntervals(group, self.options.intervals) -SVGPianoScale().run() +if __name__ == '__main__': + SVGPianoScale().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_pixel2svg.py b/extensions/fablabchemnitz/fablabchemnitz_pixel2svg.py index c4a3ff55..347414c5 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_pixel2svg.py +++ b/extensions/fablabchemnitz/fablabchemnitz_pixel2svg.py @@ -280,4 +280,5 @@ class Pixel2SVG(inkex.Effect): inkex.errormsg("Please select one or more bitmap image(s) for Pixel2SVG") sys.exit(0) -Pixel2SVG().run() \ No newline at end of file +if __name__ == '__main__': + Pixel2SVG().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_polygon.py b/extensions/fablabchemnitz/fablabchemnitz_polygon.py index d7c2fa1d..55ca5de3 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_polygon.py +++ b/extensions/fablabchemnitz/fablabchemnitz_polygon.py @@ -177,4 +177,5 @@ class Polygon(inkex.Effect): text.text+=" "+tag_2 layer.append(text) -Polygon().run() \ No newline at end of file +if __name__ == '__main__': + Polygon().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_printing_marks_dotted.py b/extensions/fablabchemnitz/fablabchemnitz_printing_marks_dotted.py index c5c883d5..11a14424 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_printing_marks_dotted.py +++ b/extensions/fablabchemnitz/fablabchemnitz_printing_marks_dotted.py @@ -473,5 +473,4 @@ class Printing_Marks (inkex.Effect): if __name__ == '__main__': - e = Printing_Marks() - e.run() \ No newline at end of file + Printing_Marks().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_purge_short_lines.inx b/extensions/fablabchemnitz/fablabchemnitz_purge_short_lines.inx deleted file mode 100644 index e966eb05..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_purge_short_lines.inx +++ /dev/null @@ -1,17 +0,0 @@ - - - Purge Short Lines - fablabchemnitz.de.purge_short_lines - 10 - - all - - - - - - - - \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_purge_short_lines.py b/extensions/fablabchemnitz/fablabchemnitz_purge_short_lines.py deleted file mode 100644 index 707e7886..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_purge_short_lines.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python3 - -# Purge short lines -# This script is designed to be used to clean up/simplify 2D vector exports from -# SketchUp. It ignores everything but paths between exactly 2 points. - -import inkex -import math -debug = False - -class EnerothPurgeShortEdges(inkex.Effect): - def __init__(self): - inkex.Effect.__init__(self) - self.arg_parser.add_argument('-w', '--length', action = 'store', - type = float, dest = 'length', default = 10.0) - - def effect(self): - length = self.options.length - svg = self.document.getroot() - - if len(self.svg.selected)==0: - self.iterate_node(self.document.getroot()) - else: - for id, node in self.svg.selected.items(): - self.iterate_node(node) - - def iterate_node(self, node): - self.do_node(node) - for child in node: - self.iterate_node(child) - - def do_node(self, node): - if node.attrib.has_key('d'): - points = [] - - instruction = None - prev_coords = [0,0] - - words = node.get('d').split(' ') - for i, word in enumerate(words): - if len(word) == 1: - instruction = word - # inkex.utils.debug(word) - else: - # Sometimes there is the case that "coords" returns only an array like [-1.29] (only one coordinate) instead of XY coordinates. Reason is the type "map" - coords = list(map(lambda c: float(c), word.split(','))) - # inkex.utils.debug(coords) - if instruction.lower() == instruction: - # inkex.utils.debug("coords len=" + str(len(coords)) + "prev_coords len=" + str(len(prev_coords))) - try: - coords[0] += prev_coords[0] - coords[1] += prev_coords[1] - # if len(coords) == 2: - # coords[1] += prev_coords[1] - prev_coords = coords - # Assume all coordinates are points of straight lines (instructor being M, m, L or l) - # inkex.utils.debug("X=" + str(coords[0]) + "Y=" + str(coords[1])) - points.append(coords) - # inkex.utils.debug("pointsCount=" + str(len(points))) - if len(points) == 2: - length = math.sqrt((points[0][0]-points[1][0])**2 + (points[0][1]-points[1][1])**2) - # inkex.utils.debug("length=" + str(length)) - if debug: - inkex.utils.debug(length) - if length < self.options.length: - # inkex.utils.debug("delete") - node.getparent().remove(node) - except: - pass #ignore errors in case of vertical lines or horizonal lines -EnerothPurgeShortEdges().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_quickjoint.py b/extensions/fablabchemnitz/fablabchemnitz_quickjoint.py index 8b90f18e..c756d2a6 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_quickjoint.py +++ b/extensions/fablabchemnitz/fablabchemnitz_quickjoint.py @@ -41,7 +41,16 @@ def linesNumber(path): return retval def to_complex(point): - return complex(point.x, point.y) + c = None + try: + c = complex(point.x, point.y) + except Exception as e: + pass + if c is not None: + return c + else: + inkex.utils.debug("The selection seems not be be a usable polypath. QuickJoint does not operate on curves. Try to flatten bezier curves or splitting up the path.") + exit(1) class QuickJoint(inkex.Effect): diff --git a/extensions/fablabchemnitz/fablabchemnitz_remove_redundant.py b/extensions/fablabchemnitz/fablabchemnitz_remove_redundant.py index 4edc4d95..976dc22c 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_remove_redundant.py +++ b/extensions/fablabchemnitz/fablabchemnitz_remove_redundant.py @@ -113,4 +113,5 @@ class RemoveRedundant(inkex.Effect): newPath = newPath[:-1] node.set('d',str(paths.Path(newPath))) -RemoveRedundant().run() \ No newline at end of file +if __name__ == '__main__': + RemoveRedundant().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_render_knob_scale.py b/extensions/fablabchemnitz/fablabchemnitz_render_knob_scale.py index 3e34690c..92813b97 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_render_knob_scale.py +++ b/extensions/fablabchemnitz/fablabchemnitz_render_knob_scale.py @@ -218,5 +218,4 @@ class Knob_Scale(inkex.Effect): subtick_length, parent) if __name__ == '__main__': - e = Knob_Scale() - e.run() \ No newline at end of file + e = Knob_Scale().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_render_scale.py b/extensions/fablabchemnitz/fablabchemnitz_render_scale.py index 4c21f3b7..ede2dfbf 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_render_scale.py +++ b/extensions/fablabchemnitz/fablabchemnitz_render_scale.py @@ -544,6 +544,5 @@ class ScaleGen(inkex.Effect): line_attribs = {'style' : str(inkex.Style(line_style)), inkex.addNS('label','inkscape') : 'name', 'd' : 'M '+str(-10)+','+str(10)+' L '+str(10)+','+str(-10)} line = etree.SubElement(grpRadMark, inkex.addNS('path','svg'), line_attribs ) -# Create effect instance and apply it. -effect = ScaleGen() -effect.run() +if __name__ == '__main__': + ScaleGen().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_reorder_sequence.inx b/extensions/fablabchemnitz/fablabchemnitz_reorder_sequence.inx deleted file mode 100644 index 2c76cb20..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_reorder_sequence.inx +++ /dev/null @@ -1,28 +0,0 @@ - - - Optimize Sequence: Travel Distances - fablabchemnitz.de.reorder_sequence - EggBot Plot Optimization Tool - -This utility will re-order objects within each layer of your -document, to reduce pen-up travel distance and time. - - - - - - - -v 2.5. Copyright 2019, Evil Mad Scientist - - all - - - - - - - - \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_reorder_sequence.py b/extensions/fablabchemnitz/fablabchemnitz_reorder_sequence.py deleted file mode 100644 index 4da2f7a6..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_reorder_sequence.py +++ /dev/null @@ -1,1240 +0,0 @@ -#!/usr/bin/env python3 -# -# SVG Path Ordering Extension -# This extension uses a simple TSP algorithm to order the paths so as -# to reduce plotting time by plotting nearby paths consecutively. -# -# Copyright 2019, Windell H. Oskay, Evil Mad Science LLC -# www.evilmadscientist.com -# -# -# While written from scratch, this is a derivative in spirit of the work by -# Matthew Beckler and Daniel C. Newman for the EggBot project. -# -# The MIT License (MIT) -# -# Copyright (c) 2019 Windell H. Oskay, Evil Mad Scientist Laboratories -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -import sys -import inkex -import gettext -import math -import plot_utils # https://github.com/evil-mad/plotink Requires version 0.15 -from lxml import etree -from inkex import Transform - -""" -TODOs: - -* Apparent difference in execution time for portrait vs landscape document orientation. - Seems to be related to the _change_ - -* Implement path functions - - -<_option value=0>Leave as is -<_option value=1>Reorder subpaths -<_option value=2>Break apart - - -self.OptionParser.add_option( "--path_handling",\ -action="store", type="int", dest="path_handling",\ -default=1,help="How compound paths are handled") - - -* Consider re-introducing GUI method for rendering: - -false - - -""" - -class ReorderEffect(inkex.Effect): - """ - Inkscape effect extension. - Re-order the objects in the SVG document for faster plotting. - Respect layers: Initialize a new dictionary of objects for each layer, and sort - objects within that layer only - Objects in root of document are treated as being on a _single_ layer, and will all - be sorted. - - """ - - def __init__( self ): - inkex.Effect.__init__( self ) - - self.arg_parser.add_argument("--reordering", type=int, default=1, help="How groups are handled") - - self.auto_rotate = False - - def effect(self): - # Main entry point of the program - - self.svg_width = 0 - self.svg_height = 0 - self.air_total_default = 0 - self.air_total_sorted = 0 - self.printPortrait = False - - # Rendering is available for debug purposes. It only previews - # pen-up movements that are reordered and typically does not - # include all possible movement. - - self.preview_rendering = False - self.layer_index = 0 # index for coloring layers - - self.svg = self.document.getroot() - - self.DocUnits = "in" # Default - self.DocUnits = self.svg.unit - - self.unit_scaling = 1 - - self.getDocProps() - - """ - Set up the document-wide transforms to handle SVG viewbox - """ - - matCurrent = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] - - viewbox = self.svg.get( 'viewBox' ) - - vb = self.svg.get('viewBox') - if vb: - p_a_r = self.svg.get('preserveAspectRatio') - sx,sy,ox,oy = plot_utils.vb_scale(vb, p_a_r, self.svg_width, self.svg_height) - else: - sx = 1.0 / float(plot_utils.PX_PER_INCH) # Handle case of no viewbox - sy = sx - ox = 0.0 - oy = 0.0 - - # Initial transform of document is based on viewbox, if present: - matCurrent = Transform('scale(' + str(sx) + ',' + str(sy) +') translate(' + str(ox) + ',' + str(oy) +')').matrix - # Set up x_last, y_last, which keep track of last known pen position - # The initial position is given by the expected initial pen position - - self.y_last = 0 - - if (self.printPortrait): - self.x_last = self.svg_width - else: - self.x_last = 0 - - parent_vis='visible' - - self.root_nodes = [] - - if self.preview_rendering: - # Remove old preview layers, if rendering is enabled - for node in self.svg: - if node.tag == inkex.addNS( 'g', 'svg' ) or node.tag == 'g': - if ( node.get( inkex.addNS( 'groupmode', 'inkscape' ) ) == 'layer' ): - LayerName = node.get( inkex.addNS( 'label', 'inkscape' ) ) - if LayerName == '% Preview': - self.svg.remove( node ) - - preview_transform = Transform( - 'translate({2:.6E},{3:.6E}) scale({0:.6E},{1:.6E})'.format( - 1.0/sx, 1.0/sy, -ox, -oy)).matrix - path_attrs = { 'transform': str(Transform(preview_transform))} - self.preview_layer = etree.Element(inkex.addNS('g', 'svg'), - path_attrs, nsmap=inkex.NSS) - - - self.preview_layer.set( inkex.addNS('groupmode', 'inkscape' ), 'layer' ) - self.preview_layer.set( inkex.addNS( 'label', 'inkscape' ), '% Preview' ) - self.svg.append( self.preview_layer ) - - - # Preview stroke width: 1/1000 of page width or height, whichever is smaller - if self.svg_width < self.svg_height: - width_du = self.svg_width / 1000.0 - else: - width_du = self.svg_height / 1000.0 - - """ - Stroke-width is a css style element, and cannot accept scientific notation. - - Thus, in cases with large scaling (i.e., high values of 1/sx, 1/sy) - resulting from the viewbox attribute of the SVG document, it may be necessary to use - a _very small_ stroke width, so that the stroke width displayed on the screen - has a reasonable width after being displayed greatly magnified thanks to the viewbox. - - Use log10(the number) to determine the scale, and thus the precision needed. - """ - - log_ten = math.log10(width_du) - if log_ten > 0: # For width_du > 1 - width_string = "{0:.3f}".format(width_du) - else: - prec = int(math.ceil(-log_ten) + 3) - width_string = "{0:.{1}f}".format(width_du, prec) - - self.p_style = {'stroke-width': width_string, 'fill': 'none', - 'stroke-linejoin': 'round', 'stroke-linecap': 'round'} - - self.svg = self.parse_svg(self.svg, matCurrent) - - - def parse_svg(self, input_node, mat_current=None, parent_vis='visible'): - """ - Input: An SVG node (usually) containing other nodes: - The SVG root, a layer, sublayer, or other group. - Output: The re-ordered node. The contents are reordered with the greedy - algorithm, except: - - Layers and sublayers are preserved. The contents of each are - re-ordered for faster plotting. - - Groups are either preserved, broken apart, or re-ordered within - the group, depending on the value of group_mode. - """ - - coord_dict = {} - # coord_dict maps a node ID to the following data: - # Is the node plottable, first coordinate pair, last coordinate pair. - # i.e., Node_id -> (Boolean: plottable, Xi, Yi, Xf, Yf) - - group_dict = {} - # group_dict maps a node ID for a group to the contents of that group. - # The contents may be a preserved nested group or a flat list, depending - # on the selected group handling mode. Example: - # group_dict = {'id_1': , - # 'id_2': - - nodes_to_delete = [] - - counter = 0 # TODO: Replace this with better unique ID system - - # Account for input_node's transform and any transforms above it: - if mat_current is None: - mat_current = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] - try: - matNew = Transform(mat_current) * Transform(input_node.get("transform")) - except AttributeError: - matNew = mat_current - - for node in input_node: - # Step through each object within the top-level input node - - try: - id = node.get( 'id' ) - except AttributeError: - id = self.uniqueId(None,True) - - # First check for object visibility: - skip_object = False - - # Check for "display:none" in the node's style attribute: - style = dict(inkex.Style.parse_str(node.get('style'))) - if 'display' in style.keys() and style['display'] == 'none': - skip_object = True # Plot neither this object nor its children - - # The node may have a display="none" attribute as well: - if node.get( 'display' ) == 'none': - skip_object = True # Plot neither this object nor its children - - # Visibility attributes control whether a given object will plot. - # Children of hidden (not visible) parents may be plotted if - # they assert visibility. - visibility = node.get( 'visibility', parent_vis ) - - if 'visibility' in style.keys(): - visibility = style['visibility'] # Style may override attribute. - - if visibility == 'inherit': - visibility = parent_vis - - if visibility != 'visible': - skip_object = True # Skip this object and its children - - # Next, check to see if this inner node is itself a group or layer: - if node.tag == inkex.addNS( 'g', 'svg' ) or node.tag == 'g': - - # Use the user-given option to decide what to do with subgroups: - subgroup_mode = self.options.reordering - -# Values of the parameter: -# subgroup_mode=="1": Preserve groups -# subgroup_mode=="2": Reorder within groups -# subgroup_mode=="3": Break apart groups - - if node.get(inkex.addNS('groupmode', 'inkscape')) == 'layer': - # The node is a layer or sub-layer, not a regular group. - # Parse it separately, and re-order its contents. - - subgroup_mode = 2 # Always sort within each layer. - self.layer_index += 1 - - layer_name = node.get( inkex.addNS( 'label', 'inkscape' ) ) - - if sys.version_info < (3,): # Yes this is ugly. More elegant suggestions welcome. :) - layer_name = layer_name.encode( 'ascii', 'ignore' ) #Drop non-ascii characters - else: - layer_name = str(layer_name) - layer_name.lstrip # Remove leading whitespace - - if layer_name: - if layer_name[0] == '%': # First character is '%'; This - skip_object = True # is a documentation layer; skip plotting. - self.layer_index -= 1 # Set this back to previous value. - - if skip_object: - # Do not re-order hidden groups or layers. - subgroup_mode = 1 # Preserve this group - - if subgroup_mode == 3: - # Break apart this non-layer subgroup and add it to - # the set of things to be re-ordered. - - nodes_to_delete.append(node) - nodes_inside_group = self.group2NodeDict(node) - - for a_node in nodes_inside_group: - try: - id = a_node.get( 'id' ) - except AttributeError: - id = self.uniqueId(None,True) - - # Use getFirstPoint and getLastPoint on each object: - start_plottable, first_point = self.getFirstPoint(a_node, matNew) - end_plottable, last_point = self.getLastPoint(a_node, matNew) - - coord_dict[id] = (start_plottable and end_plottable, - first_point[0], first_point[1], last_point[0], last_point[1] ) - # Entry in group_dict is this node - group_dict[id] = a_node - - elif subgroup_mode == 2: - # Reorder a layer or subgroup with a recursive call. - - node = self.parse_svg(node, matNew, visibility) - - # Capture the first and last x,y coordinates of the optimized node - start_plottable, first_point = self.group_first_pt(node, matNew) - end_plottable, last_point = self.group_last_pt(node, matNew) - - # Then add this optimized node to the coord_dict - coord_dict[id] = (start_plottable and end_plottable, - first_point[0], first_point[1], last_point[0], last_point[1] ) - # Entry in group_dict is this node - group_dict[id] = node - - else: # (subgroup_mode == 1) - # Preserve the group, but find its first and last point so - # that it can be re-ordered with respect to other items - - if skip_object: - start_plottable = False - end_plottable = False - first_point = [(-1.), (-1.)] - last_point = [(-1.), (-1.)] - else: - start_plottable, first_point = self.group_first_pt(node, matNew) - end_plottable, last_point = self.group_last_pt(node, matNew) - - coord_dict[id] = (start_plottable and end_plottable, - first_point[0], first_point[1], last_point[0], last_point[1] ) - # Entry in group_dict is this node - group_dict[id] = node - - else: # Handle objects that are not groups - if skip_object: - start_plottable = False - end_plottable = False - first_point = [(-1.), (-1.)] - last_point = [(-1.), (-1.)] - else: - start_plottable, first_point = self.getFirstPoint(node, matNew) - end_plottable, last_point = self.getLastPoint(node, matNew) - - coord_dict[id] = (start_plottable and end_plottable, - first_point[0], first_point[1], last_point[0], last_point[1] ) - group_dict[id] = node # Entry in group_dict is this node - - # Perform the re-ordering: - ordered_element_list = self.ReorderNodeList(coord_dict, group_dict) - - # Once a better order for the svg elements has been determined, - # All there is do to is to reintroduce the nodes to the parent in the correct order - for elt in ordered_element_list: - # Creates identical node at the correct location according to ordered_element_list - input_node.append(elt) - # Once program is finished parsing through - for element_to_remove in nodes_to_delete: - try: - input_node.remove(element_to_remove) - except ValueError: - inkex.errormsg(str(element_to_remove.get('id'))+" is not a member of " + str(input_node.get('id'))) - - return input_node - - - def break_apart_path(self, path): - """ - An SVG path may contain multiple distinct portions, that are normally separated - by pen-up movements. - - This function takes the path data string from an SVG path, parses it, and returns - a dictionary of independent path data strings, each of which represents a single - pen-down movement. It is equivalent to the Inkscape function Path > Break Apart - - Input: path data string, representing a single SVG path - Output: Dictionary of (separated) path data strings - - """ - MaxLength = len(path) - ix = 0 - move_to_location = [] - path_dictionary = {} - path_list = [] - path_number = 1 - - # Search for M or m location - while ix < MaxLength: - if(path[ix] == 'm' or path[ix] == 'M'): - move_to_location.append(ix) - ix = ix + 1 - # Iterate through every M or m location in our list of move to instructions - # Slice the path string according to path beginning and ends as indicated by the - # location of these instructions - - for counter, m in enumerate(move_to_location): - if (m == move_to_location[-1]): - # last entry - path_list.append(path[m:MaxLength].rstrip()) - else: - path_list.append(path[m:move_to_location[counter + 1]].rstrip()) - - for counter, current_path in enumerate(path_list): - - # Enumerate over every entry in the path looking for relative m commands - if current_path[0] == 'm' and counter > 0: - # If path contains relative m command, the best case is when the last command - # was a Z or z. In this case, all relative operations are performed relative to - # initial x, y coordinates of the previous path - - if path_list[counter -1][-1].upper() == 'Z': - current_path_x, current_path_y,index = self.getFirstPoint(current_path, matNew) - prev_path_x, prev_path_y,ignore = self.getFirstPoint(path_list[counter-1]) - adapted_x = current_path_x + prev_path_x - adapted_y = current_path_y + prev_path_y - # Now we can replace the path data with an Absolute Move to instruction - # HOWEVER, we need to adapt all the data until we reach a different command in the case of a repeating - path_list[counter] = "m "+str(adapted_x)+","+str(adapted_y) + ' ' +current_path[index:] - - # If there is no z or absolute commands, we need to parse the entire path - else: - - # scan path for absolute coordinates. If present, begin parsing from their index - # instead of the beginning - prev_path = path_list[counter-1] - prev_path_length = len(prev_path) - jx = 0 - x_val, y_val = 0,0 - # Check one char at a time - # until we have the moveTo Command - last_command = '' - is_absolute_command = False - repeated_command = False - # name of command - # how many parameters we need to skip - accepted_commands = { - 'M':0, - 'L':0, - 'H':0, - 'V':0, - 'C':4, - 'S':2, - 'Q':2, - 'T':0, - 'A':5 - } - - # If there is an absolute command which specifies a new initial point - # then we can save time by setting our index directly to its location in the path data - # See if an accepted_command is present in the path data. If it is present further in the - # string than any command found before, then set the pointer to that location - # if a command is not found, find() will return a -1. jx is initialized to 0, so if no matches - # are found, the program will parse from the beginning to the end of the path - - for keys in 'MLCSQTA': # TODO: Compare to last_point; see if we can clean up this part - if(prev_path.find(keys) > jx): - jx = prev_path.find(keys) - - while jx < prev_path_length: - - temp_x_val = '' - temp_y_val = '' - num_of_params_to_skip = 0 - - # SVG Path commands can be repeated - if (prev_path[jx].isdigit() and last_command): - repeated_command = True - else: - repeated_command = False - - if (prev_path[jx].isalpha() and prev_path[jx].upper() in accepted_commands) or repeated_command: - - if repeated_command: - #is_relative_command is saved from last iteration of the loop - current_command = last_command - else: - # If the character is accepted, we must parse until reach the x y coordinates - is_absolute_command = prev_path[jx].isupper() - current_command = prev_path[jx].upper() - - # Each command has a certain number of parameters we must pass before we reach the - # information we care about. We will parse until we know that we have reached them - - # Get to start of next number - # We will know we have reached a number if the current character is a +/- sign - # or current character is a digit - while jx < prev_path_length: - if(prev_path[jx] in '+-' or prev_path[jx].isdigit()): - break - jx = jx + 1 - - # We need to parse past the unused parameters in our command - # The number of parameters to parse past is dependent on the command and stored - # as the value of accepted_command - # Spaces and commas are used to deliniate paramters - while jx < prev_path_length and num_of_params_to_skip < accepted_commands[current_command]: - if(prev_path[jx].isspace() or prev_path[jx] == ','): - num_of_params_to_skip = num_of_params_to_skip + 1 - jx = jx + 1 - - # Now, we are in front of the x character - - if current_command.upper() == 'V': - temp_x_val = 0 - - if current_command.upper() == 'H': - temp_y_val = 0 - - # Parse until next character is a digit or +/- character - while jx < prev_path_length and current_command.upper() != 'V': - if(prev_path[jx] in '+-' or prev_path[jx].isdigit()): - break - jx = jx + 1 - - # Save each next character until we reach a space - while jx < prev_path_length and current_command.upper() != 'V' and not (prev_path[jx].isspace() or prev_path[jx] == ','): - temp_x_val = temp_x_val + prev_path[jx] - jx = jx + 1 - - # Then we know we have completely parsed the x character - - # Now we are in front of the y character - - # Parse until next character is a digit or +/- character - while jx < prev_path_length and current_command.upper() != 'H': - if(prev_path[jx] in '+-' or prev_path[jx].isdigit()): - break - jx = jx + 1 - - ## Save each next character until we reach a space - while jx < prev_path_length and current_command.upper() != 'H' and not (prev_path[jx].isspace() or prev_path[jx] == ','): - temp_y_val = temp_y_val + prev_path[jx] - jx = jx + 1 - - # Then we know we have completely parsed the y character - - if is_absolute_command: - - if current_command == 'H': - # Absolute commands create new x,y position - try: - x_val = float(temp_x_val) - except ValueError: - pass - elif current_command == 'V': - # Absolute commands create new x,y position - try: - y_val = float(temp_y_val) - except ValueError: - pass - else: - # Absolute commands create new x,y position - try: - x_val = float(temp_x_val) - y_val = float(temp_y_val) - except ValueError: - pass - else: - - if current_command == 'h': - # Absolute commands create new x,y position - try: - x_val = x_val + float(temp_x_val) - except ValueError: - pass - elif current_command == 'V': - # Absolute commands create new x,y position - try: - y_val = y_val + float(temp_y_val) - except ValueError: - pass - else: - # Absolute commands create new x,y position - try: - x_val = x_val + float(temp_x_val) - y_val = y_val + float(temp_y_val) - except ValueError: - pass - last_command = current_command - jx = jx + 1 - x,y,index = self.getFirstPoint(current_path,None) - path_list[counter] = "m "+str(x_val+x)+","+str(y_val+y) + ' ' + current_path[index:] - - for counter, path in enumerate(path_list): - path_dictionary['AxiDraw_Path'+ str(counter)] = path - - return path_dictionary - - - def getFirstPoint(self, node, matCurrent): - """ - Input: (non-group) node and parent transformation matrix - Output: Boolean value to indicate if the svg element is plottable and - two floats stored in a list representing the x and y coordinates we plot first - """ - - # first apply the current matrix transform to this node's transform - matNew = Transform(matCurrent) * Transform(Transform(node.get("transform")).matrix) - - point = [float(-1), float(-1)] - try: - if node.tag == inkex.addNS( 'path', 'svg' ): - - pathdata = node.get('d') - - point = plot_utils.pathdata_first_point(pathdata) - Transform(matNew).apply_to_point(point) - - return True, point - - if node.tag == inkex.addNS( 'rect', 'svg' ) or node.tag == 'rect': - - """ - The x,y coordinates for a rect are included in their specific attributes - If there is a transform, we need translate the x & y coordinates to their - correct location via Transform(matNew).apply_to_point(point). - """ - - point[0] = float( node.get( 'x' ) ) - point[1] = float( node.get( 'y' ) ) - - Transform(matNew).apply_to_point(point) - - return True, point - - if node.tag == inkex.addNS( 'line', 'svg' ) or node.tag == 'line': - """ - The x1 and y1 attributes are where we will start to draw - So, get them, apply the transform matrix, and return the point - """ - - point[0] = float( node.get( 'x1' ) ) - point[1] = float( node.get( 'y1' ) ) - - Transform(matNew).apply_to_point(point) - - return True, point - - - if node.tag == inkex.addNS( 'polyline', 'svg' ) or node.tag == 'polyline': - pl = node.get( 'points', '' ).strip() - - if pl == '': - return False, point - - pa = pl.replace(',',' ').split() # replace comma with space before splitting - - if not pa: - return False, point - pathLength = len( pa ) - if (pathLength < 4): # Minimum of x1,y1 x2,y2 required. - return False, point - - d = "M " + pa[0] + " " + pa[1] - i = 2 - while (i < (pathLength - 1 )): - d += " L " + pa[i] + " " + pa[i + 1] - i += 2 - - point = plot_utils.pathdata_first_point(d) - Transform(matNew).apply_to_point(point) - - return True, point - - if (node.tag == inkex.addNS( 'polygon', 'svg' ) or - node.tag == 'polygon'): - """ - We need to extract x1 and y1 from these: - - We accomplish this with Python string strip - and split methods. Then apply transforms - """ - # Strip() removes all whitespace from the start and end of p1 - pl = node.get( 'points', '' ).strip() - if (pl == ''): - # If pl is blank there has been an error, return False and -1,-1 to indicate a problem has occured - return False, point - # Split string by whitespace - pa = pl.split() - if not len( pa ): - # If pa is blank there has been an error, return False and -1,-1 to indicate a problem has occured - return False, point - # pa[0] = "x1,y1 - # split string via comma to get x1 and y1 individually - # then point = [x1,x2] - point = pa[0].split(",") - - point = [float(point[0]),float(point[1])] - - Transform(matNew).apply_to_point(point) - - return True, point - - if node.tag == inkex.addNS( 'ellipse', 'svg' ) or \ - node.tag == 'ellipse': - - cx = float( node.get( 'cx', '0' ) ) - cy = float( node.get( 'cy', '0' ) ) - rx = float( node.get( 'rx', '0' ) ) - - point[0] = cx - rx - point[1] = cy - - Transform(matNew).apply_to_point(point) - - return True, point - - if node.tag == inkex.addNS( 'circle', 'svg' ) or \ - node.tag == 'circle': - cx = float( node.get( 'cx', '0' ) ) - cy = float( node.get( 'cy', '0' ) ) - r = float( node.get( 'r', '0' ) ) - point[0] = cx - r - point[1] = cy - - Transform(matNew).apply_to_point(point) - - return True, point - - if node.tag == inkex.addNS('symbol', 'svg') or node.tag == 'symbol': - # A symbol is much like a group, except that - # it's an invisible object. - return False, point # Skip this element. - - if node.tag == inkex.addNS('use', 'svg') or node.tag == 'use': - - """ - A element refers to another SVG element via an xlink:href="#blah" - attribute. We will handle the element by doing an XPath search through - the document, looking for the element with the matching id="blah" - attribute. We then recursively process that element after applying - any necessary (x,y) translation. - - Notes: - 1. We ignore the height and g attributes as they do not apply to - path-like elements, and - 2. Even if the use element has visibility="hidden", SVG still calls - for processing the referenced element. The referenced element is - hidden only if its visibility is "inherit" or "hidden". - 3. We may be able to unlink clones using the code in pathmodifier.py - """ - - refid = node.get(inkex.addNS('href', 'xlink')) - - if refid is not None: - # [1:] to ignore leading '#' in reference - path = '//*[@id="{0}"]'.format(refid[1:]) - refnode = node.xpath(path) - if refnode is not None: - - x = float(node.get('x', '0')) - y = float(node.get('y', '0')) - - # Note: the transform has already been applied - if x != 0 or y != 0: - mat_new2 = Transform(matNew) * Transform('translate({0:f},{1:f})'.format(x, y)) - else: - mat_new2 = matNew - # Note that the referenced object may be a 'symbol`, - # which acts like a group, or it may be a simple - # object. - - if len(refnode) > 0: - plottable, the_point = self.group_first_pt(refnode[0], mat_new2) - else: - plottable, the_point = self.group_first_pt(refnode, mat_new2) - - return plottable, the_point - except: - pass - - # Svg Object is not a plottable element - # In this case, return False to indicate a non-plottable element - # and a default point - - return False, point - - def getLastPoint(self, node, matCurrent): - """ - Input: XML tree node and transformation matrix - Output: Boolean value to indicate if the svg element is plottable or not and - two floats stored in a list representing the x and y coordinates we plot last - """ - - # first apply the current matrix transform to this node's transform - matNew = Transform(matCurrent) * Transform(node.get("transform")) - - # If we return a negative value, we know that this function did not work - point = [float(-1), float(-1)] - try: - if node.tag == inkex.addNS( 'path', 'svg' ): - - path = node.get('d') - - point = plot_utils.pathdata_last_point(path) - Transform(matNew).apply_to_point(point) - - return True, point - - if node.tag == inkex.addNS( 'rect', 'svg' ) or node.tag == 'rect': - - """ - The x,y coordinates for a rect are included in their specific attributes - If there is a transform, we need translate the x & y coordinates to their - correct location via Transform(matNew).apply_to_point(point). - """ - - point[0] = float( node.get( 'x' ) ) - point[1] = float( node.get( 'y' ) ) - - Transform(matNew).apply_to_point(point) - - return True, point # Same start and end points - - if node.tag == inkex.addNS( 'line', 'svg' ) or node.tag == 'line': - - """ - The x2 and y2 attributes are where we will end our drawing - So, get them, apply the transform matrix, and return the point - """ - - point[0] = float( node.get( 'x2' ) ) - point[1] = float( node.get( 'y2' ) ) - - Transform(matNew).apply_to_point(point) - - return True, point - - if node.tag == inkex.addNS( 'polyline', 'svg' ) or node.tag == 'polyline': - - pl = node.get( 'points', '' ).strip() - - if pl == '': - return False, point - - pa = pl.replace(',',' ').split() - if not pa: - return False, point - pathLength = len( pa ) - if (pathLength < 4): # Minimum of x1,y1 x2,y2 required. - return False, point - - d = "M " + pa[0] + " " + pa[1] - i = 2 - while (i < (pathLength - 1 )): - d += " L " + pa[i] + " " + pa[i + 1] - i += 2 - - endpoint = plot_utils.pathdata_last_point(d) - Transform(matNew).apply_to_point(point) - - return True, endpoint - - if node.tag == inkex.addNS( 'polygon', 'svg' ) or node.tag == 'polygon': - """ - We need to extract x1 and y1 from these: - - We accomplish this with Python string strip - and split methods. Then apply transforms - """ - # Strip() removes all whitespace from the start and end of p1 - pl = node.get( 'points', '' ).strip() - if (pl == ''): - # If pl is blank there has been an error, return -1,-1 to indicate a problem has occured - return False, point - # Split string by whitespace - pa = pl.split() - if not len( pa ): - # If pl is blank there has been an error, return -1,-1 to indicate a problem has occured - return False, point - # pa[0] = "x1,y1 - # split string via comma to get x1 and y1 individually - # then point = [x1,x2] - point = pa[0].split(",") - - point = [float(point[0]),float(point[1])] - - Transform(matNew).apply_to_point(point) - - return True, point - - if node.tag == inkex.addNS( 'ellipse', 'svg' ) or node.tag == 'ellipse': - - cx = float( node.get( 'cx', '0' ) ) - cy = float( node.get( 'cy', '0' ) ) - rx = float( node.get( 'rx', '0' ) ) - - point[0] = cx - rx - point[1] = cy - - Transform(matNew).apply_to_point(point) - - return True, point - - if node.tag == inkex.addNS( 'circle', 'svg' ) or node.tag == 'circle': - cx = float( node.get( 'cx', '0' ) ) - cy = float( node.get( 'cy', '0' ) ) - r = float( node.get( 'r', '0' ) ) - point[0] = cx - r - point[1] = cy - - Transform(matNew).apply_to_point(point) - - return True, point - - if node.tag == inkex.addNS('symbol', 'svg') or node.tag == 'symbol': - # A symbol is much like a group, except that it should only be - # rendered when called within a "use" tag. - return False, point # Skip this element. - - if node.tag == inkex.addNS('use', 'svg') or node.tag == 'use': - - """ - A element refers to another SVG element via an xlink:href="#blah" - attribute. We will handle the element by doing an XPath search through - the document, looking for the element with the matching id="blah" - attribute. We then recursively process that element after applying - any necessary (x,y) translation. - - Notes: - 1. We ignore the height and g attributes as they do not apply to - path-like elements, and - 2. Even if the use element has visibility="hidden", SVG still calls - for processing the referenced element. The referenced element is - hidden only if its visibility is "inherit" or "hidden". - 3. We may be able to unlink clones using the code in pathmodifier.py - """ - - refid = node.get(inkex.addNS('href', 'xlink')) - if refid is not None: - # [1:] to ignore leading '#' in reference - path = '//*[@id="{0}"]'.format(refid[1:]) - refnode = node.xpath(path) - if refnode is not None: - x = float(node.get('x', '0')) - y = float(node.get('y', '0')) - # Note: the transform has already been applied - if x != 0 or y != 0: - mat_new2 = Transform(matNew)* Transform('translate({0:f},{1:f})'.format(x, y)) - else: - mat_new2 = matNew - if len(refnode) > 0: - plottable, the_point = self.group_last_pt(refnode[0], mat_new2) - else: - plottable, the_point = self.group_last_pt(refnode, mat_new2) - return plottable, the_point - except: - pass - - # Svg Object is not a plottable element; - # Return False and a default point - return False, point - - - def group_first_pt(self, group, matCurrent = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]): - """ - Input: A Node which we have found to be a group - Output: Boolean value to indicate if a point is plottable - float values for first x,y coordinates of svg element - """ - - if len(group) == 0: # Empty group -- The object may not be a group. - return self.getFirstPoint(group, matCurrent) - - success = False - point = [float(-1), float(-1)] - - # first apply the current matrix transform to this node's transform - matNew = Transform( matCurrent) * Transform(group.get("transform")) - - # Step through the group, we examine each element until we find a plottable object - for subnode in group: - # Check to see if the subnode we are looking at in this iteration of our for loop is a group - # If it is a group, we must recursively call this function to search for a plottable object - if subnode.tag == inkex.addNS( 'g', 'svg' ) or subnode.tag == 'g': - # Verify that the nested group has objects within it - # otherwise we will not parse it - if subnode is not None: - # Check if group contains plottable elements by recursively calling group_first_pt - # If group contains plottable subnode, then it will return that value and escape the loop - # Else function continues search for first plottable object - success, point = self.group_first_pt(subnode, matNew) - if success: - # Subnode inside nested group is plottable! - # Break from our loop so we can return the first point of this plottable subnode - break - else: - continue - else: - # Node is not a group - # Get its first (x,y) coordinates - # Also get a Boolean value to indicate if the subnode is plottable or not - # If subnode is not plottable, continue to next subnode in the group - success, point = self.getFirstPoint(subnode, matNew) - - if success: - # Subnode inside group is plottable! - # Break from our loop so we can return the first point of this plottable subnode - break - else: - continue - return success, point - - - def group_last_pt(self, group, matCurrent=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]): - """ - Input: A Node which we have found to be a group - Output: The last node within the group which can be plotted - """ - - if len(group) == 0: # Empty group -- Did someone send an object that isn't a group? - return self.getLastPoint(group, matCurrent) - - success = False - point = [float(-1),float(-1)] - - # first apply the current matrix transform to this node's transform - matNew = Transform(matCurrent) * Transform(group.get("transform")) - - # Step through the group, we examine each element until we find a plottable object - for subnode in reversed(group): - # Check to see if the subnode we are looking at in this iteration of our for loop is a group - # If it is a group, we must recursively call this function to search for a plottable object - if subnode.tag == inkex.addNS( 'g', 'svg' ) or subnode.tag == 'g': - # Verify that the nested group has objects within it - # otherwise we will not parse it - if subnode is not None: - # Check if group contains plottable elements by recursively calling group_last_pt - # If group contains plottable subnode, then it will return that value and escape the loop - # Else function continues search for last plottable object - success, point = self.group_last_pt(subnode, matNew) - if success: - # Subnode inside nested group is plottable! - # Break from our loop so we can return the first point of this plottable subnode - break - else: - continue - else: - # Node is not a group - # Get its first (x,y) coordinates - # Also get a Boolean value to indicate if the subnode is plottable or not - # If subnode is not plottable, continue to next subnode in the group - success, point = self.getLastPoint(subnode, matNew) - if success: - - # Subode inside nested group is plottable! - # Break from our loop so we can return the first point of this plottable subnode - break - else: - continue - return success, point - - - def group2NodeDict(self, group, mat_current=None): - - if mat_current is None: - mat_current = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]] - - # first apply the current matrix transform to this node's transform - matNew = Transform(mat_current) * Transform(group.get("transform")) - - nodes_in_group = [] - - # Step through the group, we examine each element until we find a plottable object - for subnode in group: - # Check to see if the subnode we are looking at in this iteration of our for loop is a group - # If it is a group, we must recursively call this function to search for a plottable object - if subnode.tag == inkex.addNS( 'g', 'svg' ) or subnode.tag == 'g': - # Verify that the nested group has objects within it - # otherwise we will not parse it - if subnode is not None: - # Check if group contains plottable elements by recursively calling group_first_pt - # If group contains plottable subnode, then it will return that value and escape the loop - # Else function continues search for first plottable object - nodes_in_group.extend(self.group2NodeDict(subnode, matNew)) - else: - Transform(matNew) * Transform(subnode) - nodes_in_group.append(subnode) - return nodes_in_group - - - def ReorderNodeList(self, coord_dict, group_dict): - # Re-order the given set of SVG elements, using a simple "greedy" algorithm. - # The first object will be the element closest to the origin - # After this choice, the algorithm loops through all remaining elements looking for the element whose first x,y - # coordinates are closest to the the previous choice's last x,y coordinates - # This process continues until all elements have been sorted into ordered_element_list and removed from group_dict - - ordered_layer_element_list = [] - - # Continue until all elements have been re-ordered - while group_dict: - - nearest_dist = float('inf') - for key,node in group_dict.items(): - # Is this node non-plottable? - # If so, exit loop and append element to ordered_layer_element_list - if not coord_dict[key][0]: - # Object is not Plottable - nearest = node - nearest_id = key - continue - - # If we reach this point, node is plottable and needs to be considered in our algo - entry_x = coord_dict[key][1] # x-coordinate of first point of the path - entry_y = coord_dict[key][2] # y-coordinate of first point of the path - - exit_x = coord_dict[key][3] # x-coordinate of last point of the path - exit_y = coord_dict[key][4] # y-coordinate of last point of the path - - object_dist = (entry_x-self.x_last)*(entry_x-self.x_last) + (entry_y-self.y_last) * (entry_y-self.y_last) - # This is actually the distance squared; calculating it rather than the pythagorean distance - # saves a square root calculation. Right now, we only care about _which distance is less_ - # not the exact value of it, so this is a harmless shortcut. - # If this distance is smaller than the previous element's distance, then replace the previous - # element's entry with our current element's distance - if nearest_dist >= object_dist: - # We have found an element closer than the previous closest element - nearest = node - nearest_id = key - nearest_dist = object_dist - nearest_start_x = entry_x - nearest_start_y = entry_y - - # Now that the closest object has been determined, it is time to add it to the - # optimized list of closest objects - ordered_layer_element_list.append(nearest) - - # To determine the closest object in the next iteration of the loop, - # we must save the last x,y coor of this element - # If this element is plottable, then save the x,y coordinates - # If this element is non-plottable, then do not save the x,y coordinates - if coord_dict[nearest_id][0]: - - # Also, draw line indicating that we've found a new point. - if self.preview_rendering: - preview_path = [] # pen-up path data for preview - - preview_path.append("M{0:.3f} {1:.3f}".format( - self.x_last, self.y_last)) - preview_path.append("{0:.3f} {1:.3f}".format( - nearest_start_x, nearest_start_y)) - self.p_style.update({'stroke': self.color_index(self.layer_index)}) - path_attrs = { - 'style': str(inkex.Style(self.p_style)), - 'd': " ".join(preview_path)} - - etree.SubElement( self.preview_layer, - inkex.addNS( 'path', 'svg '), path_attrs, nsmap=inkex.NSS ) - - self.x_last = coord_dict[nearest_id][3] - self.y_last = coord_dict[nearest_id][4] - - # Remove this element from group_dict to indicate it has been optimized - del group_dict[nearest_id] - - # Once all elements have been removed from the group_dictionary - # Return the optimized list of svg elements in the layer - return ordered_layer_element_list - - - def color_index(self, index): - index = index % 9 - - if index == 0: - return "rgb(255, 0, 0))" - elif index == 1: - return "rgb(170, 85, 0))" - elif index == 2: - return "rgb(85, 170, 0))" - elif index == 3: - return "rgb(0, 255, 0))" - elif index == 4: - return "rgb(0, 170, 85))" - elif index == 5: - return "rgb(0, 85, 170))" - elif index == 6: - return "rgb(0, 0, 255))" - elif index == 7: - return "rgb(85, 0, 170))" - else: - return "rgb(170, 0, 85))" - - - def getDocProps(self): - """ - Get the document's height and width attributes from the tag. - Use a default value in case the property is not present or is - expressed in units of percentages. - """ - - self.svg_height = plot_utils.getLengthInches(self, 'height') - self.svg_width = plot_utils.getLengthInches(self, 'width') - - width_string = self.svg.get('width') - if width_string: - value, units = plot_utils.parseLengthWithUnits(width_string) - self.doc_units = units - - if self.auto_rotate and (self.svg_height > self.svg_width): - self.printPortrait = True - if self.svg_height is None or self.svg_width is None: - return False - else: - return True - - - def get_output(self): - # Return serialized copy of svg document output - result = etree.tostring(self.document) - return result.decode("utf-8") - -# Create effect instance and apply it. - -if __name__ == '__main__': - ReorderEffect().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_roland_cutstudio.py b/extensions/fablabchemnitz/fablabchemnitz_roland_cutstudio.py index 3f2b3bab..edd7af3f 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_roland_cutstudio.py +++ b/extensions/fablabchemnitz/fablabchemnitz_roland_cutstudio.py @@ -41,6 +41,7 @@ import subprocess import shutil import numpy from functools import reduce +from pathlib import Path import inkex try: @@ -69,6 +70,7 @@ def which(program, raiseError, extraPaths=[], subdir=None): pathlist.append(os.environ.get("ProgramFiles(x86)","C:\Program Files (x86)\\")) pathlist.append("C:\Program Files\\") # needed for 64bit inkscape on 64bit Win7 machines pathlist.append(os.path.dirname(os.path.dirname(os.getcwd()))) # portable application in the current directory + pathlist += extraPaths if subdir: pathlist = [os.path.join(p, subdir) for p in pathlist] + pathlist def is_exe(fpath): @@ -404,14 +406,16 @@ if os.name=="nt": Popen([which("CutStudio\CutStudio.exe", True), "/import", filename+".cutstudio.eps"], creationflags=DETACHED_PROCESS, close_fds=True) else: #check if we have access to "wine" if which("wine", False) is not None: - if which("/opst/CutStudio/CutStudio.exe", False) is not None: - with os.popen("wine /opt/CutStudio/CutStudio.exe /import T:\\\\" + filename.split('/tmp/')[1] + ".cutstudio.eps", "r") as cutstudio: + if which("CutStudio.exe", False, [str(Path.home()) + "/.wine/drive_c/Program Files (x86)/CutStudio"]) is not None: + shutil.copyfile(filename + ".cutstudio.eps", str(Path.home()) + "/.wine/drive_c/cutstudio.eps") + inkex.utils.debug(str(Path.home()) + "/.wine/drive_c/'Program Files (x86)'/CutStudio/CutStudio.exe /import C:\\cutstudio.eps") + with os.popen("wine " + str(Path.home()) + "/.wine/drive_c/'Program Files (x86)'/CutStudio/CutStudio.exe /import C:\\cutstudio.eps", "r") as cutstudio: result = cutstudio.read() else: - inkex.utils.debug("Found a wine installation on your system but no CutStudio.exe. You can easily emulate this Windows application on Linux using wine. To do this provide a valid CutStudio installation in directory \"/opt/CutStudio/\". You may create a symlink with the shell command \"ln -sf /your/path/to/cutstudio /opt/CutStudio\" to point to this dir, or just edit the InkScape extension source code. As second step you need to configure the drive letter T: to point to the directory \"/tmp/\". This is done with a few mouse clicks within the \"winecfg\" utility. The wine emulation was tested to work properly with Roland CutStudio version 3.10. For now your file was saved to:\n" + filename + ".cutstudio.eps") + inkex.utils.debug("Found a wine installation on your system but no CutStudio.exe. You can easily emulate this Windows application on Linux using wine. To do this provide a valid CutStudio installation in directory \"$HOME/.wine/drive_c/'Program Files (x86)'/CutStudio/CutStudio.exe\". The wine emulation was tested to work properly with Roland CutStudio version 3.10. For now your file was saved to:\n" + filename + ".cutstudio.eps") #os.popen("/usr/bin/xdg-open " + filename) else: - inkex.utils.debug("Your file was saved to:\n" + filename + ".cutstudio.eps" + "\n Please open that with CutStudio.") + inkex.utils.debug("Your file was saved to:\n" + filename + ".cutstudio.eps" + "\n Please open that with CutStudio manually. Tip: install wine on your system and use it to install CutStudio on Linux. This InkScape extension will automatically detect it. It allows you to directly import the exported InkScape file into CutStudio.") #os.popen("/usr/bin/xdg-open " + filename) #Popen(["inkscape", filename+".filtered.svg"], stderr=DEVNULL) #Popen(["inkscape", filename+".cutstudio.eps"]) diff --git a/extensions/fablabchemnitz/fablabchemnitz_rounder.py b/extensions/fablabchemnitz/fablabchemnitz_rounder.py index df16bdbf..0fe751b4 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_rounder.py +++ b/extensions/fablabchemnitz/fablabchemnitz_rounder.py @@ -157,4 +157,4 @@ class svgRounder(inkex.Effect): self.opacity_round_it(node, "fill-opacity") if __name__ == '__main__': - svgRounder().run() + svgRounder().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_scaletosize.py b/extensions/fablabchemnitz/fablabchemnitz_scaletosize.py index 63e64ad9..2a48e5f9 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_scaletosize.py +++ b/extensions/fablabchemnitz/fablabchemnitz_scaletosize.py @@ -23,7 +23,7 @@ class ScaleToSize(inkex.Effect): def effect(self): unit_factor = 1.0 / self.svg.uutounit(1.0,self.options.unit) - for node in self.svg.selected: + for id, node in self.svg.selected.items(): #get recent XY coordinates (top left corner of the bounding box) bbox = node.bounding_box() diff --git a/extensions/fablabchemnitz/fablabchemnitz_sheet_conus.py b/extensions/fablabchemnitz/fablabchemnitz_sheet_conus.py index eac76dab..4ddfa65a 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_sheet_conus.py +++ b/extensions/fablabchemnitz/fablabchemnitz_sheet_conus.py @@ -427,4 +427,5 @@ class SheetMetalConus(inkex.Effect): text.text = "%4.3f" %(base_dia) text.transform = Transform(frustrum_repos) * text.transform -SheetMetalConus().run() \ No newline at end of file +if __name__ == '__main__': + SheetMetalConus().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_sheriff_star.py b/extensions/fablabchemnitz/fablabchemnitz_sheriff_star.py index 7fa823f2..9dd6c676 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_sheriff_star.py +++ b/extensions/fablabchemnitz/fablabchemnitz_sheriff_star.py @@ -146,5 +146,4 @@ class SheriffStarEffect(inkex.Effect): inkex.errormsg('Selection must contain a circle or ellipse.') if __name__ == '__main__': - effect = SheriffStarEffect() - effect.run() \ No newline at end of file + effect = SheriffStarEffect().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_slider_electrodes.py b/extensions/fablabchemnitz/fablabchemnitz_slider_electrodes.py index 157a32e3..4bb8a7be 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_slider_electrodes.py +++ b/extensions/fablabchemnitz/fablabchemnitz_slider_electrodes.py @@ -53,5 +53,4 @@ class SliderElectrodes(inkex.Effect): e = etree.SubElement(group, inkex.addNS('path', 'svg'), {'style':str(inkex.Style({'stroke':'none','fill' :'#000000'})),'d' : path}) if __name__ == '__main__': - effect = SliderElectrodes() - effect.run() \ No newline at end of file + effect = SliderElectrodes().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_sourcecodetext.py b/extensions/fablabchemnitz/fablabchemnitz_sourcecodetext.py index 3886f13c..6eda497d 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_sourcecodetext.py +++ b/extensions/fablabchemnitz/fablabchemnitz_sourcecodetext.py @@ -6,7 +6,7 @@ import random import inkex from lxml import etree -class MyEffect(inkex.Effect): +class SourceCodeText(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) self.arg_parser.add_argument("--directory", default='~/', help="Default directory") @@ -68,4 +68,5 @@ class MyEffect(inkex.Effect): rect=etree.SubElement(flowRegion,inkex.addNS('rect','svg'),rattribs) self.add_text(flowRoot) -MyEffect().run() +if __name__ == '__main__': + SourceCodeText().run() diff --git a/extensions/fablabchemnitz/fablabchemnitz_split_bezier.py b/extensions/fablabchemnitz/fablabchemnitz_split_bezier.py index 035c1718..fbf0ad67 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_split_bezier.py +++ b/extensions/fablabchemnitz/fablabchemnitz_split_bezier.py @@ -163,5 +163,7 @@ class SubdividePathEffect(inkex.Effect): cspath = getCubicSuperFromParts(parts) elem.set('d', CubicSuperPath(cspath)) except: - pass -SubdividePathEffect().run() \ No newline at end of file + pass + +if __name__ == '__main__': + SubdividePathEffect().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_sprockets.py b/extensions/fablabchemnitz/fablabchemnitz_sprockets.py index ea2b6c94..40c780ce 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_sprockets.py +++ b/extensions/fablabchemnitz/fablabchemnitz_sprockets.py @@ -21,9 +21,41 @@ Based on gears.py by Aaron Spike and Tavmjong Bah import inkex from math import * -from fablabchemnitz_svg import * from lxml import etree +def rotate(p, t): + return (p[0] * cos(t) - p[1] * sin(t), p[0] * sin(t) + p[1] * cos(t)) + +def SVG_move(p, t): + pp = rotate(p, t) + return 'M ' + str(pp[0]) + ',' + str(pp[1]) + '\n' + +def SVG_line(p, t): + pp = rotate(p, t) + return 'L ' + str(pp[0]) + ',' + str(pp[1]) + '\n' + +def SVG_circle(p, r, sweep, t): + pp = rotate(p, t) + return 'A ' + str(r) + ',' + str(r) + ' 0 0,' + str(sweep) + ' ' + str(pp[0]) + ',' + str(pp[1]) + '\n' + +def SVG_curve(p, c1, c2, t): + pp = rotate(p, t) + c1p = rotate(c1, t) + c2p = rotate(c2, t) + return 'C ' + str(pp[0]) + ',' + str(pp[1]) + ' ' + str(c1p[0]) + ',' + str(c1p[1]) + ' ' + str(c2p[0]) + ',' + str(c2p[1]) + '\n' + +def SVG_curve2(p1, c11, c12, p2, c21, c22, t): + p1p = rotate(p1, t) + c11p = rotate(c11, t) + c12p = rotate(c12, t) + p2p = rotate(p2, t) + c21p = rotate(c21, t) + c22p = rotate(c22, t) + return 'C ' + str(p1p[0]) + ',' + str(p1p[1]) + ' ' + str(c11p[0]) + ',' + str(c11p[1]) + ' ' + str(c12p[0]) + ',' + str(c12p[1]) + ' ' + str(p2p[0]) + ',' + str(p2p[1]) + ' ' + str(c21p[0]) + ',' + str(c21p[1]) + ' ' + str(c22p[0]) + ',' + str(c22p[1]) + '\n' + +def SVG_close(): + return 'Z\n' + class Sprockets(inkex.Effect): def __init__(self): inkex.Effect.__init__(self) @@ -209,4 +241,5 @@ class Sprockets(inkex.Effect): 'd' : svg } g = etree.SubElement(self.svg.get_current_layer(), inkex.addNS('path','svg'), g_attribs) -Sprockets().run() \ No newline at end of file +if __name__ == '__main__': + Sprockets().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_streaks.py b/extensions/fablabchemnitz/fablabchemnitz_streaks.py index 47008005..f305f1a8 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_streaks.py +++ b/extensions/fablabchemnitz/fablabchemnitz_streaks.py @@ -154,4 +154,5 @@ class StreaksEffect(inkex.Effect): # Connect elements together. layer.append(path) -StreaksEffect().run() \ No newline at end of file +if __name__ == '__main__': + StreaksEffect().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_strip_line.py b/extensions/fablabchemnitz/fablabchemnitz_strip_line.py index a5fd2f2d..21c4bc02 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_strip_line.py +++ b/extensions/fablabchemnitz/fablabchemnitz_strip_line.py @@ -228,4 +228,5 @@ class StripLineEffect(inkex.Effect): att3={"d":pathstr,"r":"1","fill":"none","stroke-width":"1","stroke":"white"} pt=etree.Element("path",att3) -StripLineEffect().run() \ No newline at end of file +if __name__ == '__main__': + StripLineEffect().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_strokecolor_as_fill.py b/extensions/fablabchemnitz/fablabchemnitz_strokecolor_as_fill.py index 0a73505b..cf988144 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_strokecolor_as_fill.py +++ b/extensions/fablabchemnitz/fablabchemnitz_strokecolor_as_fill.py @@ -107,4 +107,5 @@ class StrokeColorAsFill(inkex.Effect): self.color_swaper(element) sys.stdout = saveout -StrokeColorAsFill().run() \ No newline at end of file +if __name__ == '__main__': + StrokeColorAsFill().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_styles_to_layers.inx b/extensions/fablabchemnitz/fablabchemnitz_styles_to_layers.inx index 79f8efe0..d7f6a852 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_styles_to_layers.inx +++ b/extensions/fablabchemnitz/fablabchemnitz_styles_to_layers.inx @@ -17,6 +17,7 @@ 1 1 + true diff --git a/extensions/fablabchemnitz/fablabchemnitz_styles_to_layers.py b/extensions/fablabchemnitz/fablabchemnitz_styles_to_layers.py index 745ce469..099d4c94 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_styles_to_layers.py +++ b/extensions/fablabchemnitz/fablabchemnitz_styles_to_layers.py @@ -45,6 +45,7 @@ class LayerGroup(inkex.Effect): self.arg_parser.add_argument("--parsecolors",default = "hexval", help = "Sort colors by") self.arg_parser.add_argument("--subdividethreshold", type=int, default = 1, help = "Threshold for splitting into sub layers") self.arg_parser.add_argument("--decimals", type=int, default = 1, help = "Decimal tolerance") + self.arg_parser.add_argument("--cleanup", type=inkex.Boolean, default = True, help = "Decimal tolerance") def effect(self): @@ -225,5 +226,13 @@ class LayerGroup(inkex.Effect): #inkex.utils.debug(layer[1]) for newLayerNode in topLevelLayerNodeList: newLayerNode[0].append(newLayerNode[1]) #append newlayer to layer + + if self.options.cleanup == True: + try: + import fablabchemnitz_cleangroups + fablabchemnitz_cleangroups.CleanGroups.effect(self) + except: + inkex.utils.debug("Calling 'Remove Empty Groups' extension failed. Maybe the extension is not installed. You can download it from official InkScape Gallery.") -LayerGroup().run() +if __name__ == '__main__': + LayerGroup().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_svg.py b/extensions/fablabchemnitz/fablabchemnitz_svg.py deleted file mode 100644 index c7c295a1..00000000 --- a/extensions/fablabchemnitz/fablabchemnitz_svg.py +++ /dev/null @@ -1,34 +0,0 @@ -from math import * - -def rotate(p, t): - return (p[0] * cos(t) - p[1] * sin(t), p[0] * sin(t) + p[1] * cos(t)) - -def SVG_move(p, t): - pp = rotate(p, t) - return 'M ' + str(pp[0]) + ',' + str(pp[1]) + '\n' - -def SVG_line(p, t): - pp = rotate(p, t) - return 'L ' + str(pp[0]) + ',' + str(pp[1]) + '\n' - -def SVG_circle(p, r, sweep, t): - pp = rotate(p, t) - return 'A ' + str(r) + ',' + str(r) + ' 0 0,' + str(sweep) + ' ' + str(pp[0]) + ',' + str(pp[1]) + '\n' - -def SVG_curve(p, c1, c2, t): - pp = rotate(p, t) - c1p = rotate(c1, t) - c2p = rotate(c2, t) - return 'C ' + str(pp[0]) + ',' + str(pp[1]) + ' ' + str(c1p[0]) + ',' + str(c1p[1]) + ' ' + str(c2p[0]) + ',' + str(c2p[1]) + '\n' - -def SVG_curve2(p1, c11, c12, p2, c21, c22, t): - p1p = rotate(p1, t) - c11p = rotate(c11, t) - c12p = rotate(c12, t) - p2p = rotate(p2, t) - c21p = rotate(c21, t) - c22p = rotate(c22, t) - return 'C ' + str(p1p[0]) + ',' + str(p1p[1]) + ' ' + str(c11p[0]) + ',' + str(c11p[1]) + ' ' + str(c12p[0]) + ',' + str(c12p[1]) + ' ' + str(p2p[0]) + ',' + str(p2p[1]) + ' ' + str(c21p[0]) + ',' + str(c21p[1]) + ' ' + str(c22p[0]) + ',' + str(c22p[1]) + '\n' - -def SVG_close(): - return 'Z\n' \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_tangent.py b/extensions/fablabchemnitz/fablabchemnitz_tangent.py index db324df5..858c834f 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_tangent.py +++ b/extensions/fablabchemnitz/fablabchemnitz_tangent.py @@ -216,4 +216,5 @@ class Tangent(inkex.Effect): 'd':'m '+str(llx1+conversionBottom[0])+','+str(lly1+conversionBottom[1])+' l '+str(ll2x2)+','+str(ll2y2)} etree.SubElement(parent, inkex.addNS('path','svg'), attribsLine1 ) -Tangent().run() \ No newline at end of file +if __name__ == '__main__': + Tangent().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_tool_covers.py b/extensions/fablabchemnitz/fablabchemnitz_tool_covers.py index ce1a5bb9..5b305042 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_tool_covers.py +++ b/extensions/fablabchemnitz/fablabchemnitz_tool_covers.py @@ -483,4 +483,5 @@ class PliersCover(inkex.Effect): part2 = Part2(self.g, part1, opt.dia2) part2.draw(origin_vpoint) -PliersCover().run() \ No newline at end of file +if __name__ == '__main__': + PliersCover().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_travel.py b/extensions/fablabchemnitz/fablabchemnitz_travel.py index 9df67bbe..7405e08f 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_travel.py +++ b/extensions/fablabchemnitz/fablabchemnitz_travel.py @@ -99,7 +99,8 @@ class Travel(inkex.Effect): doc_h = self.svg.unittouu(svg.get('height')) # get selected items and validate - selected = self.svg.selection.paint_order() + selected = svg.get_z_selected() #works for InkScape (1:1.0+devel+202008292235+eff2292935) @ Linux and for Windows (but with deprecation) + #selected = svg.selection.paint_order() #works for InkScape 1.1dev (9b1fc87, 2020-08-27)) @ Windows if not selected: inkex.errormsg('Exactly two objects must be selected: a rect and a template. See "help" for details.') @@ -265,4 +266,5 @@ class Travel(inkex.Effect): attribs['d'] = str(Path(path)) obj_copy = etree.SubElement(group, obj.tag, attribs) -Travel().run() +if __name__ == '__main__': + Travel().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_triangulation.py b/extensions/fablabchemnitz/fablabchemnitz_triangulation.py index a7a7a16b..213b2f48 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_triangulation.py +++ b/extensions/fablabchemnitz/fablabchemnitz_triangulation.py @@ -244,4 +244,5 @@ class Triangulation(inkex.Effect): self.draw_SVG_path([v0, v1, v2], 1, tri_style, grp) -Triangulation().run() \ No newline at end of file +if __name__ == '__main__': + Triangulation().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_vh_to_line.py b/extensions/fablabchemnitz/fablabchemnitz_vh_to_line.py index dbf992d4..15631580 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_vh_to_line.py +++ b/extensions/fablabchemnitz/fablabchemnitz_vh_to_line.py @@ -60,4 +60,5 @@ class VHToLine(inkex.Effect): seg.append(simpath[i]) curr.set("d", Path(seg)) -VHToLine().run() +if __name__ == '__main__': + VHToLine().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_viewbox.py b/extensions/fablabchemnitz/fablabchemnitz_viewbox.py index 5cafab09..dc060da8 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_viewbox.py +++ b/extensions/fablabchemnitz/fablabchemnitz_viewbox.py @@ -67,4 +67,5 @@ def transformPoint(mat, pt): Transform(mat).apply_to_point(pt2) return (pt2[0], pt2[1]) -SetViewBoxEffect().run() +if __name__ == '__main__': + SetViewBoxEffect().run() diff --git a/extensions/fablabchemnitz/fablabchemnitz_zigzag.py b/extensions/fablabchemnitz/fablabchemnitz_zigzag.py index e2208daa..d7802426 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_zigzag.py +++ b/extensions/fablabchemnitz/fablabchemnitz_zigzag.py @@ -80,4 +80,5 @@ class RadiusRandomize(inkex.Effect): node.set('d',CubicSuperPath(p)) -RadiusRandomize().run() \ No newline at end of file +if __name__ == '__main__': + RadiusRandomize().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_zoetrope.py b/extensions/fablabchemnitz/fablabchemnitz_zoetrope.py index 95702858..4c40326a 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_zoetrope.py +++ b/extensions/fablabchemnitz/fablabchemnitz_zoetrope.py @@ -228,5 +228,6 @@ class Zoetrope(inkex.Effect): 'x': '0', 'y': str(ystart + font_height*3.2) } text = etree.SubElement(templategroup, 'text', text_atts) text.text = "At %d dpi. Image = %d x %d pixels" % (self.options.dpi, w, h) - -Zoetrope().run() \ No newline at end of file + +if __name__ == '__main__': + Zoetrope().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_fret_ruler.inx b/extensions/fablabchemnitz/fretruler/fablabchemnitz_fret_ruler.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_fret_ruler.inx rename to extensions/fablabchemnitz/fretruler/fablabchemnitz_fret_ruler.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_fret_ruler.py b/extensions/fablabchemnitz/fretruler/fablabchemnitz_fret_ruler.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_fret_ruler.py rename to extensions/fablabchemnitz/fretruler/fablabchemnitz_fret_ruler.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_fret_scale.py b/extensions/fablabchemnitz/fretruler/fablabchemnitz_fret_scale.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_fret_scale.py rename to extensions/fablabchemnitz/fretruler/fablabchemnitz_fret_scale.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_gcode_input.py b/extensions/fablabchemnitz/gcode_input/fablabchemnitz_gcode_input.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_gcode_input.py rename to extensions/fablabchemnitz/gcode_input/fablabchemnitz_gcode_input.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_gcode_input_gcode.inx b/extensions/fablabchemnitz/gcode_input/fablabchemnitz_gcode_input_gcode.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_gcode_input_gcode.inx rename to extensions/fablabchemnitz/gcode_input/fablabchemnitz_gcode_input_gcode.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_gcode_input_nc.inx b/extensions/fablabchemnitz/gcode_input/fablabchemnitz_gcode_input_nc.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_gcode_input_nc.inx rename to extensions/fablabchemnitz/gcode_input/fablabchemnitz_gcode_input_nc.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_gears2.inx b/extensions/fablabchemnitz/gears2/fablabchemnitz_gears2.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_gears2.inx rename to extensions/fablabchemnitz/gears2/fablabchemnitz_gears2.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_gears2.py b/extensions/fablabchemnitz/gears2/fablabchemnitz_gears2.py similarity index 98% rename from extensions/fablabchemnitz/fablabchemnitz_gears2.py rename to extensions/fablabchemnitz/gears2/fablabchemnitz_gears2.py index a7bb7c5c..78110391 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_gears2.py +++ b/extensions/fablabchemnitz/gears2/fablabchemnitz_gears2.py @@ -55,4 +55,5 @@ class Gears(inkex.Effect): 'd' : svg } g = etree.SubElement(self.svg.get_current_layer(), inkex.addNS('path','svg'), g_attribs) -Gears().run() \ No newline at end of file +if __name__ == '__main__': + Gears().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_involute.py b/extensions/fablabchemnitz/gears2/fablabchemnitz_involute.py similarity index 91% rename from extensions/fablabchemnitz/fablabchemnitz_involute.py rename to extensions/fablabchemnitz/gears2/fablabchemnitz_involute.py index ba158c07..c7817712 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_involute.py +++ b/extensions/fablabchemnitz/gears2/fablabchemnitz_involute.py @@ -7,7 +7,39 @@ # ref: YNU Digital Eng Lab Memorandum 05-1 from math import * -from fablabchemnitz_svg import * + +def rotate(p, t): + return (p[0] * cos(t) - p[1] * sin(t), p[0] * sin(t) + p[1] * cos(t)) + +def SVG_move(p, t): + pp = rotate(p, t) + return 'M ' + str(pp[0]) + ',' + str(pp[1]) + '\n' + +def SVG_line(p, t): + pp = rotate(p, t) + return 'L ' + str(pp[0]) + ',' + str(pp[1]) + '\n' + +def SVG_circle(p, r, sweep, t): + pp = rotate(p, t) + return 'A ' + str(r) + ',' + str(r) + ' 0 0,' + str(sweep) + ' ' + str(pp[0]) + ',' + str(pp[1]) + '\n' + +def SVG_curve(p, c1, c2, t): + pp = rotate(p, t) + c1p = rotate(c1, t) + c2p = rotate(c2, t) + return 'C ' + str(pp[0]) + ',' + str(pp[1]) + ' ' + str(c1p[0]) + ',' + str(c1p[1]) + ' ' + str(c2p[0]) + ',' + str(c2p[1]) + '\n' + +def SVG_curve2(p1, c11, c12, p2, c21, c22, t): + p1p = rotate(p1, t) + c11p = rotate(c11, t) + c12p = rotate(c12, t) + p2p = rotate(p2, t) + c21p = rotate(c21, t) + c22p = rotate(c22, t) + return 'C ' + str(p1p[0]) + ',' + str(p1p[1]) + ' ' + str(c11p[0]) + ',' + str(c11p[1]) + ' ' + str(c12p[0]) + ',' + str(c12p[1]) + ' ' + str(p2p[0]) + ',' + str(p2p[1]) + ' ' + str(c21p[0]) + ',' + str(c21p[1]) + ' ' + str(c22p[0]) + ',' + str(c22p[1]) + '\n' + +def SVG_close(): + return 'Z\n' def genInvolutePolar(Rb, R): # Rb = base circle radius # returns the involute angle as function of radius R. diff --git a/extensions/fablabchemnitz/geometry/Circle.py b/extensions/fablabchemnitz/geometry/Circle.py new file mode 100644 index 00000000..b3514555 --- /dev/null +++ b/extensions/fablabchemnitz/geometry/Circle.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 + +import math +import inkex +from lxml import etree + +class Circle(): + def __init__(self,_c,_r): + self.radius=_r + self.center=_c + + def __str__(self): + return "Circle: center:"+str(self.center)+" radius:"+str(self.radius)+"\n" + + def __repr__(self): + return "Circle: center"+str(self.center)+" radius:"+str(self.radius)+"\n" + + def isHit(p): + distance=(center-p).length() + if(distance0): + return True + return False#Counterclockwise + + def circumcircle(self): + #Find the length of each side + ab=(self.a-self.b).length() + bc=(self.b-self.c).length() + ca=(self.c-self.a).length() + s=(ab+bc+ca)/2.0; + area=math.sqrt(s*(s-ab)*(s-bc)*(s-ca)); + maxlength=0 + if(maxlength>> import networkx as nx - >>> G = nx.Graph() - >>> G.add_edge('A', 'B', weight=4) - >>> G.add_edge('B', 'D', weight=2) - >>> G.add_edge('A', 'C', weight=3) - >>> G.add_edge('C', 'D', weight=4) - >>> nx.shortest_path(G, 'A', 'D', weight='weight') - ['A', 'B', 'D'] - -Bugs ----- - -Please report any bugs that you find `here `_. -Or, even better, fork the repository on GitHub and create a pull request (PR). - -License -------- - -Released under the 3-Clause BSD license:: - - Copyright (C) 2004-2019 NetworkX Developers - Aric Hagberg - Dan Schult - Pieter Swart -""" -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Add platform dependent shared library path to sys.path -# - -import sys -if sys.version_info[:2] < (3, 5): - m = "Python 3.5 or later is required for NetworkX (%d.%d detected)." - raise ImportError(m % sys.version_info[:2]) -del sys - -# Release data -from networkx import release - -__author__ = '%s <%s>\n%s <%s>\n%s <%s>' % \ - (release.authors['Hagberg'] + release.authors['Schult'] + - release.authors['Swart']) -__license__ = release.license - -__date__ = release.date -__version__ = release.version - -__bibtex__ = """@inproceedings{hagberg-2008-exploring, -author = {Aric A. Hagberg and Daniel A. Schult and Pieter J. Swart}, -title = {Exploring network structure, dynamics, and function using {NetworkX}}, -year = {2008}, -month = Aug, -urlpdf = {http://math.lanl.gov/~hagberg/Papers/hagberg-2008-exploring.pdf}, -booktitle = {Proceedings of the 7th Python in Science Conference (SciPy2008)}, -editors = {G\"{a}el Varoquaux, Travis Vaught, and Jarrod Millman}, -address = {Pasadena, CA USA}, -pages = {11--15} -}""" - -# These are import orderwise -from networkx.exception import * -import networkx.utils - -import networkx.classes.filters -import networkx.classes -from networkx.classes import * - -import networkx.convert -from networkx.convert import * - -import networkx.convert_matrix -from networkx.convert_matrix import * - - -import networkx.relabel -from networkx.relabel import * - -import networkx.generators -from networkx.generators import * - -import networkx.readwrite -from networkx.readwrite import * - -# Need to test with SciPy, when available -import networkx.algorithms -from networkx.algorithms import * -import networkx.linalg - -from networkx.linalg import * -from networkx.testing.test import run as test - -import networkx.drawing -from networkx.drawing import * diff --git a/extensions/fablabchemnitz/networkx/algorithms/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/__init__.py deleted file mode 100644 index e6de2e04..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/__init__.py +++ /dev/null @@ -1,120 +0,0 @@ -from networkx.algorithms.assortativity import * -from networkx.algorithms.asteroidal import * -from networkx.algorithms.boundary import * -from networkx.algorithms.bridges import * -from networkx.algorithms.chains import * -from networkx.algorithms.centrality import * -from networkx.algorithms.chordal import * -from networkx.algorithms.cluster import * -from networkx.algorithms.clique import * -from networkx.algorithms.communicability_alg import * -from networkx.algorithms.components import * -from networkx.algorithms.coloring import * -from networkx.algorithms.core import * -from networkx.algorithms.covering import * -from networkx.algorithms.cycles import * -from networkx.algorithms.cuts import * -from networkx.algorithms.dag import * -from networkx.algorithms.distance_measures import * -from networkx.algorithms.distance_regular import * -from networkx.algorithms.dominance import * -from networkx.algorithms.dominating import * -from networkx.algorithms.efficiency_measures import * -from networkx.algorithms.euler import * -from networkx.algorithms.graphical import * -from networkx.algorithms.hierarchy import * -from networkx.algorithms.hybrid import * -from networkx.algorithms.link_analysis import * -from networkx.algorithms.link_prediction import * -from networkx.algorithms.lowest_common_ancestors import * -from networkx.algorithms.isolate import * -from networkx.algorithms.matching import * -from networkx.algorithms.minors import * -from networkx.algorithms.mis import * -from networkx.algorithms.non_randomness import * -from networkx.algorithms.operators import * -from networkx.algorithms.planarity import * -from networkx.algorithms.planar_drawing import * -from networkx.algorithms.reciprocity import * -from networkx.algorithms.richclub import * -from networkx.algorithms.shortest_paths import * -from networkx.algorithms.similarity import * -from networkx.algorithms.simple_paths import * -from networkx.algorithms.smallworld import * -from networkx.algorithms.smetric import * -from networkx.algorithms.structuralholes import * -from networkx.algorithms.sparsifiers import * -from networkx.algorithms.swap import * -from networkx.algorithms.traversal import * -from networkx.algorithms.triads import * -from networkx.algorithms.vitality import * -from networkx.algorithms.voronoi import * -from networkx.algorithms.wiener import * - -# Make certain subpackages available to the user as direct imports from -# the `networkx` namespace. -import networkx.algorithms.assortativity -import networkx.algorithms.bipartite -import networkx.algorithms.node_classification -import networkx.algorithms.centrality -import networkx.algorithms.chordal -import networkx.algorithms.cluster -import networkx.algorithms.clique -import networkx.algorithms.components -import networkx.algorithms.connectivity -import networkx.algorithms.community -import networkx.algorithms.coloring -import networkx.algorithms.flow -import networkx.algorithms.isomorphism -import networkx.algorithms.link_analysis -import networkx.algorithms.lowest_common_ancestors -import networkx.algorithms.operators -import networkx.algorithms.shortest_paths -import networkx.algorithms.tournament -import networkx.algorithms.traversal -import networkx.algorithms.tree - -# Make certain functions from some of the previous subpackages available -# to the user as direct imports from the `networkx` namespace. -from networkx.algorithms.bipartite import complete_bipartite_graph -from networkx.algorithms.bipartite import is_bipartite -from networkx.algorithms.bipartite import project -from networkx.algorithms.bipartite import projected_graph -from networkx.algorithms.connectivity import all_pairs_node_connectivity -from networkx.algorithms.connectivity import all_node_cuts -from networkx.algorithms.connectivity import average_node_connectivity -from networkx.algorithms.connectivity import edge_connectivity -from networkx.algorithms.connectivity import edge_disjoint_paths -from networkx.algorithms.connectivity import k_components -from networkx.algorithms.connectivity import k_edge_components -from networkx.algorithms.connectivity import k_edge_subgraphs -from networkx.algorithms.connectivity import k_edge_augmentation -from networkx.algorithms.connectivity import is_k_edge_connected -from networkx.algorithms.connectivity import minimum_edge_cut -from networkx.algorithms.connectivity import minimum_node_cut -from networkx.algorithms.connectivity import node_connectivity -from networkx.algorithms.connectivity import node_disjoint_paths -from networkx.algorithms.connectivity import stoer_wagner -from networkx.algorithms.flow import capacity_scaling -from networkx.algorithms.flow import cost_of_flow -from networkx.algorithms.flow import gomory_hu_tree -from networkx.algorithms.flow import max_flow_min_cost -from networkx.algorithms.flow import maximum_flow -from networkx.algorithms.flow import maximum_flow_value -from networkx.algorithms.flow import min_cost_flow -from networkx.algorithms.flow import min_cost_flow_cost -from networkx.algorithms.flow import minimum_cut -from networkx.algorithms.flow import minimum_cut_value -from networkx.algorithms.flow import network_simplex -from networkx.algorithms.isomorphism import could_be_isomorphic -from networkx.algorithms.isomorphism import fast_could_be_isomorphic -from networkx.algorithms.isomorphism import faster_could_be_isomorphic -from networkx.algorithms.isomorphism import is_isomorphic -from networkx.algorithms.tree.branchings import maximum_branching -from networkx.algorithms.tree.branchings import maximum_spanning_arborescence -from networkx.algorithms.tree.branchings import minimum_branching -from networkx.algorithms.tree.branchings import minimum_spanning_arborescence -from networkx.algorithms.tree.coding import * -from networkx.algorithms.tree.operations import * -from networkx.algorithms.tree.recognition import * -from networkx.algorithms.tree.mst import * diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/__init__.py deleted file mode 100644 index 589fb9a9..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/__init__.py +++ /dev/null @@ -1,30 +0,0 @@ -# __init__.py - package containing heuristics for optimization problems -# -# Copyright 2016-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Approximations of graph properties and Heuristic functions for optimization -problems. - - .. warning:: The approximation submodule is not imported in the top-level - ``networkx``. - - These functions can be imported with - ``from networkx.algorithms import approximation``. - -""" - -from networkx.algorithms.approximation.clustering_coefficient import * -from networkx.algorithms.approximation.clique import * -from networkx.algorithms.approximation.connectivity import * -from networkx.algorithms.approximation.dominating_set import * -from networkx.algorithms.approximation.kcomponents import * -from networkx.algorithms.approximation.independent_set import * -from networkx.algorithms.approximation.matching import * -from networkx.algorithms.approximation.ramsey import * -from networkx.algorithms.approximation.steinertree import * -from networkx.algorithms.approximation.vertex_cover import * -from networkx.algorithms.approximation.treewidth import * \ No newline at end of file diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/clique.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/clique.py deleted file mode 100644 index 85b3f1d1..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/clique.py +++ /dev/null @@ -1,172 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2011-2019 by -# Nicholas Mancuso -# All rights reserved. -# BSD license. -# Copyright 2016-2019 NetworkX developers. -# NetworkX is distributed under a BSD license -# -# Authors: Nicholas Mancuso (nick.mancuso@gmail.com) -# Jeffery Finkelstein -# Dan Schult -"""Functions for computing large cliques.""" -from operator import itemgetter - -import networkx as nx -from networkx.utils import not_implemented_for -from networkx.algorithms.approximation import ramsey - -__all__ = ["clique_removal", "max_clique", "large_clique_size"] - - -def max_clique(G): - r"""Find the Maximum Clique - - Finds the $O(|V|/(log|V|)^2)$ apx of maximum clique/independent set - in the worst case. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - Returns - ------- - clique : set - The apx-maximum clique of the graph - - Notes - ------ - A clique in an undirected graph G = (V, E) is a subset of the vertex set - `C \subseteq V` such that for every two vertices in C there exists an edge - connecting the two. This is equivalent to saying that the subgraph - induced by C is complete (in some cases, the term clique may also refer - to the subgraph). - - A maximum clique is a clique of the largest possible size in a given graph. - The clique number `\omega(G)` of a graph G is the number of - vertices in a maximum clique in G. The intersection number of - G is the smallest number of cliques that together cover all edges of G. - - https://en.wikipedia.org/wiki/Maximum_clique - - References - ---------- - .. [1] Boppana, R., & Halldórsson, M. M. (1992). - Approximating maximum independent sets by excluding subgraphs. - BIT Numerical Mathematics, 32(2), 180–196. Springer. - doi:10.1007/BF01994876 - """ - if G is None: - raise ValueError("Expected NetworkX graph!") - - # finding the maximum clique in a graph is equivalent to finding - # the independent set in the complementary graph - cgraph = nx.complement(G) - iset, _ = clique_removal(cgraph) - return iset - - -def clique_removal(G): - r""" Repeatedly remove cliques from the graph. - - Results in a $O(|V|/(\log |V|)^2)$ approximation of maximum clique - and independent set. Returns the largest independent set found, along - with found maximal cliques. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - Returns - ------- - max_ind_cliques : (set, list) tuple - 2-tuple of Maximal Independent Set and list of maximal cliques (sets). - - References - ---------- - .. [1] Boppana, R., & Halldórsson, M. M. (1992). - Approximating maximum independent sets by excluding subgraphs. - BIT Numerical Mathematics, 32(2), 180–196. Springer. - """ - graph = G.copy() - c_i, i_i = ramsey.ramsey_R2(graph) - cliques = [c_i] - isets = [i_i] - while graph: - graph.remove_nodes_from(c_i) - c_i, i_i = ramsey.ramsey_R2(graph) - if c_i: - cliques.append(c_i) - if i_i: - isets.append(i_i) - # Determine the largest independent set as measured by cardinality. - maxiset = max(isets, key=len) - return maxiset, cliques - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def large_clique_size(G): - """Find the size of a large clique in a graph. - - A *clique* is a subset of nodes in which each pair of nodes is - adjacent. This function is a heuristic for finding the size of a - large clique in the graph. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - int - The size of a large clique in the graph. - - Notes - ----- - This implementation is from [1]_. Its worst case time complexity is - :math:`O(n d^2)`, where *n* is the number of nodes in the graph and - *d* is the maximum degree. - - This function is a heuristic, which means it may work well in - practice, but there is no rigorous mathematical guarantee on the - ratio between the returned number and the actual largest clique size - in the graph. - - References - ---------- - .. [1] Pattabiraman, Bharath, et al. - "Fast Algorithms for the Maximum Clique Problem on Massive Graphs - with Applications to Overlapping Community Detection." - *Internet Mathematics* 11.4-5 (2015): 421--448. - - - See also - -------- - - :func:`networkx.algorithms.approximation.clique.max_clique` - A function that returns an approximate maximum clique with a - guarantee on the approximation ratio. - - :mod:`networkx.algorithms.clique` - Functions for finding the exact maximum clique in a graph. - - """ - degrees = G.degree - - def _clique_heuristic(G, U, size, best_size): - if not U: - return max(best_size, size) - u = max(U, key=degrees) - U.remove(u) - N_prime = {v for v in G[u] if degrees[v] >= best_size} - return _clique_heuristic(G, U & N_prime, size + 1, best_size) - - best_size = 0 - nodes = (u for u in G if degrees[u] >= best_size) - for u in nodes: - neighbors = {v for v in G[u] if degrees[v] >= best_size} - best_size = _clique_heuristic(G, neighbors, 1, best_size) - return best_size diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/clustering_coefficient.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/clustering_coefficient.py deleted file mode 100644 index 3fb9a677..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/clustering_coefficient.py +++ /dev/null @@ -1,66 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2013 by -# Fred Morstatter -# Jordi Torrents -# All rights reserved. -# BSD license. -from networkx.utils import not_implemented_for -from networkx.utils import py_random_state - -__all__ = ['average_clustering'] -__author__ = """\n""".join(['Fred Morstatter ', - 'Jordi Torrents ']) - - -@py_random_state(2) -@not_implemented_for('directed') -def average_clustering(G, trials=1000, seed=None): - r"""Estimates the average clustering coefficient of G. - - The local clustering of each node in `G` is the fraction of triangles - that actually exist over all possible triangles in its neighborhood. - The average clustering coefficient of a graph `G` is the mean of - local clusterings. - - This function finds an approximate average clustering coefficient - for G by repeating `n` times (defined in `trials`) the following - experiment: choose a node at random, choose two of its neighbors - at random, and check if they are connected. The approximate - coefficient is the fraction of triangles found over the number - of trials [1]_. - - Parameters - ---------- - G : NetworkX graph - - trials : integer - Number of trials to perform (default 1000). - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - c : float - Approximated average clustering coefficient. - - References - ---------- - .. [1] Schank, Thomas, and Dorothea Wagner. Approximating clustering - coefficient and transitivity. Universität Karlsruhe, Fakultät für - Informatik, 2004. - http://www.emis.ams.org/journals/JGAA/accepted/2005/SchankWagner2005.9.2.pdf - - """ - n = len(G) - triangles = 0 - nodes = list(G) - for i in [int(seed.random() * n) for i in range(trials)]: - nbrs = list(G[nodes[i]]) - if len(nbrs) < 2: - continue - u, v = seed.sample(nbrs, 2) - if u in G[v]: - triangles += 1 - return triangles / float(trials) diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/connectivity.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/connectivity.py deleted file mode 100644 index c880b1a1..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/connectivity.py +++ /dev/null @@ -1,405 +0,0 @@ -""" Fast approximation for node connectivity -""" -# Copyright (C) 2015 by -# Jordi Torrents -# All rights reserved. -# BSD license. -import itertools -from operator import itemgetter - -import networkx as nx - -__author__ = """\n""".join(['Jordi Torrents ']) - -__all__ = ['local_node_connectivity', - 'node_connectivity', - 'all_pairs_node_connectivity'] - -INF = float('inf') - - -def local_node_connectivity(G, source, target, cutoff=None): - """Compute node connectivity between source and target. - - Pairwise or local node connectivity between two distinct and nonadjacent - nodes is the minimum number of nodes that must be removed (minimum - separating cutset) to disconnect them. By Menger's theorem, this is equal - to the number of node independent paths (paths that share no nodes other - than source and target). Which is what we compute in this function. - - This algorithm is a fast approximation that gives an strict lower - bound on the actual number of node independent paths between two nodes [1]_. - It works for both directed and undirected graphs. - - Parameters - ---------- - - G : NetworkX graph - - source : node - Starting node for node connectivity - - target : node - Ending node for node connectivity - - cutoff : integer - Maximum node connectivity to consider. If None, the minimum degree - of source or target is used as a cutoff. Default value None. - - Returns - ------- - k: integer - pairwise node connectivity - - Examples - -------- - >>> # Platonic octahedral graph has node connectivity 4 - >>> # for each non adjacent node pair - >>> from networkx.algorithms import approximation as approx - >>> G = nx.octahedral_graph() - >>> approx.local_node_connectivity(G, 0, 5) - 4 - - Notes - ----- - This algorithm [1]_ finds node independents paths between two nodes by - computing their shortest path using BFS, marking the nodes of the path - found as 'used' and then searching other shortest paths excluding the - nodes marked as used until no more paths exist. It is not exact because - a shortest path could use nodes that, if the path were longer, may belong - to two different node independent paths. Thus it only guarantees an - strict lower bound on node connectivity. - - Note that the authors propose a further refinement, losing accuracy and - gaining speed, which is not implemented yet. - - See also - -------- - all_pairs_node_connectivity - node_connectivity - - References - ---------- - .. [1] White, Douglas R., and Mark Newman. 2001 A Fast Algorithm for - Node-Independent Paths. Santa Fe Institute Working Paper #01-07-035 - http://eclectic.ss.uci.edu/~drwhite/working.pdf - - """ - if target == source: - raise nx.NetworkXError("source and target have to be different nodes.") - - # Maximum possible node independent paths - if G.is_directed(): - possible = min(G.out_degree(source), G.in_degree(target)) - else: - possible = min(G.degree(source), G.degree(target)) - - K = 0 - if not possible: - return K - - if cutoff is None: - cutoff = INF - - exclude = set() - for i in range(min(possible, cutoff)): - try: - path = _bidirectional_shortest_path(G, source, target, exclude) - exclude.update(set(path)) - K += 1 - except nx.NetworkXNoPath: - break - - return K - - -def node_connectivity(G, s=None, t=None): - r"""Returns an approximation for node connectivity for a graph or digraph G. - - Node connectivity is equal to the minimum number of nodes that - must be removed to disconnect G or render it trivial. By Menger's theorem, - this is equal to the number of node independent paths (paths that - share no nodes other than source and target). - - If source and target nodes are provided, this function returns the - local node connectivity: the minimum number of nodes that must be - removed to break all paths from source to target in G. - - This algorithm is based on a fast approximation that gives an strict lower - bound on the actual number of node independent paths between two nodes [1]_. - It works for both directed and undirected graphs. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - s : node - Source node. Optional. Default value: None. - - t : node - Target node. Optional. Default value: None. - - Returns - ------- - K : integer - Node connectivity of G, or local node connectivity if source - and target are provided. - - Examples - -------- - >>> # Platonic octahedral graph is 4-node-connected - >>> from networkx.algorithms import approximation as approx - >>> G = nx.octahedral_graph() - >>> approx.node_connectivity(G) - 4 - - Notes - ----- - This algorithm [1]_ finds node independents paths between two nodes by - computing their shortest path using BFS, marking the nodes of the path - found as 'used' and then searching other shortest paths excluding the - nodes marked as used until no more paths exist. It is not exact because - a shortest path could use nodes that, if the path were longer, may belong - to two different node independent paths. Thus it only guarantees an - strict lower bound on node connectivity. - - See also - -------- - all_pairs_node_connectivity - local_node_connectivity - - References - ---------- - .. [1] White, Douglas R., and Mark Newman. 2001 A Fast Algorithm for - Node-Independent Paths. Santa Fe Institute Working Paper #01-07-035 - http://eclectic.ss.uci.edu/~drwhite/working.pdf - - """ - if (s is not None and t is None) or (s is None and t is not None): - raise nx.NetworkXError('Both source and target must be specified.') - - # Local node connectivity - if s is not None and t is not None: - if s not in G: - raise nx.NetworkXError('node %s not in graph' % s) - if t not in G: - raise nx.NetworkXError('node %s not in graph' % t) - return local_node_connectivity(G, s, t) - - # Global node connectivity - if G.is_directed(): - connected_func = nx.is_weakly_connected - iter_func = itertools.permutations - - def neighbors(v): - return itertools.chain(G.predecessors(v), G.successors(v)) - else: - connected_func = nx.is_connected - iter_func = itertools.combinations - neighbors = G.neighbors - - if not connected_func(G): - return 0 - - # Choose a node with minimum degree - v, minimum_degree = min(G.degree(), key=itemgetter(1)) - # Node connectivity is bounded by minimum degree - K = minimum_degree - # compute local node connectivity with all non-neighbors nodes - # and store the minimum - for w in set(G) - set(neighbors(v)) - set([v]): - K = min(K, local_node_connectivity(G, v, w, cutoff=K)) - # Same for non adjacent pairs of neighbors of v - for x, y in iter_func(neighbors(v), 2): - if y not in G[x] and x != y: - K = min(K, local_node_connectivity(G, x, y, cutoff=K)) - return K - - -def all_pairs_node_connectivity(G, nbunch=None, cutoff=None): - """ Compute node connectivity between all pairs of nodes. - - Pairwise or local node connectivity between two distinct and nonadjacent - nodes is the minimum number of nodes that must be removed (minimum - separating cutset) to disconnect them. By Menger's theorem, this is equal - to the number of node independent paths (paths that share no nodes other - than source and target). Which is what we compute in this function. - - This algorithm is a fast approximation that gives an strict lower - bound on the actual number of node independent paths between two nodes [1]_. - It works for both directed and undirected graphs. - - - Parameters - ---------- - G : NetworkX graph - - nbunch: container - Container of nodes. If provided node connectivity will be computed - only over pairs of nodes in nbunch. - - cutoff : integer - Maximum node connectivity to consider. If None, the minimum degree - of source or target is used as a cutoff in each pair of nodes. - Default value None. - - Returns - ------- - K : dictionary - Dictionary, keyed by source and target, of pairwise node connectivity - - See Also - -------- - local_node_connectivity - node_connectivity - - References - ---------- - .. [1] White, Douglas R., and Mark Newman. 2001 A Fast Algorithm for - Node-Independent Paths. Santa Fe Institute Working Paper #01-07-035 - http://eclectic.ss.uci.edu/~drwhite/working.pdf - """ - if nbunch is None: - nbunch = G - else: - nbunch = set(nbunch) - - directed = G.is_directed() - if directed: - iter_func = itertools.permutations - else: - iter_func = itertools.combinations - - all_pairs = {n: {} for n in nbunch} - - for u, v in iter_func(nbunch, 2): - k = local_node_connectivity(G, u, v, cutoff=cutoff) - all_pairs[u][v] = k - if not directed: - all_pairs[v][u] = k - - return all_pairs - - -def _bidirectional_shortest_path(G, source, target, exclude): - """Returns shortest path between source and target ignoring nodes in the - container 'exclude'. - - Parameters - ---------- - - G : NetworkX graph - - source : node - Starting node for path - - target : node - Ending node for path - - exclude: container - Container for nodes to exclude from the search for shortest paths - - Returns - ------- - path: list - Shortest path between source and target ignoring nodes in 'exclude' - - Raises - ------ - NetworkXNoPath: exception - If there is no path or if nodes are adjacent and have only one path - between them - - Notes - ----- - This function and its helper are originally from - networkx.algorithms.shortest_paths.unweighted and are modified to - accept the extra parameter 'exclude', which is a container for nodes - already used in other paths that should be ignored. - - References - ---------- - .. [1] White, Douglas R., and Mark Newman. 2001 A Fast Algorithm for - Node-Independent Paths. Santa Fe Institute Working Paper #01-07-035 - http://eclectic.ss.uci.edu/~drwhite/working.pdf - - """ - # call helper to do the real work - results = _bidirectional_pred_succ(G, source, target, exclude) - pred, succ, w = results - - # build path from pred+w+succ - path = [] - # from source to w - while w is not None: - path.append(w) - w = pred[w] - path.reverse() - # from w to target - w = succ[path[-1]] - while w is not None: - path.append(w) - w = succ[w] - - return path - - -def _bidirectional_pred_succ(G, source, target, exclude): - # does BFS from both source and target and meets in the middle - # excludes nodes in the container "exclude" from the search - if source is None or target is None: - raise nx.NetworkXException( - "Bidirectional shortest path called without source or target") - if target == source: - return ({target: None}, {source: None}, source) - - # handle either directed or undirected - if G.is_directed(): - Gpred = G.predecessors - Gsucc = G.successors - else: - Gpred = G.neighbors - Gsucc = G.neighbors - - # predecesssor and successors in search - pred = {source: None} - succ = {target: None} - - # initialize fringes, start with forward - forward_fringe = [source] - reverse_fringe = [target] - - level = 0 - - while forward_fringe and reverse_fringe: - # Make sure that we iterate one step forward and one step backwards - # thus source and target will only trigger "found path" when they are - # adjacent and then they can be safely included in the container 'exclude' - level += 1 - if not level % 2 == 0: - this_level = forward_fringe - forward_fringe = [] - for v in this_level: - for w in Gsucc(v): - if w in exclude: - continue - if w not in pred: - forward_fringe.append(w) - pred[w] = v - if w in succ: - return pred, succ, w # found path - else: - this_level = reverse_fringe - reverse_fringe = [] - for v in this_level: - for w in Gpred(v): - if w in exclude: - continue - if w not in succ: - succ[w] = v - reverse_fringe.append(w) - if w in pred: - return pred, succ, w # found path - - raise nx.NetworkXNoPath("No path between %s and %s." % (source, target)) diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/dominating_set.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/dominating_set.py deleted file mode 100644 index 80352a71..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/dominating_set.py +++ /dev/null @@ -1,131 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2011-2012 by -# Nicholas Mancuso -# All rights reserved. -# BSD license. -"""Functions for finding node and edge dominating sets. - -A `dominating set`_ for an undirected graph *G* with vertex set *V* -and edge set *E* is a subset *D* of *V* such that every vertex not in -*D* is adjacent to at least one member of *D*. An `edge dominating set`_ -is a subset *F* of *E* such that every edge not in *F* is -incident to an endpoint of at least one edge in *F*. - -.. _dominating set: https://en.wikipedia.org/wiki/Dominating_set -.. _edge dominating set: https://en.wikipedia.org/wiki/Edge_dominating_set - -""" - -from ..matching import maximal_matching -from ...utils import not_implemented_for - -__all__ = ["min_weighted_dominating_set", - "min_edge_dominating_set"] - -__author__ = """Nicholas Mancuso (nick.mancuso@gmail.com)""" - - -# TODO Why doesn't this algorithm work for directed graphs? -@not_implemented_for('directed') -def min_weighted_dominating_set(G, weight=None): - r"""Returns a dominating set that approximates the minimum weight node - dominating set. - - Parameters - ---------- - G : NetworkX graph - Undirected graph. - - weight : string - The node attribute storing the weight of an node. If provided, - the node attribute with this key must be a number for each - node. If not provided, each node is assumed to have weight one. - - Returns - ------- - min_weight_dominating_set : set - A set of nodes, the sum of whose weights is no more than `(\log - w(V)) w(V^*)`, where `w(V)` denotes the sum of the weights of - each node in the graph and `w(V^*)` denotes the sum of the - weights of each node in the minimum weight dominating set. - - Notes - ----- - This algorithm computes an approximate minimum weighted dominating - set for the graph `G`. The returned solution has weight `(\log - w(V)) w(V^*)`, where `w(V)` denotes the sum of the weights of each - node in the graph and `w(V^*)` denotes the sum of the weights of - each node in the minimum weight dominating set for the graph. - - This implementation of the algorithm runs in $O(m)$ time, where $m$ - is the number of edges in the graph. - - References - ---------- - .. [1] Vazirani, Vijay V. - *Approximation Algorithms*. - Springer Science & Business Media, 2001. - - """ - # The unique dominating set for the null graph is the empty set. - if len(G) == 0: - return set() - - # This is the dominating set that will eventually be returned. - dom_set = set() - - def _cost(node_and_neighborhood): - """Returns the cost-effectiveness of greedily choosing the given - node. - - `node_and_neighborhood` is a two-tuple comprising a node and its - closed neighborhood. - - """ - v, neighborhood = node_and_neighborhood - return G.nodes[v].get(weight, 1) / len(neighborhood - dom_set) - - # This is a set of all vertices not already covered by the - # dominating set. - vertices = set(G) - # This is a dictionary mapping each node to the closed neighborhood - # of that node. - neighborhoods = {v: {v} | set(G[v]) for v in G} - - # Continue until all vertices are adjacent to some node in the - # dominating set. - while vertices: - # Find the most cost-effective node to add, along with its - # closed neighborhood. - dom_node, min_set = min(neighborhoods.items(), key=_cost) - # Add the node to the dominating set and reduce the remaining - # set of nodes to cover. - dom_set.add(dom_node) - del neighborhoods[dom_node] - vertices -= min_set - - return dom_set - - -def min_edge_dominating_set(G): - r"""Returns minimum cardinality edge dominating set. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - Returns - ------- - min_edge_dominating_set : set - Returns a set of dominating edges whose size is no more than 2 * OPT. - - Notes - ----- - The algorithm computes an approximate solution to the edge dominating set - problem. The result is no more than 2 * OPT in terms of size of the set. - Runtime of the algorithm is $O(|E|)$. - """ - if not G: - raise ValueError("Expected non-empty NetworkX graph!") - return maximal_matching(G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/independent_set.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/independent_set.py deleted file mode 100644 index b9f3178a..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/independent_set.py +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: utf-8 -*- -r""" -Independent Set - -Independent set or stable set is a set of vertices in a graph, no two of -which are adjacent. That is, it is a set I of vertices such that for every -two vertices in I, there is no edge connecting the two. Equivalently, each -edge in the graph has at most one endpoint in I. The size of an independent -set is the number of vertices it contains. - -A maximum independent set is a largest independent set for a given graph G -and its size is denoted $\alpha(G)$. The problem of finding such a set is called -the maximum independent set problem and is an NP-hard optimization problem. -As such, it is unlikely that there exists an efficient algorithm for finding -a maximum independent set of a graph. - -`Wikipedia: Independent set `_ - -Independent set algorithm is based on the following paper: - -$O(|V|/(log|V|)^2)$ apx of maximum clique/independent set. - -Boppana, R., & Halldórsson, M. M. (1992). -Approximating maximum independent sets by excluding subgraphs. -BIT Numerical Mathematics, 32(2), 180–196. Springer. -doi:10.1007/BF01994876 - -""" -# Copyright (C) 2011-2012 by -# Nicholas Mancuso -# All rights reserved. -# BSD license. -from networkx.algorithms.approximation import clique_removal -__all__ = ["maximum_independent_set"] -__author__ = """Nicholas Mancuso (nick.mancuso@gmail.com)""" - - -def maximum_independent_set(G): - """Returns an approximate maximum independent set. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - Returns - ------- - iset : Set - The apx-maximum independent set - - Notes - ----- - Finds the $O(|V|/(log|V|)^2)$ apx of independent set in the worst case. - - - References - ---------- - .. [1] Boppana, R., & Halldórsson, M. M. (1992). - Approximating maximum independent sets by excluding subgraphs. - BIT Numerical Mathematics, 32(2), 180–196. Springer. - """ - iset, _ = clique_removal(G) - return iset diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/kcomponents.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/kcomponents.py deleted file mode 100644 index fe8ce7f4..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/kcomponents.py +++ /dev/null @@ -1,374 +0,0 @@ -""" Fast approximation for k-component structure -""" -# Copyright (C) 2015 by -# Jordi Torrents -# All rights reserved. -# BSD license. -import itertools -from collections import defaultdict -from collections.abc import Mapping - -import networkx as nx -from networkx.exception import NetworkXError -from networkx.utils import not_implemented_for - -from networkx.algorithms.approximation import local_node_connectivity -from networkx.algorithms.connectivity import \ - local_node_connectivity as exact_local_node_connectivity - - -__author__ = """\n""".join(['Jordi Torrents ']) - -__all__ = ['k_components'] - - -not_implemented_for('directed') - - -def k_components(G, min_density=0.95): - r"""Returns the approximate k-component structure of a graph G. - - A `k`-component is a maximal subgraph of a graph G that has, at least, - node connectivity `k`: we need to remove at least `k` nodes to break it - into more components. `k`-components have an inherent hierarchical - structure because they are nested in terms of connectivity: a connected - graph can contain several 2-components, each of which can contain - one or more 3-components, and so forth. - - This implementation is based on the fast heuristics to approximate - the `k`-component structure of a graph [1]_. Which, in turn, it is based on - a fast approximation algorithm for finding good lower bounds of the number - of node independent paths between two nodes [2]_. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - min_density : Float - Density relaxation threshold. Default value 0.95 - - Returns - ------- - k_components : dict - Dictionary with connectivity level `k` as key and a list of - sets of nodes that form a k-component of level `k` as values. - - - Examples - -------- - >>> # Petersen graph has 10 nodes and it is triconnected, thus all - >>> # nodes are in a single component on all three connectivity levels - >>> from networkx.algorithms import approximation as apxa - >>> G = nx.petersen_graph() - >>> k_components = apxa.k_components(G) - - Notes - ----- - The logic of the approximation algorithm for computing the `k`-component - structure [1]_ is based on repeatedly applying simple and fast algorithms - for `k`-cores and biconnected components in order to narrow down the - number of pairs of nodes over which we have to compute White and Newman's - approximation algorithm for finding node independent paths [2]_. More - formally, this algorithm is based on Whitney's theorem, which states - an inclusion relation among node connectivity, edge connectivity, and - minimum degree for any graph G. This theorem implies that every - `k`-component is nested inside a `k`-edge-component, which in turn, - is contained in a `k`-core. Thus, this algorithm computes node independent - paths among pairs of nodes in each biconnected part of each `k`-core, - and repeats this procedure for each `k` from 3 to the maximal core number - of a node in the input graph. - - Because, in practice, many nodes of the core of level `k` inside a - bicomponent actually are part of a component of level k, the auxiliary - graph needed for the algorithm is likely to be very dense. Thus, we use - a complement graph data structure (see `AntiGraph`) to save memory. - AntiGraph only stores information of the edges that are *not* present - in the actual auxiliary graph. When applying algorithms to this - complement graph data structure, it behaves as if it were the dense - version. - - See also - -------- - k_components - - References - ---------- - .. [1] Torrents, J. and F. Ferraro (2015) Structural Cohesion: - Visualization and Heuristics for Fast Computation. - https://arxiv.org/pdf/1503.04476v1 - - .. [2] White, Douglas R., and Mark Newman (2001) A Fast Algorithm for - Node-Independent Paths. Santa Fe Institute Working Paper #01-07-035 - http://eclectic.ss.uci.edu/~drwhite/working.pdf - - .. [3] Moody, J. and D. White (2003). Social cohesion and embeddedness: - A hierarchical conception of social groups. - American Sociological Review 68(1), 103--28. - http://www2.asanet.org/journals/ASRFeb03MoodyWhite.pdf - - """ - # Dictionary with connectivity level (k) as keys and a list of - # sets of nodes that form a k-component as values - k_components = defaultdict(list) - # make a few functions local for speed - node_connectivity = local_node_connectivity - k_core = nx.k_core - core_number = nx.core_number - biconnected_components = nx.biconnected_components - density = nx.density - combinations = itertools.combinations - # Exact solution for k = {1,2} - # There is a linear time algorithm for triconnectivity, if we had an - # implementation available we could start from k = 4. - for component in nx.connected_components(G): - # isolated nodes have connectivity 0 - comp = set(component) - if len(comp) > 1: - k_components[1].append(comp) - for bicomponent in nx.biconnected_components(G): - # avoid considering dyads as bicomponents - bicomp = set(bicomponent) - if len(bicomp) > 2: - k_components[2].append(bicomp) - # There is no k-component of k > maximum core number - # \kappa(G) <= \lambda(G) <= \delta(G) - g_cnumber = core_number(G) - max_core = max(g_cnumber.values()) - for k in range(3, max_core + 1): - C = k_core(G, k, core_number=g_cnumber) - for nodes in biconnected_components(C): - # Build a subgraph SG induced by the nodes that are part of - # each biconnected component of the k-core subgraph C. - if len(nodes) < k: - continue - SG = G.subgraph(nodes) - # Build auxiliary graph - H = _AntiGraph() - H.add_nodes_from(SG.nodes()) - for u, v in combinations(SG, 2): - K = node_connectivity(SG, u, v, cutoff=k) - if k > K: - H.add_edge(u, v) - for h_nodes in biconnected_components(H): - if len(h_nodes) <= k: - continue - SH = H.subgraph(h_nodes) - for Gc in _cliques_heuristic(SG, SH, k, min_density): - for k_nodes in biconnected_components(Gc): - Gk = nx.k_core(SG.subgraph(k_nodes), k) - if len(Gk) <= k: - continue - k_components[k].append(set(Gk)) - return k_components - - -def _cliques_heuristic(G, H, k, min_density): - h_cnumber = nx.core_number(H) - for i, c_value in enumerate(sorted(set(h_cnumber.values()), reverse=True)): - cands = set(n for n, c in h_cnumber.items() if c == c_value) - # Skip checking for overlap for the highest core value - if i == 0: - overlap = False - else: - overlap = set.intersection(*[ - set(x for x in H[n] if x not in cands) - for n in cands]) - if overlap and len(overlap) < k: - SH = H.subgraph(cands | overlap) - else: - SH = H.subgraph(cands) - sh_cnumber = nx.core_number(SH) - SG = nx.k_core(G.subgraph(SH), k) - while not (_same(sh_cnumber) and nx.density(SH) >= min_density): - #!! This subgraph must be writable => .copy() - SH = H.subgraph(SG).copy() - if len(SH) <= k: - break - sh_cnumber = nx.core_number(SH) - sh_deg = dict(SH.degree()) - min_deg = min(sh_deg.values()) - SH.remove_nodes_from(n for n, d in sh_deg.items() if d == min_deg) - SG = nx.k_core(G.subgraph(SH), k) - else: - yield SG - - -def _same(measure, tol=0): - vals = set(measure.values()) - if (max(vals) - min(vals)) <= tol: - return True - return False - - -class _AntiGraph(nx.Graph): - """ - Class for complement graphs. - - The main goal is to be able to work with big and dense graphs with - a low memory foodprint. - - In this class you add the edges that *do not exist* in the dense graph, - the report methods of the class return the neighbors, the edges and - the degree as if it was the dense graph. Thus it's possible to use - an instance of this class with some of NetworkX functions. In this - case we only use k-core, connected_components, and biconnected_components. - """ - - all_edge_dict = {'weight': 1} - - def single_edge_dict(self): - return self.all_edge_dict - edge_attr_dict_factory = single_edge_dict - - def __getitem__(self, n): - """Returns a dict of neighbors of node n in the dense graph. - - Parameters - ---------- - n : node - A node in the graph. - - Returns - ------- - adj_dict : dictionary - The adjacency dictionary for nodes connected to n. - - """ - all_edge_dict = self.all_edge_dict - return {node: all_edge_dict for node in - set(self._adj) - set(self._adj[n]) - set([n])} - - def neighbors(self, n): - """Returns an iterator over all neighbors of node n in the - dense graph. - """ - try: - return iter(set(self._adj) - set(self._adj[n]) - set([n])) - except KeyError: - raise NetworkXError("The node %s is not in the graph." % (n,)) - - class AntiAtlasView(Mapping): - """An adjacency inner dict for AntiGraph""" - - def __init__(self, graph, node): - self._graph = graph - self._atlas = graph._adj[node] - self._node = node - - def __len__(self): - return len(self._graph) - len(self._atlas) - 1 - - def __iter__(self): - return (n for n in self._graph if n not in self._atlas and n != self._node) - - def __getitem__(self, nbr): - nbrs = set(self._graph._adj) - set(self._atlas) - set([self._node]) - if nbr in nbrs: - return self._graph.all_edge_dict - raise KeyError(nbr) - - class AntiAdjacencyView(AntiAtlasView): - """An adjacency outer dict for AntiGraph""" - - def __init__(self, graph): - self._graph = graph - self._atlas = graph._adj - - def __len__(self): - return len(self._atlas) - - def __iter__(self): - return iter(self._graph) - - def __getitem__(self, node): - if node not in self._graph: - raise KeyError(node) - return self._graph.AntiAtlasView(self._graph, node) - - @property - def adj(self): - return self.AntiAdjacencyView(self) - - def subgraph(self, nodes): - """This subgraph method returns a full AntiGraph. Not a View""" - nodes = set(nodes) - G = _AntiGraph() - G.add_nodes_from(nodes) - for n in G: - Gnbrs = G.adjlist_inner_dict_factory() - G._adj[n] = Gnbrs - for nbr, d in self._adj[n].items(): - if nbr in G._adj: - Gnbrs[nbr] = d - G._adj[nbr][n] = d - G.graph = self.graph - return G - - class AntiDegreeView(nx.reportviews.DegreeView): - def __iter__(self): - all_nodes = set(self._succ) - for n in self._nodes: - nbrs = all_nodes - set(self._succ[n]) - set([n]) - yield (n, len(nbrs)) - - def __getitem__(self, n): - nbrs = set(self._succ) - set(self._succ[n]) - set([n]) - # AntiGraph is a ThinGraph so all edges have weight 1 - return len(nbrs) + (n in nbrs) - - @property - def degree(self): - """Returns an iterator for (node, degree) and degree for single node. - - The node degree is the number of edges adjacent to the node. - - Parameters - ---------- - nbunch : iterable container, optional (default=all nodes) - A container of nodes. The container will be iterated - through once. - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - deg: - Degree of the node, if a single node is passed as argument. - nd_iter : an iterator - The iterator returns two-tuples of (node, degree). - - See Also - -------- - degree - - Examples - -------- - >>> G = nx.path_graph(4) - >>> G.degree(0) # node 0 with degree 1 - 1 - >>> list(G.degree([0,1])) - [(0, 1), (1, 2)] - - """ - return self.AntiDegreeView(self) - - def adjacency(self): - """Returns an iterator of (node, adjacency set) tuples for all nodes - in the dense graph. - - This is the fastest way to look at every edge. - For directed graphs, only outgoing adjacencies are included. - - Returns - ------- - adj_iter : iterator - An iterator of (node, adjacency set) for all nodes in - the graph. - - """ - for n in self._adj: - yield (n, set(self._adj) - set(self._adj[n]) - set([n])) diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/matching.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/matching.py deleted file mode 100644 index d7fc4c43..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/matching.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- -""" -************** -Graph Matching -************** - -Given a graph G = (V,E), a matching M in G is a set of pairwise non-adjacent -edges; that is, no two edges share a common vertex. - -`Wikipedia: Matching `_ -""" -# Copyright (C) 2011-2012 by -# Nicholas Mancuso -# All rights reserved. -# BSD license. -import networkx as nx -__all__ = ["min_maximal_matching"] -__author__ = """Nicholas Mancuso (nick.mancuso@gmail.com)""" - - -def min_maximal_matching(G): - r"""Returns the minimum maximal matching of G. That is, out of all maximal - matchings of the graph G, the smallest is returned. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - Returns - ------- - min_maximal_matching : set - Returns a set of edges such that no two edges share a common endpoint - and every edge not in the set shares some common endpoint in the set. - Cardinality will be 2*OPT in the worst case. - - Notes - ----- - The algorithm computes an approximate solution fo the minimum maximal - cardinality matching problem. The solution is no more than 2 * OPT in size. - Runtime is $O(|E|)$. - - References - ---------- - .. [1] Vazirani, Vijay Approximation Algorithms (2001) - """ - return nx.maximal_matching(G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/ramsey.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/ramsey.py deleted file mode 100644 index 48a9df79..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/ramsey.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Ramsey numbers. -""" -# Copyright (C) 2011 by -# Nicholas Mancuso -# All rights reserved. -# BSD license. -import networkx as nx -from ...utils import arbitrary_element - -__all__ = ["ramsey_R2"] -__author__ = """Nicholas Mancuso (nick.mancuso@gmail.com)""" - - -def ramsey_R2(G): - r"""Approximately computes the Ramsey number `R(2;s,t)` for graph. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - Returns - ------- - max_pair : (set, set) tuple - Maximum clique, Maximum independent set. - """ - if not G: - return set(), set() - - node = arbitrary_element(G) - nbrs = nx.all_neighbors(G, node) - nnbrs = nx.non_neighbors(G, node) - c_1, i_1 = ramsey_R2(G.subgraph(nbrs).copy()) - c_2, i_2 = ramsey_R2(G.subgraph(nnbrs).copy()) - - c_1.add(node) - i_2.add(node) - # Choose the larger of the two cliques and the larger of the two - # independent sets, according to cardinality. - return max(c_1, c_2, key=len), max(i_1, i_2, key=len) diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/steinertree.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/steinertree.py deleted file mode 100644 index 7ad8f6e5..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/steinertree.py +++ /dev/null @@ -1,90 +0,0 @@ -from itertools import combinations, chain - -from networkx.utils import pairwise, not_implemented_for -import networkx as nx - -__all__ = ['metric_closure', 'steiner_tree'] - - -@not_implemented_for('directed') -def metric_closure(G, weight='weight'): - """ Return the metric closure of a graph. - - The metric closure of a graph *G* is the complete graph in which each edge - is weighted by the shortest path distance between the nodes in *G* . - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - NetworkX graph - Metric closure of the graph `G`. - - """ - M = nx.Graph() - - Gnodes = set(G) - - # check for connected graph while processing first node - all_paths_iter = nx.all_pairs_dijkstra(G, weight=weight) - u, (distance, path) = next(all_paths_iter) - if Gnodes - set(distance): - msg = "G is not a connected graph. metric_closure is not defined." - raise nx.NetworkXError(msg) - Gnodes.remove(u) - for v in Gnodes: - M.add_edge(u, v, distance=distance[v], path=path[v]) - - # first node done -- now process the rest - for u, (distance, path) in all_paths_iter: - Gnodes.remove(u) - for v in Gnodes: - M.add_edge(u, v, distance=distance[v], path=path[v]) - - return M - - -@not_implemented_for('multigraph') -@not_implemented_for('directed') -def steiner_tree(G, terminal_nodes, weight='weight'): - """ Return an approximation to the minimum Steiner tree of a graph. - - Parameters - ---------- - G : NetworkX graph - - terminal_nodes : list - A list of terminal nodes for which minimum steiner tree is - to be found. - - Returns - ------- - NetworkX graph - Approximation to the minimum steiner tree of `G` induced by - `terminal_nodes` . - - Notes - ----- - Steiner tree can be approximated by computing the minimum spanning - tree of the subgraph of the metric closure of the graph induced by the - terminal nodes, where the metric closure of *G* is the complete graph in - which each edge is weighted by the shortest path distance between the - nodes in *G* . - This algorithm produces a tree whose weight is within a (2 - (2 / t)) - factor of the weight of the optimal Steiner tree where *t* is number of - terminal nodes. - - """ - # M is the subgraph of the metric closure induced by the terminal nodes of - # G. - M = metric_closure(G, weight=weight) - # Use the 'distance' attribute of each edge provided by the metric closure - # graph. - H = M.subgraph(terminal_nodes) - mst_edges = nx.minimum_spanning_edges(H, weight='distance', data=True) - # Create an iterator over each edge in each shortest path; repeats are okay - edges = chain.from_iterable(pairwise(d['path']) for u, v, d in mst_edges) - T = G.edge_subgraph(edges) - return T diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_approx_clust_coeff.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_approx_clust_coeff.py deleted file mode 100644 index 8bb538dc..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_approx_clust_coeff.py +++ /dev/null @@ -1,45 +0,0 @@ -import networkx as nx -from networkx.algorithms.approximation import average_clustering - -# This approximation has to be be exact in regular graphs -# with no triangles or with all possible triangles. - - -def test_petersen(): - # Actual coefficient is 0 - G = nx.petersen_graph() - assert (average_clustering(G, trials=int(len(G) / 2)) == - nx.average_clustering(G)) - - -def test_petersen_seed(): - # Actual coefficient is 0 - G = nx.petersen_graph() - assert (average_clustering(G, trials=int(len(G) / 2), seed=1) == - nx.average_clustering(G)) - - -def test_tetrahedral(): - # Actual coefficient is 1 - G = nx.tetrahedral_graph() - assert (average_clustering(G, trials=int(len(G) / 2)) == - nx.average_clustering(G)) - - -def test_dodecahedral(): - # Actual coefficient is 0 - G = nx.dodecahedral_graph() - assert (average_clustering(G, trials=int(len(G) / 2)) == - nx.average_clustering(G)) - - -def test_empty(): - G = nx.empty_graph(5) - assert average_clustering(G, trials=int(len(G) / 2)) == 0 - - -def test_complete(): - G = nx.complete_graph(5) - assert average_clustering(G, trials=int(len(G) / 2)) == 1 - G = nx.complete_graph(7) - assert average_clustering(G, trials=int(len(G) / 2)) == 1 diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_clique.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_clique.py deleted file mode 100644 index 585c381b..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_clique.py +++ /dev/null @@ -1,115 +0,0 @@ -# test_clique.py - unit tests for the approximation.clique module -# -# Copyright 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.approximation.clique` -module. - -""" - - -import networkx as nx -from networkx.algorithms.approximation import max_clique -from networkx.algorithms.approximation import clique_removal -from networkx.algorithms.approximation import large_clique_size - - -def is_independent_set(G, nodes): - """Returns True if and only if `nodes` is a clique in `G`. - - `G` is a NetworkX graph. `nodes` is an iterable of nodes in - `G`. - - """ - return G.subgraph(nodes).number_of_edges() == 0 - - -def is_clique(G, nodes): - """Returns True if and only if `nodes` is an independent set - in `G`. - - `G` is an undirected simple graph. `nodes` is an iterable of - nodes in `G`. - - """ - H = G.subgraph(nodes) - n = len(H) - return H.number_of_edges() == n * (n - 1) // 2 - - -class TestCliqueRemoval(object): - """Unit tests for the - :func:`~networkx.algorithms.approximation.clique_removal` function. - - """ - - def test_trivial_graph(self): - G = nx.trivial_graph() - independent_set, cliques = clique_removal(G) - assert is_independent_set(G, independent_set) - assert all(is_clique(G, clique) for clique in cliques) - # In fact, we should only have 1-cliques, that is, singleton nodes. - assert all(len(clique) == 1 for clique in cliques) - - def test_complete_graph(self): - G = nx.complete_graph(10) - independent_set, cliques = clique_removal(G) - assert is_independent_set(G, independent_set) - assert all(is_clique(G, clique) for clique in cliques) - - def test_barbell_graph(self): - G = nx.barbell_graph(10, 5) - independent_set, cliques = clique_removal(G) - assert is_independent_set(G, independent_set) - assert all(is_clique(G, clique) for clique in cliques) - - -class TestMaxClique(object): - """Unit tests for the :func:`networkx.algorithms.approximation.max_clique` - function. - - """ - - def test_null_graph(self): - G = nx.null_graph() - assert len(max_clique(G)) == 0 - - def test_complete_graph(self): - graph = nx.complete_graph(30) - # this should return the entire graph - mc = max_clique(graph) - assert 30 == len(mc) - - def test_maximal_by_cardinality(self): - """Tests that the maximal clique is computed according to maximum - cardinality of the sets. - - For more information, see pull request #1531. - - """ - G = nx.complete_graph(5) - G.add_edge(4, 5) - clique = max_clique(G) - assert len(clique) > 1 - - G = nx.lollipop_graph(30, 2) - clique = max_clique(G) - assert len(clique) > 2 - - -def test_large_clique_size(): - G = nx.complete_graph(9) - nx.add_cycle(G, [9, 10, 11]) - G.add_edge(8, 9) - G.add_edge(1, 12) - G.add_node(13) - - assert large_clique_size(G) == 9 - G.remove_node(5) - assert large_clique_size(G) == 8 - G.remove_edge(2, 3) - assert large_clique_size(G) == 7 diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_connectivity.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_connectivity.py deleted file mode 100644 index 42cd9a15..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_connectivity.py +++ /dev/null @@ -1,170 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms import approximation as approx - - -def test_global_node_connectivity(): - # Figure 1 chapter on Connectivity - G = nx.Graph() - G.add_edges_from([(1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 6), (3, 4), - (3, 6), (4, 6), (4, 7), (5, 7), (6, 8), (6, 9), (7, 8), - (7, 10), (8, 11), (9, 10), (9, 11), (10, 11)]) - assert 2 == approx.local_node_connectivity(G, 1, 11) - assert 2 == approx.node_connectivity(G) - assert 2 == approx.node_connectivity(G, 1, 11) - - -def test_white_harary1(): - # Figure 1b white and harary (2001) - # A graph with high adhesion (edge connectivity) and low cohesion - # (node connectivity) - G = nx.disjoint_union(nx.complete_graph(4), nx.complete_graph(4)) - G.remove_node(7) - for i in range(4, 7): - G.add_edge(0, i) - G = nx.disjoint_union(G, nx.complete_graph(4)) - G.remove_node(G.order() - 1) - for i in range(7, 10): - G.add_edge(0, i) - assert 1 == approx.node_connectivity(G) - - -def test_complete_graphs(): - for n in range(5, 25, 5): - G = nx.complete_graph(n) - assert n - 1 == approx.node_connectivity(G) - assert n - 1 == approx.node_connectivity(G, 0, 3) - - -def test_empty_graphs(): - for k in range(5, 25, 5): - G = nx.empty_graph(k) - assert 0 == approx.node_connectivity(G) - assert 0 == approx.node_connectivity(G, 0, 3) - - -def test_petersen(): - G = nx.petersen_graph() - assert 3 == approx.node_connectivity(G) - assert 3 == approx.node_connectivity(G, 0, 5) - -# Approximation fails with tutte graph -# def test_tutte(): -# G = nx.tutte_graph() -# assert_equal(3, approx.node_connectivity(G)) - - -def test_dodecahedral(): - G = nx.dodecahedral_graph() - assert 3 == approx.node_connectivity(G) - assert 3 == approx.node_connectivity(G, 0, 5) - - -def test_octahedral(): - G = nx.octahedral_graph() - assert 4 == approx.node_connectivity(G) - assert 4 == approx.node_connectivity(G, 0, 5) - -# Approximation can fail with icosahedral graph depending -# on iteration order. -# def test_icosahedral(): -# G=nx.icosahedral_graph() -# assert_equal(5, approx.node_connectivity(G)) -# assert_equal(5, approx.node_connectivity(G, 0, 5)) - - -def test_only_source(): - G = nx.complete_graph(5) - pytest.raises(nx.NetworkXError, approx.node_connectivity, G, s=0) - - -def test_only_target(): - G = nx.complete_graph(5) - pytest.raises(nx.NetworkXError, approx.node_connectivity, G, t=0) - - -def test_missing_source(): - G = nx.path_graph(4) - pytest.raises(nx.NetworkXError, approx.node_connectivity, G, 10, 1) - - -def test_missing_target(): - G = nx.path_graph(4) - pytest.raises(nx.NetworkXError, approx.node_connectivity, G, 1, 10) - - -def test_source_equals_target(): - G = nx.complete_graph(5) - pytest.raises(nx.NetworkXError, approx.local_node_connectivity, G, 0, 0) - - -def test_directed_node_connectivity(): - G = nx.cycle_graph(10, create_using=nx.DiGraph()) # only one direction - D = nx.cycle_graph(10).to_directed() # 2 reciprocal edges - assert 1 == approx.node_connectivity(G) - assert 1 == approx.node_connectivity(G, 1, 4) - assert 2 == approx.node_connectivity(D) - assert 2 == approx.node_connectivity(D, 1, 4) - - -class TestAllPairsNodeConnectivityApprox: - - @classmethod - def setup_class(cls): - cls.path = nx.path_graph(7) - cls.directed_path = nx.path_graph(7, create_using=nx.DiGraph()) - cls.cycle = nx.cycle_graph(7) - cls.directed_cycle = nx.cycle_graph(7, create_using=nx.DiGraph()) - cls.gnp = nx.gnp_random_graph(30, 0.1) - cls.directed_gnp = nx.gnp_random_graph(30, 0.1, directed=True) - cls.K20 = nx.complete_graph(20) - cls.K10 = nx.complete_graph(10) - cls.K5 = nx.complete_graph(5) - cls.G_list = [cls.path, cls.directed_path, cls.cycle, - cls.directed_cycle, cls.gnp, cls.directed_gnp, cls.K10, - cls.K5, cls.K20] - - def test_cycles(self): - K_undir = approx.all_pairs_node_connectivity(self.cycle) - for source in K_undir: - for target, k in K_undir[source].items(): - assert k == 2 - K_dir = approx.all_pairs_node_connectivity(self.directed_cycle) - for source in K_dir: - for target, k in K_dir[source].items(): - assert k == 1 - - def test_complete(self): - for G in [self.K10, self.K5, self.K20]: - K = approx.all_pairs_node_connectivity(G) - for source in K: - for target, k in K[source].items(): - assert k == len(G) - 1 - - def test_paths(self): - K_undir = approx.all_pairs_node_connectivity(self.path) - for source in K_undir: - for target, k in K_undir[source].items(): - assert k == 1 - K_dir = approx.all_pairs_node_connectivity(self.directed_path) - for source in K_dir: - for target, k in K_dir[source].items(): - if source < target: - assert k == 1 - else: - assert k == 0 - - def test_cutoff(self): - for G in [self.K10, self.K5, self.K20]: - for mp in [2, 3, 4]: - paths = approx.all_pairs_node_connectivity(G, cutoff=mp) - for source in paths: - for target, K in paths[source].items(): - assert K == mp - - def test_all_pairs_connectivity_nbunch(self): - G = nx.complete_graph(5) - nbunch = [0, 2, 3] - C = approx.all_pairs_node_connectivity(G, nbunch=nbunch) - assert len(C) == len(nbunch) diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_dominating_set.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_dominating_set.py deleted file mode 100644 index 01ee6ab5..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_dominating_set.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python -import networkx as nx -from networkx.algorithms.approximation import min_weighted_dominating_set -from networkx.algorithms.approximation import min_edge_dominating_set - - -class TestMinWeightDominatingSet: - - def test_min_weighted_dominating_set(self): - graph = nx.Graph() - graph.add_edge(1, 2) - graph.add_edge(1, 5) - graph.add_edge(2, 3) - graph.add_edge(2, 5) - graph.add_edge(3, 4) - graph.add_edge(3, 6) - graph.add_edge(5, 6) - - vertices = set([1, 2, 3, 4, 5, 6]) - # due to ties, this might be hard to test tight bounds - dom_set = min_weighted_dominating_set(graph) - for vertex in vertices - dom_set: - neighbors = set(graph.neighbors(vertex)) - assert len(neighbors & dom_set) > 0, "Non dominating set found!" - - def test_star_graph(self): - """Tests that an approximate dominating set for the star graph, - even when the center node does not have the smallest integer - label, gives just the center node. - - For more information, see #1527. - - """ - # Create a star graph in which the center node has the highest - # label instead of the lowest. - G = nx.star_graph(10) - G = nx.relabel_nodes(G, {0: 9, 9: 0}) - assert min_weighted_dominating_set(G) == {9} - - def test_min_edge_dominating_set(self): - graph = nx.path_graph(5) - dom_set = min_edge_dominating_set(graph) - - # this is a crappy way to test, but good enough for now. - for edge in graph.edges(): - if edge in dom_set: - continue - else: - u, v = edge - found = False - for dom_edge in dom_set: - found |= u == dom_edge[0] or u == dom_edge[1] - assert found, "Non adjacent edge found!" - - graph = nx.complete_graph(10) - dom_set = min_edge_dominating_set(graph) - - # this is a crappy way to test, but good enough for now. - for edge in graph.edges(): - if edge in dom_set: - continue - else: - u, v = edge - found = False - for dom_edge in dom_set: - found |= u == dom_edge[0] or u == dom_edge[1] - assert found, "Non adjacent edge found!" diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_independent_set.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_independent_set.py deleted file mode 100644 index 4b7c4526..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_independent_set.py +++ /dev/null @@ -1,8 +0,0 @@ -import networkx as nx -import networkx.algorithms.approximation as a - - -def test_independent_set(): - # smoke test - G = nx.Graph() - assert len(a.maximum_independent_set(G)) == 0 diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_kcomponents.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_kcomponents.py deleted file mode 100644 index 9a0c5161..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_kcomponents.py +++ /dev/null @@ -1,264 +0,0 @@ -# Test for approximation to k-components algorithm -import pytest -import networkx as nx -from networkx.algorithms.approximation import k_components -from networkx.algorithms.approximation.kcomponents import _AntiGraph, _same - - -def build_k_number_dict(k_components): - k_num = {} - for k, comps in sorted(k_components.items()): - for comp in comps: - for node in comp: - k_num[node] = k - return k_num - -## -# Some nice synthetic graphs -## - - -def graph_example_1(): - G = nx.convert_node_labels_to_integers(nx.grid_graph([5, 5]), - label_attribute='labels') - rlabels = nx.get_node_attributes(G, 'labels') - labels = {v: k for k, v in rlabels.items()} - - for nodes in [(labels[(0, 0)], labels[(1, 0)]), - (labels[(0, 4)], labels[(1, 4)]), - (labels[(3, 0)], labels[(4, 0)]), - (labels[(3, 4)], labels[(4, 4)])]: - new_node = G.order() + 1 - # Petersen graph is triconnected - P = nx.petersen_graph() - G = nx.disjoint_union(G, P) - # Add two edges between the grid and P - G.add_edge(new_node + 1, nodes[0]) - G.add_edge(new_node, nodes[1]) - # K5 is 4-connected - K = nx.complete_graph(5) - G = nx.disjoint_union(G, K) - # Add three edges between P and K5 - G.add_edge(new_node + 2, new_node + 11) - G.add_edge(new_node + 3, new_node + 12) - G.add_edge(new_node + 4, new_node + 13) - # Add another K5 sharing a node - G = nx.disjoint_union(G, K) - nbrs = G[new_node + 10] - G.remove_node(new_node + 10) - for nbr in nbrs: - G.add_edge(new_node + 17, nbr) - G.add_edge(new_node + 16, new_node + 5) - return G - - -def torrents_and_ferraro_graph(): - G = nx.convert_node_labels_to_integers(nx.grid_graph([5, 5]), - label_attribute='labels') - rlabels = nx.get_node_attributes(G, 'labels') - labels = {v: k for k, v in rlabels.items()} - - for nodes in [(labels[(0, 4)], labels[(1, 4)]), - (labels[(3, 4)], labels[(4, 4)])]: - new_node = G.order() + 1 - # Petersen graph is triconnected - P = nx.petersen_graph() - G = nx.disjoint_union(G, P) - # Add two edges between the grid and P - G.add_edge(new_node + 1, nodes[0]) - G.add_edge(new_node, nodes[1]) - # K5 is 4-connected - K = nx.complete_graph(5) - G = nx.disjoint_union(G, K) - # Add three edges between P and K5 - G.add_edge(new_node + 2, new_node + 11) - G.add_edge(new_node + 3, new_node + 12) - G.add_edge(new_node + 4, new_node + 13) - # Add another K5 sharing a node - G = nx.disjoint_union(G, K) - nbrs = G[new_node + 10] - G.remove_node(new_node + 10) - for nbr in nbrs: - G.add_edge(new_node + 17, nbr) - # Commenting this makes the graph not biconnected !! - # This stupid mistake make one reviewer very angry :P - G.add_edge(new_node + 16, new_node + 8) - - for nodes in [(labels[(0, 0)], labels[(1, 0)]), - (labels[(3, 0)], labels[(4, 0)])]: - new_node = G.order() + 1 - # Petersen graph is triconnected - P = nx.petersen_graph() - G = nx.disjoint_union(G, P) - # Add two edges between the grid and P - G.add_edge(new_node + 1, nodes[0]) - G.add_edge(new_node, nodes[1]) - # K5 is 4-connected - K = nx.complete_graph(5) - G = nx.disjoint_union(G, K) - # Add three edges between P and K5 - G.add_edge(new_node + 2, new_node + 11) - G.add_edge(new_node + 3, new_node + 12) - G.add_edge(new_node + 4, new_node + 13) - # Add another K5 sharing two nodes - G = nx.disjoint_union(G, K) - nbrs = G[new_node + 10] - G.remove_node(new_node + 10) - for nbr in nbrs: - G.add_edge(new_node + 17, nbr) - nbrs2 = G[new_node + 9] - G.remove_node(new_node + 9) - for nbr in nbrs2: - G.add_edge(new_node + 18, nbr) - return G - -# Helper function - - -def _check_connectivity(G): - result = k_components(G) - for k, components in result.items(): - if k < 3: - continue - for component in components: - C = G.subgraph(component) - K = nx.node_connectivity(C) - assert K >= k - - -def test_torrents_and_ferraro_graph(): - G = torrents_and_ferraro_graph() - _check_connectivity(G) - - -def test_example_1(): - G = graph_example_1() - _check_connectivity(G) - - -def test_karate_0(): - G = nx.karate_club_graph() - _check_connectivity(G) - - -def test_karate_1(): - karate_k_num = {0: 4, 1: 4, 2: 4, 3: 4, 4: 3, 5: 3, 6: 3, 7: 4, 8: 4, 9: 2, - 10: 3, 11: 1, 12: 2, 13: 4, 14: 2, 15: 2, 16: 2, 17: 2, 18: 2, - 19: 3, 20: 2, 21: 2, 22: 2, 23: 3, 24: 3, 25: 3, 26: 2, 27: 3, - 28: 3, 29: 3, 30: 4, 31: 3, 32: 4, 33: 4} - approx_karate_k_num = karate_k_num.copy() - approx_karate_k_num[24] = 2 - approx_karate_k_num[25] = 2 - G = nx.karate_club_graph() - k_comps = k_components(G) - k_num = build_k_number_dict(k_comps) - assert k_num in (karate_k_num, approx_karate_k_num) - - -def test_example_1_detail_3_and_4(): - G = graph_example_1() - result = k_components(G) - # In this example graph there are 8 3-components, 4 with 15 nodes - # and 4 with 5 nodes. - assert len(result[3]) == 8 - assert len([c for c in result[3] if len(c) == 15]) == 4 - assert len([c for c in result[3] if len(c) == 5]) == 4 - # There are also 8 4-components all with 5 nodes. - assert len(result[4]) == 8 - assert all(len(c) == 5 for c in result[4]) - # Finally check that the k-components detected have actually node - # connectivity >= k. - for k, components in result.items(): - if k < 3: - continue - for component in components: - K = nx.node_connectivity(G.subgraph(component)) - assert K >= k - - -def test_directed(): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.gnp_random_graph(10, 0.4, directed=True) - kc = k_components(G) - - -def test_same(): - equal = {'A': 2, 'B': 2, 'C': 2} - slightly_different = {'A': 2, 'B': 1, 'C': 2} - different = {'A': 2, 'B': 8, 'C': 18} - assert _same(equal) - assert not _same(slightly_different) - assert _same(slightly_different, tol=1) - assert not _same(different) - assert not _same(different, tol=4) - - -class TestAntiGraph: - @classmethod - def setup_class(cls): - cls.Gnp = nx.gnp_random_graph(20, 0.8) - cls.Anp = _AntiGraph(nx.complement(cls.Gnp)) - cls.Gd = nx.davis_southern_women_graph() - cls.Ad = _AntiGraph(nx.complement(cls.Gd)) - cls.Gk = nx.karate_club_graph() - cls.Ak = _AntiGraph(nx.complement(cls.Gk)) - cls.GA = [(cls.Gnp, cls.Anp), - (cls.Gd, cls.Ad), - (cls.Gk, cls.Ak)] - - def test_size(self): - for G, A in self.GA: - n = G.order() - s = len(list(G.edges())) + len(list(A.edges())) - assert s == (n * (n - 1)) / 2 - - def test_degree(self): - for G, A in self.GA: - assert sorted(G.degree()) == sorted(A.degree()) - - def test_core_number(self): - for G, A in self.GA: - assert nx.core_number(G) == nx.core_number(A) - - def test_connected_components(self): - for G, A in self.GA: - gc = [set(c) for c in nx.connected_components(G)] - ac = [set(c) for c in nx.connected_components(A)] - for comp in ac: - assert comp in gc - - def test_adj(self): - for G, A in self.GA: - for n, nbrs in G.adj.items(): - a_adj = sorted((n, sorted(ad)) for n, ad in A.adj.items()) - g_adj = sorted((n, sorted(ad)) for n, ad in G.adj.items()) - assert a_adj == g_adj - - def test_adjacency(self): - for G, A in self.GA: - a_adj = list(A.adjacency()) - for n, nbrs in G.adjacency(): - assert (n, set(nbrs)) in a_adj - - def test_neighbors(self): - for G, A in self.GA: - node = list(G.nodes())[0] - assert set(G.neighbors(node)) == set(A.neighbors(node)) - - def test_node_not_in_graph(self): - for G, A in self.GA: - node = 'non_existent_node' - pytest.raises(nx.NetworkXError, A.neighbors, node) - pytest.raises(nx.NetworkXError, G.neighbors, node) - - def test_degree_thingraph(self): - for G, A in self.GA: - node = list(G.nodes())[0] - nodes = list(G.nodes())[1:4] - assert G.degree(node) == A.degree(node) - assert sum(d for n, d in G.degree()) == sum(d for n, d in A.degree()) - # AntiGraph is a ThinGraph, so all the weights are 1 - assert (sum(d for n, d in A.degree()) == - sum(d for n, d in A.degree(weight='weight'))) - assert (sum(d for n, d in G.degree(nodes)) == - sum(d for n, d in A.degree(nodes))) diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_matching.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_matching.py deleted file mode 100644 index f50da3d2..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_matching.py +++ /dev/null @@ -1,8 +0,0 @@ -import networkx as nx -import networkx.algorithms.approximation as a - - -def test_min_maximal_matching(): - # smoke test - G = nx.Graph() - assert len(a.min_maximal_matching(G)) == 0 diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_ramsey.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_ramsey.py deleted file mode 100644 index 1d011346..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_ramsey.py +++ /dev/null @@ -1,27 +0,0 @@ -import networkx as nx -import networkx.algorithms.approximation as apxa - - -def test_ramsey(): - # this should only find the complete graph - graph = nx.complete_graph(10) - c, i = apxa.ramsey_R2(graph) - cdens = nx.density(graph.subgraph(c)) - assert cdens == 1.0, "clique not found by ramsey!" - idens = nx.density(graph.subgraph(i)) - assert idens == 0.0, "i-set not found by ramsey!" - - # this trival graph has no cliques. should just find i-sets - graph = nx.trivial_graph(nx.Graph()) - c, i = apxa.ramsey_R2(graph) - cdens = nx.density(graph.subgraph(c)) - assert cdens == 0.0, "clique not found by ramsey!" - idens = nx.density(graph.subgraph(i)) - assert idens == 0.0, "i-set not found by ramsey!" - - graph = nx.barbell_graph(10, 5, nx.Graph()) - c, i = apxa.ramsey_R2(graph) - cdens = nx.density(graph.subgraph(c)) - assert cdens == 1.0, "clique not found by ramsey!" - idens = nx.density(graph.subgraph(i)) - assert idens == 0.0, "i-set not found by ramsey!" diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_steinertree.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_steinertree.py deleted file mode 100644 index 9a50112b..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_steinertree.py +++ /dev/null @@ -1,78 +0,0 @@ -import pytest -import networkx as nx -from networkx.algorithms.approximation.steinertree import metric_closure -from networkx.algorithms.approximation.steinertree import steiner_tree -from networkx.testing.utils import assert_edges_equal - - -class TestSteinerTree: - @classmethod - def setup_class(cls): - G = nx.Graph() - G.add_edge(1, 2, weight=10) - G.add_edge(2, 3, weight=10) - G.add_edge(3, 4, weight=10) - G.add_edge(4, 5, weight=10) - G.add_edge(5, 6, weight=10) - G.add_edge(2, 7, weight=1) - G.add_edge(7, 5, weight=1) - cls.G = G - cls.term_nodes = [1, 2, 3, 4, 5] - - def test_connected_metric_closure(self): - G = self.G.copy() - G.add_node(100) - pytest.raises(nx.NetworkXError, metric_closure, G) - - def test_metric_closure(self): - M = metric_closure(self.G) - mc = [(1, 2, {'distance': 10, 'path': [1, 2]}), - (1, 3, {'distance': 20, 'path': [1, 2, 3]}), - (1, 4, {'distance': 22, 'path': [1, 2, 7, 5, 4]}), - (1, 5, {'distance': 12, 'path': [1, 2, 7, 5]}), - (1, 6, {'distance': 22, 'path': [1, 2, 7, 5, 6]}), - (1, 7, {'distance': 11, 'path': [1, 2, 7]}), - (2, 3, {'distance': 10, 'path': [2, 3]}), - (2, 4, {'distance': 12, 'path': [2, 7, 5, 4]}), - (2, 5, {'distance': 2, 'path': [2, 7, 5]}), - (2, 6, {'distance': 12, 'path': [2, 7, 5, 6]}), - (2, 7, {'distance': 1, 'path': [2, 7]}), - (3, 4, {'distance': 10, 'path': [3, 4]}), - (3, 5, {'distance': 12, 'path': [3, 2, 7, 5]}), - (3, 6, {'distance': 22, 'path': [3, 2, 7, 5, 6]}), - (3, 7, {'distance': 11, 'path': [3, 2, 7]}), - (4, 5, {'distance': 10, 'path': [4, 5]}), - (4, 6, {'distance': 20, 'path': [4, 5, 6]}), - (4, 7, {'distance': 11, 'path': [4, 5, 7]}), - (5, 6, {'distance': 10, 'path': [5, 6]}), - (5, 7, {'distance': 1, 'path': [5, 7]}), - (6, 7, {'distance': 11, 'path': [6, 5, 7]})] - assert_edges_equal(list(M.edges(data=True)), mc) - - def test_steiner_tree(self): - S = steiner_tree(self.G, self.term_nodes) - expected_steiner_tree = [(1, 2, {'weight': 10}), - (2, 3, {'weight': 10}), - (2, 7, {'weight': 1}), - (3, 4, {'weight': 10}), - (5, 7, {'weight': 1})] - assert_edges_equal(list(S.edges(data=True)), expected_steiner_tree) - - def test_multigraph_steiner_tree(self): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.MultiGraph() - G.add_edges_from([ - (1, 2, 0, {'weight': 1}), - (2, 3, 0, {'weight': 999}), - (2, 3, 1, {'weight': 1}), - (3, 4, 0, {'weight': 1}), - (3, 5, 0, {'weight': 1}) - ]) - terminal_nodes = [2, 4, 5] - expected_edges = [ - (2, 3, 1, {'weight': 1}), # edge with key 1 has lower weight - (3, 4, 0, {'weight': 1}), - (3, 5, 0, {'weight': 1}) - ] - # not implemented - T = steiner_tree(G, terminal_nodes) diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_treewidth.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_treewidth.py deleted file mode 100644 index cd974dd1..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_treewidth.py +++ /dev/null @@ -1,271 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2018 by -# Rudolf-Andreas Floren -# Dominik Meier -# All rights reserved. -# BSD license. -import networkx as nx -from networkx.algorithms.approximation import treewidth_min_degree -from networkx.algorithms.approximation import treewidth_min_fill_in -from networkx.algorithms.approximation.treewidth import min_fill_in_heuristic -from networkx.algorithms.approximation.treewidth import MinDegreeHeuristic -import itertools - - -def is_tree_decomp(graph, decomp): - """Check if the given tree decomposition is valid.""" - for x in graph.nodes(): - appear_once = False - for bag in decomp.nodes(): - if x in bag: - appear_once = True - break - assert appear_once - - # Check if each connected pair of nodes are at least once together in a bag - for (x, y) in graph.edges(): - appear_together = False - for bag in decomp.nodes(): - if x in bag and y in bag: - appear_together = True - break - assert appear_together - - # Check if the nodes associated with vertex v form a connected subset of T - for v in graph.nodes(): - subset = [] - for bag in decomp.nodes(): - if v in bag: - subset.append(bag) - sub_graph = decomp.subgraph(subset) - assert nx.is_connected(sub_graph) - - -class TestTreewidthMinDegree(object): - """Unit tests for the min_degree function""" - @classmethod - def setup_class(cls): - """Setup for different kinds of trees""" - cls.complete = nx.Graph() - cls.complete.add_edge(1, 2) - cls.complete.add_edge(2, 3) - cls.complete.add_edge(1, 3) - - cls.small_tree = nx.Graph() - cls.small_tree.add_edge(1, 3) - cls.small_tree.add_edge(4, 3) - cls.small_tree.add_edge(2, 3) - cls.small_tree.add_edge(3, 5) - cls.small_tree.add_edge(5, 6) - cls.small_tree.add_edge(5, 7) - cls.small_tree.add_edge(6, 7) - - cls.deterministic_graph = nx.Graph() - cls.deterministic_graph.add_edge(0, 1) # deg(0) = 1 - - cls.deterministic_graph.add_edge(1, 2) # deg(1) = 2 - - cls.deterministic_graph.add_edge(2, 3) - cls.deterministic_graph.add_edge(2, 4) # deg(2) = 3 - - cls.deterministic_graph.add_edge(3, 4) - cls.deterministic_graph.add_edge(3, 5) - cls.deterministic_graph.add_edge(3, 6) # deg(3) = 4 - - cls.deterministic_graph.add_edge(4, 5) - cls.deterministic_graph.add_edge(4, 6) - cls.deterministic_graph.add_edge(4, 7) # deg(4) = 5 - - cls.deterministic_graph.add_edge(5, 6) - cls.deterministic_graph.add_edge(5, 7) - cls.deterministic_graph.add_edge(5, 8) - cls.deterministic_graph.add_edge(5, 9) # deg(5) = 6 - - cls.deterministic_graph.add_edge(6, 7) - cls.deterministic_graph.add_edge(6, 8) - cls.deterministic_graph.add_edge(6, 9) # deg(6) = 6 - - cls.deterministic_graph.add_edge(7, 8) - cls.deterministic_graph.add_edge(7, 9) # deg(7) = 5 - - cls.deterministic_graph.add_edge(8, 9) # deg(8) = 4 - - def test_petersen_graph(self): - """Test Petersen graph tree decomposition result""" - G = nx.petersen_graph() - _, decomp = treewidth_min_degree(G) - is_tree_decomp(G, decomp) - - def test_small_tree_treewidth(self): - """Test small tree - - Test if the computed treewidth of the known self.small_tree is 2. - As we know which value we can expect from our heuristic, values other - than two are regressions - """ - G = self.small_tree - # the order of removal should be [1,2,4]3[5,6,7] - # (with [] denoting any order of the containing nodes) - # resulting in treewidth 2 for the heuristic - treewidth, _ = treewidth_min_fill_in(G) - assert treewidth == 2 - - def test_heuristic_abort(self): - """Test heuristic abort condition for fully connected graph""" - graph = {} - for u in self.complete: - graph[u] = set() - for v in self.complete[u]: - if u != v: # ignore self-loop - graph[u].add(v) - - deg_heuristic = MinDegreeHeuristic(graph) - node = deg_heuristic.best_node(graph) - if node is None: - pass - else: - assert False - - def test_empty_graph(self): - """Test empty graph""" - G = nx.Graph() - _, _ = treewidth_min_degree(G) - - def test_two_component_graph(self): - """Test empty graph""" - G = nx.Graph() - G.add_node(1) - G.add_node(2) - treewidth, _ = treewidth_min_degree(G) - assert treewidth == 0 - - def test_heuristic_first_steps(self): - """Test first steps of min_degree heuristic""" - graph = {n: set(self.deterministic_graph[n]) - set([n]) - for n in self.deterministic_graph} - deg_heuristic = MinDegreeHeuristic(graph) - elim_node = deg_heuristic.best_node(graph) - print("Graph {}:".format(graph)) - steps = [] - - while elim_node is not None: - print("Removing {}:".format(elim_node)) - steps.append(elim_node) - nbrs = graph[elim_node] - - for u, v in itertools.permutations(nbrs, 2): - if v not in graph[u]: - graph[u].add(v) - - for u in graph: - if elim_node in graph[u]: - graph[u].remove(elim_node) - - del graph[elim_node] - print("Graph {}:".format(graph)) - elim_node = deg_heuristic.best_node(graph) - - # check only the first 5 elements for equality - assert steps[:5] == [0, 1, 2, 3, 4] - - -class TestTreewidthMinFillIn(object): - """Unit tests for the treewidth_min_fill_in function.""" - @classmethod - def setup_class(cls): - """Setup for different kinds of trees""" - cls.complete = nx.Graph() - cls.complete.add_edge(1, 2) - cls.complete.add_edge(2, 3) - cls.complete.add_edge(1, 3) - - cls.small_tree = nx.Graph() - cls.small_tree.add_edge(1, 2) - cls.small_tree.add_edge(2, 3) - cls.small_tree.add_edge(3, 4) - cls.small_tree.add_edge(1, 4) - cls.small_tree.add_edge(2, 4) - cls.small_tree.add_edge(4, 5) - cls.small_tree.add_edge(5, 6) - cls.small_tree.add_edge(5, 7) - cls.small_tree.add_edge(6, 7) - - cls.deterministic_graph = nx.Graph() - cls.deterministic_graph.add_edge(1, 2) - cls.deterministic_graph.add_edge(1, 3) - cls.deterministic_graph.add_edge(3, 4) - cls.deterministic_graph.add_edge(2, 4) - cls.deterministic_graph.add_edge(3, 5) - cls.deterministic_graph.add_edge(4, 5) - cls.deterministic_graph.add_edge(3, 6) - cls.deterministic_graph.add_edge(5, 6) - - def test_petersen_graph(self): - """Test Petersen graph tree decomposition result""" - G = nx.petersen_graph() - _, decomp = treewidth_min_fill_in(G) - is_tree_decomp(G, decomp) - - def test_small_tree_treewidth(self): - """Test if the computed treewidth of the known self.small_tree is 2""" - G = self.small_tree - # the order of removal should be [1,2,4]3[5,6,7] - # (with [] denoting any order of the containing nodes) - # resulting in treewidth 2 for the heuristic - treewidth, _ = treewidth_min_fill_in(G) - assert treewidth == 2 - - def test_heuristic_abort(self): - """Test if min_fill_in returns None for fully connected graph""" - graph = {} - for u in self.complete: - graph[u] = set() - for v in self.complete[u]: - if u != v: # ignore self-loop - graph[u].add(v) - next_node = min_fill_in_heuristic(graph) - if next_node is None: - pass - else: - assert False - - def test_empty_graph(self): - """Test empty graph""" - G = nx.Graph() - _, _ = treewidth_min_fill_in(G) - - def test_two_component_graph(self): - """Test empty graph""" - G = nx.Graph() - G.add_node(1) - G.add_node(2) - treewidth, _ = treewidth_min_fill_in(G) - assert treewidth == 0 - - def test_heuristic_first_steps(self): - """Test first steps of min_fill_in heuristic""" - graph = {n: set(self.deterministic_graph[n]) - set([n]) - for n in self.deterministic_graph} - print("Graph {}:".format(graph)) - elim_node = min_fill_in_heuristic(graph) - steps = [] - - while elim_node is not None: - print("Removing {}:".format(elim_node)) - steps.append(elim_node) - nbrs = graph[elim_node] - - for u, v in itertools.permutations(nbrs, 2): - if v not in graph[u]: - graph[u].add(v) - - for u in graph: - if elim_node in graph[u]: - graph[u].remove(elim_node) - - del graph[elim_node] - print("Graph {}:".format(graph)) - elim_node = min_fill_in_heuristic(graph) - - # check only the first 2 elements for equality - assert steps[:2] == [6, 5] diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_vertex_cover.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_vertex_cover.py deleted file mode 100644 index 89020352..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/tests/test_vertex_cover.py +++ /dev/null @@ -1,55 +0,0 @@ -import networkx as nx -from networkx.algorithms.approximation import min_weighted_vertex_cover - - -def is_cover(G, node_cover): - return all({u, v} & node_cover for u, v in G.edges()) - - -class TestMWVC(object): - """Unit tests for the approximate minimum weighted vertex cover - function, - :func:`~networkx.algorithms.approximation.vertex_cover.min_weighted_vertex_cover`. - - """ - - def test_unweighted_directed(self): - # Create a star graph in which half the nodes are directed in - # and half are directed out. - G = nx.DiGraph() - G.add_edges_from((0, v) for v in range(1, 26)) - G.add_edges_from((v, 0) for v in range(26, 51)) - cover = min_weighted_vertex_cover(G) - assert 2 == len(cover) - assert is_cover(G, cover) - - def test_unweighted_undirected(self): - # create a simple star graph - size = 50 - sg = nx.star_graph(size) - cover = min_weighted_vertex_cover(sg) - assert 2 == len(cover) - assert is_cover(sg, cover) - - def test_weighted(self): - wg = nx.Graph() - wg.add_node(0, weight=10) - wg.add_node(1, weight=1) - wg.add_node(2, weight=1) - wg.add_node(3, weight=1) - wg.add_node(4, weight=1) - - wg.add_edge(0, 1) - wg.add_edge(0, 2) - wg.add_edge(0, 3) - wg.add_edge(0, 4) - - wg.add_edge(1, 2) - wg.add_edge(2, 3) - wg.add_edge(3, 4) - wg.add_edge(4, 1) - - cover = min_weighted_vertex_cover(wg, weight="weight") - csum = sum(wg.nodes[node]["weight"] for node in cover) - assert 4 == csum - assert is_cover(wg, cover) diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/treewidth.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/treewidth.py deleted file mode 100644 index 19875c64..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/treewidth.py +++ /dev/null @@ -1,249 +0,0 @@ -# -*- coding: utf-8 -*- -"""Functions for computing treewidth decomposition. - -Treewidth of an undirected graph is a number associated with the graph. -It can be defined as the size of the largest vertex set (bag) in a tree -decomposition of the graph minus one. - -`Wikipedia: Treewidth `_ - -The notions of treewidth and tree decomposition have gained their -attractiveness partly because many graph and network problems that are -intractable (e.g., NP-hard) on arbitrary graphs become efficiently -solvable (e.g., with a linear time algorithm) when the treewidth of the -input graphs is bounded by a constant [1]_ [2]_. - -There are two different functions for computing a tree decomposition: -:func:`treewidth_min_degree` and :func:`treewidth_min_fill_in`. - -.. [1] Hans L. Bodlaender and Arie M. C. A. Koster. 2010. "Treewidth - computations I.Upper bounds". Inf. Comput. 208, 3 (March 2010),259-275. - http://dx.doi.org/10.1016/j.ic.2009.03.008 - -.. [2] Hand L. Bodlaender. "Discovering Treewidth". Institute of Information - and Computing Sciences, Utrecht University. - Technical Report UU-CS-2005-018. - http://www.cs.uu.nl - -.. [3] K. Wang, Z. Lu, and J. Hicks *Treewidth*. - http://web.eecs.utk.edu/~cphillip/cs594_spring2015_projects/treewidth.pdf - -""" - -import sys - -import networkx as nx -from networkx.utils import not_implemented_for -from heapq import heappush, heappop, heapify -import itertools - -__all__ = ["treewidth_min_degree", "treewidth_min_fill_in"] - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def treewidth_min_degree(G): - """ Returns a treewidth decomposition using the Minimum Degree heuristic. - - The heuristic chooses the nodes according to their degree, i.e., first - the node with the lowest degree is chosen, then the graph is updated - and the corresponding node is removed. Next, a new node with the lowest - degree is chosen, and so on. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - Treewidth decomposition : (int, Graph) tuple - 2-tuple with treewidth and the corresponding decomposed tree. - """ - deg_heuristic = MinDegreeHeuristic(G) - return treewidth_decomp(G, lambda graph: deg_heuristic.best_node(graph)) - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def treewidth_min_fill_in(G): - """ Returns a treewidth decomposition using the Minimum Fill-in heuristic. - - The heuristic chooses a node from the graph, where the number of edges - added turning the neighbourhood of the chosen node into clique is as - small as possible. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - Treewidth decomposition : (int, Graph) tuple - 2-tuple with treewidth and the corresponding decomposed tree. - """ - return treewidth_decomp(G, min_fill_in_heuristic) - - -class MinDegreeHeuristic: - """ Implements the Minimum Degree heuristic. - - The heuristic chooses the nodes according to their degree - (number of neighbours), i.e., first the node with the lowest degree is - chosen, then the graph is updated and the corresponding node is - removed. Next, a new node with the lowest degree is chosen, and so on. - """ - def __init__(self, graph): - self._graph = graph - - # nodes that have to be updated in the heap before each iteration - self._update_nodes = [] - - self._degreeq = [] # a heapq with 2-tuples (degree,node) - - # build heap with initial degrees - for n in graph: - self._degreeq.append((len(graph[n]), n)) - heapify(self._degreeq) - - def best_node(self, graph): - # update nodes in self._update_nodes - for n in self._update_nodes: - # insert changed degrees into degreeq - heappush(self._degreeq, (len(graph[n]), n)) - - # get the next valid (minimum degree) node - while self._degreeq: - (min_degree, elim_node) = heappop(self._degreeq) - if elim_node not in graph or len(graph[elim_node]) != min_degree: - # outdated entry in degreeq - continue - elif min_degree == len(graph) - 1: - # fully connected: abort condition - return None - - # remember to update nodes in the heap before getting the next node - self._update_nodes = graph[elim_node] - return elim_node - - # the heap is empty: abort - return None - - -def min_fill_in_heuristic(graph): - """ Implements the Minimum Degree heuristic. - - Returns the node from the graph, where the number of edges added when - turning the neighbourhood of the chosen node into clique is as small as - possible. This algorithm chooses the nodes using the Minimum Fill-In - heuristic. The running time of the algorithm is :math:`O(V^3)` and it uses - additional constant memory.""" - - if len(graph) == 0: - return None - - min_fill_in_node = None - - min_fill_in = sys.maxsize - - # create sorted list of (degree, node) - degree_list = [(len(graph[node]), node) for node in graph] - degree_list.sort() - - # abort condition - min_degree = degree_list[0][0] - if min_degree == len(graph) - 1: - return None - - for (_, node) in degree_list: - num_fill_in = 0 - nbrs = graph[node] - for nbr in nbrs: - # count how many nodes in nbrs current nbr is not connected to - # subtract 1 for the node itself - num_fill_in += len(nbrs - graph[nbr]) - 1 - if num_fill_in >= 2 * min_fill_in: - break - - num_fill_in /= 2 # divide by 2 because of double counting - - if num_fill_in < min_fill_in: # update min-fill-in node - if num_fill_in == 0: - return node - min_fill_in = num_fill_in - min_fill_in_node = node - - return min_fill_in_node - - -def treewidth_decomp(G, heuristic=min_fill_in_heuristic): - """ Returns a treewidth decomposition using the passed heuristic. - - Parameters - ---------- - G : NetworkX graph - heuristic : heuristic function - - Returns - ------- - Treewidth decomposition : (int, Graph) tuple - 2-tuple with treewidth and the corresponding decomposed tree. - """ - - # make dict-of-sets structure - graph = {n: set(G[n]) - set([n]) for n in G} - - # stack containing nodes and neighbors in the order from the heuristic - node_stack = [] - - # get first node from heuristic - elim_node = heuristic(graph) - while elim_node is not None: - # connect all neighbours with each other - nbrs = graph[elim_node] - for u, v in itertools.permutations(nbrs, 2): - if v not in graph[u]: - graph[u].add(v) - - # push node and its current neighbors on stack - node_stack.append((elim_node, nbrs)) - - # remove node from graph - for u in graph[elim_node]: - graph[u].remove(elim_node) - - del graph[elim_node] - elim_node = heuristic(graph) - - # the abort condition is met; put all remaining nodes into one bag - decomp = nx.Graph() - first_bag = frozenset(graph.keys()) - decomp.add_node(first_bag) - - treewidth = len(first_bag) - 1 - - while node_stack: - # get node and its neighbors from the stack - (curr_node, nbrs) = node_stack.pop() - - # find a bag all neighbors are in - old_bag = None - for bag in decomp.nodes: - if nbrs <= bag: - old_bag = bag - break - - if old_bag is None: - # no old_bag was found: just connect to the first_bag - old_bag = first_bag - - # create new node for decomposition - nbrs.add(curr_node) - new_bag = frozenset(nbrs) - - # update treewidth - treewidth = max(treewidth, len(new_bag) - 1) - - # add edge to decomposition (implicitly also adds the new node) - decomp.add_edge(old_bag, new_bag) - - return treewidth, decomp diff --git a/extensions/fablabchemnitz/networkx/algorithms/approximation/vertex_cover.py b/extensions/fablabchemnitz/networkx/algorithms/approximation/vertex_cover.py deleted file mode 100644 index 02b9ab81..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/approximation/vertex_cover.py +++ /dev/null @@ -1,82 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2011-2012 by -# Nicholas Mancuso -# All rights reserved. -# BSD license. -# -# Author: -# Nicholas Mancuso -"""Functions for computing an approximate minimum weight vertex cover. - -A |vertex cover|_ is a subset of nodes such that each edge in the graph -is incident to at least one node in the subset. - -.. _vertex cover: https://en.wikipedia.org/wiki/Vertex_cover -.. |vertex cover| replace:: *vertex cover* - -""" - -__all__ = ["min_weighted_vertex_cover"] - - -def min_weighted_vertex_cover(G, weight=None): - r"""Returns an approximate minimum weighted vertex cover. - - The set of nodes returned by this function is guaranteed to be a - vertex cover, and the total weight of the set is guaranteed to be at - most twice the total weight of the minimum weight vertex cover. In - other words, - - .. math:: - - w(S) \leq 2 * w(S^*), - - where $S$ is the vertex cover returned by this function, - $S^*$ is the vertex cover of minimum weight out of all vertex - covers of the graph, and $w$ is the function that computes the - sum of the weights of each node in that given set. - - Parameters - ---------- - G : NetworkX graph - - weight : string, optional (default = None) - If None, every node has weight 1. If a string, use this node - attribute as the node weight. A node without this attribute is - assumed to have weight 1. - - Returns - ------- - min_weighted_cover : set - Returns a set of nodes whose weight sum is no more than twice - the weight sum of the minimum weight vertex cover. - - Notes - ----- - For a directed graph, a vertex cover has the same definition: a set - of nodes such that each edge in the graph is incident to at least - one node in the set. Whether the node is the head or tail of the - directed edge is ignored. - - This is the local-ratio algorithm for computing an approximate - vertex cover. The algorithm greedily reduces the costs over edges, - iteratively building a cover. The worst-case runtime of this - implementation is $O(m \log n)$, where $n$ is the number - of nodes and $m$ the number of edges in the graph. - - References - ---------- - .. [1] Bar-Yehuda, R., and Even, S. (1985). "A local-ratio theorem for - approximating the weighted vertex cover problem." - *Annals of Discrete Mathematics*, 25, 27–46 - - - """ - cost = dict(G.nodes(data=weight, default=1)) - # While there are uncovered edges, choose an uncovered and update - # the cost of the remaining edges. - for u, v in G.edges(): - min_cost = min(cost[u], cost[v]) - cost[u] -= min_cost - cost[v] -= min_cost - return {u for u, c in cost.items() if c == 0} diff --git a/extensions/fablabchemnitz/networkx/algorithms/assortativity/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/assortativity/__init__.py deleted file mode 100644 index 4d988860..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/assortativity/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from networkx.algorithms.assortativity.connectivity import * -from networkx.algorithms.assortativity.correlation import * -from networkx.algorithms.assortativity.mixing import * -from networkx.algorithms.assortativity.neighbor_degree import * -from networkx.algorithms.assortativity.pairs import * diff --git a/extensions/fablabchemnitz/networkx/algorithms/assortativity/connectivity.py b/extensions/fablabchemnitz/networkx/algorithms/assortativity/connectivity.py deleted file mode 100644 index 49018fca..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/assortativity/connectivity.py +++ /dev/null @@ -1,142 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2011 by -# Jordi Torrents -# Aric Hagberg -# All rights reserved. -# BSD license. -# -# -# Authors: Jordi Torrents -# Aric Hagberg - -from collections import defaultdict - -import networkx as nx - -__all__ = ['average_degree_connectivity', - 'k_nearest_neighbors'] - - -def average_degree_connectivity(G, source="in+out", target="in+out", - nodes=None, weight=None): - r"""Compute the average degree connectivity of graph. - - The average degree connectivity is the average nearest neighbor degree of - nodes with degree k. For weighted graphs, an analogous measure can - be computed using the weighted average neighbors degree defined in - [1]_, for a node `i`, as - - .. math:: - - k_{nn,i}^{w} = \frac{1}{s_i} \sum_{j \in N(i)} w_{ij} k_j - - where `s_i` is the weighted degree of node `i`, - `w_{ij}` is the weight of the edge that links `i` and `j`, - and `N(i)` are the neighbors of node `i`. - - Parameters - ---------- - G : NetworkX graph - - source : "in"|"out"|"in+out" (default:"in+out") - Directed graphs only. Use "in"- or "out"-degree for source node. - - target : "in"|"out"|"in+out" (default:"in+out" - Directed graphs only. Use "in"- or "out"-degree for target node. - - nodes : list or iterable (optional) - Compute neighbor connectivity for these nodes. The default is all - nodes. - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used as a weight. - If None, then each edge has weight 1. - - Returns - ------- - d : dict - A dictionary keyed by degree k with the value of average connectivity. - - Raises - ------ - ValueError - If either `source` or `target` are not one of 'in', - 'out', or 'in+out'. - - Examples - -------- - >>> G=nx.path_graph(4) - >>> G.edges[1, 2]['weight'] = 3 - >>> nx.k_nearest_neighbors(G) - {1: 2.0, 2: 1.5} - >>> nx.k_nearest_neighbors(G, weight='weight') - {1: 2.0, 2: 1.75} - - See also - -------- - neighbors_average_degree - - Notes - ----- - This algorithm is sometimes called "k nearest neighbors" and is also - available as `k_nearest_neighbors`. - - References - ---------- - .. [1] A. Barrat, M. Barthélemy, R. Pastor-Satorras, and A. Vespignani, - "The architecture of complex weighted networks". - PNAS 101 (11): 3747–3752 (2004). - """ - # First, determine the type of neighbors and the type of degree to use. - if G.is_directed(): - if source not in ('in', 'out', 'in+out'): - raise ValueError('source must be one of "in", "out", or "in+out"') - if target not in ('in', 'out', 'in+out'): - raise ValueError('target must be one of "in", "out", or "in+out"') - direction = {'out': G.out_degree, - 'in': G.in_degree, - 'in+out': G.degree} - neighbor_funcs = {'out': G.successors, - 'in': G.predecessors, - 'in+out': G.neighbors} - source_degree = direction[source] - target_degree = direction[target] - neighbors = neighbor_funcs[source] - # `reverse` indicates whether to look at the in-edge when - # computing the weight of an edge. - reverse = (source == 'in') - else: - source_degree = G.degree - target_degree = G.degree - neighbors = G.neighbors - reverse = False - dsum = defaultdict(int) - dnorm = defaultdict(int) - # Check if `source_nodes` is actually a single node in the graph. - source_nodes = source_degree(nodes) - if nodes in G: - source_nodes = [(nodes, source_degree(nodes))] - for n, k in source_nodes: - nbrdeg = target_degree(neighbors(n)) - if weight is None: - s = sum(d for n, d in nbrdeg) - else: # weight nbr degree by weight of (n,nbr) edge - if reverse: - s = sum(G[nbr][n].get(weight, 1) * d for nbr, d in nbrdeg) - else: - s = sum(G[n][nbr].get(weight, 1) * d for nbr, d in nbrdeg) - dnorm[k] += source_degree(n, weight=weight) - dsum[k] += s - - # normalize - dc = {} - for k, avg in dsum.items(): - dc[k] = avg - norm = dnorm[k] - if avg > 0 and norm > 0: - dc[k] /= norm - return dc - - -k_nearest_neighbors = average_degree_connectivity diff --git a/extensions/fablabchemnitz/networkx/algorithms/assortativity/correlation.py b/extensions/fablabchemnitz/networkx/algorithms/assortativity/correlation.py deleted file mode 100644 index 16b1ca3d..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/assortativity/correlation.py +++ /dev/null @@ -1,295 +0,0 @@ -# -*- coding: utf-8 -*- -"""Node assortativity coefficients and correlation measures. -""" -import networkx as nx -from networkx.algorithms.assortativity.mixing import degree_mixing_matrix, \ - attribute_mixing_matrix, numeric_mixing_matrix -from networkx.algorithms.assortativity.pairs import node_degree_xy, \ - node_attribute_xy -__author__ = ' '.join(['Aric Hagberg ', - 'Oleguer Sagarra ']) -__all__ = ['degree_pearson_correlation_coefficient', - 'degree_assortativity_coefficient', - 'attribute_assortativity_coefficient', - 'numeric_assortativity_coefficient'] - - -def degree_assortativity_coefficient(G, x='out', y='in', weight=None, - nodes=None): - """Compute degree assortativity of graph. - - Assortativity measures the similarity of connections - in the graph with respect to the node degree. - - Parameters - ---------- - G : NetworkX graph - - x: string ('in','out') - The degree type for source node (directed graphs only). - - y: string ('in','out') - The degree type for target node (directed graphs only). - - weight: string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - nodes: list or iterable (optional) - Compute degree assortativity only for nodes in container. - The default is all nodes. - - Returns - ------- - r : float - Assortativity of graph by degree. - - Examples - -------- - >>> G=nx.path_graph(4) - >>> r=nx.degree_assortativity_coefficient(G) - >>> print("%3.1f"%r) - -0.5 - - See Also - -------- - attribute_assortativity_coefficient - numeric_assortativity_coefficient - neighbor_connectivity - degree_mixing_dict - degree_mixing_matrix - - Notes - ----- - This computes Eq. (21) in Ref. [1]_ , where e is the joint - probability distribution (mixing matrix) of the degrees. If G is - directed than the matrix e is the joint probability of the - user-specified degree type for the source and target. - - References - ---------- - .. [1] M. E. J. Newman, Mixing patterns in networks, - Physical Review E, 67 026126, 2003 - .. [2] Foster, J.G., Foster, D.V., Grassberger, P. & Paczuski, M. - Edge direction and the structure of networks, PNAS 107, 10815-20 (2010). - """ - M = degree_mixing_matrix(G, x=x, y=y, nodes=nodes, weight=weight) - return numeric_ac(M) - - -def degree_pearson_correlation_coefficient(G, x='out', y='in', - weight=None, nodes=None): - """Compute degree assortativity of graph. - - Assortativity measures the similarity of connections - in the graph with respect to the node degree. - - This is the same as degree_assortativity_coefficient but uses the - potentially faster scipy.stats.pearsonr function. - - Parameters - ---------- - G : NetworkX graph - - x: string ('in','out') - The degree type for source node (directed graphs only). - - y: string ('in','out') - The degree type for target node (directed graphs only). - - weight: string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - nodes: list or iterable (optional) - Compute pearson correlation of degrees only for specified nodes. - The default is all nodes. - - Returns - ------- - r : float - Assortativity of graph by degree. - - Examples - -------- - >>> G=nx.path_graph(4) - >>> r=nx.degree_pearson_correlation_coefficient(G) - >>> print("%3.1f"%r) - -0.5 - - Notes - ----- - This calls scipy.stats.pearsonr. - - References - ---------- - .. [1] M. E. J. Newman, Mixing patterns in networks - Physical Review E, 67 026126, 2003 - .. [2] Foster, J.G., Foster, D.V., Grassberger, P. & Paczuski, M. - Edge direction and the structure of networks, PNAS 107, 10815-20 (2010). - """ - try: - import scipy.stats as stats - except ImportError: - raise ImportError( - "Assortativity requires SciPy: http://scipy.org/ ") - xy = node_degree_xy(G, x=x, y=y, nodes=nodes, weight=weight) - x, y = zip(*xy) - return stats.pearsonr(x, y)[0] - - -def attribute_assortativity_coefficient(G, attribute, nodes=None): - """Compute assortativity for node attributes. - - Assortativity measures the similarity of connections - in the graph with respect to the given attribute. - - Parameters - ---------- - G : NetworkX graph - - attribute : string - Node attribute key - - nodes: list or iterable (optional) - Compute attribute assortativity for nodes in container. - The default is all nodes. - - Returns - ------- - r: float - Assortativity of graph for given attribute - - Examples - -------- - >>> G=nx.Graph() - >>> G.add_nodes_from([0,1],color='red') - >>> G.add_nodes_from([2,3],color='blue') - >>> G.add_edges_from([(0,1),(2,3)]) - >>> print(nx.attribute_assortativity_coefficient(G,'color')) - 1.0 - - Notes - ----- - This computes Eq. (2) in Ref. [1]_ , (trace(M)-sum(M^2))/(1-sum(M^2)), - where M is the joint probability distribution (mixing matrix) - of the specified attribute. - - References - ---------- - .. [1] M. E. J. Newman, Mixing patterns in networks, - Physical Review E, 67 026126, 2003 - """ - M = attribute_mixing_matrix(G, attribute, nodes) - return attribute_ac(M) - - -def numeric_assortativity_coefficient(G, attribute, nodes=None): - """Compute assortativity for numerical node attributes. - - Assortativity measures the similarity of connections - in the graph with respect to the given numeric attribute. - The numeric attribute must be an integer. - - Parameters - ---------- - G : NetworkX graph - - attribute : string - Node attribute key. The corresponding attribute value must be an - integer. - - nodes: list or iterable (optional) - Compute numeric assortativity only for attributes of nodes in - container. The default is all nodes. - - Returns - ------- - r: float - Assortativity of graph for given attribute - - Examples - -------- - >>> G=nx.Graph() - >>> G.add_nodes_from([0,1],size=2) - >>> G.add_nodes_from([2,3],size=3) - >>> G.add_edges_from([(0,1),(2,3)]) - >>> print(nx.numeric_assortativity_coefficient(G,'size')) - 1.0 - - Notes - ----- - This computes Eq. (21) in Ref. [1]_ , for the mixing matrix of - of the specified attribute. - - References - ---------- - .. [1] M. E. J. Newman, Mixing patterns in networks - Physical Review E, 67 026126, 2003 - """ - a = numeric_mixing_matrix(G, attribute, nodes) - return numeric_ac(a) - - -def attribute_ac(M): - """Compute assortativity for attribute matrix M. - - Parameters - ---------- - M : numpy array or matrix - Attribute mixing matrix. - - Notes - ----- - This computes Eq. (2) in Ref. [1]_ , (trace(e)-sum(e^2))/(1-sum(e^2)), - where e is the joint probability distribution (mixing matrix) - of the specified attribute. - - References - ---------- - .. [1] M. E. J. Newman, Mixing patterns in networks, - Physical Review E, 67 026126, 2003 - """ - try: - import numpy - except ImportError: - raise ImportError( - "attribute_assortativity requires NumPy: http://scipy.org/ ") - if M.sum() != 1.0: - M = M / float(M.sum()) - M = numpy.asmatrix(M) - s = (M * M).sum() - t = M.trace() - r = (t - s) / (1 - s) - return float(r) - - -def numeric_ac(M): - # M is a numpy matrix or array - # numeric assortativity coefficient, pearsonr - try: - import numpy - except ImportError: - raise ImportError('numeric_assortativity requires ', - 'NumPy: http://scipy.org/') - if M.sum() != 1.0: - M = M / float(M.sum()) - nx, ny = M.shape # nx=ny - x = numpy.arange(nx) - y = numpy.arange(ny) - a = M.sum(axis=0) - b = M.sum(axis=1) - vara = (a * x**2).sum() - ((a * x).sum())**2 - varb = (b * x**2).sum() - ((b * x).sum())**2 - xy = numpy.outer(x, y) - ab = numpy.outer(a, b) - return (xy * (M - ab)).sum() / numpy.sqrt(vara * varb) - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/assortativity/mixing.py b/extensions/fablabchemnitz/networkx/algorithms/assortativity/mixing.py deleted file mode 100644 index 40a0096a..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/assortativity/mixing.py +++ /dev/null @@ -1,244 +0,0 @@ -#-*- coding: utf-8 -*- -""" -Mixing matrices for node attributes and degree. -""" -import networkx as nx -from networkx.utils import dict_to_numpy_array -from networkx.algorithms.assortativity.pairs import node_degree_xy, \ - node_attribute_xy -__author__ = ' '.join(['Aric Hagberg ']) -__all__ = ['attribute_mixing_matrix', - 'attribute_mixing_dict', - 'degree_mixing_matrix', - 'degree_mixing_dict', - 'numeric_mixing_matrix', - 'mixing_dict'] - - -def attribute_mixing_dict(G, attribute, nodes=None, normalized=False): - """Returns dictionary representation of mixing matrix for attribute. - - Parameters - ---------- - G : graph - NetworkX graph object. - - attribute : string - Node attribute key. - - nodes: list or iterable (optional) - Unse nodes in container to build the dict. The default is all nodes. - - normalized : bool (default=False) - Return counts if False or probabilities if True. - - Examples - -------- - >>> G=nx.Graph() - >>> G.add_nodes_from([0,1],color='red') - >>> G.add_nodes_from([2,3],color='blue') - >>> G.add_edge(1,3) - >>> d=nx.attribute_mixing_dict(G,'color') - >>> print(d['red']['blue']) - 1 - >>> print(d['blue']['red']) # d symmetric for undirected graphs - 1 - - Returns - ------- - d : dictionary - Counts or joint probability of occurrence of attribute pairs. - """ - xy_iter = node_attribute_xy(G, attribute, nodes) - return mixing_dict(xy_iter, normalized=normalized) - - -def attribute_mixing_matrix(G, attribute, nodes=None, mapping=None, - normalized=True): - """Returns mixing matrix for attribute. - - Parameters - ---------- - G : graph - NetworkX graph object. - - attribute : string - Node attribute key. - - nodes: list or iterable (optional) - Use only nodes in container to build the matrix. The default is - all nodes. - - mapping : dictionary, optional - Mapping from node attribute to integer index in matrix. - If not specified, an arbitrary ordering will be used. - - normalized : bool (default=True) - Return counts if False or probabilities if True. - - Returns - ------- - m: numpy array - Counts or joint probability of occurrence of attribute pairs. - """ - d = attribute_mixing_dict(G, attribute, nodes) - a = dict_to_numpy_array(d, mapping=mapping) - if normalized: - a = a / a.sum() - return a - - -def degree_mixing_dict(G, x='out', y='in', weight=None, - nodes=None, normalized=False): - """Returns dictionary representation of mixing matrix for degree. - - Parameters - ---------- - G : graph - NetworkX graph object. - - x: string ('in','out') - The degree type for source node (directed graphs only). - - y: string ('in','out') - The degree type for target node (directed graphs only). - - weight: string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - normalized : bool (default=False) - Return counts if False or probabilities if True. - - Returns - ------- - d: dictionary - Counts or joint probability of occurrence of degree pairs. - """ - xy_iter = node_degree_xy(G, x=x, y=y, nodes=nodes, weight=weight) - return mixing_dict(xy_iter, normalized=normalized) - - -def degree_mixing_matrix(G, x='out', y='in', weight=None, - nodes=None, normalized=True): - """Returns mixing matrix for attribute. - - Parameters - ---------- - G : graph - NetworkX graph object. - - x: string ('in','out') - The degree type for source node (directed graphs only). - - y: string ('in','out') - The degree type for target node (directed graphs only). - - nodes: list or iterable (optional) - Build the matrix using only nodes in container. - The default is all nodes. - - weight: string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - normalized : bool (default=True) - Return counts if False or probabilities if True. - - Returns - ------- - m: numpy array - Counts, or joint probability, of occurrence of node degree. - """ - d = degree_mixing_dict(G, x=x, y=y, nodes=nodes, weight=weight) - s = set(d.keys()) - for k, v in d.items(): - s.update(v.keys()) - m = max(s) - mapping = {x: x for x in range(m + 1)} - a = dict_to_numpy_array(d, mapping=mapping) - if normalized: - a = a / a.sum() - return a - - -def numeric_mixing_matrix(G, attribute, nodes=None, normalized=True): - """Returns numeric mixing matrix for attribute. - - The attribute must be an integer. - - Parameters - ---------- - G : graph - NetworkX graph object. - - attribute : string - Node attribute key. The corresponding attribute must be an integer. - - nodes: list or iterable (optional) - Build the matrix only with nodes in container. The default is all nodes. - - normalized : bool (default=True) - Return counts if False or probabilities if True. - - Returns - ------- - m: numpy array - Counts, or joint, probability of occurrence of node attribute pairs. - """ - d = attribute_mixing_dict(G, attribute, nodes) - s = set(d.keys()) - for k, v in d.items(): - s.update(v.keys()) - m = max(s) - mapping = {x: x for x in range(m + 1)} - a = dict_to_numpy_array(d, mapping=mapping) - if normalized: - a = a / a.sum() - return a - - -def mixing_dict(xy, normalized=False): - """Returns a dictionary representation of mixing matrix. - - Parameters - ---------- - xy : list or container of two-tuples - Pairs of (x,y) items. - - attribute : string - Node attribute key - - normalized : bool (default=False) - Return counts if False or probabilities if True. - - Returns - ------- - d: dictionary - Counts or Joint probability of occurrence of values in xy. - """ - d = {} - psum = 0.0 - for x, y in xy: - if x not in d: - d[x] = {} - if y not in d: - d[y] = {} - v = d[x].get(y, 0) - d[x][y] = v + 1 - psum += 1 - - if normalized: - for k, jdict in d.items(): - for j in jdict: - jdict[j] /= psum - return d - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/assortativity/neighbor_degree.py b/extensions/fablabchemnitz/networkx/algorithms/assortativity/neighbor_degree.py deleted file mode 100644 index 1a0dbebb..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/assortativity/neighbor_degree.py +++ /dev/null @@ -1,132 +0,0 @@ -#-*- coding: utf-8 -*- -# Copyright (C) 2011 by -# Jordi Torrents -# Aric Hagberg -# All rights reserved. -# BSD license. -import networkx as nx -__author__ = """\n""".join(['Jordi Torrents ', - 'Aric Hagberg (hagberg@lanl.gov)']) -__all__ = ["average_neighbor_degree"] - - -def _average_nbr_deg(G, source_degree, target_degree, nodes=None, weight=None): - # average degree of neighbors - avg = {} - for n, deg in source_degree(nodes, weight=weight): - # normalize but not by zero degree - if deg == 0: - deg = 1 - nbrdeg = target_degree(G[n]) - if weight is None: - avg[n] = sum(d for n, d in nbrdeg) / float(deg) - else: - avg[n] = sum((G[n][nbr].get(weight, 1) * d - for nbr, d in nbrdeg)) / float(deg) - return avg - - -def average_neighbor_degree(G, source='out', target='out', - nodes=None, weight=None): - r"""Returns the average degree of the neighborhood of each node. - - The average neighborhood degree of a node `i` is - - .. math:: - - k_{nn,i} = \frac{1}{|N(i)|} \sum_{j \in N(i)} k_j - - where `N(i)` are the neighbors of node `i` and `k_j` is - the degree of node `j` which belongs to `N(i)`. For weighted - graphs, an analogous measure can be defined [1]_, - - .. math:: - - k_{nn,i}^{w} = \frac{1}{s_i} \sum_{j \in N(i)} w_{ij} k_j - - where `s_i` is the weighted degree of node `i`, `w_{ij}` - is the weight of the edge that links `i` and `j` and - `N(i)` are the neighbors of node `i`. - - - Parameters - ---------- - G : NetworkX graph - - source : string ("in"|"out") - Directed graphs only. - Use "in"- or "out"-degree for source node. - - target : string ("in"|"out") - Directed graphs only. - Use "in"- or "out"-degree for target node. - - nodes : list or iterable, optional - Compute neighbor degree for specified nodes. The default is - all nodes in the graph. - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used as a weight. - If None, then each edge has weight 1. - - Returns - ------- - d: dict - A dictionary keyed by node with average neighbors degree value. - - Examples - -------- - >>> G=nx.path_graph(4) - >>> G.edges[0, 1]['weight'] = 5 - >>> G.edges[2, 3]['weight'] = 3 - - >>> nx.average_neighbor_degree(G) - {0: 2.0, 1: 1.5, 2: 1.5, 3: 2.0} - >>> nx.average_neighbor_degree(G, weight='weight') - {0: 2.0, 1: 1.1666666666666667, 2: 1.25, 3: 2.0} - - >>> G=nx.DiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> nx.average_neighbor_degree(G, source='in', target='in') - {0: 1.0, 1: 1.0, 2: 1.0, 3: 0.0} - - >>> nx.average_neighbor_degree(G, source='out', target='out') - {0: 1.0, 1: 1.0, 2: 0.0, 3: 0.0} - - Notes - ----- - For directed graphs you can also specify in-degree or out-degree - by passing keyword arguments. - - See Also - -------- - average_degree_connectivity - - References - ---------- - .. [1] A. Barrat, M. Barthélemy, R. Pastor-Satorras, and A. Vespignani, - "The architecture of complex weighted networks". - PNAS 101 (11): 3747–3752 (2004). - """ - source_degree = G.degree - target_degree = G.degree - if G.is_directed(): - direction = {'out': G.out_degree, - 'in': G.in_degree} - source_degree = direction[source] - target_degree = direction[target] - return _average_nbr_deg(G, source_degree, target_degree, - nodes=nodes, weight=weight) - -# obsolete -# def average_neighbor_in_degree(G, nodes=None, weight=None): -# if not G.is_directed(): -# raise nx.NetworkXError("Not defined for undirected graphs.") -# return _average_nbr_deg(G, G.in_degree, G.in_degree, nodes, weight) -# average_neighbor_in_degree.__doc__=average_neighbor_degree.__doc__ - -# def average_neighbor_out_degree(G, nodes=None, weight=None): -# if not G.is_directed(): -# raise nx.NetworkXError("Not defined for undirected graphs.") -# return _average_nbr_deg(G, G.out_degree, G.out_degree, nodes, weight) -# average_neighbor_out_degree.__doc__=average_neighbor_degree.__doc__ diff --git a/extensions/fablabchemnitz/networkx/algorithms/assortativity/pairs.py b/extensions/fablabchemnitz/networkx/algorithms/assortativity/pairs.py deleted file mode 100644 index 8648d870..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/assortativity/pairs.py +++ /dev/null @@ -1,128 +0,0 @@ -#-*- coding: utf-8 -*- -"""Generators of x-y pairs of node data.""" -import networkx as nx -__author__ = ' '.join(['Aric Hagberg ']) -__all__ = ['node_attribute_xy', - 'node_degree_xy'] - - -def node_attribute_xy(G, attribute, nodes=None): - """Returns iterator of node-attribute pairs for all edges in G. - - Parameters - ---------- - G: NetworkX graph - - attribute: key - The node attribute key. - - nodes: list or iterable (optional) - Use only edges that are adjacency to specified nodes. - The default is all nodes. - - Returns - ------- - (x,y): 2-tuple - Generates 2-tuple of (attribute,attribute) values. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_node(1,color='red') - >>> G.add_node(2,color='blue') - >>> G.add_edge(1,2) - >>> list(nx.node_attribute_xy(G,'color')) - [('red', 'blue')] - - Notes - ----- - For undirected graphs each edge is produced twice, once for each edge - representation (u,v) and (v,u), with the exception of self-loop edges - which only appear once. - """ - if nodes is None: - nodes = set(G) - else: - nodes = set(nodes) - Gnodes = G.nodes - for u, nbrsdict in G.adjacency(): - if u not in nodes: - continue - uattr = Gnodes[u].get(attribute, None) - if G.is_multigraph(): - for v, keys in nbrsdict.items(): - vattr = Gnodes[v].get(attribute, None) - for k, d in keys.items(): - yield (uattr, vattr) - else: - for v, eattr in nbrsdict.items(): - vattr = Gnodes[v].get(attribute, None) - yield (uattr, vattr) - - -def node_degree_xy(G, x='out', y='in', weight=None, nodes=None): - """Generate node degree-degree pairs for edges in G. - - Parameters - ---------- - G: NetworkX graph - - x: string ('in','out') - The degree type for source node (directed graphs only). - - y: string ('in','out') - The degree type for target node (directed graphs only). - - weight: string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - nodes: list or iterable (optional) - Use only edges that are adjacency to specified nodes. - The default is all nodes. - - Returns - ------- - (x,y): 2-tuple - Generates 2-tuple of (degree,degree) values. - - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_edge(1,2) - >>> list(nx.node_degree_xy(G,x='out',y='in')) - [(1, 1)] - >>> list(nx.node_degree_xy(G,x='in',y='out')) - [(0, 0)] - - Notes - ----- - For undirected graphs each edge is produced twice, once for each edge - representation (u,v) and (v,u), with the exception of self-loop edges - which only appear once. - """ - if nodes is None: - nodes = set(G) - else: - nodes = set(nodes) - xdeg = G.degree - ydeg = G.degree - if G.is_directed(): - direction = {'out': G.out_degree, - 'in': G.in_degree} - xdeg = direction[x] - ydeg = direction[y] - - for u, degu in xdeg(nodes, weight=weight): - neighbors = (nbr for _, nbr in G.edges(u) if nbr in nodes) - for v, degv in ydeg(neighbors, weight=weight): - yield degu, degv - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/base_test.py b/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/base_test.py deleted file mode 100644 index 41fea1cb..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/base_test.py +++ /dev/null @@ -1,53 +0,0 @@ -import networkx as nx - - -class BaseTestAttributeMixing(object): - - @classmethod - def setup_class(cls): - G = nx.Graph() - G.add_nodes_from([0, 1], fish='one') - G.add_nodes_from([2, 3], fish='two') - G.add_nodes_from([4], fish='red') - G.add_nodes_from([5], fish='blue') - G.add_edges_from([(0, 1), (2, 3), (0, 4), (2, 5)]) - cls.G = G - - D = nx.DiGraph() - D.add_nodes_from([0, 1], fish='one') - D.add_nodes_from([2, 3], fish='two') - D.add_nodes_from([4], fish='red') - D.add_nodes_from([5], fish='blue') - D.add_edges_from([(0, 1), (2, 3), (0, 4), (2, 5)]) - cls.D = D - - M = nx.MultiGraph() - M.add_nodes_from([0, 1], fish='one') - M.add_nodes_from([2, 3], fish='two') - M.add_nodes_from([4], fish='red') - M.add_nodes_from([5], fish='blue') - M.add_edges_from([(0, 1), (0, 1), (2, 3)]) - cls.M = M - - S = nx.Graph() - S.add_nodes_from([0, 1], fish='one') - S.add_nodes_from([2, 3], fish='two') - S.add_nodes_from([4], fish='red') - S.add_nodes_from([5], fish='blue') - S.add_edge(0, 0) - S.add_edge(2, 2) - cls.S = S - - -class BaseTestDegreeMixing(object): - - @classmethod - def setup_class(cls): - cls.P4 = nx.path_graph(4) - cls.D = nx.DiGraph() - cls.D.add_edges_from([(0, 2), (0, 3), (1, 3), (2, 3)]) - cls.M = nx.MultiGraph() - nx.add_path(cls.M, range(4)) - cls.M.add_edge(0, 1) - cls.S = nx.Graph() - cls.S.add_edges_from([(0, 0), (1, 1)]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/test_connectivity.py b/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/test_connectivity.py deleted file mode 100644 index 9c0562fc..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/test_connectivity.py +++ /dev/null @@ -1,141 +0,0 @@ -from itertools import permutations - -import pytest - -import networkx as nx -from networkx.testing import almost_equal - - -class TestNeighborConnectivity(object): - - def test_degree_p4(self): - G = nx.path_graph(4) - answer = {1: 2.0, 2: 1.5} - nd = nx.average_degree_connectivity(G) - assert nd == answer - - D = G.to_directed() - answer = {2: 2.0, 4: 1.5} - nd = nx.average_degree_connectivity(D) - assert nd == answer - - answer = {1: 2.0, 2: 1.5} - D = G.to_directed() - nd = nx.average_degree_connectivity(D, source='in', target='in') - assert nd == answer - - D = G.to_directed() - nd = nx.average_degree_connectivity(D, source='in', target='in') - assert nd == answer - - def test_degree_p4_weighted(self): - G = nx.path_graph(4) - G[1][2]['weight'] = 4 - answer = {1: 2.0, 2: 1.8} - nd = nx.average_degree_connectivity(G, weight='weight') - assert nd == answer - answer = {1: 2.0, 2: 1.5} - nd = nx.average_degree_connectivity(G) - assert nd == answer - - D = G.to_directed() - answer = {2: 2.0, 4: 1.8} - nd = nx.average_degree_connectivity(D, weight='weight') - assert nd == answer - - answer = {1: 2.0, 2: 1.8} - D = G.to_directed() - nd = nx.average_degree_connectivity(D, weight='weight', source='in', - target='in') - assert nd == answer - - D = G.to_directed() - nd = nx.average_degree_connectivity(D, source='in', target='out', - weight='weight') - assert nd == answer - - def test_weight_keyword(self): - G = nx.path_graph(4) - G[1][2]['other'] = 4 - answer = {1: 2.0, 2: 1.8} - nd = nx.average_degree_connectivity(G, weight='other') - assert nd == answer - answer = {1: 2.0, 2: 1.5} - nd = nx.average_degree_connectivity(G, weight=None) - assert nd == answer - - D = G.to_directed() - answer = {2: 2.0, 4: 1.8} - nd = nx.average_degree_connectivity(D, weight='other') - assert nd == answer - - answer = {1: 2.0, 2: 1.8} - D = G.to_directed() - nd = nx.average_degree_connectivity(D, weight='other', source='in', - target='in') - assert nd == answer - - D = G.to_directed() - nd = nx.average_degree_connectivity(D, weight='other', source='in', - target='in') - assert nd == answer - - def test_degree_barrat(self): - G = nx.star_graph(5) - G.add_edges_from([(5, 6), (5, 7), (5, 8), (5, 9)]) - G[0][5]['weight'] = 5 - nd = nx.average_degree_connectivity(G)[5] - assert nd == 1.8 - nd = nx.average_degree_connectivity(G, weight='weight')[5] - assert almost_equal(nd, 3.222222, places=5) - nd = nx.k_nearest_neighbors(G, weight='weight')[5] - assert almost_equal(nd, 3.222222, places=5) - - def test_zero_deg(self): - G = nx.DiGraph() - G.add_edge(1, 2) - G.add_edge(1, 3) - G.add_edge(1, 4) - c = nx.average_degree_connectivity(G) - assert c == {1: 0, 3: 1} - c = nx.average_degree_connectivity(G, source='in', target='in') - assert c == {0: 0, 1: 0} - c = nx.average_degree_connectivity(G, source='in', target='out') - assert c == {0: 0, 1: 3} - c = nx.average_degree_connectivity(G, source='in', target='in+out') - assert c == {0: 0, 1: 3} - c = nx.average_degree_connectivity(G, source='out', target='out') - assert c == {0: 0, 3: 0} - c = nx.average_degree_connectivity(G, source='out', target='in') - assert c == {0: 0, 3: 1} - c = nx.average_degree_connectivity(G, source='out', target='in+out') - assert c == {0: 0, 3: 1} - - def test_in_out_weight(self): - G = nx.DiGraph() - G.add_edge(1, 2, weight=1) - G.add_edge(1, 3, weight=1) - G.add_edge(3, 1, weight=1) - for s, t in permutations(['in', 'out', 'in+out'], 2): - c = nx.average_degree_connectivity(G, source=s, target=t) - cw = nx.average_degree_connectivity(G, source=s, target=t, - weight='weight') - assert c == cw - - def test_invalid_source(self): - with pytest.raises(ValueError): - G = nx.DiGraph() - nx.average_degree_connectivity(G, source='bogus') - - def test_invalid_target(self): - with pytest.raises(ValueError): - G = nx.DiGraph() - nx.average_degree_connectivity(G, target='bogus') - - def test_single_node(self): - # TODO Is this really the intended behavior for providing a - # single node as the argument `nodes`? Shouldn't the function - # just return the connectivity value itself? - G = nx.trivial_graph() - conn = nx.average_degree_connectivity(G, nodes=0) - assert conn == {0: 0} diff --git a/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/test_correlation.py b/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/test_correlation.py deleted file mode 100644 index ef0a2ebf..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/test_correlation.py +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env python -import pytest -np = pytest.importorskip('numpy') -npt = pytest.importorskip('numpy.testing') -scipy = pytest.importorskip('scipy') - - -import networkx as nx -from .base_test import BaseTestAttributeMixing, BaseTestDegreeMixing -from networkx.algorithms.assortativity.correlation import attribute_ac - - -class TestDegreeMixingCorrelation(BaseTestDegreeMixing): - - def test_degree_assortativity_undirected(self): - r = nx.degree_assortativity_coefficient(self.P4) - npt.assert_almost_equal(r, -1.0 / 2, decimal=4) - - def test_degree_assortativity_directed(self): - r = nx.degree_assortativity_coefficient(self.D) - npt.assert_almost_equal(r, -0.57735, decimal=4) - - def test_degree_assortativity_multigraph(self): - r = nx.degree_assortativity_coefficient(self.M) - npt.assert_almost_equal(r, -1.0 / 7.0, decimal=4) - - def test_degree_pearson_assortativity_undirected(self): - r = nx.degree_pearson_correlation_coefficient(self.P4) - npt.assert_almost_equal(r, -1.0 / 2, decimal=4) - - def test_degree_pearson_assortativity_directed(self): - r = nx.degree_pearson_correlation_coefficient(self.D) - npt.assert_almost_equal(r, -0.57735, decimal=4) - - def test_degree_pearson_assortativity_multigraph(self): - r = nx.degree_pearson_correlation_coefficient(self.M) - npt.assert_almost_equal(r, -1.0 / 7.0, decimal=4) - - -class TestAttributeMixingCorrelation(BaseTestAttributeMixing): - - def test_attribute_assortativity_undirected(self): - r = nx.attribute_assortativity_coefficient(self.G, 'fish') - assert r == 6.0 / 22.0 - - def test_attribute_assortativity_directed(self): - r = nx.attribute_assortativity_coefficient(self.D, 'fish') - assert r == 1.0 / 3.0 - - def test_attribute_assortativity_multigraph(self): - r = nx.attribute_assortativity_coefficient(self.M, 'fish') - assert r == 1.0 - - def test_attribute_assortativity_coefficient(self): - # from "Mixing patterns in networks" - a = np.array([[0.258, 0.016, 0.035, 0.013], - [0.012, 0.157, 0.058, 0.019], - [0.013, 0.023, 0.306, 0.035], - [0.005, 0.007, 0.024, 0.016]]) - r = attribute_ac(a) - npt.assert_almost_equal(r, 0.623, decimal=3) - - def test_attribute_assortativity_coefficient2(self): - a = np.array([[0.18, 0.02, 0.01, 0.03], - [0.02, 0.20, 0.03, 0.02], - [0.01, 0.03, 0.16, 0.01], - [0.03, 0.02, 0.01, 0.22]]) - - r = attribute_ac(a) - npt.assert_almost_equal(r, 0.68, decimal=2) - - def test_attribute_assortativity(self): - a = np.array([[50, 50, 0], [50, 50, 0], [0, 0, 2]]) - r = attribute_ac(a) - npt.assert_almost_equal(r, 0.029, decimal=3) diff --git a/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/test_mixing.py b/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/test_mixing.py deleted file mode 100644 index 620236f6..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/test_mixing.py +++ /dev/null @@ -1,163 +0,0 @@ -#!/usr/bin/env python -import pytest -np = pytest.importorskip('numpy') -npt = pytest.importorskip('numpy.testing') - - -import networkx as nx -from .base_test import BaseTestAttributeMixing, BaseTestDegreeMixing - - -class TestDegreeMixingDict(BaseTestDegreeMixing): - def test_degree_mixing_dict_undirected(self): - d = nx.degree_mixing_dict(self.P4) - d_result = {1: {2: 2}, - 2: {1: 2, 2: 2}, - } - assert d == d_result - - def test_degree_mixing_dict_undirected_normalized(self): - d = nx.degree_mixing_dict(self.P4, normalized=True) - d_result = {1: {2: 1.0 / 3}, - 2: {1: 1.0 / 3, 2: 1.0 / 3}, - } - assert d == d_result - - def test_degree_mixing_dict_directed(self): - d = nx.degree_mixing_dict(self.D) - print(d) - d_result = {1: {3: 2}, - 2: {1: 1, 3: 1}, - 3: {} - } - assert d == d_result - - def test_degree_mixing_dict_multigraph(self): - d = nx.degree_mixing_dict(self.M) - d_result = {1: {2: 1}, - 2: {1: 1, 3: 3}, - 3: {2: 3} - } - assert d == d_result - - -class TestDegreeMixingMatrix(BaseTestDegreeMixing): - - - def test_degree_mixing_matrix_undirected(self): - a_result = np.array([[0, 0, 0], - [0, 0, 2], - [0, 2, 2]] - ) - a = nx.degree_mixing_matrix(self.P4, normalized=False) - npt.assert_equal(a, a_result) - a = nx.degree_mixing_matrix(self.P4) - npt.assert_equal(a, a_result / float(a_result.sum())) - - def test_degree_mixing_matrix_directed(self): - a_result = np.array([[0, 0, 0, 0], - [0, 0, 0, 2], - [0, 1, 0, 1], - [0, 0, 0, 0]] - ) - a = nx.degree_mixing_matrix(self.D, normalized=False) - npt.assert_equal(a, a_result) - a = nx.degree_mixing_matrix(self.D) - npt.assert_equal(a, a_result / float(a_result.sum())) - - def test_degree_mixing_matrix_multigraph(self): - a_result = np.array([[0, 0, 0, 0], - [0, 0, 1, 0], - [0, 1, 0, 3], - [0, 0, 3, 0]] - ) - a = nx.degree_mixing_matrix(self.M, normalized=False) - npt.assert_equal(a, a_result) - a = nx.degree_mixing_matrix(self.M) - npt.assert_equal(a, a_result / float(a_result.sum())) - - def test_degree_mixing_matrix_selfloop(self): - a_result = np.array([[0, 0, 0], - [0, 0, 0], - [0, 0, 2]] - ) - a = nx.degree_mixing_matrix(self.S, normalized=False) - npt.assert_equal(a, a_result) - a = nx.degree_mixing_matrix(self.S) - npt.assert_equal(a, a_result / float(a_result.sum())) - - -class TestAttributeMixingDict(BaseTestAttributeMixing): - - def test_attribute_mixing_dict_undirected(self): - d = nx.attribute_mixing_dict(self.G, 'fish') - d_result = {'one': {'one': 2, 'red': 1}, - 'two': {'two': 2, 'blue': 1}, - 'red': {'one': 1}, - 'blue': {'two': 1} - } - assert d == d_result - - def test_attribute_mixing_dict_directed(self): - d = nx.attribute_mixing_dict(self.D, 'fish') - d_result = {'one': {'one': 1, 'red': 1}, - 'two': {'two': 1, 'blue': 1}, - 'red': {}, - 'blue': {} - } - assert d == d_result - - def test_attribute_mixing_dict_multigraph(self): - d = nx.attribute_mixing_dict(self.M, 'fish') - d_result = {'one': {'one': 4}, - 'two': {'two': 2}, - } - assert d == d_result - - -class TestAttributeMixingMatrix(BaseTestAttributeMixing): - - def test_attribute_mixing_matrix_undirected(self): - mapping = {'one': 0, 'two': 1, 'red': 2, 'blue': 3} - a_result = np.array([[2, 0, 1, 0], - [0, 2, 0, 1], - [1, 0, 0, 0], - [0, 1, 0, 0]] - ) - a = nx.attribute_mixing_matrix(self.G, 'fish', - mapping=mapping, - normalized=False) - npt.assert_equal(a, a_result) - a = nx.attribute_mixing_matrix(self.G, 'fish', - mapping=mapping) - npt.assert_equal(a, a_result / float(a_result.sum())) - - def test_attribute_mixing_matrix_directed(self): - mapping = {'one': 0, 'two': 1, 'red': 2, 'blue': 3} - a_result = np.array([[1, 0, 1, 0], - [0, 1, 0, 1], - [0, 0, 0, 0], - [0, 0, 0, 0]] - ) - a = nx.attribute_mixing_matrix(self.D, 'fish', - mapping=mapping, - normalized=False) - npt.assert_equal(a, a_result) - a = nx.attribute_mixing_matrix(self.D, 'fish', - mapping=mapping) - npt.assert_equal(a, a_result / float(a_result.sum())) - - def test_attribute_mixing_matrix_multigraph(self): - mapping = {'one': 0, 'two': 1, 'red': 2, 'blue': 3} - a_result = np.array([[4, 0, 0, 0], - [0, 2, 0, 0], - [0, 0, 0, 0], - [0, 0, 0, 0]] - ) - a = nx.attribute_mixing_matrix(self.M, 'fish', - mapping=mapping, - normalized=False) - npt.assert_equal(a, a_result) - a = nx.attribute_mixing_matrix(self.M, 'fish', - mapping=mapping) - npt.assert_equal(a, a_result / float(a_result.sum())) diff --git a/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/test_neighbor_degree.py b/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/test_neighbor_degree.py deleted file mode 100644 index ab3209de..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/test_neighbor_degree.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python -import networkx as nx -from networkx.testing import almost_equal - - -class TestAverageNeighbor(object): - - def test_degree_p4(self): - G = nx.path_graph(4) - answer = {0: 2, 1: 1.5, 2: 1.5, 3: 2} - nd = nx.average_neighbor_degree(G) - assert nd == answer - - D = G.to_directed() - nd = nx.average_neighbor_degree(D) - assert nd == answer - - D = G.to_directed() - nd = nx.average_neighbor_degree(D) - assert nd == answer - - D = G.to_directed() - nd = nx.average_neighbor_degree(D, source='in', target='in') - assert nd == answer - - def test_degree_p4_weighted(self): - G = nx.path_graph(4) - G[1][2]['weight'] = 4 - answer = {0: 2, 1: 1.8, 2: 1.8, 3: 2} - nd = nx.average_neighbor_degree(G, weight='weight') - assert nd == answer - - D = G.to_directed() - nd = nx.average_neighbor_degree(D, weight='weight') - assert nd == answer - - D = G.to_directed() - nd = nx.average_neighbor_degree(D, weight='weight') - assert nd == answer - nd = nx.average_neighbor_degree(D, source='out', target='out', - weight='weight') - assert nd == answer - - D = G.to_directed() - nd = nx.average_neighbor_degree(D, source='in', target='in', - weight='weight') - assert nd == answer - - def test_degree_k4(self): - G = nx.complete_graph(4) - answer = {0: 3, 1: 3, 2: 3, 3: 3} - nd = nx.average_neighbor_degree(G) - assert nd == answer - - D = G.to_directed() - nd = nx.average_neighbor_degree(D) - assert nd == answer - - D = G.to_directed() - nd = nx.average_neighbor_degree(D) - assert nd == answer - - D = G.to_directed() - nd = nx.average_neighbor_degree(D, source='in', target='in') - assert nd == answer - - def test_degree_k4_nodes(self): - G = nx.complete_graph(4) - answer = {1: 3.0, 2: 3.0} - nd = nx.average_neighbor_degree(G, nodes=[1, 2]) - assert nd == answer - - def test_degree_barrat(self): - G = nx.star_graph(5) - G.add_edges_from([(5, 6), (5, 7), (5, 8), (5, 9)]) - G[0][5]['weight'] = 5 - nd = nx.average_neighbor_degree(G)[5] - assert nd == 1.8 - nd = nx.average_neighbor_degree(G, weight='weight')[5] - assert almost_equal(nd, 3.222222, places=5) diff --git a/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/test_pairs.py b/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/test_pairs.py deleted file mode 100644 index 2e8f5562..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/assortativity/tests/test_pairs.py +++ /dev/null @@ -1,109 +0,0 @@ -#!/usr/bin/env python -import networkx as nx -from .base_test import BaseTestAttributeMixing, BaseTestDegreeMixing - - -class TestAttributeMixingXY(BaseTestAttributeMixing): - - def test_node_attribute_xy_undirected(self): - attrxy = sorted(nx.node_attribute_xy(self.G, 'fish')) - attrxy_result = sorted([('one', 'one'), - ('one', 'one'), - ('two', 'two'), - ('two', 'two'), - ('one', 'red'), - ('red', 'one'), - ('blue', 'two'), - ('two', 'blue') - ]) - assert attrxy == attrxy_result - - def test_node_attribute_xy_undirected_nodes(self): - attrxy = sorted(nx.node_attribute_xy(self.G, 'fish', - nodes=['one', 'yellow'])) - attrxy_result = sorted([ - ]) - assert attrxy == attrxy_result - - def test_node_attribute_xy_directed(self): - attrxy = sorted(nx.node_attribute_xy(self.D, 'fish')) - attrxy_result = sorted([('one', 'one'), - ('two', 'two'), - ('one', 'red'), - ('two', 'blue') - ]) - assert attrxy == attrxy_result - - def test_node_attribute_xy_multigraph(self): - attrxy = sorted(nx.node_attribute_xy(self.M, 'fish')) - attrxy_result = [('one', 'one'), - ('one', 'one'), - ('one', 'one'), - ('one', 'one'), - ('two', 'two'), - ('two', 'two') - ] - assert attrxy == attrxy_result - - def test_node_attribute_xy_selfloop(self): - attrxy = sorted(nx.node_attribute_xy(self.S, 'fish')) - attrxy_result = [('one', 'one'), - ('two', 'two') - ] - assert attrxy == attrxy_result - - -class TestDegreeMixingXY(BaseTestDegreeMixing): - - def test_node_degree_xy_undirected(self): - xy = sorted(nx.node_degree_xy(self.P4)) - xy_result = sorted([(1, 2), - (2, 1), - (2, 2), - (2, 2), - (1, 2), - (2, 1)]) - assert xy == xy_result - - def test_node_degree_xy_undirected_nodes(self): - xy = sorted(nx.node_degree_xy(self.P4, nodes=[0, 1, -1])) - xy_result = sorted([(1, 2), - (2, 1), ]) - assert xy == xy_result - - def test_node_degree_xy_directed(self): - xy = sorted(nx.node_degree_xy(self.D)) - xy_result = sorted([(2, 1), - (2, 3), - (1, 3), - (1, 3)]) - assert xy == xy_result - - def test_node_degree_xy_multigraph(self): - xy = sorted(nx.node_degree_xy(self.M)) - xy_result = sorted([(2, 3), - (2, 3), - (3, 2), - (3, 2), - (2, 3), - (3, 2), - (1, 2), - (2, 1)]) - assert xy == xy_result - - def test_node_degree_xy_selfloop(self): - xy = sorted(nx.node_degree_xy(self.S)) - xy_result = sorted([(2, 2), - (2, 2)]) - assert xy == xy_result - - def test_node_degree_xy_weighted(self): - G = nx.Graph() - G.add_edge(1, 2, weight=7) - G.add_edge(2, 3, weight=10) - xy = sorted(nx.node_degree_xy(G, weight='weight')) - xy_result = sorted([(7, 17), - (17, 10), - (17, 7), - (10, 17)]) - assert xy == xy_result diff --git a/extensions/fablabchemnitz/networkx/algorithms/asteroidal.py b/extensions/fablabchemnitz/networkx/algorithms/asteroidal.py deleted file mode 100644 index 7d33671f..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/asteroidal.py +++ /dev/null @@ -1,175 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Haakon H. Rød (haakonhr@gmail.com) -""" -Algorithms for asteroidal triples and asteroidal numbers in graphs. - -An asteroidal triple in a graph G is a set of three non-adjacent vertices -u, v and w such that there exist a path between any two of them that avoids -closed neighborhood of the third. More formally, v_j, v_k belongs to the same -connected component of G - N[v_i], where N[v_i] denotes the closed neighborhood -of v_i. A graph which does not contain any asteroidal triples is called -an AT-free graph. The class of AT-free graphs is a graph class for which -many NP-complete problems are solvable in polynomial time. Amongst them, -independent set and coloring. -""" -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ["is_at_free", "find_asteroidal_triple"] - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -def find_asteroidal_triple(G): - r"""Find an asteroidal triple in the given graph. - - An asteroidal triple is a triple of non-adjacent vertices such that - there exists a path between any two of them which avoids the closed - neighborhood of the third. It checks all independent triples of vertices - and whether they are an asteroidal triple or not. This is done with the - help of a data structure called a component structure. - A component structure encodes information about which vertices belongs to - the same connected component when the closed neighborhood of a given vertex - is removed from the graph. The algorithm used to check is the trivial - one, outlined in [1]_, which has a runtime of - :math:`O(|V||\overline{E} + |V||E|)`, where the second term is the - creation of the component structure. - - Parameters - ---------- - G : NetworkX Graph - The graph to check whether is AT-free or not - - Returns - ------- - list or None - An asteroidal triple is returned as a list of nodes. If no asteroidal - triple exists, i.e. the graph is AT-free, then None is returned. - The returned value depends on the certificate parameter. The default - option is a bool which is True if the graph is AT-free, i.e. the - given graph contains no asteroidal triples, and False otherwise, i.e. - if the graph contains at least one asteroidal triple. - - Notes - ----- - The component structure and the algorithm is described in [1]_. The current - implementation implements the trivial algorithm for simple graphs. - - References - ---------- - .. [1] Ekkehard Köhler, - "Recognizing Graphs without asteroidal triples", - Journal of Discrete Algorithms 2, pages 439-452, 2004. - https://www.sciencedirect.com/science/article/pii/S157086670400019X - """ - V = set(G.nodes) - - if len(V) < 6: - # An asteroidal triple cannot exist in a graph with 5 or less vertices. - return None - - component_structure = create_component_structure(G) - E_complement = set(nx.complement(G).edges) - - for e in E_complement: - u = e[0] - v = e[1] - u_neighborhood = set(G[u]).union([u]) - v_neighborhood = set(G[v]).union([v]) - union_of_neighborhoods = u_neighborhood.union(v_neighborhood) - for w in V - union_of_neighborhoods: - """Check for each pair of vertices whether they belong to the - same connected component when the closed neighborhood of the - third is removed.""" - if (component_structure[u][v] == component_structure[u][w] and - component_structure[v][u] == component_structure[v][w] and - component_structure[w][u] == component_structure[w][v]): - return [u, v, w] - - return None - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -def is_at_free(G): - """Check if a graph is AT-free. - - The method uses the `find_asteroidal_triple` method to recognize - an AT-free graph. If no asteroidal triple is found the graph is - AT-free and True is returned. If at least one asteroidal triple is - found the graph is not AT-free and False is returned. - - Parameters - ---------- - G : NetworkX Graph - The graph to check whether is AT-free or not. - - Returns - ------- - bool - True if G is AT-free and False otherwise. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (1, 2), (1, 3), (1, 4), (4, 5)]) - >>> nx.is_at_free(G) - True - - >>> G = nx.cycle_graph(6) - >>> nx.is_at_free(G) - False - """ - return find_asteroidal_triple(G) is None - - -@not_implemented_for("directed") -@not_implemented_for("multigraph") -def create_component_structure(G): - r"""Create component structure for G. - - A *component structure* is an `nxn` array, denoted `c`, where `n` is - the number of vertices, where each row and column corresponds to a vertex. - - .. math:: - c_{uv} = \begin{cases} 0, if v \in N[u] \\ - k, if v \in component k of G \setminus N[u] \end{cases} - - Where `k` is an arbitrary label for each component. The structure is used - to simplify the detection of asteroidal triples. - - Parameters - ---------- - G : NetworkX Graph - Undirected, simple graph. - - Returns - ------- - component_structure : dictionary - A dictionary of dictionaries, keyed by pairs of vertices. - - """ - V = set(G.nodes) - component_structure = {} - for v in V: - label = 0 - closed_neighborhood = set(G[v]).union(set([v])) - row_dict = {} - for u in closed_neighborhood: - row_dict[u] = 0 - - G_reduced = G.subgraph(set(G.nodes) - closed_neighborhood) - for cc in nx.connected_components(G_reduced): - label += 1 - for u in cc: - row_dict[u] = label - - component_structure[v] = row_dict - - return component_structure diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/__init__.py deleted file mode 100644 index 23c6fc36..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/__init__.py +++ /dev/null @@ -1,87 +0,0 @@ -r""" This module provides functions and operations for bipartite -graphs. Bipartite graphs `B = (U, V, E)` have two node sets `U,V` and edges in -`E` that only connect nodes from opposite sets. It is common in the literature -to use an spatial analogy referring to the two node sets as top and bottom nodes. - -The bipartite algorithms are not imported into the networkx namespace -at the top level so the easiest way to use them is with: - ->>> import networkx as nx ->>> from networkx.algorithms import bipartite - -NetworkX does not have a custom bipartite graph class but the Graph() -or DiGraph() classes can be used to represent bipartite graphs. However, -you have to keep track of which set each node belongs to, and make -sure that there is no edge between nodes of the same set. The convention used -in NetworkX is to use a node attribute named `bipartite` with values 0 or 1 to -identify the sets each node belongs to. This convention is not enforced in -the source code of bipartite functions, it's only a recommendation. - -For example: - ->>> B = nx.Graph() ->>> # Add nodes with the node attribute "bipartite" ->>> B.add_nodes_from([1, 2, 3, 4], bipartite=0) ->>> B.add_nodes_from(['a', 'b', 'c'], bipartite=1) ->>> # Add edges only between nodes of opposite node sets ->>> B.add_edges_from([(1, 'a'), (1, 'b'), (2, 'b'), (2, 'c'), (3, 'c'), (4, 'a')]) - -Many algorithms of the bipartite module of NetworkX require, as an argument, a -container with all the nodes that belong to one set, in addition to the bipartite -graph `B`. The functions in the bipartite package do not check that the node set -is actually correct nor that the input graph is actually bipartite. -If `B` is connected, you can find the two node sets using a two-coloring -algorithm: - ->>> nx.is_connected(B) -True ->>> bottom_nodes, top_nodes = bipartite.sets(B) - -However, if the input graph is not connected, there are more than one possible -colorations. This is the reason why we require the user to pass a container -with all nodes of one bipartite node set as an argument to most bipartite -functions. In the face of ambiguity, we refuse the temptation to guess and -raise an :exc:`AmbiguousSolution ` -Exception if the input graph for -:func:`bipartite.sets ` -is disconnected. - -Using the `bipartite` node attribute, you can easily get the two node sets: - ->>> top_nodes = {n for n, d in B.nodes(data=True) if d['bipartite']==0} ->>> bottom_nodes = set(B) - top_nodes - -So you can easily use the bipartite algorithms that require, as an argument, a -container with all nodes that belong to one node set: - ->>> print(round(bipartite.density(B, bottom_nodes), 2)) -0.5 ->>> G = bipartite.projected_graph(B, top_nodes) - -All bipartite graph generators in NetworkX build bipartite graphs with the -`bipartite` node attribute. Thus, you can use the same approach: - ->>> RB = bipartite.random_graph(5, 7, 0.2) ->>> RB_top = {n for n, d in RB.nodes(data=True) if d['bipartite']==0} ->>> RB_bottom = set(RB) - RB_top ->>> list(RB_top) -[0, 1, 2, 3, 4] ->>> list(RB_bottom) -[5, 6, 7, 8, 9, 10, 11] - -For other bipartite graph generators see -:mod:`Generators `. - -""" - -from networkx.algorithms.bipartite.basic import * -from networkx.algorithms.bipartite.centrality import * -from networkx.algorithms.bipartite.cluster import * -from networkx.algorithms.bipartite.covering import * -from networkx.algorithms.bipartite.edgelist import * -from networkx.algorithms.bipartite.matching import * -from networkx.algorithms.bipartite.matrix import * -from networkx.algorithms.bipartite.projection import * -from networkx.algorithms.bipartite.redundancy import * -from networkx.algorithms.bipartite.spectral import * -from networkx.algorithms.bipartite.generators import * diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/basic.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/basic.py deleted file mode 100644 index 56cf4bb8..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/basic.py +++ /dev/null @@ -1,307 +0,0 @@ -# -*- coding: utf-8 -*- -""" -========================== -Bipartite Graph Algorithms -========================== -""" -# Copyright (C) 2013-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -import networkx as nx -from networkx.algorithms.components import connected_components -__author__ = """\n""".join(['Jordi Torrents ', - 'Aric Hagberg ']) -__all__ = ['is_bipartite', - 'is_bipartite_node_set', - 'color', - 'sets', - 'density', - 'degrees'] - - -def color(G): - """Returns a two-coloring of the graph. - - Raises an exception if the graph is not bipartite. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - color : dictionary - A dictionary keyed by node with a 1 or 0 as data for each node color. - - Raises - ------ - exc:`NetworkXError` if the graph is not two-colorable. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.path_graph(4) - >>> c = bipartite.color(G) - >>> print(c) - {0: 1, 1: 0, 2: 1, 3: 0} - - You can use this to set a node attribute indicating the biparite set: - - >>> nx.set_node_attributes(G, c, 'bipartite') - >>> print(G.nodes[0]['bipartite']) - 1 - >>> print(G.nodes[1]['bipartite']) - 0 - """ - if G.is_directed(): - import itertools - - def neighbors(v): - return itertools.chain.from_iterable([G.predecessors(v), - G.successors(v)]) - else: - neighbors = G.neighbors - - color = {} - for n in G: # handle disconnected graphs - if n in color or len(G[n]) == 0: # skip isolates - continue - queue = [n] - color[n] = 1 # nodes seen with color (1 or 0) - while queue: - v = queue.pop() - c = 1 - color[v] # opposite color of node v - for w in neighbors(v): - if w in color: - if color[w] == color[v]: - raise nx.NetworkXError("Graph is not bipartite.") - else: - color[w] = c - queue.append(w) - # color isolates with 0 - color.update(dict.fromkeys(nx.isolates(G), 0)) - return color - - -def is_bipartite(G): - """ Returns True if graph G is bipartite, False if not. - - Parameters - ---------- - G : NetworkX graph - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.path_graph(4) - >>> print(bipartite.is_bipartite(G)) - True - - See Also - -------- - color, is_bipartite_node_set - """ - try: - color(G) - return True - except nx.NetworkXError: - return False - - -def is_bipartite_node_set(G, nodes): - """Returns True if nodes and G/nodes are a bipartition of G. - - Parameters - ---------- - G : NetworkX graph - - nodes: list or container - Check if nodes are a one of a bipartite set. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.path_graph(4) - >>> X = set([1,3]) - >>> bipartite.is_bipartite_node_set(G,X) - True - - Notes - ----- - For connected graphs the bipartite sets are unique. This function handles - disconnected graphs. - """ - S = set(nodes) - for CC in (G.subgraph(c).copy() for c in connected_components(G)): - X, Y = sets(CC) - if not ((X.issubset(S) and Y.isdisjoint(S)) or - (Y.issubset(S) and X.isdisjoint(S))): - return False - return True - - -def sets(G, top_nodes=None): - """Returns bipartite node sets of graph G. - - Raises an exception if the graph is not bipartite or if the input - graph is disconnected and thus more than one valid solution exists. - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - Parameters - ---------- - G : NetworkX graph - - top_nodes : container, optional - Container with all nodes in one bipartite node set. If not supplied - it will be computed. But if more than one solution exists an exception - will be raised. - - Returns - ------- - X : set - Nodes from one side of the bipartite graph. - Y : set - Nodes from the other side. - - Raises - ------ - AmbiguousSolution - Raised if the input bipartite graph is disconnected and no container - with all nodes in one bipartite set is provided. When determining - the nodes in each bipartite set more than one valid solution is - possible if the input graph is disconnected. - NetworkXError - Raised if the input graph is not bipartite. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.path_graph(4) - >>> X, Y = bipartite.sets(G) - >>> list(X) - [0, 2] - >>> list(Y) - [1, 3] - - See Also - -------- - color - - """ - if G.is_directed(): - is_connected = nx.is_weakly_connected - else: - is_connected = nx.is_connected - if top_nodes is not None: - X = set(top_nodes) - Y = set(G) - X - else: - if not is_connected(G): - msg = 'Disconnected graph: Ambiguous solution for bipartite sets.' - raise nx.AmbiguousSolution(msg) - c = color(G) - X = {n for n, is_top in c.items() if is_top} - Y = {n for n, is_top in c.items() if not is_top} - return (X, Y) - - -def density(B, nodes): - """Returns density of bipartite graph B. - - Parameters - ---------- - G : NetworkX graph - - nodes: list or container - Nodes in one node set of the bipartite graph. - - Returns - ------- - d : float - The bipartite density - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.complete_bipartite_graph(3,2) - >>> X=set([0,1,2]) - >>> bipartite.density(G,X) - 1.0 - >>> Y=set([3,4]) - >>> bipartite.density(G,Y) - 1.0 - - Notes - ----- - The container of nodes passed as argument must contain all nodes - in one of the two bipartite node sets to avoid ambiguity in the - case of disconnected graphs. - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - color - """ - n = len(B) - m = nx.number_of_edges(B) - nb = len(nodes) - nt = n - nb - if m == 0: # includes cases n==0 and n==1 - d = 0.0 - else: - if B.is_directed(): - d = m / (2.0 * float(nb * nt)) - else: - d = m / float(nb * nt) - return d - - -def degrees(B, nodes, weight=None): - """Returns the degrees of the two node sets in the bipartite graph B. - - Parameters - ---------- - G : NetworkX graph - - nodes: list or container - Nodes in one node set of the bipartite graph. - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used as a weight. - If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - (degX,degY) : tuple of dictionaries - The degrees of the two bipartite sets as dictionaries keyed by node. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.complete_bipartite_graph(3,2) - >>> Y=set([3,4]) - >>> degX,degY=bipartite.degrees(G,Y) - >>> dict(degX) - {0: 2, 1: 2, 2: 2} - - Notes - ----- - The container of nodes passed as argument must contain all nodes - in one of the two bipartite node sets to avoid ambiguity in the - case of disconnected graphs. - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - color, density - """ - bottom = set(nodes) - top = set(B) - bottom - return (B.degree(top, weight), B.degree(bottom, weight)) diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/centrality.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/centrality.py deleted file mode 100644 index b1ce57b3..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/centrality.py +++ /dev/null @@ -1,274 +0,0 @@ -#-*- coding: utf-8 -*- -# Copyright (C) 2011 by -# Jordi Torrents -# Aric Hagberg -# All rights reserved. -# BSD license. -import networkx as nx -__author__ = """\n""".join(['Jordi Torrents ', - 'Aric Hagberg (hagberg@lanl.gov)']) -__all__ = ['degree_centrality', - 'betweenness_centrality', - 'closeness_centrality'] - - -def degree_centrality(G, nodes): - r"""Compute the degree centrality for nodes in a bipartite network. - - The degree centrality for a node `v` is the fraction of nodes - connected to it. - - Parameters - ---------- - G : graph - A bipartite network - - nodes : list or container - Container with all nodes in one bipartite node set. - - Returns - ------- - centrality : dictionary - Dictionary keyed by node with bipartite degree centrality as the value. - - See Also - -------- - betweenness_centrality, - closeness_centrality, - sets, - is_bipartite - - Notes - ----- - The nodes input parameter must contain all nodes in one bipartite node set, - but the dictionary returned contains all nodes from both bipartite node - sets. See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - For unipartite networks, the degree centrality values are - normalized by dividing by the maximum possible degree (which is - `n-1` where `n` is the number of nodes in G). - - In the bipartite case, the maximum possible degree of a node in a - bipartite node set is the number of nodes in the opposite node set - [1]_. The degree centrality for a node `v` in the bipartite - sets `U` with `n` nodes and `V` with `m` nodes is - - .. math:: - - d_{v} = \frac{deg(v)}{m}, \mbox{for} v \in U , - - d_{v} = \frac{deg(v)}{n}, \mbox{for} v \in V , - - - where `deg(v)` is the degree of node `v`. - - References - ---------- - .. [1] Borgatti, S.P. and Halgin, D. In press. "Analyzing Affiliation - Networks". In Carrington, P. and Scott, J. (eds) The Sage Handbook - of Social Network Analysis. Sage Publications. - http://www.steveborgatti.com/research/publications/bhaffiliations.pdf - """ - top = set(nodes) - bottom = set(G) - top - s = 1.0 / len(bottom) - centrality = dict((n, d * s) for n, d in G.degree(top)) - s = 1.0 / len(top) - centrality.update(dict((n, d * s) for n, d in G.degree(bottom))) - return centrality - - -def betweenness_centrality(G, nodes): - r"""Compute betweenness centrality for nodes in a bipartite network. - - Betweenness centrality of a node `v` is the sum of the - fraction of all-pairs shortest paths that pass through `v`. - - Values of betweenness are normalized by the maximum possible - value which for bipartite graphs is limited by the relative size - of the two node sets [1]_. - - Let `n` be the number of nodes in the node set `U` and - `m` be the number of nodes in the node set `V`, then - nodes in `U` are normalized by dividing by - - .. math:: - - \frac{1}{2} [m^2 (s + 1)^2 + m (s + 1)(2t - s - 1) - t (2s - t + 3)] , - - where - - .. math:: - - s = (n - 1) \div m , t = (n - 1) \mod m , - - and nodes in `V` are normalized by dividing by - - .. math:: - - \frac{1}{2} [n^2 (p + 1)^2 + n (p + 1)(2r - p - 1) - r (2p - r + 3)] , - - where, - - .. math:: - - p = (m - 1) \div n , r = (m - 1) \mod n . - - Parameters - ---------- - G : graph - A bipartite graph - - nodes : list or container - Container with all nodes in one bipartite node set. - - Returns - ------- - betweenness : dictionary - Dictionary keyed by node with bipartite betweenness centrality - as the value. - - See Also - -------- - degree_centrality, - closeness_centrality, - sets, - is_bipartite - - Notes - ----- - The nodes input parameter must contain all nodes in one bipartite node set, - but the dictionary returned contains all nodes from both node sets. - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - - References - ---------- - .. [1] Borgatti, S.P. and Halgin, D. In press. "Analyzing Affiliation - Networks". In Carrington, P. and Scott, J. (eds) The Sage Handbook - of Social Network Analysis. Sage Publications. - http://www.steveborgatti.com/research/publications/bhaffiliations.pdf - """ - top = set(nodes) - bottom = set(G) - top - n = float(len(top)) - m = float(len(bottom)) - s = (n - 1) // m - t = (n - 1) % m - bet_max_top = (((m**2) * ((s + 1)**2)) + - (m * (s + 1) * (2 * t - s - 1)) - - (t * ((2 * s) - t + 3))) / 2.0 - p = (m - 1) // n - r = (m - 1) % n - bet_max_bot = (((n**2) * ((p + 1)**2)) + - (n * (p + 1) * (2 * r - p - 1)) - - (r * ((2 * p) - r + 3))) / 2.0 - betweenness = nx.betweenness_centrality(G, normalized=False, - weight=None) - for node in top: - betweenness[node] /= bet_max_top - for node in bottom: - betweenness[node] /= bet_max_bot - return betweenness - - -def closeness_centrality(G, nodes, normalized=True): - r"""Compute the closeness centrality for nodes in a bipartite network. - - The closeness of a node is the distance to all other nodes in the - graph or in the case that the graph is not connected to all other nodes - in the connected component containing that node. - - Parameters - ---------- - G : graph - A bipartite network - - nodes : list or container - Container with all nodes in one bipartite node set. - - normalized : bool, optional - If True (default) normalize by connected component size. - - Returns - ------- - closeness : dictionary - Dictionary keyed by node with bipartite closeness centrality - as the value. - - See Also - -------- - betweenness_centrality, - degree_centrality - sets, - is_bipartite - - Notes - ----- - The nodes input parameter must contain all nodes in one bipartite node set, - but the dictionary returned contains all nodes from both node sets. - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - - Closeness centrality is normalized by the minimum distance possible. - In the bipartite case the minimum distance for a node in one bipartite - node set is 1 from all nodes in the other node set and 2 from all - other nodes in its own set [1]_. Thus the closeness centrality - for node `v` in the two bipartite sets `U` with - `n` nodes and `V` with `m` nodes is - - .. math:: - - c_{v} = \frac{m + 2(n - 1)}{d}, \mbox{for} v \in U, - - c_{v} = \frac{n + 2(m - 1)}{d}, \mbox{for} v \in V, - - where `d` is the sum of the distances from `v` to all - other nodes. - - Higher values of closeness indicate higher centrality. - - As in the unipartite case, setting normalized=True causes the - values to normalized further to n-1 / size(G)-1 where n is the - number of nodes in the connected part of graph containing the - node. If the graph is not completely connected, this algorithm - computes the closeness centrality for each connected part - separately. - - References - ---------- - .. [1] Borgatti, S.P. and Halgin, D. In press. "Analyzing Affiliation - Networks". In Carrington, P. and Scott, J. (eds) The Sage Handbook - of Social Network Analysis. Sage Publications. - http://www.steveborgatti.com/research/publications/bhaffiliations.pdf - """ - closeness = {} - path_length = nx.single_source_shortest_path_length - top = set(nodes) - bottom = set(G) - top - n = float(len(top)) - m = float(len(bottom)) - for node in top: - sp = dict(path_length(G, node)) - totsp = sum(sp.values()) - if totsp > 0.0 and len(G) > 1: - closeness[node] = (m + 2 * (n - 1)) / totsp - if normalized: - s = (len(sp) - 1.0) / (len(G) - 1) - closeness[node] *= s - else: - closeness[n] = 0.0 - for node in bottom: - sp = dict(path_length(G, node)) - totsp = sum(sp.values()) - if totsp > 0.0 and len(G) > 1: - closeness[node] = (n + 2 * (m - 1)) / totsp - if normalized: - s = (len(sp) - 1.0) / (len(G) - 1) - closeness[node] *= s - else: - closeness[n] = 0.0 - return closeness diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/cluster.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/cluster.py deleted file mode 100644 index f29bd151..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/cluster.py +++ /dev/null @@ -1,280 +0,0 @@ -#-*- coding: utf-8 -*- -# Copyright (C) 2011 by -# Jordi Torrents -# Aric Hagberg -# All rights reserved. -# BSD license. -import itertools -import networkx as nx -__author__ = """\n""".join(['Jordi Torrents ', - 'Aric Hagberg (hagberg@lanl.gov)']) -__all__ = ['clustering', - 'average_clustering', - 'latapy_clustering', - 'robins_alexander_clustering'] - -# functions for computing clustering of pairs - - -def cc_dot(nu, nv): - return float(len(nu & nv)) / len(nu | nv) - - -def cc_max(nu, nv): - return float(len(nu & nv)) / max(len(nu), len(nv)) - - -def cc_min(nu, nv): - return float(len(nu & nv)) / min(len(nu), len(nv)) - - -modes = {'dot': cc_dot, - 'min': cc_min, - 'max': cc_max} - - -def latapy_clustering(G, nodes=None, mode='dot'): - r"""Compute a bipartite clustering coefficient for nodes. - - The bipartie clustering coefficient is a measure of local density - of connections defined as [1]_: - - .. math:: - - c_u = \frac{\sum_{v \in N(N(u))} c_{uv} }{|N(N(u))|} - - where `N(N(u))` are the second order neighbors of `u` in `G` excluding `u`, - and `c_{uv}` is the pairwise clustering coefficient between nodes - `u` and `v`. - - The mode selects the function for `c_{uv}` which can be: - - `dot`: - - .. math:: - - c_{uv}=\frac{|N(u)\cap N(v)|}{|N(u) \cup N(v)|} - - `min`: - - .. math:: - - c_{uv}=\frac{|N(u)\cap N(v)|}{min(|N(u)|,|N(v)|)} - - `max`: - - .. math:: - - c_{uv}=\frac{|N(u)\cap N(v)|}{max(|N(u)|,|N(v)|)} - - - Parameters - ---------- - G : graph - A bipartite graph - - nodes : list or iterable (optional) - Compute bipartite clustering for these nodes. The default - is all nodes in G. - - mode : string - The pariwise bipartite clustering method to be used in the computation. - It must be "dot", "max", or "min". - - Returns - ------- - clustering : dictionary - A dictionary keyed by node with the clustering coefficient value. - - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.path_graph(4) # path graphs are bipartite - >>> c = bipartite.clustering(G) - >>> c[0] - 0.5 - >>> c = bipartite.clustering(G,mode='min') - >>> c[0] - 1.0 - - See Also - -------- - robins_alexander_clustering - square_clustering - average_clustering - - References - ---------- - .. [1] Latapy, Matthieu, Clémence Magnien, and Nathalie Del Vecchio (2008). - Basic notions for the analysis of large two-mode networks. - Social Networks 30(1), 31--48. - """ - if not nx.algorithms.bipartite.is_bipartite(G): - raise nx.NetworkXError("Graph is not bipartite") - - try: - cc_func = modes[mode] - except KeyError: - raise nx.NetworkXError( - "Mode for bipartite clustering must be: dot, min or max") - - if nodes is None: - nodes = G - ccs = {} - for v in nodes: - cc = 0.0 - nbrs2 = set([u for nbr in G[v] for u in G[nbr]]) - set([v]) - for u in nbrs2: - cc += cc_func(set(G[u]), set(G[v])) - if cc > 0.0: # len(nbrs2)>0 - cc /= len(nbrs2) - ccs[v] = cc - return ccs - - -clustering = latapy_clustering - - -def average_clustering(G, nodes=None, mode='dot'): - r"""Compute the average bipartite clustering coefficient. - - A clustering coefficient for the whole graph is the average, - - .. math:: - - C = \frac{1}{n}\sum_{v \in G} c_v, - - where `n` is the number of nodes in `G`. - - Similar measures for the two bipartite sets can be defined [1]_ - - .. math:: - - C_X = \frac{1}{|X|}\sum_{v \in X} c_v, - - where `X` is a bipartite set of `G`. - - Parameters - ---------- - G : graph - a bipartite graph - - nodes : list or iterable, optional - A container of nodes to use in computing the average. - The nodes should be either the entire graph (the default) or one of the - bipartite sets. - - mode : string - The pariwise bipartite clustering method. - It must be "dot", "max", or "min" - - Returns - ------- - clustering : float - The average bipartite clustering for the given set of nodes or the - entire graph if no nodes are specified. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G=nx.star_graph(3) # star graphs are bipartite - >>> bipartite.average_clustering(G) - 0.75 - >>> X,Y=bipartite.sets(G) - >>> bipartite.average_clustering(G,X) - 0.0 - >>> bipartite.average_clustering(G,Y) - 1.0 - - See Also - -------- - clustering - - Notes - ----- - The container of nodes passed to this function must contain all of the nodes - in one of the bipartite sets ("top" or "bottom") in order to compute - the correct average bipartite clustering coefficients. - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - - References - ---------- - .. [1] Latapy, Matthieu, Clémence Magnien, and Nathalie Del Vecchio (2008). - Basic notions for the analysis of large two-mode networks. - Social Networks 30(1), 31--48. - """ - if nodes is None: - nodes = G - ccs = latapy_clustering(G, nodes=nodes, mode=mode) - return float(sum(ccs[v] for v in nodes)) / len(nodes) - - -def robins_alexander_clustering(G): - r"""Compute the bipartite clustering of G. - - Robins and Alexander [1]_ defined bipartite clustering coefficient as - four times the number of four cycles `C_4` divided by the number of - three paths `L_3` in a bipartite graph: - - .. math:: - - CC_4 = \frac{4 * C_4}{L_3} - - Parameters - ---------- - G : graph - a bipartite graph - - Returns - ------- - clustering : float - The Robins and Alexander bipartite clustering for the input graph. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.davis_southern_women_graph() - >>> print(round(bipartite.robins_alexander_clustering(G), 3)) - 0.468 - - See Also - -------- - latapy_clustering - square_clustering - - References - ---------- - .. [1] Robins, G. and M. Alexander (2004). Small worlds among interlocking - directors: Network structure and distance in bipartite graphs. - Computational & Mathematical Organization Theory 10(1), 69–94. - - """ - if G.order() < 4 or G.size() < 3: - return 0 - L_3 = _threepaths(G) - if L_3 == 0: - return 0 - C_4 = _four_cycles(G) - return (4. * C_4) / L_3 - - -def _four_cycles(G): - cycles = 0 - for v in G: - for u, w in itertools.combinations(G[v], 2): - cycles += len((set(G[u]) & set(G[w])) - set([v])) - return cycles / 4 - - -def _threepaths(G): - paths = 0 - for v in G: - for u in G[v]: - for w in set(G[u]) - set([v]): - paths += len(set(G[w]) - set([v, u])) - # Divide by two because we count each three path twice - # one for each possible starting point - return paths / 2 diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/covering.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/covering.py deleted file mode 100644 index bc8f571b..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/covering.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2016-2019 NetworkX developers. -# Copyright (C) 2016 by -# Nishant Nikhil -# All rights reserved. -# BSD license. - -""" Functions related to graph covers.""" - -from networkx.utils import not_implemented_for -from networkx.algorithms.bipartite.matching import hopcroft_karp_matching -from networkx.algorithms.covering import min_edge_cover as _min_edge_cover - -__all__ = ['min_edge_cover'] - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def min_edge_cover(G, matching_algorithm=None): - """Returns a set of edges which constitutes - the minimum edge cover of the graph. - - The smallest edge cover can be found in polynomial time by finding - a maximum matching and extending it greedily so that all nodes - are covered. - - Parameters - ---------- - G : NetworkX graph - An undirected bipartite graph. - - matching_algorithm : function - A function that returns a maximum cardinality matching in a - given bipartite graph. The function must take one input, the - graph ``G``, and return a dictionary mapping each node to its - mate. If not specified, - :func:`~networkx.algorithms.bipartite.matching.hopcroft_karp_matching` - will be used. Other possibilities include - :func:`~networkx.algorithms.bipartite.matching.eppstein_matching`, - - Returns - ------- - set - A set of the edges in a minimum edge cover of the graph, given as - pairs of nodes. It contains both the edges `(u, v)` and `(v, u)` - for given nodes `u` and `v` among the edges of minimum edge cover. - - Notes - ----- - An edge cover of a graph is a set of edges such that every node of - the graph is incident to at least one edge of the set. - A minimum edge cover is an edge covering of smallest cardinality. - - Due to its implementation, the worst-case running time of this algorithm - is bounded by the worst-case running time of the function - ``matching_algorithm``. - """ - if G.order() == 0: # Special case for the empty graph - return set() - if matching_algorithm is None: - matching_algorithm = hopcroft_karp_matching - return _min_edge_cover(G, matching_algorithm=matching_algorithm) diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/edgelist.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/edgelist.py deleted file mode 100644 index c504ed9f..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/edgelist.py +++ /dev/null @@ -1,357 +0,0 @@ -""" -********** -Bipartite Edge Lists -********** -Read and write NetworkX graphs as bipartite edge lists. - -Format ------- -You can read or write three formats of edge lists with these functions. - -Node pairs with no data:: - - 1 2 - -Python dictionary as data:: - - 1 2 {'weight':7, 'color':'green'} - -Arbitrary data:: - - 1 2 7 green - -For each edge (u, v) the node u is assigned to part 0 and the node v to part 1. -""" -# Copyright (C) 2015 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -__all__ = ['generate_edgelist', - 'write_edgelist', - 'parse_edgelist', - 'read_edgelist'] - -import networkx as nx -from networkx.utils import open_file, make_str, not_implemented_for - - -@open_file(1, mode='wb') -def write_edgelist(G, path, comments="#", delimiter=' ', data=True, - encoding='utf-8'): - """Write a bipartite graph as a list of edges. - - Parameters - ---------- - G : Graph - A NetworkX bipartite graph - path : file or string - File or filename to write. If a file is provided, it must be - opened in 'wb' mode. Filenames ending in .gz or .bz2 will be compressed. - comments : string, optional - The character used to indicate the start of a comment - delimiter : string, optional - The string used to separate values. The default is whitespace. - data : bool or list, optional - If False write no edge data. - If True write a string representation of the edge data dictionary.. - If a list (or other iterable) is provided, write the keys specified - in the list. - encoding: string, optional - Specify which encoding to use when writing file. - - Examples - -------- - >>> G=nx.path_graph(4) - >>> G.add_nodes_from([0,2], bipartite=0) - >>> G.add_nodes_from([1,3], bipartite=1) - >>> nx.write_edgelist(G, "test.edgelist") - >>> fh=open("test.edgelist",'wb') - >>> nx.write_edgelist(G, fh) - >>> nx.write_edgelist(G, "test.edgelist.gz") - >>> nx.write_edgelist(G, "test.edgelist.gz", data=False) - - >>> G=nx.Graph() - >>> G.add_edge(1,2,weight=7,color='red') - >>> nx.write_edgelist(G,'test.edgelist',data=False) - >>> nx.write_edgelist(G,'test.edgelist',data=['color']) - >>> nx.write_edgelist(G,'test.edgelist',data=['color','weight']) - - See Also - -------- - write_edgelist() - generate_edgelist() - """ - for line in generate_edgelist(G, delimiter, data): - line += '\n' - path.write(line.encode(encoding)) - - -@not_implemented_for('directed') -def generate_edgelist(G, delimiter=' ', data=True): - """Generate a single line of the bipartite graph G in edge list format. - - Parameters - ---------- - G : NetworkX graph - The graph is assumed to have node attribute `part` set to 0,1 representing - the two graph parts - - delimiter : string, optional - Separator for node labels - - data : bool or list of keys - If False generate no edge data. If True use a dictionary - representation of edge data. If a list of keys use a list of data - values corresponding to the keys. - - Returns - ------- - lines : string - Lines of data in adjlist format. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.path_graph(4) - >>> G.add_nodes_from([0,2], bipartite=0) - >>> G.add_nodes_from([1,3], bipartite=1) - >>> G[1][2]['weight'] = 3 - >>> G[2][3]['capacity'] = 12 - >>> for line in bipartite.generate_edgelist(G, data=False): - ... print(line) - 0 1 - 2 1 - 2 3 - - >>> for line in bipartite.generate_edgelist(G): - ... print(line) - 0 1 {} - 2 1 {'weight': 3} - 2 3 {'capacity': 12} - - >>> for line in bipartite.generate_edgelist(G,data=['weight']): - ... print(line) - 0 1 - 2 1 3 - 2 3 - """ - try: - part0 = [n for n, d in G.nodes.items() if d['bipartite'] == 0] - except: - raise AttributeError("Missing node attribute `bipartite`") - if data is True or data is False: - for n in part0: - for e in G.edges(n, data=data): - yield delimiter.join(map(make_str, e)) - else: - for n in part0: - for u, v, d in G.edges(n, data=True): - e = [u, v] - try: - e.extend(d[k] for k in data) - except KeyError: - pass # missing data for this edge, should warn? - yield delimiter.join(map(make_str, e)) - - -def parse_edgelist(lines, comments='#', delimiter=None, - create_using=None, nodetype=None, data=True): - """Parse lines of an edge list representation of a bipartite graph. - - Parameters - ---------- - lines : list or iterator of strings - Input data in edgelist format - comments : string, optional - Marker for comment lines - delimiter : string, optional - Separator for node labels - create_using: NetworkX graph container, optional - Use given NetworkX graph for holding nodes or edges. - nodetype : Python type, optional - Convert nodes to this type. - data : bool or list of (label,type) tuples - If False generate no edge data or if True use a dictionary - representation of edge data or a list tuples specifying dictionary - key names and types for edge data. - - Returns - ------- - G: NetworkX Graph - The bipartite graph corresponding to lines - - Examples - -------- - Edgelist with no data: - - >>> from networkx.algorithms import bipartite - >>> lines = ["1 2", - ... "2 3", - ... "3 4"] - >>> G = bipartite.parse_edgelist(lines, nodetype = int) - >>> sorted(G.nodes()) - [1, 2, 3, 4] - >>> sorted(G.nodes(data=True)) - [(1, {'bipartite': 0}), (2, {'bipartite': 0}), (3, {'bipartite': 0}), (4, {'bipartite': 1})] - >>> sorted(G.edges()) - [(1, 2), (2, 3), (3, 4)] - - Edgelist with data in Python dictionary representation: - - >>> lines = ["1 2 {'weight':3}", - ... "2 3 {'weight':27}", - ... "3 4 {'weight':3.0}"] - >>> G = bipartite.parse_edgelist(lines, nodetype = int) - >>> sorted(G.nodes()) - [1, 2, 3, 4] - >>> sorted(G.edges(data = True)) - [(1, 2, {'weight': 3}), (2, 3, {'weight': 27}), (3, 4, {'weight': 3.0})] - - Edgelist with data in a list: - - >>> lines = ["1 2 3", - ... "2 3 27", - ... "3 4 3.0"] - >>> G = bipartite.parse_edgelist(lines, nodetype = int, data=(('weight',float),)) - >>> sorted(G.nodes()) - [1, 2, 3, 4] - >>> sorted(G.edges(data = True)) - [(1, 2, {'weight': 3.0}), (2, 3, {'weight': 27.0}), (3, 4, {'weight': 3.0})] - - See Also - -------- - """ - from ast import literal_eval - G = nx.empty_graph(0, create_using) - for line in lines: - p = line.find(comments) - if p >= 0: - line = line[:p] - if not len(line): - continue - # split line, should have 2 or more - s = line.strip().split(delimiter) - if len(s) < 2: - continue - u = s.pop(0) - v = s.pop(0) - d = s - if nodetype is not None: - try: - u = nodetype(u) - v = nodetype(v) - except: - raise TypeError("Failed to convert nodes %s,%s to type %s." - % (u, v, nodetype)) - - if len(d) == 0 or data is False: - # no data or data type specified - edgedata = {} - elif data is True: - # no edge types specified - try: # try to evaluate as dictionary - edgedata = dict(literal_eval(' '.join(d))) - except: - raise TypeError( - "Failed to convert edge data (%s) to dictionary." % (d)) - else: - # convert edge data to dictionary with specified keys and type - if len(d) != len(data): - raise IndexError( - "Edge data %s and data_keys %s are not the same length" % - (d, data)) - edgedata = {} - for (edge_key, edge_type), edge_value in zip(data, d): - try: - edge_value = edge_type(edge_value) - except: - raise TypeError( - "Failed to convert %s data %s to type %s." - % (edge_key, edge_value, edge_type)) - edgedata.update({edge_key: edge_value}) - G.add_node(u, bipartite=0) - G.add_node(v, bipartite=1) - G.add_edge(u, v, **edgedata) - return G - - -@open_file(0, mode='rb') -def read_edgelist(path, comments="#", - delimiter=None, create_using=None, - nodetype=None, data=True, edgetype=None, - encoding='utf-8'): - """Read a bipartite graph from a list of edges. - - Parameters - ---------- - path : file or string - File or filename to read. If a file is provided, it must be - opened in 'rb' mode. - Filenames ending in .gz or .bz2 will be uncompressed. - comments : string, optional - The character used to indicate the start of a comment. - delimiter : string, optional - The string used to separate values. The default is whitespace. - create_using : Graph container, optional, - Use specified container to build graph. The default is networkx.Graph, - an undirected graph. - nodetype : int, float, str, Python type, optional - Convert node data from strings to specified type - data : bool or list of (label,type) tuples - Tuples specifying dictionary key names and types for edge data - edgetype : int, float, str, Python type, optional OBSOLETE - Convert edge data from strings to specified type and use as 'weight' - encoding: string, optional - Specify which encoding to use when reading file. - - Returns - ------- - G : graph - A networkx Graph or other type specified with create_using - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.path_graph(4) - >>> G.add_nodes_from([0,2], bipartite=0) - >>> G.add_nodes_from([1,3], bipartite=1) - >>> bipartite.write_edgelist(G, "test.edgelist") - >>> G = bipartite.read_edgelist("test.edgelist") - - >>> fh = open("test.edgelist", 'rb') - >>> G = bipartite.read_edgelist(fh) - >>> fh.close() - - >>> G=bipartite.read_edgelist("test.edgelist", nodetype=int) - - Edgelist with data in a list: - - >>> textline = '1 2 3' - >>> fh = open('test.edgelist','w') - >>> d = fh.write(textline) - >>> fh.close() - >>> G = bipartite.read_edgelist('test.edgelist', nodetype=int, data=(('weight',float),)) - >>> list(G) - [1, 2] - >>> list(G.edges(data=True)) - [(1, 2, {'weight': 3.0})] - - See parse_edgelist() for more examples of formatting. - - See Also - -------- - parse_edgelist - - Notes - ----- - Since nodes must be hashable, the function nodetype must return hashable - types (e.g. int, float, str, frozenset - or tuples of those, etc.) - """ - lines = (line.decode(encoding) for line in path) - return parse_edgelist(lines, comments=comments, - delimiter=delimiter, - create_using=create_using, - nodetype=nodetype, - data=data) diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/generators.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/generators.py deleted file mode 100644 index 00635ff8..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/generators.py +++ /dev/null @@ -1,606 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2006-2011 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg -# Pieter Swart -# Dan Schult -""" -Generators and functions for bipartite graphs. -""" -import math -import numbers -import random -from functools import reduce -import networkx as nx -from networkx.utils import nodes_or_number, py_random_state - -__all__ = ['configuration_model', - 'havel_hakimi_graph', - 'reverse_havel_hakimi_graph', - 'alternating_havel_hakimi_graph', - 'preferential_attachment_graph', - 'random_graph', - 'gnmk_random_graph', - 'complete_bipartite_graph', - ] - - -@nodes_or_number([0, 1]) -def complete_bipartite_graph(n1, n2, create_using=None): - """Returns the complete bipartite graph `K_{n_1,n_2}`. - - The graph is composed of two partitions with nodes 0 to (n1 - 1) - in the first and nodes n1 to (n1 + n2 - 1) in the second. - Each node in the first is connected to each node in the second. - - Parameters - ---------- - n1 : integer - Number of nodes for node set A. - n2 : integer - Number of nodes for node set B. - create_using : NetworkX graph instance, optional - Return graph of this type. - - Notes - ----- - Node labels are the integers 0 to `n_1 + n_2 - 1`. - - The nodes are assigned the attribute 'bipartite' with the value 0 or 1 - to indicate which bipartite set the node belongs to. - - This function is not imported in the main namespace. - To use it use nx.bipartite.complete_bipartite_graph - """ - G = nx.empty_graph(0, create_using) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - n1, top = n1 - n2, bottom = n2 - if isinstance(n2, numbers.Integral): - bottom = [n1 + i for i in bottom] - G.add_nodes_from(top, bipartite=0) - G.add_nodes_from(bottom, bipartite=1) - G.add_edges_from((u, v) for u in top for v in bottom) - G.graph['name'] = "complete_bipartite_graph(%s,%s)" % (n1, n2) - return G - - -@py_random_state(3) -def configuration_model(aseq, bseq, create_using=None, seed=None): - """Returns a random bipartite graph from two given degree sequences. - - Parameters - ---------- - aseq : list - Degree sequence for node set A. - bseq : list - Degree sequence for node set B. - create_using : NetworkX graph instance, optional - Return graph of this type. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - The graph is composed of two partitions. Set A has nodes 0 to - (len(aseq) - 1) and set B has nodes len(aseq) to (len(bseq) - 1). - Nodes from set A are connected to nodes in set B by choosing - randomly from the possible free stubs, one in A and one in B. - - Notes - ----- - The sum of the two sequences must be equal: sum(aseq)=sum(bseq) - If no graph type is specified use MultiGraph with parallel edges. - If you want a graph with no parallel edges use create_using=Graph() - but then the resulting degree sequences might not be exact. - - The nodes are assigned the attribute 'bipartite' with the value 0 or 1 - to indicate which bipartite set the node belongs to. - - This function is not imported in the main namespace. - To use it use nx.bipartite.configuration_model - """ - G = nx.empty_graph(0, create_using, default=nx.MultiGraph) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - # length and sum of each sequence - lena = len(aseq) - lenb = len(bseq) - suma = sum(aseq) - sumb = sum(bseq) - - if not suma == sumb: - raise nx.NetworkXError( - 'invalid degree sequences, sum(aseq)!=sum(bseq),%s,%s' - % (suma, sumb)) - - G = _add_nodes_with_bipartite_label(G, lena, lenb) - - if len(aseq) == 0 or max(aseq) == 0: - return G # done if no edges - - # build lists of degree-repeated vertex numbers - stubs = [] - stubs.extend([[v] * aseq[v] for v in range(0, lena)]) - astubs = [] - astubs = [x for subseq in stubs for x in subseq] - - stubs = [] - stubs.extend([[v] * bseq[v - lena] for v in range(lena, lena + lenb)]) - bstubs = [] - bstubs = [x for subseq in stubs for x in subseq] - - # shuffle lists - seed.shuffle(astubs) - seed.shuffle(bstubs) - - G.add_edges_from([[astubs[i], bstubs[i]] for i in range(suma)]) - - G.name = "bipartite_configuration_model" - return G - - -def havel_hakimi_graph(aseq, bseq, create_using=None): - """Returns a bipartite graph from two given degree sequences using a - Havel-Hakimi style construction. - - The graph is composed of two partitions. Set A has nodes 0 to - (len(aseq) - 1) and set B has nodes len(aseq) to (len(bseq) - 1). - Nodes from the set A are connected to nodes in the set B by - connecting the highest degree nodes in set A to the highest degree - nodes in set B until all stubs are connected. - - Parameters - ---------- - aseq : list - Degree sequence for node set A. - bseq : list - Degree sequence for node set B. - create_using : NetworkX graph instance, optional - Return graph of this type. - - Notes - ----- - The sum of the two sequences must be equal: sum(aseq)=sum(bseq) - If no graph type is specified use MultiGraph with parallel edges. - If you want a graph with no parallel edges use create_using=Graph() - but then the resulting degree sequences might not be exact. - - The nodes are assigned the attribute 'bipartite' with the value 0 or 1 - to indicate which bipartite set the node belongs to. - - This function is not imported in the main namespace. - To use it use nx.bipartite.havel_hakimi_graph - """ - G = nx.empty_graph(0, create_using, default=nx.MultiGraph) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - # length of the each sequence - naseq = len(aseq) - nbseq = len(bseq) - - suma = sum(aseq) - sumb = sum(bseq) - - if not suma == sumb: - raise nx.NetworkXError( - 'invalid degree sequences, sum(aseq)!=sum(bseq),%s,%s' - % (suma, sumb)) - - G = _add_nodes_with_bipartite_label(G, naseq, nbseq) - - if len(aseq) == 0 or max(aseq) == 0: - return G # done if no edges - - # build list of degree-repeated vertex numbers - astubs = [[aseq[v], v] for v in range(0, naseq)] - bstubs = [[bseq[v - naseq], v] for v in range(naseq, naseq + nbseq)] - astubs.sort() - while astubs: - (degree, u) = astubs.pop() # take of largest degree node in the a set - if degree == 0: - break # done, all are zero - # connect the source to largest degree nodes in the b set - bstubs.sort() - for target in bstubs[-degree:]: - v = target[1] - G.add_edge(u, v) - target[0] -= 1 # note this updates bstubs too. - if target[0] == 0: - bstubs.remove(target) - - G.name = "bipartite_havel_hakimi_graph" - return G - - -def reverse_havel_hakimi_graph(aseq, bseq, create_using=None): - """Returns a bipartite graph from two given degree sequences using a - Havel-Hakimi style construction. - - The graph is composed of two partitions. Set A has nodes 0 to - (len(aseq) - 1) and set B has nodes len(aseq) to (len(bseq) - 1). - Nodes from set A are connected to nodes in the set B by connecting - the highest degree nodes in set A to the lowest degree nodes in - set B until all stubs are connected. - - Parameters - ---------- - aseq : list - Degree sequence for node set A. - bseq : list - Degree sequence for node set B. - create_using : NetworkX graph instance, optional - Return graph of this type. - - Notes - ----- - The sum of the two sequences must be equal: sum(aseq)=sum(bseq) - If no graph type is specified use MultiGraph with parallel edges. - If you want a graph with no parallel edges use create_using=Graph() - but then the resulting degree sequences might not be exact. - - The nodes are assigned the attribute 'bipartite' with the value 0 or 1 - to indicate which bipartite set the node belongs to. - - This function is not imported in the main namespace. - To use it use nx.bipartite.reverse_havel_hakimi_graph - """ - G = nx.empty_graph(0, create_using, default=nx.MultiGraph) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - # length of the each sequence - lena = len(aseq) - lenb = len(bseq) - suma = sum(aseq) - sumb = sum(bseq) - - if not suma == sumb: - raise nx.NetworkXError( - 'invalid degree sequences, sum(aseq)!=sum(bseq),%s,%s' - % (suma, sumb)) - - G = _add_nodes_with_bipartite_label(G, lena, lenb) - - if len(aseq) == 0 or max(aseq) == 0: - return G # done if no edges - - # build list of degree-repeated vertex numbers - astubs = [[aseq[v], v] for v in range(0, lena)] - bstubs = [[bseq[v - lena], v] for v in range(lena, lena + lenb)] - astubs.sort() - bstubs.sort() - while astubs: - (degree, u) = astubs.pop() # take of largest degree node in the a set - if degree == 0: - break # done, all are zero - # connect the source to the smallest degree nodes in the b set - for target in bstubs[0:degree]: - v = target[1] - G.add_edge(u, v) - target[0] -= 1 # note this updates bstubs too. - if target[0] == 0: - bstubs.remove(target) - - G.name = "bipartite_reverse_havel_hakimi_graph" - return G - - -def alternating_havel_hakimi_graph(aseq, bseq, create_using=None): - """Returns a bipartite graph from two given degree sequences using - an alternating Havel-Hakimi style construction. - - The graph is composed of two partitions. Set A has nodes 0 to - (len(aseq) - 1) and set B has nodes len(aseq) to (len(bseq) - 1). - Nodes from the set A are connected to nodes in the set B by - connecting the highest degree nodes in set A to alternatively the - highest and the lowest degree nodes in set B until all stubs are - connected. - - Parameters - ---------- - aseq : list - Degree sequence for node set A. - bseq : list - Degree sequence for node set B. - create_using : NetworkX graph instance, optional - Return graph of this type. - - Notes - ----- - The sum of the two sequences must be equal: sum(aseq)=sum(bseq) - If no graph type is specified use MultiGraph with parallel edges. - If you want a graph with no parallel edges use create_using=Graph() - but then the resulting degree sequences might not be exact. - - The nodes are assigned the attribute 'bipartite' with the value 0 or 1 - to indicate which bipartite set the node belongs to. - - This function is not imported in the main namespace. - To use it use nx.bipartite.alternating_havel_hakimi_graph - """ - G = nx.empty_graph(0, create_using, default=nx.MultiGraph) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - # length of the each sequence - naseq = len(aseq) - nbseq = len(bseq) - suma = sum(aseq) - sumb = sum(bseq) - - if not suma == sumb: - raise nx.NetworkXError( - 'invalid degree sequences, sum(aseq)!=sum(bseq),%s,%s' - % (suma, sumb)) - - G = _add_nodes_with_bipartite_label(G, naseq, nbseq) - - if len(aseq) == 0 or max(aseq) == 0: - return G # done if no edges - # build list of degree-repeated vertex numbers - astubs = [[aseq[v], v] for v in range(0, naseq)] - bstubs = [[bseq[v - naseq], v] for v in range(naseq, naseq + nbseq)] - while astubs: - astubs.sort() - (degree, u) = astubs.pop() # take of largest degree node in the a set - if degree == 0: - break # done, all are zero - bstubs.sort() - small = bstubs[0:degree // 2] # add these low degree targets - large = bstubs[(-degree + degree // 2):] # now high degree targets - stubs = [x for z in zip(large, small) for x in z] # combine, sorry - if len(stubs) < len(small) + len(large): # check for zip truncation - stubs.append(large.pop()) - for target in stubs: - v = target[1] - G.add_edge(u, v) - target[0] -= 1 # note this updates bstubs too. - if target[0] == 0: - bstubs.remove(target) - - G.name = "bipartite_alternating_havel_hakimi_graph" - return G - - -@py_random_state(3) -def preferential_attachment_graph(aseq, p, create_using=None, seed=None): - """Create a bipartite graph with a preferential attachment model from - a given single degree sequence. - - The graph is composed of two partitions. Set A has nodes 0 to - (len(aseq) - 1) and set B has nodes starting with node len(aseq). - The number of nodes in set B is random. - - Parameters - ---------- - aseq : list - Degree sequence for node set A. - p : float - Probability that a new bottom node is added. - create_using : NetworkX graph instance, optional - Return graph of this type. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - References - ---------- - .. [1] Guillaume, J.L. and Latapy, M., - Bipartite graphs as models of complex networks. - Physica A: Statistical Mechanics and its Applications, - 2006, 371(2), pp.795-813. - .. [2] Jean-Loup Guillaume and Matthieu Latapy, - Bipartite structure of all complex networks, - Inf. Process. Lett. 90, 2004, pg. 215-221 - https://doi.org/10.1016/j.ipl.2004.03.007 - - Notes - ----- - The nodes are assigned the attribute 'bipartite' with the value 0 or 1 - to indicate which bipartite set the node belongs to. - - This function is not imported in the main namespace. - To use it use nx.bipartite.preferential_attachment_graph - """ - G = nx.empty_graph(0, create_using, default=nx.MultiGraph) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - if p > 1: - raise nx.NetworkXError("probability %s > 1" % (p)) - - naseq = len(aseq) - G = _add_nodes_with_bipartite_label(G, naseq, 0) - vv = [[v] * aseq[v] for v in range(0, naseq)] - while vv: - while vv[0]: - source = vv[0][0] - vv[0].remove(source) - if seed.random() < p or len(G) == naseq: - target = len(G) - G.add_node(target, bipartite=1) - G.add_edge(source, target) - else: - bb = [[b] * G.degree(b) for b in range(naseq, len(G))] - # flatten the list of lists into a list. - bbstubs = reduce(lambda x, y: x + y, bb) - # choose preferentially a bottom node. - target = seed.choice(bbstubs) - G.add_node(target, bipartite=1) - G.add_edge(source, target) - vv.remove(vv[0]) - G.name = "bipartite_preferential_attachment_model" - return G - - -@py_random_state(3) -def random_graph(n, m, p, seed=None, directed=False): - """Returns a bipartite random graph. - - This is a bipartite version of the binomial (Erdős-Rényi) graph. - The graph is composed of two partitions. Set A has nodes 0 to - (n - 1) and set B has nodes n to (n + m - 1). - - Parameters - ---------- - n : int - The number of nodes in the first bipartite set. - m : int - The number of nodes in the second bipartite set. - p : float - Probability for edge creation. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - directed : bool, optional (default=False) - If True return a directed graph - - Notes - ----- - The bipartite random graph algorithm chooses each of the n*m (undirected) - or 2*nm (directed) possible edges with probability p. - - This algorithm is $O(n+m)$ where $m$ is the expected number of edges. - - The nodes are assigned the attribute 'bipartite' with the value 0 or 1 - to indicate which bipartite set the node belongs to. - - This function is not imported in the main namespace. - To use it use nx.bipartite.random_graph - - See Also - -------- - gnp_random_graph, configuration_model - - References - ---------- - .. [1] Vladimir Batagelj and Ulrik Brandes, - "Efficient generation of large random networks", - Phys. Rev. E, 71, 036113, 2005. - """ - G = nx.Graph() - G = _add_nodes_with_bipartite_label(G, n, m) - if directed: - G = nx.DiGraph(G) - G.name = "fast_gnp_random_graph(%s,%s,%s)" % (n, m, p) - - if p <= 0: - return G - if p >= 1: - return nx.complete_bipartite_graph(n, m) - - lp = math.log(1.0 - p) - - v = 0 - w = -1 - while v < n: - lr = math.log(1.0 - seed.random()) - w = w + 1 + int(lr / lp) - while w >= m and v < n: - w = w - m - v = v + 1 - if v < n: - G.add_edge(v, n + w) - - if directed: - # use the same algorithm to - # add edges from the "m" to "n" set - v = 0 - w = -1 - while v < n: - lr = math.log(1.0 - seed.random()) - w = w + 1 + int(lr / lp) - while w >= m and v < n: - w = w - m - v = v + 1 - if v < n: - G.add_edge(n + w, v) - - return G - - -@py_random_state(3) -def gnmk_random_graph(n, m, k, seed=None, directed=False): - """Returns a random bipartite graph G_{n,m,k}. - - Produces a bipartite graph chosen randomly out of the set of all graphs - with n top nodes, m bottom nodes, and k edges. - The graph is composed of two sets of nodes. - Set A has nodes 0 to (n - 1) and set B has nodes n to (n + m - 1). - - Parameters - ---------- - n : int - The number of nodes in the first bipartite set. - m : int - The number of nodes in the second bipartite set. - k : int - The number of edges - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - directed : bool, optional (default=False) - If True return a directed graph - - Examples - -------- - from nx.algorithms import bipartite - G = bipartite.gnmk_random_graph(10,20,50) - - See Also - -------- - gnm_random_graph - - Notes - ----- - If k > m * n then a complete bipartite graph is returned. - - This graph is a bipartite version of the `G_{nm}` random graph model. - - The nodes are assigned the attribute 'bipartite' with the value 0 or 1 - to indicate which bipartite set the node belongs to. - - This function is not imported in the main namespace. - To use it use nx.bipartite.gnmk_random_graph - """ - G = nx.Graph() - G = _add_nodes_with_bipartite_label(G, n, m) - if directed: - G = nx.DiGraph(G) - G.name = "bipartite_gnm_random_graph(%s,%s,%s)" % (n, m, k) - if n == 1 or m == 1: - return G - max_edges = n * m # max_edges for bipartite networks - if k >= max_edges: # Maybe we should raise an exception here - return nx.complete_bipartite_graph(n, m, create_using=G) - - top = [n for n, d in G.nodes(data=True) if d['bipartite'] == 0] - bottom = list(set(G) - set(top)) - edge_count = 0 - while edge_count < k: - # generate random edge,u,v - u = seed.choice(top) - v = seed.choice(bottom) - if v in G[u]: - continue - else: - G.add_edge(u, v) - edge_count += 1 - return G - - -def _add_nodes_with_bipartite_label(G, lena, lenb): - G.add_nodes_from(range(0, lena + lenb)) - b = dict(zip(range(0, lena), [0] * lena)) - b.update(dict(zip(range(lena, lena + lenb), [1] * lenb))) - nx.set_node_attributes(G, b, 'bipartite') - return G diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/matching.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/matching.py deleted file mode 100644 index 1c866cdf..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/matching.py +++ /dev/null @@ -1,580 +0,0 @@ -# matching.py - bipartite graph maximum matching algorithms -# -# Copyright 2015 Jeffrey Finkelstein , -# Copyright 2019 Søren Fuglede Jørgensen -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -# -# This module uses material from the Wikipedia article Hopcroft--Karp algorithm -# , accessed on -# January 3, 2015, which is released under the Creative Commons -# Attribution-Share-Alike License 3.0 -# . That article includes -# pseudocode, which has been translated into the corresponding Python code. -# -# Portions of this module use code from David Eppstein's Python Algorithms and -# Data Structures (PADS) library, which is dedicated to the public domain (for -# proof, see ). -"""Provides functions for computing maximum cardinality matchings and minimum -weight full matchings in a bipartite graph. - -If you don't care about the particular implementation of the maximum matching -algorithm, simply use the :func:`maximum_matching`. If you do care, you can -import one of the named maximum matching algorithms directly. - -For example, to find a maximum matching in the complete bipartite graph with -two vertices on the left and three vertices on the right: - ->>> import networkx as nx ->>> G = nx.complete_bipartite_graph(2, 3) ->>> left, right = nx.bipartite.sets(G) ->>> list(left) -[0, 1] ->>> list(right) -[2, 3, 4] ->>> nx.bipartite.maximum_matching(G) -{0: 2, 1: 3, 2: 0, 3: 1} - -The dictionary returned by :func:`maximum_matching` includes a mapping for -vertices in both the left and right vertex sets. - -Similarly, :func:`minimum_weight_full_matching` produces, for a complete -weighted bipartite graph, a matching whose cardinality is the cardinality of -the smaller of the two partitions, and for which the sum of the weights of the -edges included in the matching is minimal. - -""" -import collections -import itertools - -from networkx.algorithms.bipartite.matrix import biadjacency_matrix -from networkx.algorithms.bipartite import sets as bipartite_sets -import networkx as nx - -__all__ = ['maximum_matching', 'hopcroft_karp_matching', 'eppstein_matching', - 'to_vertex_cover', 'minimum_weight_full_matching'] - -INFINITY = float('inf') - - -def hopcroft_karp_matching(G, top_nodes=None): - """Returns the maximum cardinality matching of the bipartite graph `G`. - - Parameters - ---------- - G : NetworkX graph - - Undirected bipartite graph - - top_nodes : container - - Container with all nodes in one bipartite node set. If not supplied - it will be computed. But if more than one solution exists an exception - will be raised. - - Returns - ------- - matches : dictionary - - The matching is returned as a dictionary, `matches`, such that - ``matches[v] == w`` if node `v` is matched to node `w`. Unmatched - nodes do not occur as a key in mate. - - Raises - ------ - AmbiguousSolution : Exception - - Raised if the input bipartite graph is disconnected and no container - with all nodes in one bipartite set is provided. When determining - the nodes in each bipartite set more than one valid solution is - possible if the input graph is disconnected. - - Notes - ----- - This function is implemented with the `Hopcroft--Karp matching algorithm - `_ for - bipartite graphs. - - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - - eppstein_matching - - References - ---------- - .. [1] John E. Hopcroft and Richard M. Karp. "An n^{5 / 2} Algorithm for - Maximum Matchings in Bipartite Graphs" In: **SIAM Journal of Computing** - 2.4 (1973), pp. 225--231. . - - """ - # First we define some auxiliary search functions. - # - # If you are a human reading these auxiliary search functions, the "global" - # variables `leftmatches`, `rightmatches`, `distances`, etc. are defined - # below the functions, so that they are initialized close to the initial - # invocation of the search functions. - def breadth_first_search(): - for v in left: - if leftmatches[v] is None: - distances[v] = 0 - queue.append(v) - else: - distances[v] = INFINITY - distances[None] = INFINITY - while queue: - v = queue.popleft() - if distances[v] < distances[None]: - for u in G[v]: - if distances[rightmatches[u]] is INFINITY: - distances[rightmatches[u]] = distances[v] + 1 - queue.append(rightmatches[u]) - return distances[None] is not INFINITY - - def depth_first_search(v): - if v is not None: - for u in G[v]: - if distances[rightmatches[u]] == distances[v] + 1: - if depth_first_search(rightmatches[u]): - rightmatches[u] = v - leftmatches[v] = u - return True - distances[v] = INFINITY - return False - return True - - # Initialize the "global" variables that maintain state during the search. - left, right = bipartite_sets(G, top_nodes) - leftmatches = {v: None for v in left} - rightmatches = {v: None for v in right} - distances = {} - queue = collections.deque() - - # Implementation note: this counter is incremented as pairs are matched but - # it is currently not used elsewhere in the computation. - num_matched_pairs = 0 - while breadth_first_search(): - for v in left: - if leftmatches[v] is None: - if depth_first_search(v): - num_matched_pairs += 1 - - # Strip the entries matched to `None`. - leftmatches = {k: v for k, v in leftmatches.items() if v is not None} - rightmatches = {k: v for k, v in rightmatches.items() if v is not None} - - # At this point, the left matches and the right matches are inverses of one - # another. In other words, - # - # leftmatches == {v, k for k, v in rightmatches.items()} - # - # Finally, we combine both the left matches and right matches. - return dict(itertools.chain(leftmatches.items(), rightmatches.items())) - - -def eppstein_matching(G, top_nodes=None): - """Returns the maximum cardinality matching of the bipartite graph `G`. - - Parameters - ---------- - G : NetworkX graph - - Undirected bipartite graph - - top_nodes : container - - Container with all nodes in one bipartite node set. If not supplied - it will be computed. But if more than one solution exists an exception - will be raised. - - Returns - ------- - matches : dictionary - - The matching is returned as a dictionary, `matching`, such that - ``matching[v] == w`` if node `v` is matched to node `w`. Unmatched - nodes do not occur as a key in mate. - - Raises - ------ - AmbiguousSolution : Exception - - Raised if the input bipartite graph is disconnected and no container - with all nodes in one bipartite set is provided. When determining - the nodes in each bipartite set more than one valid solution is - possible if the input graph is disconnected. - - Notes - ----- - This function is implemented with David Eppstein's version of the algorithm - Hopcroft--Karp algorithm (see :func:`hopcroft_karp_matching`), which - originally appeared in the `Python Algorithms and Data Structures library - (PADS) `_. - - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - - hopcroft_karp_matching - - """ - # Due to its original implementation, a directed graph is needed - # so that the two sets of bipartite nodes can be distinguished - left, right = bipartite_sets(G, top_nodes) - G = nx.DiGraph(G.edges(left)) - # initialize greedy matching (redundant, but faster than full search) - matching = {} - for u in G: - for v in G[u]: - if v not in matching: - matching[v] = u - break - while True: - # structure residual graph into layers - # pred[u] gives the neighbor in the previous layer for u in U - # preds[v] gives a list of neighbors in the previous layer for v in V - # unmatched gives a list of unmatched vertices in final layer of V, - # and is also used as a flag value for pred[u] when u is in the first - # layer - preds = {} - unmatched = [] - pred = {u: unmatched for u in G} - for v in matching: - del pred[matching[v]] - layer = list(pred) - - # repeatedly extend layering structure by another pair of layers - while layer and not unmatched: - newLayer = {} - for u in layer: - for v in G[u]: - if v not in preds: - newLayer.setdefault(v, []).append(u) - layer = [] - for v in newLayer: - preds[v] = newLayer[v] - if v in matching: - layer.append(matching[v]) - pred[matching[v]] = v - else: - unmatched.append(v) - - # did we finish layering without finding any alternating paths? - if not unmatched: - unlayered = {} - for u in G: - # TODO Why is extra inner loop necessary? - for v in G[u]: - if v not in preds: - unlayered[v] = None - # TODO Originally, this function returned a three-tuple: - # - # return (matching, list(pred), list(unlayered)) - # - # For some reason, the documentation for this function - # indicated that the second and third elements of the returned - # three-tuple would be the vertices in the left and right vertex - # sets, respectively, that are also in the maximum independent set. - # However, what I think the author meant was that the second - # element is the list of vertices that were unmatched and the third - # element was the list of vertices that were matched. Since that - # seems to be the case, they don't really need to be returned, - # since that information can be inferred from the matching - # dictionary. - - # All the matched nodes must be a key in the dictionary - for key in matching.copy(): - matching[matching[key]] = key - return matching - - # recursively search backward through layers to find alternating paths - # recursion returns true if found path, false otherwise - def recurse(v): - if v in preds: - L = preds.pop(v) - for u in L: - if u in pred: - pu = pred.pop(u) - if pu is unmatched or recurse(pu): - matching[v] = u - return True - return False - - for v in unmatched: - recurse(v) - - -def _is_connected_by_alternating_path(G, v, matched_edges, unmatched_edges, - targets): - """Returns True if and only if the vertex `v` is connected to one of - the target vertices by an alternating path in `G`. - - An *alternating path* is a path in which every other edge is in the - specified maximum matching (and the remaining edges in the path are not in - the matching). An alternating path may have matched edges in the even - positions or in the odd positions, as long as the edges alternate between - 'matched' and 'unmatched'. - - `G` is an undirected bipartite NetworkX graph. - - `v` is a vertex in `G`. - - `matched_edges` is a set of edges present in a maximum matching in `G`. - - `unmatched_edges` is a set of edges not present in a maximum - matching in `G`. - - `targets` is a set of vertices. - - """ - def _alternating_dfs(u, along_matched=True): - """Returns True if and only if `u` is connected to one of the - targets by an alternating path. - - `u` is a vertex in the graph `G`. - - If `along_matched` is True, this step of the depth-first search - will continue only through edges in the given matching. Otherwise, it - will continue only through edges *not* in the given matching. - - """ - if along_matched: - edges = itertools.cycle([matched_edges, unmatched_edges]) - else: - edges = itertools.cycle([unmatched_edges, matched_edges]) - visited = set() - stack = [(u, iter(G[u]), next(edges))] - while stack: - parent, children, valid_edges = stack[-1] - try: - child = next(children) - if child not in visited: - if ((parent, child) in valid_edges - or (child, parent) in valid_edges): - if child in targets: - return True - visited.add(child) - stack.append((child, iter(G[child]), next(edges))) - except StopIteration: - stack.pop() - return False - - # Check for alternating paths starting with edges in the matching, then - # check for alternating paths starting with edges not in the - # matching. - return (_alternating_dfs(v, along_matched=True) or - _alternating_dfs(v, along_matched=False)) - - -def _connected_by_alternating_paths(G, matching, targets): - """Returns the set of vertices that are connected to one of the target - vertices by an alternating path in `G` or are themselves a target. - - An *alternating path* is a path in which every other edge is in the - specified maximum matching (and the remaining edges in the path are not in - the matching). An alternating path may have matched edges in the even - positions or in the odd positions, as long as the edges alternate between - 'matched' and 'unmatched'. - - `G` is an undirected bipartite NetworkX graph. - - `matching` is a dictionary representing a maximum matching in `G`, as - returned by, for example, :func:`maximum_matching`. - - `targets` is a set of vertices. - - """ - # Get the set of matched edges and the set of unmatched edges. Only include - # one version of each undirected edge (for example, include edge (1, 2) but - # not edge (2, 1)). Using frozensets as an intermediary step we do not - # require nodes to be orderable. - edge_sets = {frozenset((u, v)) for u, v in matching.items()} - matched_edges = {tuple(edge) for edge in edge_sets} - unmatched_edges = {(u, v) for (u, v) in G.edges() - if frozenset((u, v)) not in edge_sets} - - return {v for v in G if v in targets or - _is_connected_by_alternating_path(G, v, matched_edges, - unmatched_edges, targets)} - - -def to_vertex_cover(G, matching, top_nodes=None): - """Returns the minimum vertex cover corresponding to the given maximum - matching of the bipartite graph `G`. - - Parameters - ---------- - G : NetworkX graph - - Undirected bipartite graph - - matching : dictionary - - A dictionary whose keys are vertices in `G` and whose values are the - distinct neighbors comprising the maximum matching for `G`, as returned - by, for example, :func:`maximum_matching`. The dictionary *must* - represent the maximum matching. - - top_nodes : container - - Container with all nodes in one bipartite node set. If not supplied - it will be computed. But if more than one solution exists an exception - will be raised. - - Returns - ------- - vertex_cover : :class:`set` - - The minimum vertex cover in `G`. - - Raises - ------ - AmbiguousSolution : Exception - - Raised if the input bipartite graph is disconnected and no container - with all nodes in one bipartite set is provided. When determining - the nodes in each bipartite set more than one valid solution is - possible if the input graph is disconnected. - - Notes - ----- - This function is implemented using the procedure guaranteed by `Konig's - theorem - `_, - which proves an equivalence between a maximum matching and a minimum vertex - cover in bipartite graphs. - - Since a minimum vertex cover is the complement of a maximum independent set - for any graph, one can compute the maximum independent set of a bipartite - graph this way: - - >>> import networkx as nx - >>> G = nx.complete_bipartite_graph(2, 3) - >>> matching = nx.bipartite.maximum_matching(G) - >>> vertex_cover = nx.bipartite.to_vertex_cover(G, matching) - >>> independent_set = set(G) - vertex_cover - >>> print(list(independent_set)) - [2, 3, 4] - - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - """ - # This is a Python implementation of the algorithm described at - # . - L, R = bipartite_sets(G, top_nodes) - # Let U be the set of unmatched vertices in the left vertex set. - unmatched_vertices = set(G) - set(matching) - U = unmatched_vertices & L - # Let Z be the set of vertices that are either in U or are connected to U - # by alternating paths. - Z = _connected_by_alternating_paths(G, matching, U) - # At this point, every edge either has a right endpoint in Z or a left - # endpoint not in Z. This gives us the vertex cover. - return (L - Z) | (R & Z) - - -#: Returns the maximum cardinality matching in the given bipartite graph. -#: -#: This function is simply an alias for :func:`hopcroft_karp_matching`. -maximum_matching = hopcroft_karp_matching - - -def minimum_weight_full_matching(G, top_nodes=None, weight='weight'): - r"""Returns the minimum weight full matching of the bipartite graph `G`. - - Let :math:`G = ((U, V), E)` be a complete weighted bipartite graph with - real weights :math:`w : E \to \mathbb{R}`. This function then produces - a maximum matching :math:`M \subseteq E` which, since the graph is - assumed to be complete, has cardinality - - .. math:: - \lvert M \rvert = \min(\lvert U \rvert, \lvert V \rvert), - - and which minimizes the sum of the weights of the edges included in the - matching, :math:`\sum_{e \in M} w(e)`. - - When :math:`\lvert U \rvert = \lvert V \rvert`, this is commonly - referred to as a perfect matching; here, since we allow - :math:`\lvert U \rvert` and :math:`\lvert V \rvert` to differ, we - follow Karp [1]_ and refer to the matching as *full*. - - Parameters - ---------- - G : NetworkX graph - - Undirected bipartite graph - - top_nodes : container - - Container with all nodes in one bipartite node set. If not supplied - it will be computed. - - weight : string, optional (default='weight') - - The edge data key used to provide each value in the matrix. - - Returns - ------- - matches : dictionary - - The matching is returned as a dictionary, `matches`, such that - ``matches[v] == w`` if node `v` is matched to node `w`. Unmatched - nodes do not occur as a key in matches. - - Raises - ------ - ValueError : Exception - - Raised if the input bipartite graph is not complete. - - ImportError : Exception - - Raised if SciPy is not available. - - Notes - ----- - The problem of determining a minimum weight full matching is also known as - the rectangular linear assignment problem. This implementation defers the - calculation of the assignment to SciPy. - - References - ---------- - .. [1] Richard Manning Karp: - An algorithm to Solve the m x n Assignment Problem in Expected Time - O(mn log n). - Networks, 10(2):143–152, 1980. - - """ - try: - import scipy.optimize - except ImportError: - raise ImportError('minimum_weight_full_matching requires SciPy: ' + - 'https://scipy.org/') - left, right = nx.bipartite.sets(G, top_nodes) - # Ensure that the graph is complete. This is currently a requirement in - # the underlying optimization algorithm from SciPy, but the constraint - # will be removed in SciPy 1.4.0, at which point it can also be removed - # here. - for (u, v) in itertools.product(left, right): - # As the graph is undirected, make sure to check for edges in - # both directions - if (u, v) not in G.edges() and (v, u) not in G.edges(): - raise ValueError('The bipartite graph must be complete.') - U = list(left) - V = list(right) - weights = biadjacency_matrix(G, row_order=U, - column_order=V, weight=weight).toarray() - left_matches = scipy.optimize.linear_sum_assignment(weights) - d = {U[u]: V[v] for u, v in zip(*left_matches)} - # d will contain the matching from edges in left to right; we need to - # add the ones from right to left as well. - d.update({v: u for u, v in d.items()}) - return d diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/matrix.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/matrix.py deleted file mode 100644 index f3856c1e..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/matrix.py +++ /dev/null @@ -1,175 +0,0 @@ -# -*- coding: utf-8 -*- -""" -==================== -Biadjacency matrices -==================== -""" -# Copyright (C) 2013-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -import itertools -from networkx.convert_matrix import _generate_weighted_edges -import networkx as nx -__author__ = """\n""".join(['Jordi Torrents ', - 'Aric Hagberg ']) -__all__ = ['biadjacency_matrix', 'from_biadjacency_matrix'] - - -def biadjacency_matrix(G, row_order, column_order=None, - dtype=None, weight='weight', format='csr'): - r"""Returns the biadjacency matrix of the bipartite graph G. - - Let `G = (U, V, E)` be a bipartite graph with node sets - `U = u_{1},...,u_{r}` and `V = v_{1},...,v_{s}`. The biadjacency - matrix [1]_ is the `r` x `s` matrix `B` in which `b_{i,j} = 1` - if, and only if, `(u_i, v_j) \in E`. If the parameter `weight` is - not `None` and matches the name of an edge attribute, its value is - used instead of 1. - - Parameters - ---------- - G : graph - A NetworkX graph - - row_order : list of nodes - The rows of the matrix are ordered according to the list of nodes. - - column_order : list, optional - The columns of the matrix are ordered according to the list of nodes. - If column_order is None, then the ordering of columns is arbitrary. - - dtype : NumPy data-type, optional - A valid NumPy dtype used to initialize the array. If None, then the - NumPy default is used. - - weight : string or None, optional (default='weight') - The edge data key used to provide each value in the matrix. - If None, then each edge has weight 1. - - format : str in {'bsr', 'csr', 'csc', 'coo', 'lil', 'dia', 'dok'} - The type of the matrix to be returned (default 'csr'). For - some algorithms different implementations of sparse matrices - can perform better. See [2]_ for details. - - Returns - ------- - M : SciPy sparse matrix - Biadjacency matrix representation of the bipartite graph G. - - Notes - ----- - No attempt is made to check that the input graph is bipartite. - - For directed bipartite graphs only successors are considered as neighbors. - To obtain an adjacency matrix with ones (or weight values) for both - predecessors and successors you have to generate two biadjacency matrices - where the rows of one of them are the columns of the other, and then add - one to the transpose of the other. - - See Also - -------- - adjacency_matrix - from_biadjacency_matrix - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Adjacency_matrix#Adjacency_matrix_of_a_bipartite_graph - .. [2] Scipy Dev. References, "Sparse Matrices", - https://docs.scipy.org/doc/scipy/reference/sparse.html - """ - from scipy import sparse - nlen = len(row_order) - if nlen == 0: - raise nx.NetworkXError("row_order is empty list") - if len(row_order) != len(set(row_order)): - msg = "Ambiguous ordering: `row_order` contained duplicates." - raise nx.NetworkXError(msg) - if column_order is None: - column_order = list(set(G) - set(row_order)) - mlen = len(column_order) - if len(column_order) != len(set(column_order)): - msg = "Ambiguous ordering: `column_order` contained duplicates." - raise nx.NetworkXError(msg) - - row_index = dict(zip(row_order, itertools.count())) - col_index = dict(zip(column_order, itertools.count())) - - if G.number_of_edges() == 0: - row, col, data = [], [], [] - else: - row, col, data = zip(*((row_index[u], col_index[v], d.get(weight, 1)) - for u, v, d in G.edges(row_order, data=True) - if u in row_index and v in col_index)) - M = sparse.coo_matrix((data, (row, col)), - shape=(nlen, mlen), dtype=dtype) - try: - return M.asformat(format) - # From Scipy 1.1.0, asformat will throw a ValueError instead of an - # AttributeError if the format if not recognized. - except (AttributeError, ValueError): - raise nx.NetworkXError("Unknown sparse matrix format: %s" % format) - - -def from_biadjacency_matrix(A, create_using=None, edge_attribute='weight'): - r"""Creates a new bipartite graph from a biadjacency matrix given as a - SciPy sparse matrix. - - Parameters - ---------- - A: scipy sparse matrix - A biadjacency matrix representation of a graph - - create_using: NetworkX graph - Use specified graph for result. The default is Graph() - - edge_attribute: string - Name of edge attribute to store matrix numeric value. The data will - have the same type as the matrix entry (int, float, (real,imag)). - - Notes - ----- - The nodes are labeled with the attribute `bipartite` set to an integer - 0 or 1 representing membership in part 0 or part 1 of the bipartite graph. - - If `create_using` is an instance of :class:`networkx.MultiGraph` or - :class:`networkx.MultiDiGraph` and the entries of `A` are of - type :class:`int`, then this function returns a multigraph (of the same - type as `create_using`) with parallel edges. In this case, `edge_attribute` - will be ignored. - - See Also - -------- - biadjacency_matrix - from_numpy_matrix - - References - ---------- - [1] https://en.wikipedia.org/wiki/Adjacency_matrix#Adjacency_matrix_of_a_bipartite_graph - """ - G = nx.empty_graph(0, create_using) - n, m = A.shape - # Make sure we get even the isolated nodes of the graph. - G.add_nodes_from(range(n), bipartite=0) - G.add_nodes_from(range(n, n + m), bipartite=1) - # Create an iterable over (u, v, w) triples and for each triple, add an - # edge from u to v with weight w. - triples = ((u, n + v, d) for (u, v, d) in _generate_weighted_edges(A)) - # If the entries in the adjacency matrix are integers and the graph is a - # multigraph, then create parallel edges, each with weight 1, for each - # entry in the adjacency matrix. Otherwise, create one edge for each - # positive entry in the adjacency matrix and set the weight of that edge to - # be the entry in the matrix. - if A.dtype.kind in ('i', 'u') and G.is_multigraph(): - chain = itertools.chain.from_iterable - triples = chain(((u, v, 1) for d in range(w)) for (u, v, w) in triples) - G.add_weighted_edges_from(triples, weight=edge_attribute) - return G - - -# fixture for pytest -def setup_module(module): - import pytest - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/projection.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/projection.py deleted file mode 100644 index 69c5f6bd..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/projection.py +++ /dev/null @@ -1,517 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2017-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg -# Jordi Torrents -"""One-mode (unipartite) projections of bipartite graphs.""" -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ['project', - 'projected_graph', - 'weighted_projected_graph', - 'collaboration_weighted_projected_graph', - 'overlap_weighted_projected_graph', - 'generic_weighted_projected_graph'] - - -def projected_graph(B, nodes, multigraph=False): - r"""Returns the projection of B onto one of its node sets. - - Returns the graph G that is the projection of the bipartite graph B - onto the specified nodes. They retain their attributes and are connected - in G if they have a common neighbor in B. - - Parameters - ---------- - B : NetworkX graph - The input graph should be bipartite. - - nodes : list or iterable - Nodes to project onto (the "bottom" nodes). - - multigraph: bool (default=False) - If True return a multigraph where the multiple edges represent multiple - shared neighbors. They edge key in the multigraph is assigned to the - label of the neighbor. - - Returns - ------- - Graph : NetworkX graph or multigraph - A graph that is the projection onto the given nodes. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> B = nx.path_graph(4) - >>> G = bipartite.projected_graph(B, [1, 3]) - >>> list(G) - [1, 3] - >>> list(G.edges()) - [(1, 3)] - - If nodes `a`, and `b` are connected through both nodes 1 and 2 then - building a multigraph results in two edges in the projection onto - [`a`, `b`]: - - >>> B = nx.Graph() - >>> B.add_edges_from([('a', 1), ('b', 1), ('a', 2), ('b', 2)]) - >>> G = bipartite.projected_graph(B, ['a', 'b'], multigraph=True) - >>> print([sorted((u, v)) for u, v in G.edges()]) - [['a', 'b'], ['a', 'b']] - - Notes - ----- - No attempt is made to verify that the input graph B is bipartite. - Returns a simple graph that is the projection of the bipartite graph B - onto the set of nodes given in list nodes. If multigraph=True then - a multigraph is returned with an edge for every shared neighbor. - - Directed graphs are allowed as input. The output will also then - be a directed graph with edges if there is a directed path between - the nodes. - - The graph and node properties are (shallow) copied to the projected graph. - - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - is_bipartite, - is_bipartite_node_set, - sets, - weighted_projected_graph, - collaboration_weighted_projected_graph, - overlap_weighted_projected_graph, - generic_weighted_projected_graph - """ - if B.is_multigraph(): - raise nx.NetworkXError("not defined for multigraphs") - if B.is_directed(): - directed = True - if multigraph: - G = nx.MultiDiGraph() - else: - G = nx.DiGraph() - else: - directed = False - if multigraph: - G = nx.MultiGraph() - else: - G = nx.Graph() - G.graph.update(B.graph) - G.add_nodes_from((n, B.nodes[n]) for n in nodes) - for u in nodes: - nbrs2 = set(v for nbr in B[u] for v in B[nbr] if v != u) - if multigraph: - for n in nbrs2: - if directed: - links = set(B[u]) & set(B.pred[n]) - else: - links = set(B[u]) & set(B[n]) - for l in links: - if not G.has_edge(u, n, l): - G.add_edge(u, n, key=l) - else: - G.add_edges_from((u, n) for n in nbrs2) - return G - - -@not_implemented_for('multigraph') -def weighted_projected_graph(B, nodes, ratio=False): - r"""Returns a weighted projection of B onto one of its node sets. - - The weighted projected graph is the projection of the bipartite - network B onto the specified nodes with weights representing the - number of shared neighbors or the ratio between actual shared - neighbors and possible shared neighbors if ``ratio is True`` [1]_. - The nodes retain their attributes and are connected in the resulting - graph if they have an edge to a common node in the original graph. - - Parameters - ---------- - B : NetworkX graph - The input graph should be bipartite. - - nodes : list or iterable - Nodes to project onto (the "bottom" nodes). - - ratio: Bool (default=False) - If True, edge weight is the ratio between actual shared neighbors - and maximum possible shared neighbors (i.e., the size of the other - node set). If False, edges weight is the number of shared neighbors. - - Returns - ------- - Graph : NetworkX graph - A graph that is the projection onto the given nodes. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> B = nx.path_graph(4) - >>> G = bipartite.weighted_projected_graph(B, [1, 3]) - >>> list(G) - [1, 3] - >>> list(G.edges(data=True)) - [(1, 3, {'weight': 1})] - >>> G = bipartite.weighted_projected_graph(B, [1, 3], ratio=True) - >>> list(G.edges(data=True)) - [(1, 3, {'weight': 0.5})] - - Notes - ----- - No attempt is made to verify that the input graph B is bipartite. - The graph and node properties are (shallow) copied to the projected graph. - - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - is_bipartite, - is_bipartite_node_set, - sets, - collaboration_weighted_projected_graph, - overlap_weighted_projected_graph, - generic_weighted_projected_graph - projected_graph - - References - ---------- - .. [1] Borgatti, S.P. and Halgin, D. In press. "Analyzing Affiliation - Networks". In Carrington, P. and Scott, J. (eds) The Sage Handbook - of Social Network Analysis. Sage Publications. - """ - if B.is_directed(): - pred = B.pred - G = nx.DiGraph() - else: - pred = B.adj - G = nx.Graph() - G.graph.update(B.graph) - G.add_nodes_from((n, B.nodes[n]) for n in nodes) - n_top = float(len(B) - len(nodes)) - for u in nodes: - unbrs = set(B[u]) - nbrs2 = set((n for nbr in unbrs for n in B[nbr])) - set([u]) - for v in nbrs2: - vnbrs = set(pred[v]) - common = unbrs & vnbrs - if not ratio: - weight = len(common) - else: - weight = len(common) / n_top - G.add_edge(u, v, weight=weight) - return G - - -@not_implemented_for('multigraph') -def collaboration_weighted_projected_graph(B, nodes): - r"""Newman's weighted projection of B onto one of its node sets. - - The collaboration weighted projection is the projection of the - bipartite network B onto the specified nodes with weights assigned - using Newman's collaboration model [1]_: - - .. math:: - - w_{u, v} = \sum_k \frac{\delta_{u}^{k} \delta_{v}^{k}}{d_k - 1} - - where `u` and `v` are nodes from the bottom bipartite node set, - and `k` is a node of the top node set. - The value `d_k` is the degree of node `k` in the bipartite - network and `\delta_{u}^{k}` is 1 if node `u` is - linked to node `k` in the original bipartite graph or 0 otherwise. - - The nodes retain their attributes and are connected in the resulting - graph if have an edge to a common node in the original bipartite - graph. - - Parameters - ---------- - B : NetworkX graph - The input graph should be bipartite. - - nodes : list or iterable - Nodes to project onto (the "bottom" nodes). - - Returns - ------- - Graph : NetworkX graph - A graph that is the projection onto the given nodes. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> B = nx.path_graph(5) - >>> B.add_edge(1, 5) - >>> G = bipartite.collaboration_weighted_projected_graph(B, [0, 2, 4, 5]) - >>> list(G) - [0, 2, 4, 5] - >>> for edge in sorted(G.edges(data=True)): print(edge) - ... - (0, 2, {'weight': 0.5}) - (0, 5, {'weight': 0.5}) - (2, 4, {'weight': 1.0}) - (2, 5, {'weight': 0.5}) - - Notes - ----- - No attempt is made to verify that the input graph B is bipartite. - The graph and node properties are (shallow) copied to the projected graph. - - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - is_bipartite, - is_bipartite_node_set, - sets, - weighted_projected_graph, - overlap_weighted_projected_graph, - generic_weighted_projected_graph, - projected_graph - - References - ---------- - .. [1] Scientific collaboration networks: II. - Shortest paths, weighted networks, and centrality, - M. E. J. Newman, Phys. Rev. E 64, 016132 (2001). - """ - if B.is_directed(): - pred = B.pred - G = nx.DiGraph() - else: - pred = B.adj - G = nx.Graph() - G.graph.update(B.graph) - G.add_nodes_from((n, B.nodes[n]) for n in nodes) - for u in nodes: - unbrs = set(B[u]) - nbrs2 = set(n for nbr in unbrs for n in B[nbr] if n != u) - for v in nbrs2: - vnbrs = set(pred[v]) - common_degree = (len(B[n]) for n in unbrs & vnbrs) - weight = sum(1.0 / (deg - 1) for deg in common_degree if deg > 1) - G.add_edge(u, v, weight=weight) - return G - - -@not_implemented_for('multigraph') -def overlap_weighted_projected_graph(B, nodes, jaccard=True): - r"""Overlap weighted projection of B onto one of its node sets. - - The overlap weighted projection is the projection of the bipartite - network B onto the specified nodes with weights representing - the Jaccard index between the neighborhoods of the two nodes in the - original bipartite network [1]_: - - .. math:: - - w_{v, u} = \frac{|N(u) \cap N(v)|}{|N(u) \cup N(v)|} - - or if the parameter 'jaccard' is False, the fraction of common - neighbors by minimum of both nodes degree in the original - bipartite graph [1]_: - - .. math:: - - w_{v, u} = \frac{|N(u) \cap N(v)|}{min(|N(u)|, |N(v)|)} - - The nodes retain their attributes and are connected in the resulting - graph if have an edge to a common node in the original bipartite graph. - - Parameters - ---------- - B : NetworkX graph - The input graph should be bipartite. - - nodes : list or iterable - Nodes to project onto (the "bottom" nodes). - - jaccard: Bool (default=True) - - Returns - ------- - Graph : NetworkX graph - A graph that is the projection onto the given nodes. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> B = nx.path_graph(5) - >>> nodes = [0, 2, 4] - >>> G = bipartite.overlap_weighted_projected_graph(B, nodes) - >>> list(G) - [0, 2, 4] - >>> list(G.edges(data=True)) - [(0, 2, {'weight': 0.5}), (2, 4, {'weight': 0.5})] - >>> G = bipartite.overlap_weighted_projected_graph(B, nodes, jaccard=False) - >>> list(G.edges(data=True)) - [(0, 2, {'weight': 1.0}), (2, 4, {'weight': 1.0})] - - Notes - ----- - No attempt is made to verify that the input graph B is bipartite. - The graph and node properties are (shallow) copied to the projected graph. - - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - is_bipartite, - is_bipartite_node_set, - sets, - weighted_projected_graph, - collaboration_weighted_projected_graph, - generic_weighted_projected_graph, - projected_graph - - References - ---------- - .. [1] Borgatti, S.P. and Halgin, D. In press. Analyzing Affiliation - Networks. In Carrington, P. and Scott, J. (eds) The Sage Handbook - of Social Network Analysis. Sage Publications. - - """ - if B.is_directed(): - pred = B.pred - G = nx.DiGraph() - else: - pred = B.adj - G = nx.Graph() - G.graph.update(B.graph) - G.add_nodes_from((n, B.nodes[n]) for n in nodes) - for u in nodes: - unbrs = set(B[u]) - nbrs2 = set((n for nbr in unbrs for n in B[nbr])) - set([u]) - for v in nbrs2: - vnbrs = set(pred[v]) - if jaccard: - wt = float(len(unbrs & vnbrs)) / len(unbrs | vnbrs) - else: - wt = float(len(unbrs & vnbrs)) / min(len(unbrs), len(vnbrs)) - G.add_edge(u, v, weight=wt) - return G - - -@not_implemented_for('multigraph') -def generic_weighted_projected_graph(B, nodes, weight_function=None): - r"""Weighted projection of B with a user-specified weight function. - - The bipartite network B is projected on to the specified nodes - with weights computed by a user-specified function. This function - must accept as a parameter the neighborhood sets of two nodes and - return an integer or a float. - - The nodes retain their attributes and are connected in the resulting graph - if they have an edge to a common node in the original graph. - - Parameters - ---------- - B : NetworkX graph - The input graph should be bipartite. - - nodes : list or iterable - Nodes to project onto (the "bottom" nodes). - - weight_function : function - This function must accept as parameters the same input graph - that this function, and two nodes; and return an integer or a float. - The default function computes the number of shared neighbors. - - Returns - ------- - Graph : NetworkX graph - A graph that is the projection onto the given nodes. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> # Define some custom weight functions - >>> def jaccard(G, u, v): - ... unbrs = set(G[u]) - ... vnbrs = set(G[v]) - ... return float(len(unbrs & vnbrs)) / len(unbrs | vnbrs) - ... - >>> def my_weight(G, u, v, weight='weight'): - ... w = 0 - ... for nbr in set(G[u]) & set(G[v]): - ... w += G[u][nbr].get(weight, 1) + G[v][nbr].get(weight, 1) - ... return w - ... - >>> # A complete bipartite graph with 4 nodes and 4 edges - >>> B = nx.complete_bipartite_graph(2, 2) - >>> # Add some arbitrary weight to the edges - >>> for i,(u,v) in enumerate(B.edges()): - ... B.edges[u, v]['weight'] = i + 1 - ... - >>> for edge in B.edges(data=True): - ... print(edge) - ... - (0, 2, {'weight': 1}) - (0, 3, {'weight': 2}) - (1, 2, {'weight': 3}) - (1, 3, {'weight': 4}) - >>> # By default, the weight is the number of shared neighbors - >>> G = bipartite.generic_weighted_projected_graph(B, [0, 1]) - >>> print(list(G.edges(data=True))) - [(0, 1, {'weight': 2})] - >>> # To specify a custom weight function use the weight_function parameter - >>> G = bipartite.generic_weighted_projected_graph(B, [0, 1], weight_function=jaccard) - >>> print(list(G.edges(data=True))) - [(0, 1, {'weight': 1.0})] - >>> G = bipartite.generic_weighted_projected_graph(B, [0, 1], weight_function=my_weight) - >>> print(list(G.edges(data=True))) - [(0, 1, {'weight': 10})] - - Notes - ----- - No attempt is made to verify that the input graph B is bipartite. - The graph and node properties are (shallow) copied to the projected graph. - - See :mod:`bipartite documentation ` - for further details on how bipartite graphs are handled in NetworkX. - - See Also - -------- - is_bipartite, - is_bipartite_node_set, - sets, - weighted_projected_graph, - collaboration_weighted_projected_graph, - overlap_weighted_projected_graph, - projected_graph - - """ - if B.is_directed(): - pred = B.pred - G = nx.DiGraph() - else: - pred = B.adj - G = nx.Graph() - if weight_function is None: - def weight_function(G, u, v): - # Notice that we use set(pred[v]) for handling the directed case. - return len(set(G[u]) & set(pred[v])) - G.graph.update(B.graph) - G.add_nodes_from((n, B.nodes[n]) for n in nodes) - for u in nodes: - nbrs2 = set((n for nbr in set(B[u]) for n in B[nbr])) - set([u]) - for v in nbrs2: - weight = weight_function(B, u, v) - G.add_edge(u, v, weight=weight) - return G - - -def project(B, nodes, create_using=None): - return projected_graph(B, nodes) diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/redundancy.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/redundancy.py deleted file mode 100644 index 02f6f89f..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/redundancy.py +++ /dev/null @@ -1,120 +0,0 @@ -# -*- coding: utf-8 -*- -"""Node redundancy for bipartite graphs.""" -# Copyright (C) 2011 by -# Jordi Torrents -# Aric Hagberg -# All rights reserved. -# BSD license. - -from itertools import combinations - -from networkx import NetworkXError - -__author__ = """\n""".join(['Jordi Torrents ', - 'Aric Hagberg (hagberg@lanl.gov)']) -__all__ = ['node_redundancy'] - - -def node_redundancy(G, nodes=None): - r"""Computes the node redundancy coefficients for the nodes in the bipartite - graph `G`. - - The redundancy coefficient of a node `v` is the fraction of pairs of - neighbors of `v` that are both linked to other nodes. In a one-mode - projection these nodes would be linked together even if `v` were - not there. - - More formally, for any vertex `v`, the *redundancy coefficient of `v`* is - defined by - - .. math:: - - rc(v) = \frac{|\{\{u, w\} \subseteq N(v), - \: \exists v' \neq v,\: (v',u) \in E\: - \mathrm{and}\: (v',w) \in E\}|}{ \frac{|N(v)|(|N(v)|-1)}{2}}, - - where `N(v)` is the set of neighbors of `v` in `G`. - - Parameters - ---------- - G : graph - A bipartite graph - - nodes : list or iterable (optional) - Compute redundancy for these nodes. The default is all nodes in G. - - Returns - ------- - redundancy : dictionary - A dictionary keyed by node with the node redundancy value. - - Examples - -------- - Compute the redundancy coefficient of each node in a graph:: - - >>> import networkx as nx - >>> from networkx.algorithms import bipartite - >>> G = nx.cycle_graph(4) - >>> rc = bipartite.node_redundancy(G) - >>> rc[0] - 1.0 - - Compute the average redundancy for the graph:: - - >>> import networkx as nx - >>> from networkx.algorithms import bipartite - >>> G = nx.cycle_graph(4) - >>> rc = bipartite.node_redundancy(G) - >>> sum(rc.values()) / len(G) - 1.0 - - Compute the average redundancy for a set of nodes:: - - >>> import networkx as nx - >>> from networkx.algorithms import bipartite - >>> G = nx.cycle_graph(4) - >>> rc = bipartite.node_redundancy(G) - >>> nodes = [0, 2] - >>> sum(rc[n] for n in nodes) / len(nodes) - 1.0 - - Raises - ------ - NetworkXError - If any of the nodes in the graph (or in `nodes`, if specified) has - (out-)degree less than two (which would result in division by zero, - according to the definition of the redundancy coefficient). - - References - ---------- - .. [1] Latapy, Matthieu, Clémence Magnien, and Nathalie Del Vecchio (2008). - Basic notions for the analysis of large two-mode networks. - Social Networks 30(1), 31--48. - - """ - if nodes is None: - nodes = G - if any(len(G[v]) < 2 for v in nodes): - raise NetworkXError('Cannot compute redundancy coefficient for a node' - ' that has fewer than two neighbors.') - # TODO This can be trivially parallelized. - return {v: _node_redundancy(G, v) for v in nodes} - - -def _node_redundancy(G, v): - """Returns the redundancy of the node `v` in the bipartite graph `G`. - - If `G` is a graph with `n` nodes, the redundancy of a node is the ratio - of the "overlap" of `v` to the maximum possible overlap of `v` - according to its degree. The overlap of `v` is the number of pairs of - neighbors that have mutual neighbors themselves, other than `v`. - - `v` must have at least two neighbors in `G`. - - """ - n = len(G[v]) - # TODO On Python 3, we could just use `G[u].keys() & G[w].keys()` instead - # of instantiating the entire sets. - overlap = sum(1 for (u, w) in combinations(G[v], 2) - if (set(G[u]) & set(G[w])) - {v}) - return (2 * overlap) / (n * (n - 1)) diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/spectral.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/spectral.py deleted file mode 100644 index 3b1dda0e..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/spectral.py +++ /dev/null @@ -1,84 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Spectral bipartivity measure. -""" -import networkx as nx -__author__ = """Aric Hagberg (hagberg@lanl.gov)""" -# Copyright (C) 2011 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -__all__ = ['spectral_bipartivity'] - - -def spectral_bipartivity(G, nodes=None, weight='weight'): - """Returns the spectral bipartivity. - - Parameters - ---------- - G : NetworkX graph - - nodes : list or container optional(default is all nodes) - Nodes to return value of spectral bipartivity contribution. - - weight : string or None optional (default = 'weight') - Edge data key to use for edge weights. If None, weights set to 1. - - Returns - ------- - sb : float or dict - A single number if the keyword nodes is not specified, or - a dictionary keyed by node with the spectral bipartivity contribution - of that node as the value. - - Examples - -------- - >>> from networkx.algorithms import bipartite - >>> G = nx.path_graph(4) - >>> bipartite.spectral_bipartivity(G) - 1.0 - - Notes - ----- - This implementation uses Numpy (dense) matrices which are not efficient - for storing large sparse graphs. - - See Also - -------- - color - - References - ---------- - .. [1] E. Estrada and J. A. Rodríguez-Velázquez, "Spectral measures of - bipartivity in complex networks", PhysRev E 72, 046105 (2005) - """ - try: - import scipy.linalg - except ImportError: - raise ImportError('spectral_bipartivity() requires SciPy: ', - 'http://scipy.org/') - nodelist = list(G) # ordering of nodes in matrix - A = nx.to_numpy_matrix(G, nodelist, weight=weight) - expA = scipy.linalg.expm(A) - expmA = scipy.linalg.expm(-A) - coshA = 0.5 * (expA + expmA) - if nodes is None: - # return single number for entire graph - return coshA.diagonal().sum() / expA.diagonal().sum() - else: - # contribution for individual nodes - index = dict(zip(nodelist, range(len(nodelist)))) - sb = {} - for n in nodes: - i = index[n] - sb[n] = coshA[i, i] / expA[i, i] - return sb - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_basic.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_basic.py deleted file mode 100644 index 747985fb..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_basic.py +++ /dev/null @@ -1,123 +0,0 @@ -#!/usr/bin/env python -import pytest - -import networkx as nx -from networkx.algorithms import bipartite - - -class TestBipartiteBasic: - - def test_is_bipartite(self): - assert bipartite.is_bipartite(nx.path_graph(4)) - assert bipartite.is_bipartite(nx.DiGraph([(1, 0)])) - assert not bipartite.is_bipartite(nx.complete_graph(3)) - - def test_bipartite_color(self): - G = nx.path_graph(4) - c = bipartite.color(G) - assert c == {0: 1, 1: 0, 2: 1, 3: 0} - - def test_not_bipartite_color(self): - with pytest.raises(nx.NetworkXError): - c = bipartite.color(nx.complete_graph(4)) - - def test_bipartite_directed(self): - G = bipartite.random_graph(10, 10, 0.1, directed=True) - assert bipartite.is_bipartite(G) - - def test_bipartite_sets(self): - G = nx.path_graph(4) - X, Y = bipartite.sets(G) - assert X == {0, 2} - assert Y == {1, 3} - - def test_bipartite_sets_directed(self): - G = nx.path_graph(4) - D = G.to_directed() - X, Y = bipartite.sets(D) - assert X == {0, 2} - assert Y == {1, 3} - - def test_bipartite_sets_given_top_nodes(self): - G = nx.path_graph(4) - top_nodes = [0, 2] - X, Y = bipartite.sets(G, top_nodes) - assert X == {0, 2} - assert Y == {1, 3} - - def test_bipartite_sets_disconnected(self): - with pytest.raises(nx.AmbiguousSolution): - G = nx.path_graph(4) - G.add_edges_from([(5, 6), (6, 7)]) - X, Y = bipartite.sets(G) - - def test_is_bipartite_node_set(self): - G = nx.path_graph(4) - assert bipartite.is_bipartite_node_set(G, [0, 2]) - assert bipartite.is_bipartite_node_set(G, [1, 3]) - assert not bipartite.is_bipartite_node_set(G, [1, 2]) - G.add_edge(10, 20) - assert bipartite.is_bipartite_node_set(G, [0, 2, 10]) - assert bipartite.is_bipartite_node_set(G, [0, 2, 20]) - assert bipartite.is_bipartite_node_set(G, [1, 3, 10]) - assert bipartite.is_bipartite_node_set(G, [1, 3, 20]) - - def test_bipartite_density(self): - G = nx.path_graph(5) - X, Y = bipartite.sets(G) - density = float(len(list(G.edges()))) / (len(X) * len(Y)) - assert bipartite.density(G, X) == density - D = nx.DiGraph(G.edges()) - assert bipartite.density(D, X) == density / 2.0 - assert bipartite.density(nx.Graph(), {}) == 0.0 - - def test_bipartite_degrees(self): - G = nx.path_graph(5) - X = set([1, 3]) - Y = set([0, 2, 4]) - u, d = bipartite.degrees(G, Y) - assert dict(u) == {1: 2, 3: 2} - assert dict(d) == {0: 1, 2: 2, 4: 1} - - def test_bipartite_weighted_degrees(self): - G = nx.path_graph(5) - G.add_edge(0, 1, weight=0.1, other=0.2) - X = set([1, 3]) - Y = set([0, 2, 4]) - u, d = bipartite.degrees(G, Y, weight='weight') - assert dict(u) == {1: 1.1, 3: 2} - assert dict(d) == {0: 0.1, 2: 2, 4: 1} - u, d = bipartite.degrees(G, Y, weight='other') - assert dict(u) == {1: 1.2, 3: 2} - assert dict(d) == {0: 0.2, 2: 2, 4: 1} - - def test_biadjacency_matrix_weight(self): - scipy = pytest.importorskip('scipy') - G = nx.path_graph(5) - G.add_edge(0, 1, weight=2, other=4) - X = [1, 3] - Y = [0, 2, 4] - M = bipartite.biadjacency_matrix(G, X, weight='weight') - assert M[0, 0] == 2 - M = bipartite.biadjacency_matrix(G, X, weight='other') - assert M[0, 0] == 4 - - def test_biadjacency_matrix(self): - scipy = pytest.importorskip('scipy') - tops = [2, 5, 10] - bots = [5, 10, 15] - for i in range(len(tops)): - G = bipartite.random_graph(tops[i], bots[i], 0.2) - top = [n for n, d in G.nodes(data=True) if d['bipartite'] == 0] - M = bipartite.biadjacency_matrix(G, top) - assert M.shape[0] == tops[i] - assert M.shape[1] == bots[i] - - def test_biadjacency_matrix_order(self): - scipy = pytest.importorskip('scipy') - G = nx.path_graph(5) - G.add_edge(0, 1, weight=2) - X = [3, 1] - Y = [4, 2, 0] - M = bipartite.biadjacency_matrix(G, X, Y, weight='weight') - assert M[1, 2] == 2 diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_centrality.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_centrality.py deleted file mode 100644 index 143d5364..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_centrality.py +++ /dev/null @@ -1,168 +0,0 @@ -import networkx as nx -from networkx.algorithms import bipartite -from networkx.testing import almost_equal - -class TestBipartiteCentrality(object): - - @classmethod - def setup_class(cls): - cls.P4 = nx.path_graph(4) - cls.K3 = nx.complete_bipartite_graph(3, 3) - cls.C4 = nx.cycle_graph(4) - cls.davis = nx.davis_southern_women_graph() - cls.top_nodes = [n for n, d in cls.davis.nodes(data=True) - if d['bipartite'] == 0] - - def test_degree_centrality(self): - d = bipartite.degree_centrality(self.P4, [1, 3]) - answer = {0: 0.5, 1: 1.0, 2: 1.0, 3: 0.5} - assert d == answer - d = bipartite.degree_centrality(self.K3, [0, 1, 2]) - answer = {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0, 4: 1.0, 5: 1.0} - assert d == answer - d = bipartite.degree_centrality(self.C4, [0, 2]) - answer = {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0} - assert d == answer - - def test_betweenness_centrality(self): - c = bipartite.betweenness_centrality(self.P4, [1, 3]) - answer = {0: 0.0, 1: 1.0, 2: 1.0, 3: 0.0} - assert c == answer - c = bipartite.betweenness_centrality(self.K3, [0, 1, 2]) - answer = {0: 0.125, 1: 0.125, 2: 0.125, 3: 0.125, 4: 0.125, 5: 0.125} - assert c == answer - c = bipartite.betweenness_centrality(self.C4, [0, 2]) - answer = {0: 0.25, 1: 0.25, 2: 0.25, 3: 0.25} - assert c == answer - - def test_closeness_centrality(self): - c = bipartite.closeness_centrality(self.P4, [1, 3]) - answer = {0: 2.0 / 3, 1: 1.0, 2: 1.0, 3: 2.0 / 3} - assert c == answer - c = bipartite.closeness_centrality(self.K3, [0, 1, 2]) - answer = {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0, 4: 1.0, 5: 1.0} - assert c == answer - c = bipartite.closeness_centrality(self.C4, [0, 2]) - answer = {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0} - assert c == answer - G = nx.Graph() - G.add_node(0) - G.add_node(1) - c = bipartite.closeness_centrality(G, [0]) - assert c == {1: 0.0} - c = bipartite.closeness_centrality(G, [1]) - assert c == {1: 0.0} - - def test_davis_degree_centrality(self): - G = self.davis - deg = bipartite.degree_centrality(G, self.top_nodes) - answer = {'E8': 0.78, - 'E9': 0.67, - 'E7': 0.56, - 'Nora Fayette': 0.57, - 'Evelyn Jefferson': 0.57, - 'Theresa Anderson': 0.57, - 'E6': 0.44, - 'Sylvia Avondale': 0.50, - 'Laura Mandeville': 0.50, - 'Brenda Rogers': 0.50, - 'Katherina Rogers': 0.43, - 'E5': 0.44, - 'Helen Lloyd': 0.36, - 'E3': 0.33, - 'Ruth DeSand': 0.29, - 'Verne Sanderson': 0.29, - 'E12': 0.33, - 'Myra Liddel': 0.29, - 'E11': 0.22, - 'Eleanor Nye': 0.29, - 'Frances Anderson': 0.29, - 'Pearl Oglethorpe': 0.21, - 'E4': 0.22, - 'Charlotte McDowd': 0.29, - 'E10': 0.28, - 'Olivia Carleton': 0.14, - 'Flora Price': 0.14, - 'E2': 0.17, - 'E1': 0.17, - 'Dorothy Murchison': 0.14, - 'E13': 0.17, - 'E14': 0.17} - for node, value in answer.items(): - assert almost_equal(value, deg[node], places=2) - - def test_davis_betweenness_centrality(self): - G = self.davis - bet = bipartite.betweenness_centrality(G, self.top_nodes) - answer = {'E8': 0.24, - 'E9': 0.23, - 'E7': 0.13, - 'Nora Fayette': 0.11, - 'Evelyn Jefferson': 0.10, - 'Theresa Anderson': 0.09, - 'E6': 0.07, - 'Sylvia Avondale': 0.07, - 'Laura Mandeville': 0.05, - 'Brenda Rogers': 0.05, - 'Katherina Rogers': 0.05, - 'E5': 0.04, - 'Helen Lloyd': 0.04, - 'E3': 0.02, - 'Ruth DeSand': 0.02, - 'Verne Sanderson': 0.02, - 'E12': 0.02, - 'Myra Liddel': 0.02, - 'E11': 0.02, - 'Eleanor Nye': 0.01, - 'Frances Anderson': 0.01, - 'Pearl Oglethorpe': 0.01, - 'E4': 0.01, - 'Charlotte McDowd': 0.01, - 'E10': 0.01, - 'Olivia Carleton': 0.01, - 'Flora Price': 0.01, - 'E2': 0.00, - 'E1': 0.00, - 'Dorothy Murchison': 0.00, - 'E13': 0.00, - 'E14': 0.00} - for node, value in answer.items(): - assert almost_equal(value, bet[node], places=2) - - def test_davis_closeness_centrality(self): - G = self.davis - clos = bipartite.closeness_centrality(G, self.top_nodes) - answer = {'E8': 0.85, - 'E9': 0.79, - 'E7': 0.73, - 'Nora Fayette': 0.80, - 'Evelyn Jefferson': 0.80, - 'Theresa Anderson': 0.80, - 'E6': 0.69, - 'Sylvia Avondale': 0.77, - 'Laura Mandeville': 0.73, - 'Brenda Rogers': 0.73, - 'Katherina Rogers': 0.73, - 'E5': 0.59, - 'Helen Lloyd': 0.73, - 'E3': 0.56, - 'Ruth DeSand': 0.71, - 'Verne Sanderson': 0.71, - 'E12': 0.56, - 'Myra Liddel': 0.69, - 'E11': 0.54, - 'Eleanor Nye': 0.67, - 'Frances Anderson': 0.67, - 'Pearl Oglethorpe': 0.67, - 'E4': 0.54, - 'Charlotte McDowd': 0.60, - 'E10': 0.55, - 'Olivia Carleton': 0.59, - 'Flora Price': 0.59, - 'E2': 0.52, - 'E1': 0.52, - 'Dorothy Murchison': 0.65, - 'E13': 0.52, - 'E14': 0.52} - for node, value in answer.items(): - assert almost_equal(value, clos[node], places=2) diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_cluster.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_cluster.py deleted file mode 100644 index 7f4cb01a..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_cluster.py +++ /dev/null @@ -1,79 +0,0 @@ -import networkx as nx -import pytest -from networkx.algorithms.bipartite.cluster import cc_dot, cc_min, cc_max -import networkx.algorithms.bipartite as bipartite - - -def test_pairwise_bipartite_cc_functions(): - # Test functions for different kinds of bipartite clustering coefficients - # between pairs of nodes using 3 example graphs from figure 5 p. 40 - # Latapy et al (2008) - G1 = nx.Graph([(0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (1, 5), (1, 6), (1, 7)]) - G2 = nx.Graph([(0, 2), (0, 3), (0, 4), (1, 3), (1, 4), (1, 5)]) - G3 = nx.Graph([(0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9)]) - result = {0: [1 / 3.0, 2 / 3.0, 2 / 5.0], - 1: [1 / 2.0, 2 / 3.0, 2 / 3.0], - 2: [2 / 8.0, 2 / 5.0, 2 / 5.0]} - for i, G in enumerate([G1, G2, G3]): - assert(bipartite.is_bipartite(G)) - assert(cc_dot(set(G[0]), set(G[1])) == result[i][0]) - assert(cc_min(set(G[0]), set(G[1])) == result[i][1]) - assert(cc_max(set(G[0]), set(G[1])) == result[i][2]) - - -def test_star_graph(): - G = nx.star_graph(3) - # all modes are the same - answer = {0: 0, 1: 1, 2: 1, 3: 1} - assert bipartite.clustering(G, mode='dot') == answer - assert bipartite.clustering(G, mode='min') == answer - assert bipartite.clustering(G, mode='max') == answer - - -def test_not_bipartite(): - with pytest.raises(nx.NetworkXError): - bipartite.clustering(nx.complete_graph(4)) - - -def test_bad_mode(): - with pytest.raises(nx.NetworkXError): - bipartite.clustering(nx.path_graph(4), mode='foo') - - -def test_path_graph(): - G = nx.path_graph(4) - answer = {0: 0.5, 1: 0.5, 2: 0.5, 3: 0.5} - assert bipartite.clustering(G, mode='dot') == answer - assert bipartite.clustering(G, mode='max') == answer - answer = {0: 1, 1: 1, 2: 1, 3: 1} - assert bipartite.clustering(G, mode='min') == answer - - -def test_average_path_graph(): - G = nx.path_graph(4) - assert bipartite.average_clustering(G, mode='dot') == 0.5 - assert bipartite.average_clustering(G, mode='max') == 0.5 - assert bipartite.average_clustering(G, mode='min') == 1 - - -def test_ra_clustering_davis(): - G = nx.davis_southern_women_graph() - cc4 = round(bipartite.robins_alexander_clustering(G), 3) - assert cc4 == 0.468 - - -def test_ra_clustering_square(): - G = nx.path_graph(4) - G.add_edge(0, 3) - assert bipartite.robins_alexander_clustering(G) == 1.0 - - -def test_ra_clustering_zero(): - G = nx.Graph() - assert bipartite.robins_alexander_clustering(G) == 0 - G.add_nodes_from(range(4)) - assert bipartite.robins_alexander_clustering(G) == 0 - G.add_edges_from([(0, 1), (2, 3), (3, 4)]) - assert bipartite.robins_alexander_clustering(G) == 0 - G.add_edge(1, 2) - assert bipartite.robins_alexander_clustering(G) == 0 diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_covering.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_covering.py deleted file mode 100644 index 2fd7173b..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_covering.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2016-2019 NetworkX developers. -# Copyright (C) 2016 by -# Nishant Nikhil -# All rights reserved. -# BSD license. - -import networkx as nx -import networkx.algorithms.bipartite as bipartite - - -class TestMinEdgeCover: - """Tests for :func:`networkx.algorithms.bipartite.min_edge_cover`""" - - def test_empty_graph(self): - G = nx.Graph() - assert bipartite.min_edge_cover(G) == set() - - def test_graph_single_edge(self): - G = nx.Graph() - G.add_edge(0, 1) - assert (bipartite.min_edge_cover(G) == - {(0, 1), (1, 0)}) - - def test_bipartite_default(self): - G = nx.Graph() - G.add_nodes_from([1, 2, 3, 4], bipartite=0) - G.add_nodes_from(['a', 'b', 'c'], bipartite=1) - G.add_edges_from([(1, 'a'), (1, 'b'), (2, 'b'), - (2, 'c'), (3, 'c'), (4, 'a')]) - min_cover = bipartite.min_edge_cover(G) - assert nx.is_edge_cover(G, min_cover) - assert len(min_cover) == 8 - - def test_bipartite_explicit(self): - G = nx.Graph() - G.add_nodes_from([1, 2, 3, 4], bipartite=0) - G.add_nodes_from(['a', 'b', 'c'], bipartite=1) - G.add_edges_from([(1, 'a'), (1, 'b'), (2, 'b'), - (2, 'c'), (3, 'c'), (4, 'a')]) - min_cover = bipartite.min_edge_cover(G, - bipartite.eppstein_matching) - assert nx.is_edge_cover(G, min_cover) - assert len(min_cover) == 8 diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_edgelist.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_edgelist.py deleted file mode 100644 index 5febdd15..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_edgelist.py +++ /dev/null @@ -1,205 +0,0 @@ -""" - Unit tests for bipartite edgelists. -""" -import pytest -import io -import tempfile -import os - -import networkx as nx -from networkx.testing import (assert_edges_equal, assert_nodes_equal, - assert_graphs_equal) -from networkx.algorithms import bipartite - - -class TestEdgelist: - - @classmethod - def setup_class(cls): - cls.G = nx.Graph(name="test") - e = [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'e'), ('e', 'f'), ('a', 'f')] - cls.G.add_edges_from(e) - cls.G.add_nodes_from(['a', 'c', 'e'], bipartite=0) - cls.G.add_nodes_from(['b', 'd', 'f'], bipartite=1) - cls.G.add_node('g', bipartite=0) - cls.DG = nx.DiGraph(cls.G) - cls.MG = nx.MultiGraph() - cls.MG.add_edges_from([(1, 2), (1, 2), (1, 2)]) - cls.MG.add_node(1, bipartite=0) - cls.MG.add_node(2, bipartite=1) - - def test_read_edgelist_1(self): - s = b"""\ -# comment line -1 2 -# comment line -2 3 -""" - bytesIO = io.BytesIO(s) - G = bipartite.read_edgelist(bytesIO, nodetype=int) - assert_edges_equal(G.edges(), [(1, 2), (2, 3)]) - - def test_read_edgelist_3(self): - s = b"""\ -# comment line -1 2 {'weight':2.0} -# comment line -2 3 {'weight':3.0} -""" - bytesIO = io.BytesIO(s) - G = bipartite.read_edgelist(bytesIO, nodetype=int, data=False) - assert_edges_equal(G.edges(), [(1, 2), (2, 3)]) - - bytesIO = io.BytesIO(s) - G = bipartite.read_edgelist(bytesIO, nodetype=int, data=True) - assert_edges_equal(G.edges(data=True), - [(1, 2, {'weight': 2.0}), (2, 3, {'weight': 3.0})]) - - def test_write_edgelist_1(self): - fh = io.BytesIO() - G = nx.Graph() - G.add_edges_from([(1, 2), (2, 3)]) - G.add_node(1, bipartite=0) - G.add_node(2, bipartite=1) - G.add_node(3, bipartite=0) - bipartite.write_edgelist(G, fh, data=False) - fh.seek(0) - assert fh.read() == b"1 2\n3 2\n" - - def test_write_edgelist_2(self): - fh = io.BytesIO() - G = nx.Graph() - G.add_edges_from([(1, 2), (2, 3)]) - G.add_node(1, bipartite=0) - G.add_node(2, bipartite=1) - G.add_node(3, bipartite=0) - bipartite.write_edgelist(G, fh, data=True) - fh.seek(0) - assert fh.read() == b"1 2 {}\n3 2 {}\n" - - def test_write_edgelist_3(self): - fh = io.BytesIO() - G = nx.Graph() - G.add_edge(1, 2, weight=2.0) - G.add_edge(2, 3, weight=3.0) - G.add_node(1, bipartite=0) - G.add_node(2, bipartite=1) - G.add_node(3, bipartite=0) - bipartite.write_edgelist(G, fh, data=True) - fh.seek(0) - assert fh.read() == b"1 2 {'weight': 2.0}\n3 2 {'weight': 3.0}\n" - - def test_write_edgelist_4(self): - fh = io.BytesIO() - G = nx.Graph() - G.add_edge(1, 2, weight=2.0) - G.add_edge(2, 3, weight=3.0) - G.add_node(1, bipartite=0) - G.add_node(2, bipartite=1) - G.add_node(3, bipartite=0) - bipartite.write_edgelist(G, fh, data=[('weight')]) - fh.seek(0) - assert fh.read() == b"1 2 2.0\n3 2 3.0\n" - - def test_unicode(self): - G = nx.Graph() - try: # Python 3.x - name1 = chr(2344) + chr(123) + chr(6543) - name2 = chr(5543) + chr(1543) + chr(324) - except ValueError: # Python 2.6+ - name1 = unichr(2344) + unichr(123) + unichr(6543) - name2 = unichr(5543) + unichr(1543) + unichr(324) - G.add_edge(name1, 'Radiohead', **{name2: 3}) - G.add_node(name1, bipartite=0) - G.add_node('Radiohead', bipartite=1) - fd, fname = tempfile.mkstemp() - bipartite.write_edgelist(G, fname) - H = bipartite.read_edgelist(fname) - assert_graphs_equal(G, H) - os.close(fd) - os.unlink(fname) - - def test_latin1_issue(self): - G = nx.Graph() - try: # Python 3.x - name1 = chr(2344) + chr(123) + chr(6543) - name2 = chr(5543) + chr(1543) + chr(324) - except ValueError: # Python 2.6+ - name1 = unichr(2344) + unichr(123) + unichr(6543) - name2 = unichr(5543) + unichr(1543) + unichr(324) - G.add_edge(name1, 'Radiohead', **{name2: 3}) - G.add_node(name1, bipartite=0) - G.add_node('Radiohead', bipartite=1) - fd, fname = tempfile.mkstemp() - pytest.raises(UnicodeEncodeError, - bipartite.write_edgelist, - G, fname, encoding='latin-1') - os.close(fd) - os.unlink(fname) - - def test_latin1(self): - G = nx.Graph() - try: # Python 3.x - blurb = chr(1245) # just to trigger the exception - name1 = 'Bj' + chr(246) + 'rk' - name2 = chr(220) + 'ber' - except ValueError: # Python 2.6+ - name1 = 'Bj' + unichr(246) + 'rk' - name2 = unichr(220) + 'ber' - G.add_edge(name1, 'Radiohead', **{name2: 3}) - G.add_node(name1, bipartite=0) - G.add_node('Radiohead', bipartite=1) - fd, fname = tempfile.mkstemp() - bipartite.write_edgelist(G, fname, encoding='latin-1') - H = bipartite.read_edgelist(fname, encoding='latin-1') - assert_graphs_equal(G, H) - os.close(fd) - os.unlink(fname) - - def test_edgelist_graph(self): - G = self.G - (fd, fname) = tempfile.mkstemp() - bipartite.write_edgelist(G, fname) - H = bipartite.read_edgelist(fname) - H2 = bipartite.read_edgelist(fname) - assert H != H2 # they should be different graphs - G.remove_node('g') # isolated nodes are not written in edgelist - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_edgelist_integers(self): - G = nx.convert_node_labels_to_integers(self.G) - (fd, fname) = tempfile.mkstemp() - bipartite.write_edgelist(G, fname) - H = bipartite.read_edgelist(fname, nodetype=int) - # isolated nodes are not written in edgelist - G.remove_nodes_from(list(nx.isolates(G))) - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_edgelist_multigraph(self): - G = self.MG - (fd, fname) = tempfile.mkstemp() - bipartite.write_edgelist(G, fname) - H = bipartite.read_edgelist(fname, nodetype=int, create_using=nx.MultiGraph()) - H2 = bipartite.read_edgelist(fname, nodetype=int, create_using=nx.MultiGraph()) - assert H != H2 # they should be different graphs - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_empty_digraph(self): - with pytest.raises(nx.NetworkXNotImplemented): - bytesIO = io.BytesIO() - bipartite.write_edgelist(nx.DiGraph(), bytesIO) - - def test_raise_attribute(self): - with pytest.raises(AttributeError): - G = nx.path_graph(4) - bytesIO = io.BytesIO() - bipartite.write_edgelist(G, bytesIO) diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_generators.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_generators.py deleted file mode 100644 index 33a39769..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_generators.py +++ /dev/null @@ -1,351 +0,0 @@ -#!/usr/bin/env python - -import pytest -import networkx as nx -from networkx.algorithms.bipartite.generators import * - -"""Generators - Bipartite ----------------------- -""" - - -class TestGeneratorsBipartite(): - def test_complete_bipartite_graph(self): - G = complete_bipartite_graph(0, 0) - assert nx.is_isomorphic(G, nx.null_graph()) - - for i in [1, 5]: - G = complete_bipartite_graph(i, 0) - assert nx.is_isomorphic(G, nx.empty_graph(i)) - G = complete_bipartite_graph(0, i) - assert nx.is_isomorphic(G, nx.empty_graph(i)) - - G = complete_bipartite_graph(2, 2) - assert nx.is_isomorphic(G, nx.cycle_graph(4)) - - G = complete_bipartite_graph(1, 5) - assert nx.is_isomorphic(G, nx.star_graph(5)) - - G = complete_bipartite_graph(5, 1) - assert nx.is_isomorphic(G, nx.star_graph(5)) - - # complete_bipartite_graph(m1,m2) is a connected graph with - # m1+m2 nodes and m1*m2 edges - for m1, m2 in [(5, 11), (7, 3)]: - G = complete_bipartite_graph(m1, m2) - assert nx.number_of_nodes(G) == m1 + m2 - assert nx.number_of_edges(G) == m1 * m2 - - pytest.raises(nx.NetworkXError, complete_bipartite_graph, - 7, 3, create_using=nx.DiGraph) - pytest.raises(nx.NetworkXError, complete_bipartite_graph, - 7, 3, create_using=nx.DiGraph) - pytest.raises(nx.NetworkXError, complete_bipartite_graph, - 7, 3, create_using=nx.MultiDiGraph) - - mG = complete_bipartite_graph(7, 3, create_using=nx.MultiGraph) - assert mG.is_multigraph() - assert sorted(mG.edges()) == sorted(G.edges()) - - mG = complete_bipartite_graph(7, 3, create_using=nx.MultiGraph) - assert mG.is_multigraph() - assert sorted(mG.edges()) == sorted(G.edges()) - - mG = complete_bipartite_graph(7, 3) # default to Graph - assert sorted(mG.edges()) == sorted(G.edges()) - assert not mG.is_multigraph() - assert not mG.is_directed() - - # specify nodes rather than number of nodes - G = complete_bipartite_graph([1, 2], ['a', 'b']) - has_edges = G.has_edge(1, 'a') & G.has_edge(1, 'b') &\ - G.has_edge(2, 'a') & G.has_edge(2, 'b') - assert has_edges - assert G.size() == 4 - - def test_configuration_model(self): - aseq = [] - bseq = [] - G = configuration_model(aseq, bseq) - assert len(G) == 0 - - aseq = [0, 0] - bseq = [0, 0] - G = configuration_model(aseq, bseq) - assert len(G) == 4 - assert G.number_of_edges() == 0 - - aseq = [3, 3, 3, 3] - bseq = [2, 2, 2, 2, 2] - pytest.raises(nx.NetworkXError, - configuration_model, aseq, bseq) - - aseq = [3, 3, 3, 3] - bseq = [2, 2, 2, 2, 2, 2] - G = configuration_model(aseq, bseq) - assert (sorted(d for n, d in G.degree()) == - [2, 2, 2, 2, 2, 2, 3, 3, 3, 3]) - - aseq = [2, 2, 2, 2, 2, 2] - bseq = [3, 3, 3, 3] - G = configuration_model(aseq, bseq) - assert (sorted(d for n, d in G.degree()) == - [2, 2, 2, 2, 2, 2, 3, 3, 3, 3]) - - aseq = [2, 2, 2, 1, 1, 1] - bseq = [3, 3, 3] - G = configuration_model(aseq, bseq) - assert G.is_multigraph() - assert not G.is_directed() - assert (sorted(d for n, d in G.degree()) == - [1, 1, 1, 2, 2, 2, 3, 3, 3]) - - GU = nx.project(nx.Graph(G), range(len(aseq))) - assert GU.number_of_nodes() == 6 - - GD = nx.project(nx.Graph(G), range(len(aseq), len(aseq) + len(bseq))) - assert GD.number_of_nodes() == 3 - - G = reverse_havel_hakimi_graph(aseq, bseq, create_using=nx.Graph) - assert not G.is_multigraph() - assert not G.is_directed() - - pytest.raises(nx.NetworkXError, - configuration_model, aseq, bseq, - create_using=nx.DiGraph()) - pytest.raises(nx.NetworkXError, - configuration_model, aseq, bseq, - create_using=nx.DiGraph) - pytest.raises(nx.NetworkXError, - configuration_model, aseq, bseq, - create_using=nx.MultiDiGraph) - - def test_havel_hakimi_graph(self): - aseq = [] - bseq = [] - G = havel_hakimi_graph(aseq, bseq) - assert len(G) == 0 - - aseq = [0, 0] - bseq = [0, 0] - G = havel_hakimi_graph(aseq, bseq) - assert len(G) == 4 - assert G.number_of_edges() == 0 - - aseq = [3, 3, 3, 3] - bseq = [2, 2, 2, 2, 2] - pytest.raises(nx.NetworkXError, - havel_hakimi_graph, aseq, bseq) - - bseq = [2, 2, 2, 2, 2, 2] - G = havel_hakimi_graph(aseq, bseq) - assert (sorted(d for n, d in G.degree()) == - [2, 2, 2, 2, 2, 2, 3, 3, 3, 3]) - - aseq = [2, 2, 2, 2, 2, 2] - bseq = [3, 3, 3, 3] - G = havel_hakimi_graph(aseq, bseq) - assert G.is_multigraph() - assert not G.is_directed() - assert (sorted(d for n, d in G.degree()) == - [2, 2, 2, 2, 2, 2, 3, 3, 3, 3]) - - GU = nx.project(nx.Graph(G), range(len(aseq))) - assert GU.number_of_nodes() == 6 - - GD = nx.project(nx.Graph(G), range(len(aseq), len(aseq) + len(bseq))) - assert GD.number_of_nodes() == 4 - - G = reverse_havel_hakimi_graph(aseq, bseq, create_using=nx.Graph) - assert not G.is_multigraph() - assert not G.is_directed() - - pytest.raises(nx.NetworkXError, - havel_hakimi_graph, aseq, bseq, - create_using=nx.DiGraph) - pytest.raises(nx.NetworkXError, - havel_hakimi_graph, aseq, bseq, - create_using=nx.DiGraph) - pytest.raises(nx.NetworkXError, - havel_hakimi_graph, aseq, bseq, - create_using=nx.MultiDiGraph) - - def test_reverse_havel_hakimi_graph(self): - aseq = [] - bseq = [] - G = reverse_havel_hakimi_graph(aseq, bseq) - assert len(G) == 0 - - aseq = [0, 0] - bseq = [0, 0] - G = reverse_havel_hakimi_graph(aseq, bseq) - assert len(G) == 4 - assert G.number_of_edges() == 0 - - aseq = [3, 3, 3, 3] - bseq = [2, 2, 2, 2, 2] - pytest.raises(nx.NetworkXError, - reverse_havel_hakimi_graph, aseq, bseq) - - bseq = [2, 2, 2, 2, 2, 2] - G = reverse_havel_hakimi_graph(aseq, bseq) - assert (sorted(d for n, d in G.degree()) == - [2, 2, 2, 2, 2, 2, 3, 3, 3, 3]) - - aseq = [2, 2, 2, 2, 2, 2] - bseq = [3, 3, 3, 3] - G = reverse_havel_hakimi_graph(aseq, bseq) - assert (sorted(d for n, d in G.degree()) == - [2, 2, 2, 2, 2, 2, 3, 3, 3, 3]) - - aseq = [2, 2, 2, 1, 1, 1] - bseq = [3, 3, 3] - G = reverse_havel_hakimi_graph(aseq, bseq) - assert G.is_multigraph() - assert not G.is_directed() - assert (sorted(d for n, d in G.degree()) == - [1, 1, 1, 2, 2, 2, 3, 3, 3]) - - GU = nx.project(nx.Graph(G), range(len(aseq))) - assert GU.number_of_nodes() == 6 - - GD = nx.project(nx.Graph(G), range(len(aseq), len(aseq) + len(bseq))) - assert GD.number_of_nodes() == 3 - - G = reverse_havel_hakimi_graph(aseq, bseq, create_using=nx.Graph) - assert not G.is_multigraph() - assert not G.is_directed() - - pytest.raises(nx.NetworkXError, - reverse_havel_hakimi_graph, aseq, bseq, - create_using=nx.DiGraph) - pytest.raises(nx.NetworkXError, - reverse_havel_hakimi_graph, aseq, bseq, - create_using=nx.DiGraph) - pytest.raises(nx.NetworkXError, - reverse_havel_hakimi_graph, aseq, bseq, - create_using=nx.MultiDiGraph) - - def test_alternating_havel_hakimi_graph(self): - aseq = [] - bseq = [] - G = alternating_havel_hakimi_graph(aseq, bseq) - assert len(G) == 0 - - aseq = [0, 0] - bseq = [0, 0] - G = alternating_havel_hakimi_graph(aseq, bseq) - assert len(G) == 4 - assert G.number_of_edges() == 0 - - aseq = [3, 3, 3, 3] - bseq = [2, 2, 2, 2, 2] - pytest.raises(nx.NetworkXError, - alternating_havel_hakimi_graph, aseq, bseq) - - bseq = [2, 2, 2, 2, 2, 2] - G = alternating_havel_hakimi_graph(aseq, bseq) - assert (sorted(d for n, d in G.degree()) == - [2, 2, 2, 2, 2, 2, 3, 3, 3, 3]) - - aseq = [2, 2, 2, 2, 2, 2] - bseq = [3, 3, 3, 3] - G = alternating_havel_hakimi_graph(aseq, bseq) - assert (sorted(d for n, d in G.degree()) == - [2, 2, 2, 2, 2, 2, 3, 3, 3, 3]) - - aseq = [2, 2, 2, 1, 1, 1] - bseq = [3, 3, 3] - G = alternating_havel_hakimi_graph(aseq, bseq) - assert G.is_multigraph() - assert not G.is_directed() - assert (sorted(d for n, d in G.degree()) == - [1, 1, 1, 2, 2, 2, 3, 3, 3]) - - GU = nx.project(nx.Graph(G), range(len(aseq))) - assert GU.number_of_nodes() == 6 - - GD = nx.project(nx.Graph(G), range(len(aseq), len(aseq) + len(bseq))) - assert GD.number_of_nodes() == 3 - - G = reverse_havel_hakimi_graph(aseq, bseq, create_using=nx.Graph) - assert not G.is_multigraph() - assert not G.is_directed() - - pytest.raises(nx.NetworkXError, - alternating_havel_hakimi_graph, aseq, bseq, - create_using=nx.DiGraph) - pytest.raises(nx.NetworkXError, - alternating_havel_hakimi_graph, aseq, bseq, - create_using=nx.DiGraph) - pytest.raises(nx.NetworkXError, - alternating_havel_hakimi_graph, aseq, bseq, - create_using=nx.MultiDiGraph) - - def test_preferential_attachment(self): - aseq = [3, 2, 1, 1] - G = preferential_attachment_graph(aseq, 0.5) - assert G.is_multigraph() - assert not G.is_directed() - - G = preferential_attachment_graph(aseq, 0.5, create_using=nx.Graph) - assert not G.is_multigraph() - assert not G.is_directed() - - pytest.raises(nx.NetworkXError, - preferential_attachment_graph, aseq, 0.5, - create_using=nx.DiGraph()) - pytest.raises(nx.NetworkXError, - preferential_attachment_graph, aseq, 0.5, - create_using=nx.DiGraph()) - pytest.raises(nx.NetworkXError, - preferential_attachment_graph, aseq, 0.5, - create_using=nx.DiGraph()) - - def test_random_graph(self): - n = 10 - m = 20 - G = random_graph(n, m, 0.9) - assert len(G) == 30 - assert nx.is_bipartite(G) - X, Y = nx.algorithms.bipartite.sets(G) - assert set(range(n)) == X - assert set(range(n, n + m)) == Y - - def test_random_digraph(self): - n = 10 - m = 20 - G = random_graph(n, m, 0.9, directed=True) - assert len(G) == 30 - assert nx.is_bipartite(G) - X, Y = nx.algorithms.bipartite.sets(G) - assert set(range(n)) == X - assert set(range(n, n + m)) == Y - - def test_gnmk_random_graph(self): - n = 10 - m = 20 - edges = 100 - # set seed because sometimes it is not connected - # which raises an error in bipartite.sets(G) below. - G = gnmk_random_graph(n, m, edges, seed=1234) - assert len(G) == n + m - assert nx.is_bipartite(G) - X, Y = nx.algorithms.bipartite.sets(G) - #print(X) - assert set(range(n)) == X - assert set(range(n, n + m)) == Y - assert edges == len(list(G.edges())) - - def test_gnmk_random_graph_complete(self): - n = 10 - m = 20 - edges = 200 - G = gnmk_random_graph(n, m, edges) - assert len(G) == n + m - assert nx.is_bipartite(G) - X, Y = nx.algorithms.bipartite.sets(G) - #print(X) - assert set(range(n)) == X - assert set(range(n, n + m)) == Y - assert edges == len(list(G.edges())) diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_matching.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_matching.py deleted file mode 100644 index 1be2dcd6..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_matching.py +++ /dev/null @@ -1,300 +0,0 @@ -# test_matching.py - unit tests for bipartite matching algorithms -# -# Copyright 2015 Jeffrey Finkelstein , -# Copyright 2019 Søren Fuglede Jørgensen -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.bipartite.matching` module.""" -import itertools - -import networkx as nx - -import pytest - -from networkx.algorithms.bipartite.matching import eppstein_matching -from networkx.algorithms.bipartite.matching import hopcroft_karp_matching -from networkx.algorithms.bipartite.matching import maximum_matching -from networkx.algorithms.bipartite.matching import minimum_weight_full_matching -from networkx.algorithms.bipartite.matching import to_vertex_cover - - -class TestMatching(): - """Tests for bipartite matching algorithms.""" - - def setup(self): - """Creates a bipartite graph for use in testing matching algorithms. - - The bipartite graph has a maximum cardinality matching that leaves - vertex 1 and vertex 10 unmatched. The first six numbers are the left - vertices and the next six numbers are the right vertices. - - """ - self.simple_graph = nx.complete_bipartite_graph(2, 3) - self.simple_solution = {0: 2, 1: 3, 2: 0, 3: 1} - - edges = [(0, 7), (0, 8), (2, 6), (2, 9), (3, 8), (4, 8), (4, 9), - (5, 11)] - self.top_nodes = set(range(6)) - self.graph = nx.Graph() - self.graph.add_nodes_from(range(12)) - self.graph.add_edges_from(edges) - - # Example bipartite graph from issue 2127 - G = nx.Graph() - G.add_nodes_from([ - (1, 'C'), (1, 'B'), (0, 'G'), (1, 'F'), - (1, 'E'), (0, 'C'), (1, 'D'), (1, 'I'), - (0, 'A'), (0, 'D'), (0, 'F'), (0, 'E'), - (0, 'H'), (1, 'G'), (1, 'A'), (0, 'I'), - (0, 'B'), (1, 'H'), - ]) - G.add_edge((1, 'C'), (0, 'A')) - G.add_edge((1, 'B'), (0, 'A')) - G.add_edge((0, 'G'), (1, 'I')) - G.add_edge((0, 'G'), (1, 'H')) - G.add_edge((1, 'F'), (0, 'A')) - G.add_edge((1, 'F'), (0, 'C')) - G.add_edge((1, 'F'), (0, 'E')) - G.add_edge((1, 'E'), (0, 'A')) - G.add_edge((1, 'E'), (0, 'C')) - G.add_edge((0, 'C'), (1, 'D')) - G.add_edge((0, 'C'), (1, 'I')) - G.add_edge((0, 'C'), (1, 'G')) - G.add_edge((0, 'C'), (1, 'H')) - G.add_edge((1, 'D'), (0, 'A')) - G.add_edge((1, 'I'), (0, 'A')) - G.add_edge((1, 'I'), (0, 'E')) - G.add_edge((0, 'A'), (1, 'G')) - G.add_edge((0, 'A'), (1, 'H')) - G.add_edge((0, 'E'), (1, 'G')) - G.add_edge((0, 'E'), (1, 'H')) - self.disconnected_graph = G - - def check_match(self, matching): - """Asserts that the matching is what we expect from the bipartite graph - constructed in the :meth:`setup` fixture. - - """ - # For the sake of brevity, rename `matching` to `M`. - M = matching - matched_vertices = frozenset(itertools.chain(*M.items())) - # Assert that the maximum number of vertices (10) is matched. - assert matched_vertices == frozenset(range(12)) - {1, 10} - # Assert that no vertex appears in two edges, or in other words, that - # the matching (u, v) and (v, u) both appear in the matching - # dictionary. - assert all(u == M[M[u]] for u in range(12) if u in M) - - def check_vertex_cover(self, vertices): - """Asserts that the given set of vertices is the vertex cover we - expected from the bipartite graph constructed in the :meth:`setup` - fixture. - - """ - # By Konig's theorem, the number of edges in a maximum matching equals - # the number of vertices in a minimum vertex cover. - assert len(vertices) == 5 - # Assert that the set is truly a vertex cover. - for (u, v) in self.graph.edges(): - assert u in vertices or v in vertices - # TODO Assert that the vertices are the correct ones. - - def test_eppstein_matching(self): - """Tests that David Eppstein's implementation of the Hopcroft--Karp - algorithm produces a maximum cardinality matching. - - """ - self.check_match(eppstein_matching(self.graph, self.top_nodes)) - - def test_hopcroft_karp_matching(self): - """Tests that the Hopcroft--Karp algorithm produces a maximum - cardinality matching in a bipartite graph. - - """ - self.check_match(hopcroft_karp_matching(self.graph, self.top_nodes)) - - def test_to_vertex_cover(self): - """Test for converting a maximum matching to a minimum vertex cover.""" - matching = maximum_matching(self.graph, self.top_nodes) - vertex_cover = to_vertex_cover(self.graph, matching, self.top_nodes) - self.check_vertex_cover(vertex_cover) - - def test_eppstein_matching_simple(self): - match = eppstein_matching(self.simple_graph) - assert match == self.simple_solution - - def test_hopcroft_karp_matching_simple(self): - match = hopcroft_karp_matching(self.simple_graph) - assert match == self.simple_solution - - def test_eppstein_matching_disconnected(self): - with pytest.raises(nx.AmbiguousSolution): - match = eppstein_matching(self.disconnected_graph) - - def test_hopcroft_karp_matching_disconnected(self): - with pytest.raises(nx.AmbiguousSolution): - match = hopcroft_karp_matching(self.disconnected_graph) - - def test_issue_2127(self): - """Test from issue 2127""" - # Build the example DAG - G = nx.DiGraph() - G.add_edge("A", "C") - G.add_edge("A", "B") - G.add_edge("C", "E") - G.add_edge("C", "D") - G.add_edge("E", "G") - G.add_edge("E", "F") - G.add_edge("G", "I") - G.add_edge("G", "H") - - tc = nx.transitive_closure(G) - btc = nx.Graph() - - # Create a bipartite graph based on the transitive closure of G - for v in tc.nodes(): - btc.add_node((0, v)) - btc.add_node((1, v)) - - for u, v in tc.edges(): - btc.add_edge((0, u), (1, v)) - - top_nodes = {n for n in btc if n[0] == 0} - matching = hopcroft_karp_matching(btc, top_nodes) - vertex_cover = to_vertex_cover(btc, matching, top_nodes) - independent_set = set(G) - {v for _, v in vertex_cover} - assert {'B', 'D', 'F', 'I', 'H'} == independent_set - - def test_vertex_cover_issue_2384(self): - G = nx.Graph([(0, 3), (1, 3), (1, 4), (2, 3)]) - matching = maximum_matching(G) - vertex_cover = to_vertex_cover(G, matching) - for u, v in G.edges(): - assert u in vertex_cover or v in vertex_cover - - def test_unorderable_nodes(self): - a = object() - b = object() - c = object() - d = object() - e = object() - G = nx.Graph([(a, d), (b, d), (b, e), (c, d)]) - matching = maximum_matching(G) - vertex_cover = to_vertex_cover(G, matching) - for u, v in G.edges(): - assert u in vertex_cover or v in vertex_cover - - -def test_eppstein_matching(): - """Test in accordance to issue #1927""" - G = nx.Graph() - G.add_nodes_from(['a', 2, 3, 4], bipartite=0) - G.add_nodes_from([1, 'b', 'c'], bipartite=1) - G.add_edges_from([('a', 1), ('a', 'b'), (2, 'b'), - (2, 'c'), (3, 'c'), (4, 1)]) - matching = eppstein_matching(G) - assert len(matching) == len(maximum_matching(G)) - assert all(x in set(matching.keys()) for x in set(matching.values())) - - -class TestMinimumWeightFullMatching(object): - - @classmethod - def setup_class(cls): - global scipy - scipy = pytest.importorskip('scipy') - - def test_minimum_weight_full_matching_square(self): - G = nx.complete_bipartite_graph(3, 3) - G.add_edge(0, 3, weight=400) - G.add_edge(0, 4, weight=150) - G.add_edge(0, 5, weight=400) - G.add_edge(1, 3, weight=400) - G.add_edge(1, 4, weight=450) - G.add_edge(1, 5, weight=600) - G.add_edge(2, 3, weight=300) - G.add_edge(2, 4, weight=225) - G.add_edge(2, 5, weight=300) - matching = minimum_weight_full_matching(G) - assert matching == {0: 4, 1: 3, 2: 5, 4: 0, 3: 1, 5: 2} - - def test_minimum_weight_full_matching_smaller_left(self): - G = nx.complete_bipartite_graph(3, 4) - G.add_edge(0, 3, weight=400) - G.add_edge(0, 4, weight=150) - G.add_edge(0, 5, weight=400) - G.add_edge(0, 6, weight=1) - G.add_edge(1, 3, weight=400) - G.add_edge(1, 4, weight=450) - G.add_edge(1, 5, weight=600) - G.add_edge(1, 6, weight=2) - G.add_edge(2, 3, weight=300) - G.add_edge(2, 4, weight=225) - G.add_edge(2, 5, weight=290) - G.add_edge(2, 6, weight=3) - matching = minimum_weight_full_matching(G) - assert matching == {0: 4, 1: 6, 2: 5, 4: 0, 5: 2, 6: 1} - - def test_minimum_weight_full_matching_smaller_top_nodes_right(self): - G = nx.complete_bipartite_graph(3, 4) - G.add_edge(0, 3, weight=400) - G.add_edge(0, 4, weight=150) - G.add_edge(0, 5, weight=400) - G.add_edge(0, 6, weight=1) - G.add_edge(1, 3, weight=400) - G.add_edge(1, 4, weight=450) - G.add_edge(1, 5, weight=600) - G.add_edge(1, 6, weight=2) - G.add_edge(2, 3, weight=300) - G.add_edge(2, 4, weight=225) - G.add_edge(2, 5, weight=290) - G.add_edge(2, 6, weight=3) - matching = minimum_weight_full_matching(G, top_nodes=[3, 4, 5, 6]) - assert matching == {0: 4, 1: 6, 2: 5, 4: 0, 5: 2, 6: 1} - - def test_minimum_weight_full_matching_smaller_right(self): - G = nx.complete_bipartite_graph(4, 3) - G.add_edge(0, 4, weight=400) - G.add_edge(0, 5, weight=400) - G.add_edge(0, 6, weight=300) - G.add_edge(1, 4, weight=150) - G.add_edge(1, 5, weight=450) - G.add_edge(1, 6, weight=225) - G.add_edge(2, 4, weight=400) - G.add_edge(2, 5, weight=600) - G.add_edge(2, 6, weight=290) - G.add_edge(3, 4, weight=1) - G.add_edge(3, 5, weight=2) - G.add_edge(3, 6, weight=3) - matching = minimum_weight_full_matching(G) - assert matching == {1: 4, 2: 6, 3: 5, 4: 1, 5: 3, 6: 2} - - def test_minimum_weight_full_matching_negative_weights(self): - G = nx.complete_bipartite_graph(2, 2) - G.add_edge(0, 2, weight=-2) - G.add_edge(0, 3, weight=0.2) - G.add_edge(1, 2, weight=-2) - G.add_edge(1, 3, weight=0.3) - matching = minimum_weight_full_matching(G) - assert matching == {0: 3, 1: 2, 2: 1, 3: 0} - - def test_minimum_weight_full_matching_different_weight_key(self): - G = nx.complete_bipartite_graph(2, 2) - G.add_edge(0, 2, mass=2) - G.add_edge(0, 3, mass=0.2) - G.add_edge(1, 2, mass=1) - G.add_edge(1, 3, mass=2) - matching = minimum_weight_full_matching(G, weight='mass') - assert matching == {0: 3, 1: 2, 2: 1, 3: 0} - - def test_minimum_weight_full_matching_requires_complete_input(self): - with pytest.raises(ValueError): - G = nx.Graph() - G.add_nodes_from([1, 2, 3, 4], bipartite=0) - G.add_nodes_from(['a', 'b', 'c'], bipartite=1) - G.add_edges_from([(1, 'a'), (1, 'b'), (2, 'b'), - (2, 'c'), (3, 'c'), (4, 'a')]) - minimum_weight_full_matching(G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_matrix.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_matrix.py deleted file mode 100644 index 129941de..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_matrix.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env python -import pytest -np = pytest.importorskip('numpy') -sp = pytest.importorskip('scipy') -sparse = pytest.importorskip('scipy.sparse') - - -import networkx as nx -from networkx.algorithms import bipartite -from networkx.testing.utils import assert_edges_equal - - -class TestBiadjacencyMatrix: - - def test_biadjacency_matrix_weight(self): - G = nx.path_graph(5) - G.add_edge(0, 1, weight=2, other=4) - X = [1, 3] - Y = [0, 2, 4] - M = bipartite.biadjacency_matrix(G, X, weight='weight') - assert M[0, 0] == 2 - M = bipartite.biadjacency_matrix(G, X, weight='other') - assert M[0, 0] == 4 - - def test_biadjacency_matrix(self): - tops = [2, 5, 10] - bots = [5, 10, 15] - for i in range(len(tops)): - G = bipartite.random_graph(tops[i], bots[i], 0.2) - top = [n for n, d in G.nodes(data=True) if d['bipartite'] == 0] - M = bipartite.biadjacency_matrix(G, top) - assert M.shape[0] == tops[i] - assert M.shape[1] == bots[i] - - def test_biadjacency_matrix_order(self): - G = nx.path_graph(5) - G.add_edge(0, 1, weight=2) - X = [3, 1] - Y = [4, 2, 0] - M = bipartite.biadjacency_matrix(G, X, Y, weight='weight') - assert M[1, 2] == 2 - - def test_null_graph(self): - with pytest.raises(nx.NetworkXError): - bipartite.biadjacency_matrix(nx.Graph(), []) - - def test_empty_graph(self): - with pytest.raises(nx.NetworkXError): - bipartite.biadjacency_matrix(nx.Graph([(1, 0)]), []) - - def test_duplicate_row(self): - with pytest.raises(nx.NetworkXError): - bipartite.biadjacency_matrix(nx.Graph([(1, 0)]), [1, 1]) - - def test_duplicate_col(self): - with pytest.raises(nx.NetworkXError): - bipartite.biadjacency_matrix(nx.Graph([(1, 0)]), [0], [1, 1]) - - def test_duplicate_col(self): - with pytest.raises(nx.NetworkXError): - bipartite.biadjacency_matrix(nx.Graph([(1, 0)]), [0], [1, 1]) - - def test_format_keyword(self): - with pytest.raises(nx.NetworkXError): - bipartite.biadjacency_matrix(nx.Graph([(1, 0)]), [0], format='foo') - - def test_from_biadjacency_roundtrip(self): - B1 = nx.path_graph(5) - M = bipartite.biadjacency_matrix(B1, [0, 2, 4]) - B2 = bipartite.from_biadjacency_matrix(M) - assert nx.is_isomorphic(B1, B2) - - def test_from_biadjacency_weight(self): - M = sparse.csc_matrix([[1, 2], [0, 3]]) - B = bipartite.from_biadjacency_matrix(M) - assert_edges_equal(B.edges(), [(0, 2), (0, 3), (1, 3)]) - B = bipartite.from_biadjacency_matrix(M, edge_attribute='weight') - e = [(0, 2, {'weight': 1}), (0, 3, {'weight': 2}), (1, 3, {'weight': 3})] - assert_edges_equal(B.edges(data=True), e) - - def test_from_biadjacency_multigraph(self): - M = sparse.csc_matrix([[1, 2], [0, 3]]) - B = bipartite.from_biadjacency_matrix(M, create_using=nx.MultiGraph()) - assert_edges_equal(B.edges(), [(0, 2), (0, 3), (0, 3), (1, 3), (1, 3), (1, 3)]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_project.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_project.py deleted file mode 100644 index 5871c4dc..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_project.py +++ /dev/null @@ -1,364 +0,0 @@ -#!/usr/bin/env python -import networkx as nx -from networkx.algorithms import bipartite -from networkx.testing import assert_edges_equal, assert_nodes_equal - - -class TestBipartiteProject: - - def test_path_projected_graph(self): - G = nx.path_graph(4) - P = bipartite.projected_graph(G, [1, 3]) - assert_nodes_equal(list(P), [1, 3]) - assert_edges_equal(list(P.edges()), [(1, 3)]) - P = bipartite.projected_graph(G, [0, 2]) - assert_nodes_equal(list(P), [0, 2]) - assert_edges_equal(list(P.edges()), [(0, 2)]) - - def test_path_projected_properties_graph(self): - G = nx.path_graph(4) - G.add_node(1, name='one') - G.add_node(2, name='two') - P = bipartite.projected_graph(G, [1, 3]) - assert_nodes_equal(list(P), [1, 3]) - assert_edges_equal(list(P.edges()), [(1, 3)]) - assert P.nodes[1]['name'] == G.nodes[1]['name'] - P = bipartite.projected_graph(G, [0, 2]) - assert_nodes_equal(list(P), [0, 2]) - assert_edges_equal(list(P.edges()), [(0, 2)]) - assert P.nodes[2]['name'] == G.nodes[2]['name'] - - def test_path_collaboration_projected_graph(self): - G = nx.path_graph(4) - P = bipartite.collaboration_weighted_projected_graph(G, [1, 3]) - assert_nodes_equal(list(P), [1, 3]) - assert_edges_equal(list(P.edges()), [(1, 3)]) - P[1][3]['weight'] = 1 - P = bipartite.collaboration_weighted_projected_graph(G, [0, 2]) - assert_nodes_equal(list(P), [0, 2]) - assert_edges_equal(list(P.edges()), [(0, 2)]) - P[0][2]['weight'] = 1 - - def test_directed_path_collaboration_projected_graph(self): - G = nx.DiGraph() - nx.add_path(G, range(4)) - P = bipartite.collaboration_weighted_projected_graph(G, [1, 3]) - assert_nodes_equal(list(P), [1, 3]) - assert_edges_equal(list(P.edges()), [(1, 3)]) - P[1][3]['weight'] = 1 - P = bipartite.collaboration_weighted_projected_graph(G, [0, 2]) - assert_nodes_equal(list(P), [0, 2]) - assert_edges_equal(list(P.edges()), [(0, 2)]) - P[0][2]['weight'] = 1 - - def test_path_weighted_projected_graph(self): - G = nx.path_graph(4) - P = bipartite.weighted_projected_graph(G, [1, 3]) - assert_nodes_equal(list(P), [1, 3]) - assert_edges_equal(list(P.edges()), [(1, 3)]) - P[1][3]['weight'] = 1 - P = bipartite.weighted_projected_graph(G, [0, 2]) - assert_nodes_equal(list(P), [0, 2]) - assert_edges_equal(list(P.edges()), [(0, 2)]) - P[0][2]['weight'] = 1 - - def test_path_weighted_projected_directed_graph(self): - G = nx.DiGraph() - nx.add_path(G, range(4)) - P = bipartite.weighted_projected_graph(G, [1, 3]) - assert_nodes_equal(list(P), [1, 3]) - assert_edges_equal(list(P.edges()), [(1, 3)]) - P[1][3]['weight'] = 1 - P = bipartite.weighted_projected_graph(G, [0, 2]) - assert_nodes_equal(list(P), [0, 2]) - assert_edges_equal(list(P.edges()), [(0, 2)]) - P[0][2]['weight'] = 1 - - def test_star_projected_graph(self): - G = nx.star_graph(3) - P = bipartite.projected_graph(G, [1, 2, 3]) - assert_nodes_equal(list(P), [1, 2, 3]) - assert_edges_equal(list(P.edges()), [(1, 2), (1, 3), (2, 3)]) - P = bipartite.weighted_projected_graph(G, [1, 2, 3]) - assert_nodes_equal(list(P), [1, 2, 3]) - assert_edges_equal(list(P.edges()), [(1, 2), (1, 3), (2, 3)]) - - P = bipartite.projected_graph(G, [0]) - assert_nodes_equal(list(P), [0]) - assert_edges_equal(list(P.edges()), []) - - def test_project_multigraph(self): - G = nx.Graph() - G.add_edge('a', 1) - G.add_edge('b', 1) - G.add_edge('a', 2) - G.add_edge('b', 2) - P = bipartite.projected_graph(G, 'ab') - assert_edges_equal(list(P.edges()), [('a', 'b')]) - P = bipartite.weighted_projected_graph(G, 'ab') - assert_edges_equal(list(P.edges()), [('a', 'b')]) - P = bipartite.projected_graph(G, 'ab', multigraph=True) - assert_edges_equal(list(P.edges()), [('a', 'b'), ('a', 'b')]) - - def test_project_collaboration(self): - G = nx.Graph() - G.add_edge('a', 1) - G.add_edge('b', 1) - G.add_edge('b', 2) - G.add_edge('c', 2) - G.add_edge('c', 3) - G.add_edge('c', 4) - G.add_edge('b', 4) - P = bipartite.collaboration_weighted_projected_graph(G, 'abc') - assert P['a']['b']['weight'] == 1 - assert P['b']['c']['weight'] == 2 - - def test_directed_projection(self): - G = nx.DiGraph() - G.add_edge('A', 1) - G.add_edge(1, 'B') - G.add_edge('A', 2) - G.add_edge('B', 2) - P = bipartite.projected_graph(G, 'AB') - assert_edges_equal(list(P.edges()), [('A', 'B')]) - P = bipartite.weighted_projected_graph(G, 'AB') - assert_edges_equal(list(P.edges()), [('A', 'B')]) - assert P['A']['B']['weight'] == 1 - - P = bipartite.projected_graph(G, 'AB', multigraph=True) - assert_edges_equal(list(P.edges()), [('A', 'B')]) - - G = nx.DiGraph() - G.add_edge('A', 1) - G.add_edge(1, 'B') - G.add_edge('A', 2) - G.add_edge(2, 'B') - P = bipartite.projected_graph(G, 'AB') - assert_edges_equal(list(P.edges()), [('A', 'B')]) - P = bipartite.weighted_projected_graph(G, 'AB') - assert_edges_equal(list(P.edges()), [('A', 'B')]) - assert P['A']['B']['weight'] == 2 - - P = bipartite.projected_graph(G, 'AB', multigraph=True) - assert_edges_equal(list(P.edges()), [('A', 'B'), ('A', 'B')]) - - -class TestBipartiteWeightedProjection: - - @classmethod - def setup_class(cls): - # Tore Opsahl's example - # http://toreopsahl.com/2009/05/01/projecting-two-mode-networks-onto-weighted-one-mode-networks/ - cls.G = nx.Graph() - cls.G.add_edge('A', 1) - cls.G.add_edge('A', 2) - cls.G.add_edge('B', 1) - cls.G.add_edge('B', 2) - cls.G.add_edge('B', 3) - cls.G.add_edge('B', 4) - cls.G.add_edge('B', 5) - cls.G.add_edge('C', 1) - cls.G.add_edge('D', 3) - cls.G.add_edge('E', 4) - cls.G.add_edge('E', 5) - cls.G.add_edge('E', 6) - cls.G.add_edge('F', 6) - # Graph based on figure 6 from Newman (2001) - cls.N = nx.Graph() - cls.N.add_edge('A', 1) - cls.N.add_edge('A', 2) - cls.N.add_edge('A', 3) - cls.N.add_edge('B', 1) - cls.N.add_edge('B', 2) - cls.N.add_edge('B', 3) - cls.N.add_edge('C', 1) - cls.N.add_edge('D', 1) - cls.N.add_edge('E', 3) - - def test_project_weighted_shared(self): - edges = [('A', 'B', 2), - ('A', 'C', 1), - ('B', 'C', 1), - ('B', 'D', 1), - ('B', 'E', 2), - ('E', 'F', 1)] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.weighted_projected_graph(self.G, 'ABCDEF') - assert_edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]['weight'] == Panswer[u][v]['weight'] - - edges = [('A', 'B', 3), - ('A', 'E', 1), - ('A', 'C', 1), - ('A', 'D', 1), - ('B', 'E', 1), - ('B', 'C', 1), - ('B', 'D', 1), - ('C', 'D', 1)] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.weighted_projected_graph(self.N, 'ABCDE') - assert_edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]['weight'] == Panswer[u][v]['weight'] - - def test_project_weighted_newman(self): - edges = [('A', 'B', 1.5), - ('A', 'C', 0.5), - ('B', 'C', 0.5), - ('B', 'D', 1), - ('B', 'E', 2), - ('E', 'F', 1)] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.collaboration_weighted_projected_graph(self.G, 'ABCDEF') - assert_edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]['weight'] == Panswer[u][v]['weight'] - - edges = [('A', 'B', 11 / 6.0), - ('A', 'E', 1 / 2.0), - ('A', 'C', 1 / 3.0), - ('A', 'D', 1 / 3.0), - ('B', 'E', 1 / 2.0), - ('B', 'C', 1 / 3.0), - ('B', 'D', 1 / 3.0), - ('C', 'D', 1 / 3.0)] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.collaboration_weighted_projected_graph(self.N, 'ABCDE') - assert_edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]['weight'] == Panswer[u][v]['weight'] - - def test_project_weighted_ratio(self): - edges = [('A', 'B', 2 / 6.0), - ('A', 'C', 1 / 6.0), - ('B', 'C', 1 / 6.0), - ('B', 'D', 1 / 6.0), - ('B', 'E', 2 / 6.0), - ('E', 'F', 1 / 6.0)] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.weighted_projected_graph(self.G, 'ABCDEF', ratio=True) - assert_edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]['weight'] == Panswer[u][v]['weight'] - - edges = [('A', 'B', 3 / 3.0), - ('A', 'E', 1 / 3.0), - ('A', 'C', 1 / 3.0), - ('A', 'D', 1 / 3.0), - ('B', 'E', 1 / 3.0), - ('B', 'C', 1 / 3.0), - ('B', 'D', 1 / 3.0), - ('C', 'D', 1 / 3.0)] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.weighted_projected_graph(self.N, 'ABCDE', ratio=True) - assert_edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]['weight'] == Panswer[u][v]['weight'] - - def test_project_weighted_overlap(self): - edges = [('A', 'B', 2 / 2.0), - ('A', 'C', 1 / 1.0), - ('B', 'C', 1 / 1.0), - ('B', 'D', 1 / 1.0), - ('B', 'E', 2 / 3.0), - ('E', 'F', 1 / 1.0)] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.overlap_weighted_projected_graph(self.G, 'ABCDEF', jaccard=False) - assert_edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]['weight'] == Panswer[u][v]['weight'] - - edges = [('A', 'B', 3 / 3.0), - ('A', 'E', 1 / 1.0), - ('A', 'C', 1 / 1.0), - ('A', 'D', 1 / 1.0), - ('B', 'E', 1 / 1.0), - ('B', 'C', 1 / 1.0), - ('B', 'D', 1 / 1.0), - ('C', 'D', 1 / 1.0)] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.overlap_weighted_projected_graph(self.N, 'ABCDE', jaccard=False) - assert_edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]['weight'] == Panswer[u][v]['weight'] - - def test_project_weighted_jaccard(self): - edges = [('A', 'B', 2 / 5.0), - ('A', 'C', 1 / 2.0), - ('B', 'C', 1 / 5.0), - ('B', 'D', 1 / 5.0), - ('B', 'E', 2 / 6.0), - ('E', 'F', 1 / 3.0)] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.overlap_weighted_projected_graph(self.G, 'ABCDEF') - assert_edges_equal(list(P.edges()), Panswer.edges()) - for u, v in list(P.edges()): - assert P[u][v]['weight'] == Panswer[u][v]['weight'] - - edges = [('A', 'B', 3 / 3.0), - ('A', 'E', 1 / 3.0), - ('A', 'C', 1 / 3.0), - ('A', 'D', 1 / 3.0), - ('B', 'E', 1 / 3.0), - ('B', 'C', 1 / 3.0), - ('B', 'D', 1 / 3.0), - ('C', 'D', 1 / 1.0)] - Panswer = nx.Graph() - Panswer.add_weighted_edges_from(edges) - P = bipartite.overlap_weighted_projected_graph(self.N, 'ABCDE') - assert_edges_equal(list(P.edges()), Panswer.edges()) - for u, v in P.edges(): - assert P[u][v]['weight'] == Panswer[u][v]['weight'] - - def test_generic_weighted_projected_graph_simple(self): - def shared(G, u, v): - return len(set(G[u]) & set(G[v])) - B = nx.path_graph(5) - G = bipartite.generic_weighted_projected_graph(B, [0, 2, 4], weight_function=shared) - assert_nodes_equal(list(G), [0, 2, 4]) - assert_edges_equal(list(list(G.edges(data=True))), - [(0, 2, {'weight': 1}), (2, 4, {'weight': 1})]) - - G = bipartite.generic_weighted_projected_graph(B, [0, 2, 4]) - assert_nodes_equal(list(G), [0, 2, 4]) - assert_edges_equal(list(list(G.edges(data=True))), - [(0, 2, {'weight': 1}), (2, 4, {'weight': 1})]) - B = nx.DiGraph() - nx.add_path(B, range(5)) - G = bipartite.generic_weighted_projected_graph(B, [0, 2, 4]) - assert_nodes_equal(list(G), [0, 2, 4]) - assert_edges_equal(list(G.edges(data=True)), - [(0, 2, {'weight': 1}), (2, 4, {'weight': 1})]) - - def test_generic_weighted_projected_graph_custom(self): - def jaccard(G, u, v): - unbrs = set(G[u]) - vnbrs = set(G[v]) - return float(len(unbrs & vnbrs)) / len(unbrs | vnbrs) - - def my_weight(G, u, v, weight='weight'): - w = 0 - for nbr in set(G[u]) & set(G[v]): - w += G.edges[u, nbr].get(weight, 1) + G.edges[v, nbr].get(weight, 1) - return w - B = nx.bipartite.complete_bipartite_graph(2, 2) - for i, (u, v) in enumerate(B.edges()): - B.edges[u, v]['weight'] = i + 1 - G = bipartite.generic_weighted_projected_graph(B, [0, 1], - weight_function=jaccard) - assert_edges_equal(list(G.edges(data=True)), [(0, 1, {'weight': 1.0})]) - G = bipartite.generic_weighted_projected_graph(B, [0, 1], - weight_function=my_weight) - assert_edges_equal(list(G.edges(data=True)), [(0, 1, {'weight': 10})]) - G = bipartite.generic_weighted_projected_graph(B, [0, 1]) - assert_edges_equal(list(G.edges(data=True)), [(0, 1, {'weight': 2})]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_redundancy.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_redundancy.py deleted file mode 100644 index e575a71d..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_redundancy.py +++ /dev/null @@ -1,41 +0,0 @@ -# test_redundancy.py - unit tests for the bipartite.redundancy module -# -# Copyright 2015 Jeffrey Finkelstein . -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.bipartite.redundancy` module. - -""" - -import pytest - -from networkx import cycle_graph -from networkx import NetworkXError -from networkx.algorithms.bipartite import complete_bipartite_graph -from networkx.algorithms.bipartite import node_redundancy - - -def test_no_redundant_nodes(): - G = complete_bipartite_graph(2, 2) - rc = node_redundancy(G) - assert all(redundancy == 1 for redundancy in rc.values()) - - -def test_redundant_nodes(): - G = cycle_graph(6) - edge = {0, 3} - G.add_edge(*edge) - redundancy = node_redundancy(G) - for v in edge: - assert redundancy[v] == 2 / 3 - for v in set(G) - edge: - assert redundancy[v] == 1 - - -def test_not_enough_neighbors(): - with pytest.raises(NetworkXError): - G = complete_bipartite_graph(1, 2) - node_redundancy(G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_spectral_bipartivity.py b/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_spectral_bipartivity.py deleted file mode 100644 index d26d36fb..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bipartite/tests/test_spectral_bipartivity.py +++ /dev/null @@ -1,86 +0,0 @@ -# -*- coding: utf-8 -*- -import pytest - -import networkx as nx -from networkx.algorithms.bipartite import spectral_bipartivity as sb -from networkx.testing import almost_equal - -# Examples from Figure 1 -# E. Estrada and J. A. Rodríguez-Velázquez, "Spectral measures of -# bipartivity in complex networks", PhysRev E 72, 046105 (2005) - - -class TestSpectralBipartivity(object): - @classmethod - def setup_class(cls): - global scipy - scipy = pytest.importorskip('scipy') - - def test_star_like(self): - # star-like - - G = nx.star_graph(2) - G.add_edge(1, 2) - assert almost_equal(sb(G), 0.843, places=3) - - G = nx.star_graph(3) - G.add_edge(1, 2) - assert almost_equal(sb(G), 0.871, places=3) - - G = nx.star_graph(4) - G.add_edge(1, 2) - assert almost_equal(sb(G), 0.890, places=3) - - def k23_like(self): - # K2,3-like - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(0, 1) - assert almost_equal(sb(G), 0.769, places=3) - - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(2, 4) - assert almost_equal(sb(G), 0.829, places=3) - - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(2, 4) - G.add_edge(3, 4) - assert almost_equal(sb(G), 0.731, places=3) - - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(0, 1) - G.add_edge(2, 4) - assert almost_equal(sb(G), 0.692, places=3) - - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(2, 4) - G.add_edge(3, 4) - G.add_edge(0, 1) - assert almost_equal(sb(G), 0.645, places=3) - - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(2, 4) - G.add_edge(3, 4) - G.add_edge(2, 3) - assert almost_equal(sb(G), 0.645, places=3) - - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(2, 4) - G.add_edge(3, 4) - G.add_edge(2, 3) - G.add_edge(0, 1) - assert almost_equal(sb(G), 0.597, places=3) - - def test_single_nodes(self): - - # single nodes - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(2, 4) - sbn = sb(G, nodes=[1, 2]) - assert almost_equal(sbn[1], 0.85, places=2) - assert almost_equal(sbn[2], 0.77, places=2) - - G = nx.complete_bipartite_graph(2, 3) - G.add_edge(0, 1) - sbn = sb(G, nodes=[1, 2]) - assert almost_equal(sbn[1], 0.73, places=2) - assert almost_equal(sbn[2], 0.82, places=2) diff --git a/extensions/fablabchemnitz/networkx/algorithms/boundary.py b/extensions/fablabchemnitz/networkx/algorithms/boundary.py deleted file mode 100644 index 98311416..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/boundary.py +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# Copyright 2015 NetworkX developers. -# All rights reserved. -# BSD license. -"""Routines to find the boundary of a set of nodes. - -An edge boundary is a set of edges, each of which has exactly one -endpoint in a given set of nodes (or, in the case of directed graphs, -the set of edges whose source node is in the set). - -A node boundary of a set *S* of nodes is the set of (out-)neighbors of -nodes in *S* that are outside *S*. - -""" -from itertools import chain - -__author__ = """Aric Hagberg (hagberg@lanl.gov)\nPieter Swart (swart@lanl.gov)\nDan Schult (dschult@colgate.edu)""" - -__all__ = ['edge_boundary', 'node_boundary'] - - -def edge_boundary(G, nbunch1, nbunch2=None, data=False, keys=False, - default=None): - """Returns the edge boundary of `nbunch1`. - - The *edge boundary* of a set *S* with respect to a set *T* is the - set of edges (*u*, *v*) such that *u* is in *S* and *v* is in *T*. - If *T* is not specified, it is assumed to be the set of all nodes - not in *S*. - - Parameters - ---------- - G : NetworkX graph - - nbunch1 : iterable - Iterable of nodes in the graph representing the set of nodes - whose edge boundary will be returned. (This is the set *S* from - the definition above.) - - nbunch2 : iterable - Iterable of nodes representing the target (or "exterior") set of - nodes. (This is the set *T* from the definition above.) If not - specified, this is assumed to be the set of all nodes in `G` - not in `nbunch1`. - - keys : bool - This parameter has the same meaning as in - :meth:`MultiGraph.edges`. - - data : bool or object - This parameter has the same meaning as in - :meth:`MultiGraph.edges`. - - default : object - This parameter has the same meaning as in - :meth:`MultiGraph.edges`. - - Returns - ------- - iterator - An iterator over the edges in the boundary of `nbunch1` with - respect to `nbunch2`. If `keys`, `data`, or `default` - are specified and `G` is a multigraph, then edges are returned - with keys and/or data, as in :meth:`MultiGraph.edges`. - - Notes - ----- - Any element of `nbunch` that is not in the graph `G` will be - ignored. - - `nbunch1` and `nbunch2` are usually meant to be disjoint, but in - the interest of speed and generality, that is not required here. - - """ - nset1 = {v for v in G if v in nbunch1} - # Here we create an iterator over edges incident to nodes in the set - # `nset1`. The `Graph.edges()` method does not provide a guarantee - # on the orientation of the edges, so our algorithm below must - # handle the case in which exactly one orientation, either (u, v) or - # (v, u), appears in this iterable. - if G.is_multigraph(): - edges = G.edges(nset1, data=data, keys=keys, default=default) - else: - edges = G.edges(nset1, data=data, default=default) - # If `nbunch2` is not provided, then it is assumed to be the set - # complement of `nbunch1`. For the sake of efficiency, this is - # implemented by using the `not in` operator, instead of by creating - # an additional set and using the `in` operator. - if nbunch2 is None: - return (e for e in edges if (e[0] in nset1) ^ (e[1] in nset1)) - nset2 = set(nbunch2) - return (e for e in edges - if (e[0] in nset1 and e[1] in nset2) - or (e[1] in nset1 and e[0] in nset2)) - - -def node_boundary(G, nbunch1, nbunch2=None): - """Returns the node boundary of `nbunch1`. - - The *node boundary* of a set *S* with respect to a set *T* is the - set of nodes *v* in *T* such that for some *u* in *S*, there is an - edge joining *u* to *v*. If *T* is not specified, it is assumed to - be the set of all nodes not in *S*. - - Parameters - ---------- - G : NetworkX graph - - nbunch1 : iterable - Iterable of nodes in the graph representing the set of nodes - whose node boundary will be returned. (This is the set *S* from - the definition above.) - - nbunch2 : iterable - Iterable of nodes representing the target (or "exterior") set of - nodes. (This is the set *T* from the definition above.) If not - specified, this is assumed to be the set of all nodes in `G` - not in `nbunch1`. - - Returns - ------- - set - The node boundary of `nbunch1` with respect to `nbunch2`. - - Notes - ----- - Any element of `nbunch` that is not in the graph `G` will be - ignored. - - `nbunch1` and `nbunch2` are usually meant to be disjoint, but in - the interest of speed and generality, that is not required here. - - """ - nset1 = {n for n in nbunch1 if n in G} - bdy = set(chain.from_iterable(G[v] for v in nset1)) - nset1 - # If `nbunch2` is not specified, it is assumed to be the set - # complement of `nbunch1`. - if nbunch2 is not None: - bdy &= set(nbunch2) - return bdy diff --git a/extensions/fablabchemnitz/networkx/algorithms/bridges.py b/extensions/fablabchemnitz/networkx/algorithms/bridges.py deleted file mode 100644 index 667a2227..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/bridges.py +++ /dev/null @@ -1,190 +0,0 @@ -# -*- coding: utf-8 -*- -# bridges.py - bridge-finding algorithms -# -# Copyright 2004-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Bridge-finding algorithms.""" -from itertools import chain - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ['bridges', 'has_bridges', 'local_bridges'] - - -@not_implemented_for('multigraph') -@not_implemented_for('directed') -def bridges(G, root=None): - """Generate all bridges in a graph. - - A *bridge* in a graph is an edge whose removal causes the number of - connected components of the graph to increase. Equivalently, a bridge is an - edge that does not belong to any cycle. - - Parameters - ---------- - G : undirected graph - - root : node (optional) - A node in the graph `G`. If specified, only the bridges in the - connected component containing this node will be returned. - - Yields - ------ - e : edge - An edge in the graph whose removal disconnects the graph (or - causes the number of connected components to increase). - - Raises - ------ - NodeNotFound - If `root` is not in the graph `G`. - - Examples - -------- - The barbell graph with parameter zero has a single bridge: - - >>> G = nx.barbell_graph(10, 0) - >>> list(nx.bridges(G)) - [(9, 10)] - - Notes - ----- - This is an implementation of the algorithm described in _[1]. An edge is a - bridge if and only if it is not contained in any chain. Chains are found - using the :func:`networkx.chain_decomposition` function. - - Ignoring polylogarithmic factors, the worst-case time complexity is the - same as the :func:`networkx.chain_decomposition` function, - $O(m + n)$, where $n$ is the number of nodes in the graph and $m$ is - the number of edges. - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Bridge_%28graph_theory%29#Bridge-Finding_with_Chain_Decompositions - """ - chains = nx.chain_decomposition(G, root=root) - chain_edges = set(chain.from_iterable(chains)) - for u, v in G.edges(): - if (u, v) not in chain_edges and (v, u) not in chain_edges: - yield u, v - - -@not_implemented_for('multigraph') -@not_implemented_for('directed') -def has_bridges(G, root=None): - """Decide whether a graph has any bridges. - - A *bridge* in a graph is an edge whose removal causes the number of - connected components of the graph to increase. - - Parameters - ---------- - G : undirected graph - - root : node (optional) - A node in the graph `G`. If specified, only the bridges in the - connected component containing this node will be considered. - - Returns - ------- - bool - Whether the graph (or the connected component containing `root`) - has any bridges. - - Raises - ------ - NodeNotFound - If `root` is not in the graph `G`. - - Examples - -------- - The barbell graph with parameter zero has a single bridge:: - - >>> G = nx.barbell_graph(10, 0) - >>> nx.has_bridges(G) - True - - On the other hand, the cycle graph has no bridges:: - - >>> G = nx.cycle_graph(5) - >>> nx.has_bridges(G) - False - - Notes - ----- - This implementation uses the :func:`networkx.bridges` function, so - it shares its worst-case time complexity, $O(m + n)$, ignoring - polylogarithmic factors, where $n$ is the number of nodes in the - graph and $m$ is the number of edges. - - """ - try: - next(bridges(G)) - except StopIteration: - return False - else: - return True - - -@not_implemented_for('multigraph') -@not_implemented_for('directed') -def local_bridges(G, with_span=True, weight=None): - """Iterate over local bridges of `G` optionally computing the span - - A *local bridge* is an edge whose endpoints have no common neighbors. - That is, the edge is not part of a triangle in the graph. - - The *span* of a *local bridge* is the shortest path length between - the endpoints if the local bridge is removed. - - Parameters - ---------- - G : undirected graph - - with_span : bool - If True, yield a 3-tuple `(u, v, span)` - - weight : function, string or None (default: None) - If function, used to compute edge weights for the span. - If string, the edge data attribute used in calculating span. - If None, all edges have weight 1. - - Yields - ------ - e : edge - The local bridges as an edge 2-tuple of nodes `(u, v)` or - as a 3-tuple `(u, v, span)` when `with_span is True`. - - Examples - -------- - A cycle graph has every edge a local bridge with span N-1. - - >>> G = nx.cycle_graph(9) - >>> (0, 8, 8) in set(nx.local_bridges(G)) - True - """ - if with_span is not True: - for u, v in G.edges: - if not (set(G[u]) & set(G[v])): - yield u, v - else: - wt = nx.weighted._weight_function(G, weight) - for u, v in G.edges: - if not (set(G[u]) & set(G[v])): - enodes = {u, v} - - def hide_edge(n, nbr, d): - if n not in enodes or nbr not in enodes: - return wt(n, nbr, d) - return None - - try: - span = nx.shortest_path_length(G, u, v, weight=hide_edge) - yield u, v, span - except nx.NetworkXNoPath: - yield u, v, float('inf') diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/__init__.py deleted file mode 100644 index 99dccd62..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -from .betweenness import * -from .betweenness_subset import * -from .closeness import * -from .subgraph_alg import * -from .current_flow_closeness import * -from .current_flow_betweenness import * -from .current_flow_betweenness_subset import * -from .degree_alg import * -from .dispersion import * -from .eigenvector import * -from .group import * -from .harmonic import * -from .katz import * -from .load import * -from .reaching import * -from .percolation import * -from .second_order import * -from .voterank_alg import * diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/betweenness.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/betweenness.py deleted file mode 100644 index b848b635..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/betweenness.py +++ /dev/null @@ -1,393 +0,0 @@ -# coding=utf8 -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Author: Aric Hagberg (hagberg@lanl.gov) -"""Betweenness centrality measures.""" -from heapq import heappush, heappop -from itertools import count - -import networkx as nx -from networkx.utils import py_random_state -from networkx.utils.decorators import not_implemented_for - -__all__ = ['betweenness_centrality', 'edge_betweenness_centrality', - 'edge_betweenness'] - - -@py_random_state(5) -@not_implemented_for('multigraph') -def betweenness_centrality(G, k=None, normalized=True, weight=None, - endpoints=False, seed=None): - r"""Compute the shortest-path betweenness centrality for nodes. - - Betweenness centrality of a node $v$ is the sum of the - fraction of all-pairs shortest paths that pass through $v$ - - .. math:: - - c_B(v) =\sum_{s,t \in V} \frac{\sigma(s, t|v)}{\sigma(s, t)} - - where $V$ is the set of nodes, $\sigma(s, t)$ is the number of - shortest $(s, t)$-paths, and $\sigma(s, t|v)$ is the number of - those paths passing through some node $v$ other than $s, t$. - If $s = t$, $\sigma(s, t) = 1$, and if $v \in {s, t}$, - $\sigma(s, t|v) = 0$ [2]_. - - Parameters - ---------- - G : graph - A NetworkX graph. - - k : int, optional (default=None) - If k is not None use k node samples to estimate betweenness. - The value of k <= n where n is the number of nodes in the graph. - Higher values give better approximation. - - normalized : bool, optional - If True the betweenness values are normalized by `2/((n-1)(n-2))` - for graphs, and `1/((n-1)(n-2))` for directed graphs where `n` - is the number of nodes in G. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - - endpoints : bool, optional - If True include the endpoints in the shortest path counts. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - Note that this is only used if k is not None. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with betweenness centrality as the value. - - See Also - -------- - edge_betweenness_centrality - load_centrality - - Notes - ----- - The algorithm is from Ulrik Brandes [1]_. - See [4]_ for the original first published version and [2]_ for details on - algorithms for variations and related metrics. - - For approximate betweenness calculations set k=#samples to use - k nodes ("pivots") to estimate the betweenness values. For an estimate - of the number of pivots needed see [3]_. - - For weighted graphs the edge weights must be greater than zero. - Zero edge weights can produce an infinite number of equal length - paths between pairs of nodes. - - The total number of paths between source and target is counted - differently for directed and undirected graphs. Directed paths - are easy to count. Undirected paths are tricky: should a path - from "u" to "v" count as 1 undirected path or as 2 directed paths? - - For betweenness_centrality we report the number of undirected - paths when G is undirected. - - For betweenness_centrality_subset the reporting is different. - If the source and target subsets are the same, then we want - to count undirected paths. But if the source and target subsets - differ -- for example, if sources is {0} and targets is {1}, - then we are only counting the paths in one direction. They are - undirected paths but we are counting them in a directed way. - To count them as undirected paths, each should count as half a path. - - References - ---------- - .. [1] Ulrik Brandes: - A Faster Algorithm for Betweenness Centrality. - Journal of Mathematical Sociology 25(2):163-177, 2001. - http://www.inf.uni-konstanz.de/algo/publications/b-fabc-01.pdf - .. [2] Ulrik Brandes: - On Variants of Shortest-Path Betweenness - Centrality and their Generic Computation. - Social Networks 30(2):136-145, 2008. - http://www.inf.uni-konstanz.de/algo/publications/b-vspbc-08.pdf - .. [3] Ulrik Brandes and Christian Pich: - Centrality Estimation in Large Networks. - International Journal of Bifurcation and Chaos 17(7):2303-2318, 2007. - http://www.inf.uni-konstanz.de/algo/publications/bp-celn-06.pdf - .. [4] Linton C. Freeman: - A set of measures of centrality based on betweenness. - Sociometry 40: 35–41, 1977 - http://moreno.ss.uci.edu/23.pdf - """ - betweenness = dict.fromkeys(G, 0.0) # b[v]=0 for v in G - if k is None: - nodes = G - else: - nodes = seed.sample(G.nodes(), k) - for s in nodes: - # single source shortest paths - if weight is None: # use BFS - S, P, sigma = _single_source_shortest_path_basic(G, s) - else: # use Dijkstra's algorithm - S, P, sigma = _single_source_dijkstra_path_basic(G, s, weight) - # accumulation - if endpoints: - betweenness = _accumulate_endpoints(betweenness, S, P, sigma, s) - else: - betweenness = _accumulate_basic(betweenness, S, P, sigma, s) - # rescaling - betweenness = _rescale(betweenness, len(G), normalized=normalized, - directed=G.is_directed(), k=k, endpoints=endpoints) - return betweenness - - -@py_random_state(4) -def edge_betweenness_centrality(G, k=None, normalized=True, weight=None, - seed=None): - r"""Compute betweenness centrality for edges. - - Betweenness centrality of an edge $e$ is the sum of the - fraction of all-pairs shortest paths that pass through $e$ - - .. math:: - - c_B(e) =\sum_{s,t \in V} \frac{\sigma(s, t|e)}{\sigma(s, t)} - - where $V$ is the set of nodes, $\sigma(s, t)$ is the number of - shortest $(s, t)$-paths, and $\sigma(s, t|e)$ is the number of - those paths passing through edge $e$ [2]_. - - Parameters - ---------- - G : graph - A NetworkX graph. - - k : int, optional (default=None) - If k is not None use k node samples to estimate betweenness. - The value of k <= n where n is the number of nodes in the graph. - Higher values give better approximation. - - normalized : bool, optional - If True the betweenness values are normalized by $2/(n(n-1))$ - for graphs, and $1/(n(n-1))$ for directed graphs where $n$ - is the number of nodes in G. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - Note that this is only used if k is not None. - - Returns - ------- - edges : dictionary - Dictionary of edges with betweenness centrality as the value. - - See Also - -------- - betweenness_centrality - edge_load - - Notes - ----- - The algorithm is from Ulrik Brandes [1]_. - - For weighted graphs the edge weights must be greater than zero. - Zero edge weights can produce an infinite number of equal length - paths between pairs of nodes. - - References - ---------- - .. [1] A Faster Algorithm for Betweenness Centrality. Ulrik Brandes, - Journal of Mathematical Sociology 25(2):163-177, 2001. - http://www.inf.uni-konstanz.de/algo/publications/b-fabc-01.pdf - .. [2] Ulrik Brandes: On Variants of Shortest-Path Betweenness - Centrality and their Generic Computation. - Social Networks 30(2):136-145, 2008. - http://www.inf.uni-konstanz.de/algo/publications/b-vspbc-08.pdf - """ - betweenness = dict.fromkeys(G, 0.0) # b[v]=0 for v in G - # b[e]=0 for e in G.edges() - betweenness.update(dict.fromkeys(G.edges(), 0.0)) - if k is None: - nodes = G - else: - nodes = seed.sample(G.nodes(), k) - for s in nodes: - # single source shortest paths - if weight is None: # use BFS - S, P, sigma = _single_source_shortest_path_basic(G, s) - else: # use Dijkstra's algorithm - S, P, sigma = _single_source_dijkstra_path_basic(G, s, weight) - # accumulation - betweenness = _accumulate_edges(betweenness, S, P, sigma, s) - # rescaling - for n in G: # remove nodes to only return edges - del betweenness[n] - betweenness = _rescale_e(betweenness, len(G), normalized=normalized, - directed=G.is_directed()) - return betweenness - -# obsolete name - - -def edge_betweenness(G, k=None, normalized=True, weight=None, seed=None): - return edge_betweenness_centrality(G, k, normalized, weight, seed) - - -# helpers for betweenness centrality - -def _single_source_shortest_path_basic(G, s): - S = [] - P = {} - for v in G: - P[v] = [] - sigma = dict.fromkeys(G, 0.0) # sigma[v]=0 for v in G - D = {} - sigma[s] = 1.0 - D[s] = 0 - Q = [s] - while Q: # use BFS to find shortest paths - v = Q.pop(0) - S.append(v) - Dv = D[v] - sigmav = sigma[v] - for w in G[v]: - if w not in D: - Q.append(w) - D[w] = Dv + 1 - if D[w] == Dv + 1: # this is a shortest path, count paths - sigma[w] += sigmav - P[w].append(v) # predecessors - return S, P, sigma - - -def _single_source_dijkstra_path_basic(G, s, weight): - # modified from Eppstein - S = [] - P = {} - for v in G: - P[v] = [] - sigma = dict.fromkeys(G, 0.0) # sigma[v]=0 for v in G - D = {} - sigma[s] = 1.0 - push = heappush - pop = heappop - seen = {s: 0} - c = count() - Q = [] # use Q as heap with (distance,node id) tuples - push(Q, (0, next(c), s, s)) - while Q: - (dist, _, pred, v) = pop(Q) - if v in D: - continue # already searched this node. - sigma[v] += sigma[pred] # count paths - S.append(v) - D[v] = dist - for w, edgedata in G[v].items(): - vw_dist = dist + edgedata.get(weight, 1) - if w not in D and (w not in seen or vw_dist < seen[w]): - seen[w] = vw_dist - push(Q, (vw_dist, next(c), v, w)) - sigma[w] = 0.0 - P[w] = [v] - elif vw_dist == seen[w]: # handle equal paths - sigma[w] += sigma[v] - P[w].append(v) - return S, P, sigma - - -def _accumulate_basic(betweenness, S, P, sigma, s): - delta = dict.fromkeys(S, 0) - while S: - w = S.pop() - coeff = (1 + delta[w]) / sigma[w] - for v in P[w]: - delta[v] += sigma[v] * coeff - if w != s: - betweenness[w] += delta[w] - return betweenness - - -def _accumulate_endpoints(betweenness, S, P, sigma, s): - betweenness[s] += len(S) - 1 - delta = dict.fromkeys(S, 0) - while S: - w = S.pop() - coeff = (1 + delta[w]) / sigma[w] - for v in P[w]: - delta[v] += sigma[v] * coeff - if w != s: - betweenness[w] += delta[w] + 1 - return betweenness - - -def _accumulate_edges(betweenness, S, P, sigma, s): - delta = dict.fromkeys(S, 0) - while S: - w = S.pop() - coeff = (1 + delta[w]) / sigma[w] - for v in P[w]: - c = sigma[v] * coeff - if (v, w) not in betweenness: - betweenness[(w, v)] += c - else: - betweenness[(v, w)] += c - delta[v] += c - if w != s: - betweenness[w] += delta[w] - return betweenness - - -def _rescale(betweenness, n, normalized, - directed=False, k=None, endpoints=False): - if normalized: - if endpoints: - if n < 2: - scale = None # no normalization - else: - # Scale factor should include endpoint nodes - scale = 1 / (n * (n - 1)) - elif n <= 2: - scale = None # no normalization b=0 for all nodes - else: - scale = 1 / ((n - 1) * (n - 2)) - else: # rescale by 2 for undirected graphs - if not directed: - scale = 0.5 - else: - scale = None - if scale is not None: - if k is not None: - scale = scale * n / k - for v in betweenness: - betweenness[v] *= scale - return betweenness - - -def _rescale_e(betweenness, n, normalized, directed=False, k=None): - if normalized: - if n <= 1: - scale = None # no normalization b=0 for all nodes - else: - scale = 1 / (n * (n - 1)) - else: # rescale by 2 for undirected graphs - if not directed: - scale = 0.5 - else: - scale = None - if scale is not None: - if k is not None: - scale = scale * n / k - for v in betweenness: - betweenness[v] *= scale - return betweenness diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/betweenness_subset.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/betweenness_subset.py deleted file mode 100644 index 3019240a..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/betweenness_subset.py +++ /dev/null @@ -1,278 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Author: Aric Hagberg (hagberg@lanl.gov) -"""Betweenness centrality measures for subsets of nodes.""" -import networkx as nx - -from networkx.algorithms.centrality.betweenness import\ - _single_source_dijkstra_path_basic as dijkstra -from networkx.algorithms.centrality.betweenness import\ - _single_source_shortest_path_basic as shortest_path - -__all__ = ['betweenness_centrality_subset', 'betweenness_centrality_source', - 'edge_betweenness_centrality_subset'] - - -def betweenness_centrality_subset(G, sources, targets, normalized=False, - weight=None): - r"""Compute betweenness centrality for a subset of nodes. - - .. math:: - - c_B(v) =\sum_{s\in S, t \in T} \frac{\sigma(s, t|v)}{\sigma(s, t)} - - where $S$ is the set of sources, $T$ is the set of targets, - $\sigma(s, t)$ is the number of shortest $(s, t)$-paths, - and $\sigma(s, t|v)$ is the number of those paths - passing through some node $v$ other than $s, t$. - If $s = t$, $\sigma(s, t) = 1$, - and if $v \in {s, t}$, $\sigma(s, t|v) = 0$ [2]_. - - - Parameters - ---------- - G : graph - A NetworkX graph. - - sources: list of nodes - Nodes to use as sources for shortest paths in betweenness - - targets: list of nodes - Nodes to use as targets for shortest paths in betweenness - - normalized : bool, optional - If True the betweenness values are normalized by $2/((n-1)(n-2))$ - for graphs, and $1/((n-1)(n-2))$ for directed graphs where $n$ - is the number of nodes in G. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with betweenness centrality as the value. - - See Also - -------- - edge_betweenness_centrality - load_centrality - - Notes - ----- - The basic algorithm is from [1]_. - - For weighted graphs the edge weights must be greater than zero. - Zero edge weights can produce an infinite number of equal length - paths between pairs of nodes. - - The normalization might seem a little strange but it is - designed to make betweenness_centrality(G) be the same as - betweenness_centrality_subset(G,sources=G.nodes(),targets=G.nodes()). - - The total number of paths between source and target is counted - differently for directed and undirected graphs. Directed paths - are easy to count. Undirected paths are tricky: should a path - from "u" to "v" count as 1 undirected path or as 2 directed paths? - - For betweenness_centrality we report the number of undirected - paths when G is undirected. - - For betweenness_centrality_subset the reporting is different. - If the source and target subsets are the same, then we want - to count undirected paths. But if the source and target subsets - differ -- for example, if sources is {0} and targets is {1}, - then we are only counting the paths in one direction. They are - undirected paths but we are counting them in a directed way. - To count them as undirected paths, each should count as half a path. - - References - ---------- - .. [1] Ulrik Brandes, A Faster Algorithm for Betweenness Centrality. - Journal of Mathematical Sociology 25(2):163-177, 2001. - http://www.inf.uni-konstanz.de/algo/publications/b-fabc-01.pdf - .. [2] Ulrik Brandes: On Variants of Shortest-Path Betweenness - Centrality and their Generic Computation. - Social Networks 30(2):136-145, 2008. - http://www.inf.uni-konstanz.de/algo/publications/b-vspbc-08.pdf - """ - b = dict.fromkeys(G, 0.0) # b[v]=0 for v in G - for s in sources: - # single source shortest paths - if weight is None: # use BFS - S, P, sigma = shortest_path(G, s) - else: # use Dijkstra's algorithm - S, P, sigma = dijkstra(G, s, weight) - b = _accumulate_subset(b, S, P, sigma, s, targets) - b = _rescale(b, len(G), normalized=normalized, directed=G.is_directed()) - return b - - -def edge_betweenness_centrality_subset(G, sources, targets, normalized=False, - weight=None): - r"""Compute betweenness centrality for edges for a subset of nodes. - - .. math:: - - c_B(v) =\sum_{s\in S,t \in T} \frac{\sigma(s, t|e)}{\sigma(s, t)} - - where $S$ is the set of sources, $T$ is the set of targets, - $\sigma(s, t)$ is the number of shortest $(s, t)$-paths, - and $\sigma(s, t|e)$ is the number of those paths - passing through edge $e$ [2]_. - - Parameters - ---------- - G : graph - A networkx graph. - - sources: list of nodes - Nodes to use as sources for shortest paths in betweenness - - targets: list of nodes - Nodes to use as targets for shortest paths in betweenness - - normalized : bool, optional - If True the betweenness values are normalized by `2/(n(n-1))` - for graphs, and `1/(n(n-1))` for directed graphs where `n` - is the number of nodes in G. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - - Returns - ------- - edges : dictionary - Dictionary of edges with Betweenness centrality as the value. - - See Also - -------- - betweenness_centrality - edge_load - - Notes - ----- - The basic algorithm is from [1]_. - - For weighted graphs the edge weights must be greater than zero. - Zero edge weights can produce an infinite number of equal length - paths between pairs of nodes. - - The normalization might seem a little strange but it is the same - as in edge_betweenness_centrality() and is designed to make - edge_betweenness_centrality(G) be the same as - edge_betweenness_centrality_subset(G,sources=G.nodes(),targets=G.nodes()). - - References - ---------- - .. [1] Ulrik Brandes, A Faster Algorithm for Betweenness Centrality. - Journal of Mathematical Sociology 25(2):163-177, 2001. - http://www.inf.uni-konstanz.de/algo/publications/b-fabc-01.pdf - .. [2] Ulrik Brandes: On Variants of Shortest-Path Betweenness - Centrality and their Generic Computation. - Social Networks 30(2):136-145, 2008. - http://www.inf.uni-konstanz.de/algo/publications/b-vspbc-08.pdf - """ - b = dict.fromkeys(G, 0.0) # b[v]=0 for v in G - b.update(dict.fromkeys(G.edges(), 0.0)) # b[e] for e in G.edges() - for s in sources: - # single source shortest paths - if weight is None: # use BFS - S, P, sigma = shortest_path(G, s) - else: # use Dijkstra's algorithm - S, P, sigma = dijkstra(G, s, weight) - b = _accumulate_edges_subset(b, S, P, sigma, s, targets) - for n in G: # remove nodes to only return edges - del b[n] - b = _rescale_e(b, len(G), normalized=normalized, directed=G.is_directed()) - return b - - -# obsolete name -def betweenness_centrality_source(G, normalized=True, weight=None, - sources=None): - if sources is None: - sources = G.nodes() - targets = list(G) - return betweenness_centrality_subset(G, sources, targets, normalized, - weight) - - -def _accumulate_subset(betweenness, S, P, sigma, s, targets): - delta = dict.fromkeys(S, 0.0) - target_set = set(targets) - {s} - while S: - w = S.pop() - if w in target_set: - coeff = (delta[w] + 1.0) / sigma[w] - else: - coeff = delta[w] / sigma[w] - for v in P[w]: - delta[v] += sigma[v] * coeff - if w != s: - betweenness[w] += delta[w] - return betweenness - - -def _accumulate_edges_subset(betweenness, S, P, sigma, s, targets): - """edge_betweenness_centrality_subset helper.""" - delta = dict.fromkeys(S, 0) - target_set = set(targets) - while S: - w = S.pop() - for v in P[w]: - if w in target_set: - c = (sigma[v] / sigma[w]) * (1.0 + delta[w]) - else: - c = delta[w] / len(P[w]) - if (v, w) not in betweenness: - betweenness[(w, v)] += c - else: - betweenness[(v, w)] += c - delta[v] += c - if w != s: - betweenness[w] += delta[w] - return betweenness - - -def _rescale(betweenness, n, normalized, directed=False): - """betweenness_centrality_subset helper.""" - if normalized: - if n <= 2: - scale = None # no normalization b=0 for all nodes - else: - scale = 1.0 / ((n - 1) * (n - 2)) - else: # rescale by 2 for undirected graphs - if not directed: - scale = 0.5 - else: - scale = None - if scale is not None: - for v in betweenness: - betweenness[v] *= scale - return betweenness - - -def _rescale_e(betweenness, n, normalized, directed=False): - """edge_betweenness_centrality_subset helper.""" - if normalized: - if n <= 1: - scale = None # no normalization b=0 for all nodes - else: - scale = 1.0 / (n * (n - 1)) - else: # rescale by 2 for undirected graphs - if not directed: - scale = 0.5 - else: - scale = None - if scale is not None: - for v in betweenness: - betweenness[v] *= scale - return betweenness diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/closeness.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/closeness.py deleted file mode 100644 index 1a21fa0d..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/closeness.py +++ /dev/null @@ -1,284 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg -# Pieter Swart -# Sasha Gutfraind -# Dan Schult -# Michael Lauria -""" -Closeness centrality measures. -""" -import functools -import networkx as nx -from networkx.exception import NetworkXError -from networkx.utils.decorators import not_implemented_for - -__all__ = ['closeness_centrality', 'incremental_closeness_centrality'] - - -def closeness_centrality(G, u=None, distance=None, wf_improved=True): - r"""Compute closeness centrality for nodes. - - Closeness centrality [1]_ of a node `u` is the reciprocal of the - average shortest path distance to `u` over all `n-1` reachable nodes. - - .. math:: - - C(u) = \frac{n - 1}{\sum_{v=1}^{n-1} d(v, u)}, - - where `d(v, u)` is the shortest-path distance between `v` and `u`, - and `n` is the number of nodes that can reach `u`. Notice that the - closeness distance function computes the incoming distance to `u` - for directed graphs. To use outward distance, act on `G.reverse()`. - - Notice that higher values of closeness indicate higher centrality. - - Wasserman and Faust propose an improved formula for graphs with - more than one connected component. The result is "a ratio of the - fraction of actors in the group who are reachable, to the average - distance" from the reachable actors [2]_. You might think this - scale factor is inverted but it is not. As is, nodes from small - components receive a smaller closeness value. Letting `N` denote - the number of nodes in the graph, - - .. math:: - - C_{WF}(u) = \frac{n-1}{N-1} \frac{n - 1}{\sum_{v=1}^{n-1} d(v, u)}, - - Parameters - ---------- - G : graph - A NetworkX graph - - u : node, optional - Return only the value for node u - - distance : edge attribute key, optional (default=None) - Use the specified edge attribute as the edge distance in shortest - path calculations - - wf_improved : bool, optional (default=True) - If True, scale by the fraction of nodes reachable. This gives the - Wasserman and Faust improved formula. For single component graphs - it is the same as the original formula. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with closeness centrality as the value. - - See Also - -------- - betweenness_centrality, load_centrality, eigenvector_centrality, - degree_centrality, incremental_closeness_centrality - - Notes - ----- - The closeness centrality is normalized to `(n-1)/(|G|-1)` where - `n` is the number of nodes in the connected part of graph - containing the node. If the graph is not completely connected, - this algorithm computes the closeness centrality for each - connected part separately scaled by that parts size. - - If the 'distance' keyword is set to an edge attribute key then the - shortest-path length will be computed using Dijkstra's algorithm with - that edge attribute as the edge weight. - - The closeness centrality uses *inward* distance to a node, not outward. - If you want to use outword distances apply the function to `G.reverse()` - - In NetworkX 2.2 and earlier a bug caused Dijkstra's algorithm to use the - outward distance rather than the inward distance. If you use a 'distance' - keyword and a DiGraph, your results will change between v2.2 and v2.3. - - References - ---------- - .. [1] Linton C. Freeman: Centrality in networks: I. - Conceptual clarification. Social Networks 1:215-239, 1979. - http://leonidzhukov.ru/hse/2013/socialnetworks/papers/freeman79-centrality.pdf - .. [2] pg. 201 of Wasserman, S. and Faust, K., - Social Network Analysis: Methods and Applications, 1994, - Cambridge University Press. - """ - if G.is_directed(): - G = G.reverse() # create a reversed graph view - - if distance is not None: - # use Dijkstra's algorithm with specified attribute as edge weight - path_length = functools.partial( - nx.single_source_dijkstra_path_length, weight=distance) - else: - path_length = nx.single_source_shortest_path_length - - if u is None: - nodes = G.nodes - else: - nodes = [u] - closeness_centrality = {} - for n in nodes: - sp = path_length(G, n) - totsp = sum(sp.values()) - len_G = len(G) - _closeness_centrality = 0.0 - if totsp > 0.0 and len_G > 1: - _closeness_centrality = (len(sp) - 1.0) / totsp - # normalize to number of nodes-1 in connected part - if wf_improved: - s = (len(sp) - 1.0) / (len_G - 1) - _closeness_centrality *= s - closeness_centrality[n] = _closeness_centrality - if u is not None: - return closeness_centrality[u] - else: - return closeness_centrality - - -@not_implemented_for('directed') -def incremental_closeness_centrality(G, - edge, - prev_cc=None, - insertion=True, - wf_improved=True): - r"""Incremental closeness centrality for nodes. - - Compute closeness centrality for nodes using level-based work filtering - as described in Incremental Algorithms for Closeness Centrality by Sariyuce et al. - - Level-based work filtering detects unnecessary updates to the closeness - centrality and filters them out. - - --- - From "Incremental Algorithms for Closeness Centrality": - - Theorem 1: Let :math:`G = (V, E)` be a graph and u and v be two vertices in V - such that there is no edge (u, v) in E. Let :math:`G' = (V, E \cup uv)` - Then :math:`cc[s] = cc'[s]` if and only if :math:`\left|dG(s, u) - dG(s, v)\right| \leq 1`. - - Where :math:`dG(u, v)` denotes the length of the shortest path between - two vertices u, v in a graph G, cc[s] is the closeness centrality for a - vertex s in V, and cc'[s] is the closeness centrality for a - vertex s in V, with the (u, v) edge added. - --- - - We use Theorem 1 to filter out updates when adding or removing an edge. - When adding an edge (u, v), we compute the shortest path lengths from all - other nodes to u and to v before the node is added. When removing an edge, - we compute the shortest path lengths after the edge is removed. Then we - apply Theorem 1 to use previously computed closeness centrality for nodes - where :math:`\left|dG(s, u) - dG(s, v)\right| \leq 1`. This works only for - undirected, unweighted graphs; the distance argument is not supported. - - Closeness centrality [1]_ of a node `u` is the reciprocal of the - sum of the shortest path distances from `u` to all `n-1` other nodes. - Since the sum of distances depends on the number of nodes in the - graph, closeness is normalized by the sum of minimum possible - distances `n-1`. - - .. math:: - - C(u) = \frac{n - 1}{\sum_{v=1}^{n-1} d(v, u)}, - - where `d(v, u)` is the shortest-path distance between `v` and `u`, - and `n` is the number of nodes in the graph. - - Notice that higher values of closeness indicate higher centrality. - - Parameters - ---------- - G : graph - A NetworkX graph - - edge : tuple - The modified edge (u, v) in the graph. - - prev_cc : dictionary - The previous closeness centrality for all nodes in the graph. - - insertion : bool, optional - If True (default) the edge was inserted, otherwise it was deleted from the graph. - - wf_improved : bool, optional (default=True) - If True, scale by the fraction of nodes reachable. This gives the - Wasserman and Faust improved formula. For single component graphs - it is the same as the original formula. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with closeness centrality as the value. - - See Also - -------- - betweenness_centrality, load_centrality, eigenvector_centrality, - degree_centrality, closeness_centrality - - Notes - ----- - The closeness centrality is normalized to `(n-1)/(|G|-1)` where - `n` is the number of nodes in the connected part of graph - containing the node. If the graph is not completely connected, - this algorithm computes the closeness centrality for each - connected part separately. - - References - ---------- - .. [1] Freeman, L.C., 1979. Centrality in networks: I. - Conceptual clarification. Social Networks 1, 215--239. - http://www.soc.ucsb.edu/faculty/friedkin/Syllabi/Soc146/Freeman78.PDF - .. [2] Sariyuce, A.E. ; Kaya, K. ; Saule, E. ; Catalyiirek, U.V. Incremental - Algorithms for Closeness Centrality. 2013 IEEE International Conference on Big Data - http://sariyuce.com/papers/bigdata13.pdf - """ - if prev_cc is not None and set(prev_cc.keys()) != set(G.nodes()): - raise NetworkXError('prev_cc and G do not have the same nodes') - - # Unpack edge - (u, v) = edge - path_length = nx.single_source_shortest_path_length - - if insertion: - # For edge insertion, we want shortest paths before the edge is inserted - du = path_length(G, u) - dv = path_length(G, v) - - G.add_edge(u, v) - else: - G.remove_edge(u, v) - - # For edge removal, we want shortest paths after the edge is removed - du = path_length(G, u) - dv = path_length(G, v) - - if prev_cc is None: - return nx.closeness_centrality(G) - - nodes = G.nodes() - closeness_centrality = {} - for n in nodes: - if (n in du and n in dv and abs(du[n] - dv[n]) <= 1): - closeness_centrality[n] = prev_cc[n] - else: - sp = path_length(G, n) - totsp = sum(sp.values()) - len_G = len(G) - _closeness_centrality = 0.0 - if totsp > 0.0 and len_G > 1: - _closeness_centrality = (len(sp) - 1.0) / totsp - # normalize to number of nodes-1 in connected part - if wf_improved: - s = (len(sp) - 1.0) / (len_G - 1) - _closeness_centrality *= s - closeness_centrality[n] = _closeness_centrality - - # Leave the graph as we found it - if insertion: - G.remove_edge(u, v) - else: - G.add_edge(u, v) - - return closeness_centrality diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/current_flow_betweenness.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/current_flow_betweenness.py deleted file mode 100644 index 10f88807..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/current_flow_betweenness.py +++ /dev/null @@ -1,365 +0,0 @@ -# Copyright (C) 2010-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Author: Aric Hagberg (hagberg@lanl.gov) -"""Current-flow betweenness centrality measures.""" -import networkx as nx -from networkx.algorithms.centrality.flow_matrix import * -from networkx.utils import (not_implemented_for, - reverse_cuthill_mckee_ordering, - py_random_state) - -__all__ = ['current_flow_betweenness_centrality', - 'approximate_current_flow_betweenness_centrality', - 'edge_current_flow_betweenness_centrality'] - - -@py_random_state(7) -@not_implemented_for('directed') -def approximate_current_flow_betweenness_centrality(G, normalized=True, - weight=None, - dtype=float, solver='full', - epsilon=0.5, kmax=10000, - seed=None): - r"""Compute the approximate current-flow betweenness centrality for nodes. - - Approximates the current-flow betweenness centrality within absolute - error of epsilon with high probability [1]_. - - - Parameters - ---------- - G : graph - A NetworkX graph - - normalized : bool, optional (default=True) - If True the betweenness values are normalized by 2/[(n-1)(n-2)] where - n is the number of nodes in G. - - weight : string or None, optional (default=None) - Key for edge data used as the edge weight. - If None, then use 1 as each edge weight. - - dtype : data type (float) - Default data type for internal matrices. - Set to np.float32 for lower memory consumption. - - solver : string (default='lu') - Type of linear solver to use for computing the flow matrix. - Options are "full" (uses most memory), "lu" (recommended), and - "cg" (uses least memory). - - epsilon: float - Absolute error tolerance. - - kmax: int - Maximum number of sample node pairs to use for approximation. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with betweenness centrality as the value. - - See Also - -------- - current_flow_betweenness_centrality - - Notes - ----- - The running time is $O((1/\epsilon^2)m{\sqrt k} \log n)$ - and the space required is $O(m)$ for $n$ nodes and $m$ edges. - - If the edges have a 'weight' attribute they will be used as - weights in this algorithm. Unspecified weights are set to 1. - - References - ---------- - .. [1] Ulrik Brandes and Daniel Fleischer: - Centrality Measures Based on Current Flow. - Proc. 22nd Symp. Theoretical Aspects of Computer Science (STACS '05). - LNCS 3404, pp. 533-544. Springer-Verlag, 2005. - http://algo.uni-konstanz.de/publications/bf-cmbcf-05.pdf - """ - try: - import numpy as np - except ImportError: - raise ImportError('current_flow_betweenness_centrality requires NumPy ', - 'http://scipy.org/') - try: - from scipy import sparse - from scipy.sparse import linalg - except ImportError: - raise ImportError('current_flow_betweenness_centrality requires SciPy ', - 'http://scipy.org/') - if not nx.is_connected(G): - raise nx.NetworkXError("Graph not connected.") - solvername = {"full": FullInverseLaplacian, - "lu": SuperLUInverseLaplacian, - "cg": CGInverseLaplacian} - n = G.number_of_nodes() - ordering = list(reverse_cuthill_mckee_ordering(G)) - # make a copy with integer labels according to rcm ordering - # this could be done without a copy if we really wanted to - H = nx.relabel_nodes(G, dict(zip(ordering, range(n)))) - L = laplacian_sparse_matrix(H, nodelist=range(n), weight=weight, - dtype=dtype, format='csc') - C = solvername[solver](L, dtype=dtype) # initialize solver - betweenness = dict.fromkeys(H, 0.0) - nb = (n - 1.0) * (n - 2.0) # normalization factor - cstar = n * (n - 1) / nb - l = 1 # parameter in approximation, adjustable - k = l * int(np.ceil((cstar / epsilon)**2 * np.log(n))) - if k > kmax: - msg = 'Number random pairs k>kmax (%d>%d) ' % (k, kmax) - raise nx.NetworkXError(msg, 'Increase kmax or epsilon') - cstar2k = cstar / (2 * k) - for i in range(k): - s, t = seed.sample(range(n), 2) - b = np.zeros(n, dtype=dtype) - b[s] = 1 - b[t] = -1 - p = C.solve(b) - for v in H: - if v == s or v == t: - continue - for nbr in H[v]: - w = H[v][nbr].get(weight, 1.0) - betweenness[v] += w * np.abs(p[v] - p[nbr]) * cstar2k - if normalized: - factor = 1.0 - else: - factor = nb / 2.0 - # remap to original node names and "unnormalize" if required - return dict((ordering[k], float(v * factor)) for k, v in betweenness.items()) - - -@not_implemented_for('directed') -def current_flow_betweenness_centrality(G, normalized=True, weight=None, - dtype=float, solver='full'): - r"""Compute current-flow betweenness centrality for nodes. - - Current-flow betweenness centrality uses an electrical current - model for information spreading in contrast to betweenness - centrality which uses shortest paths. - - Current-flow betweenness centrality is also known as - random-walk betweenness centrality [2]_. - - Parameters - ---------- - G : graph - A NetworkX graph - - normalized : bool, optional (default=True) - If True the betweenness values are normalized by 2/[(n-1)(n-2)] where - n is the number of nodes in G. - - weight : string or None, optional (default=None) - Key for edge data used as the edge weight. - If None, then use 1 as each edge weight. - - dtype : data type (float) - Default data type for internal matrices. - Set to np.float32 for lower memory consumption. - - solver : string (default='lu') - Type of linear solver to use for computing the flow matrix. - Options are "full" (uses most memory), "lu" (recommended), and - "cg" (uses least memory). - - Returns - ------- - nodes : dictionary - Dictionary of nodes with betweenness centrality as the value. - - See Also - -------- - approximate_current_flow_betweenness_centrality - betweenness_centrality - edge_betweenness_centrality - edge_current_flow_betweenness_centrality - - Notes - ----- - Current-flow betweenness can be computed in $O(I(n-1)+mn \log n)$ - time [1]_, where $I(n-1)$ is the time needed to compute the - inverse Laplacian. For a full matrix this is $O(n^3)$ but using - sparse methods you can achieve $O(nm{\sqrt k})$ where $k$ is the - Laplacian matrix condition number. - - The space required is $O(nw)$ where $w$ is the width of the sparse - Laplacian matrix. Worse case is $w=n$ for $O(n^2)$. - - If the edges have a 'weight' attribute they will be used as - weights in this algorithm. Unspecified weights are set to 1. - - References - ---------- - .. [1] Centrality Measures Based on Current Flow. - Ulrik Brandes and Daniel Fleischer, - Proc. 22nd Symp. Theoretical Aspects of Computer Science (STACS '05). - LNCS 3404, pp. 533-544. Springer-Verlag, 2005. - http://algo.uni-konstanz.de/publications/bf-cmbcf-05.pdf - - .. [2] A measure of betweenness centrality based on random walks, - M. E. J. Newman, Social Networks 27, 39-54 (2005). - """ - try: - import numpy as np - except ImportError: - raise ImportError('current_flow_betweenness_centrality requires NumPy ', - 'http://scipy.org/') - try: - import scipy - except ImportError: - raise ImportError('current_flow_betweenness_centrality requires SciPy ', - 'http://scipy.org/') - if not nx.is_connected(G): - raise nx.NetworkXError("Graph not connected.") - n = G.number_of_nodes() - ordering = list(reverse_cuthill_mckee_ordering(G)) - # make a copy with integer labels according to rcm ordering - # this could be done without a copy if we really wanted to - H = nx.relabel_nodes(G, dict(zip(ordering, range(n)))) - betweenness = dict.fromkeys(H, 0.0) # b[v]=0 for v in H - for row, (s, t) in flow_matrix_row(H, weight=weight, dtype=dtype, - solver=solver): - pos = dict(zip(row.argsort()[::-1], range(n))) - for i in range(n): - betweenness[s] += (i - pos[i]) * row[i] - betweenness[t] += (n - i - 1 - pos[i]) * row[i] - if normalized: - nb = (n - 1.0) * (n - 2.0) # normalization factor - else: - nb = 2.0 - for v in H: - betweenness[v] = float((betweenness[v] - v) * 2.0 / nb) - return dict((ordering[k], v) for k, v in betweenness.items()) - - -@not_implemented_for('directed') -def edge_current_flow_betweenness_centrality(G, normalized=True, - weight=None, - dtype=float, solver='full'): - r"""Compute current-flow betweenness centrality for edges. - - Current-flow betweenness centrality uses an electrical current - model for information spreading in contrast to betweenness - centrality which uses shortest paths. - - Current-flow betweenness centrality is also known as - random-walk betweenness centrality [2]_. - - Parameters - ---------- - G : graph - A NetworkX graph - - normalized : bool, optional (default=True) - If True the betweenness values are normalized by 2/[(n-1)(n-2)] where - n is the number of nodes in G. - - weight : string or None, optional (default=None) - Key for edge data used as the edge weight. - If None, then use 1 as each edge weight. - - dtype : data type (default=float) - Default data type for internal matrices. - Set to np.float32 for lower memory consumption. - - solver : string (default='lu') - Type of linear solver to use for computing the flow matrix. - Options are "full" (uses most memory), "lu" (recommended), and - "cg" (uses least memory). - - Returns - ------- - nodes : dictionary - Dictionary of edge tuples with betweenness centrality as the value. - - Raises - ------ - NetworkXError - The algorithm does not support DiGraphs. - If the input graph is an instance of DiGraph class, NetworkXError - is raised. - - See Also - -------- - betweenness_centrality - edge_betweenness_centrality - current_flow_betweenness_centrality - - Notes - ----- - Current-flow betweenness can be computed in $O(I(n-1)+mn \log n)$ - time [1]_, where $I(n-1)$ is the time needed to compute the - inverse Laplacian. For a full matrix this is $O(n^3)$ but using - sparse methods you can achieve $O(nm{\sqrt k})$ where $k$ is the - Laplacian matrix condition number. - - The space required is $O(nw)$ where $w$ is the width of the sparse - Laplacian matrix. Worse case is $w=n$ for $O(n^2)$. - - If the edges have a 'weight' attribute they will be used as - weights in this algorithm. Unspecified weights are set to 1. - - References - ---------- - .. [1] Centrality Measures Based on Current Flow. - Ulrik Brandes and Daniel Fleischer, - Proc. 22nd Symp. Theoretical Aspects of Computer Science (STACS '05). - LNCS 3404, pp. 533-544. Springer-Verlag, 2005. - http://algo.uni-konstanz.de/publications/bf-cmbcf-05.pdf - - .. [2] A measure of betweenness centrality based on random walks, - M. E. J. Newman, Social Networks 27, 39-54 (2005). - """ - from networkx.utils import reverse_cuthill_mckee_ordering - try: - import numpy as np - except ImportError: - raise ImportError('current_flow_betweenness_centrality requires NumPy ', - 'http://scipy.org/') - try: - import scipy - except ImportError: - raise ImportError('current_flow_betweenness_centrality requires SciPy ', - 'http://scipy.org/') - if not nx.is_connected(G): - raise nx.NetworkXError("Graph not connected.") - n = G.number_of_nodes() - ordering = list(reverse_cuthill_mckee_ordering(G)) - # make a copy with integer labels according to rcm ordering - # this could be done without a copy if we really wanted to - H = nx.relabel_nodes(G, dict(zip(ordering, range(n)))) - edges = (tuple(sorted((u, v))) for u, v in H.edges()) - betweenness = dict.fromkeys(edges, 0.0) - if normalized: - nb = (n - 1.0) * (n - 2.0) # normalization factor - else: - nb = 2.0 - for row, (e) in flow_matrix_row(H, weight=weight, dtype=dtype, - solver=solver): - pos = dict(zip(row.argsort()[::-1], range(1, n + 1))) - for i in range(n): - betweenness[e] += (i + 1 - pos[i]) * row[i] - betweenness[e] += (n - i - pos[i]) * row[i] - betweenness[e] /= nb - return dict(((ordering[s], ordering[t]), float(v)) - for (s, t), v in betweenness.items()) - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/current_flow_betweenness_subset.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/current_flow_betweenness_subset.py deleted file mode 100644 index 7ffa67e6..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/current_flow_betweenness_subset.py +++ /dev/null @@ -1,255 +0,0 @@ -# Copyright (C) 2010-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Author: Aric Hagberg (hagberg@lanl.gov) -"""Current-flow betweenness centrality measures for subsets of nodes.""" -import itertools - -import networkx as nx -from networkx.algorithms.centrality.flow_matrix import * -from networkx.utils import not_implemented_for, reverse_cuthill_mckee_ordering - -__all__ = ['current_flow_betweenness_centrality_subset', - 'edge_current_flow_betweenness_centrality_subset'] - - -@not_implemented_for('directed') -def current_flow_betweenness_centrality_subset(G, sources, targets, - normalized=True, - weight=None, - dtype=float, solver='lu'): - r"""Compute current-flow betweenness centrality for subsets of nodes. - - Current-flow betweenness centrality uses an electrical current - model for information spreading in contrast to betweenness - centrality which uses shortest paths. - - Current-flow betweenness centrality is also known as - random-walk betweenness centrality [2]_. - - Parameters - ---------- - G : graph - A NetworkX graph - - sources: list of nodes - Nodes to use as sources for current - - targets: list of nodes - Nodes to use as sinks for current - - normalized : bool, optional (default=True) - If True the betweenness values are normalized by b=b/(n-1)(n-2) where - n is the number of nodes in G. - - weight : string or None, optional (default=None) - Key for edge data used as the edge weight. - If None, then use 1 as each edge weight. - - dtype: data type (float) - Default data type for internal matrices. - Set to np.float32 for lower memory consumption. - - solver: string (default='lu') - Type of linear solver to use for computing the flow matrix. - Options are "full" (uses most memory), "lu" (recommended), and - "cg" (uses least memory). - - Returns - ------- - nodes : dictionary - Dictionary of nodes with betweenness centrality as the value. - - See Also - -------- - approximate_current_flow_betweenness_centrality - betweenness_centrality - edge_betweenness_centrality - edge_current_flow_betweenness_centrality - - Notes - ----- - Current-flow betweenness can be computed in $O(I(n-1)+mn \log n)$ - time [1]_, where $I(n-1)$ is the time needed to compute the - inverse Laplacian. For a full matrix this is $O(n^3)$ but using - sparse methods you can achieve $O(nm{\sqrt k})$ where $k$ is the - Laplacian matrix condition number. - - The space required is $O(nw)$ where $w$ is the width of the sparse - Laplacian matrix. Worse case is $w=n$ for $O(n^2)$. - - If the edges have a 'weight' attribute they will be used as - weights in this algorithm. Unspecified weights are set to 1. - - References - ---------- - .. [1] Centrality Measures Based on Current Flow. - Ulrik Brandes and Daniel Fleischer, - Proc. 22nd Symp. Theoretical Aspects of Computer Science (STACS '05). - LNCS 3404, pp. 533-544. Springer-Verlag, 2005. - http://algo.uni-konstanz.de/publications/bf-cmbcf-05.pdf - - .. [2] A measure of betweenness centrality based on random walks, - M. E. J. Newman, Social Networks 27, 39-54 (2005). - """ - from networkx.utils import reverse_cuthill_mckee_ordering - try: - import numpy as np - except ImportError: - raise ImportError('current_flow_betweenness_centrality requires NumPy ', - 'http://scipy.org/') - try: - import scipy - except ImportError: - raise ImportError('current_flow_betweenness_centrality requires SciPy ', - 'http://scipy.org/') - if not nx.is_connected(G): - raise nx.NetworkXError("Graph not connected.") - n = G.number_of_nodes() - ordering = list(reverse_cuthill_mckee_ordering(G)) - # make a copy with integer labels according to rcm ordering - # this could be done without a copy if we really wanted to - mapping = dict(zip(ordering, range(n))) - H = nx.relabel_nodes(G, mapping) - betweenness = dict.fromkeys(H, 0.0) # b[v]=0 for v in H - for row, (s, t) in flow_matrix_row(H, weight=weight, dtype=dtype, - solver=solver): - for ss in sources: - i = mapping[ss] - for tt in targets: - j = mapping[tt] - betweenness[s] += 0.5 * np.abs(row[i] - row[j]) - betweenness[t] += 0.5 * np.abs(row[i] - row[j]) - if normalized: - nb = (n - 1.0) * (n - 2.0) # normalization factor - else: - nb = 2.0 - for v in H: - betweenness[v] = betweenness[v] / nb + 1.0 / (2 - n) - return dict((ordering[k], v) for k, v in betweenness.items()) - - -@not_implemented_for('directed') -def edge_current_flow_betweenness_centrality_subset(G, sources, targets, - normalized=True, - weight=None, - dtype=float, solver='lu'): - r"""Compute current-flow betweenness centrality for edges using subsets - of nodes. - - Current-flow betweenness centrality uses an electrical current - model for information spreading in contrast to betweenness - centrality which uses shortest paths. - - Current-flow betweenness centrality is also known as - random-walk betweenness centrality [2]_. - - Parameters - ---------- - G : graph - A NetworkX graph - - sources: list of nodes - Nodes to use as sources for current - - targets: list of nodes - Nodes to use as sinks for current - - normalized : bool, optional (default=True) - If True the betweenness values are normalized by b=b/(n-1)(n-2) where - n is the number of nodes in G. - - weight : string or None, optional (default=None) - Key for edge data used as the edge weight. - If None, then use 1 as each edge weight. - - dtype: data type (float) - Default data type for internal matrices. - Set to np.float32 for lower memory consumption. - - solver: string (default='lu') - Type of linear solver to use for computing the flow matrix. - Options are "full" (uses most memory), "lu" (recommended), and - "cg" (uses least memory). - - Returns - ------- - nodes : dict - Dictionary of edge tuples with betweenness centrality as the value. - - See Also - -------- - betweenness_centrality - edge_betweenness_centrality - current_flow_betweenness_centrality - - Notes - ----- - Current-flow betweenness can be computed in $O(I(n-1)+mn \log n)$ - time [1]_, where $I(n-1)$ is the time needed to compute the - inverse Laplacian. For a full matrix this is $O(n^3)$ but using - sparse methods you can achieve $O(nm{\sqrt k})$ where $k$ is the - Laplacian matrix condition number. - - The space required is $O(nw)$ where $w$ is the width of the sparse - Laplacian matrix. Worse case is $w=n$ for $O(n^2)$. - - If the edges have a 'weight' attribute they will be used as - weights in this algorithm. Unspecified weights are set to 1. - - References - ---------- - .. [1] Centrality Measures Based on Current Flow. - Ulrik Brandes and Daniel Fleischer, - Proc. 22nd Symp. Theoretical Aspects of Computer Science (STACS '05). - LNCS 3404, pp. 533-544. Springer-Verlag, 2005. - http://algo.uni-konstanz.de/publications/bf-cmbcf-05.pdf - - .. [2] A measure of betweenness centrality based on random walks, - M. E. J. Newman, Social Networks 27, 39-54 (2005). - """ - try: - import numpy as np - except ImportError: - raise ImportError('current_flow_betweenness_centrality requires NumPy ', - 'http://scipy.org/') - try: - import scipy - except ImportError: - raise ImportError('current_flow_betweenness_centrality requires SciPy ', - 'http://scipy.org/') - if not nx.is_connected(G): - raise nx.NetworkXError("Graph not connected.") - n = G.number_of_nodes() - ordering = list(reverse_cuthill_mckee_ordering(G)) - # make a copy with integer labels according to rcm ordering - # this could be done without a copy if we really wanted to - mapping = dict(zip(ordering, range(n))) - H = nx.relabel_nodes(G, mapping) - edges = (tuple(sorted((u, v))) for u, v in H.edges()) - betweenness = dict.fromkeys(edges, 0.0) - if normalized: - nb = (n - 1.0) * (n - 2.0) # normalization factor - else: - nb = 2.0 - for row, (e) in flow_matrix_row(H, weight=weight, dtype=dtype, - solver=solver): - for ss in sources: - i = mapping[ss] - for tt in targets: - j = mapping[tt] - betweenness[e] += 0.5 * np.abs(row[i] - row[j]) - betweenness[e] /= nb - return dict(((ordering[s], ordering[t]), v) - for (s, t), v in betweenness.items()) - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/current_flow_closeness.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/current_flow_closeness.py deleted file mode 100644 index 042c8d7e..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/current_flow_closeness.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright (C) 2010-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Author: Aric Hagberg (hagberg@lanl.gov) -"""Current-flow closeness centrality measures.""" -import networkx as nx - -from networkx.utils import not_implemented_for, reverse_cuthill_mckee_ordering -from networkx.algorithms.centrality.flow_matrix import * - -__all__ = ['current_flow_closeness_centrality', 'information_centrality'] - - -@not_implemented_for('directed') -def current_flow_closeness_centrality(G, weight=None, - dtype=float, solver='lu'): - """Compute current-flow closeness centrality for nodes. - - Current-flow closeness centrality is variant of closeness - centrality based on effective resistance between nodes in - a network. This metric is also known as information centrality. - - Parameters - ---------- - G : graph - A NetworkX graph. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - - dtype: data type (default=float) - Default data type for internal matrices. - Set to np.float32 for lower memory consumption. - - solver: string (default='lu') - Type of linear solver to use for computing the flow matrix. - Options are "full" (uses most memory), "lu" (recommended), and - "cg" (uses least memory). - - Returns - ------- - nodes : dictionary - Dictionary of nodes with current flow closeness centrality as the value. - - See Also - -------- - closeness_centrality - - Notes - ----- - The algorithm is from Brandes [1]_. - - See also [2]_ for the original definition of information centrality. - - References - ---------- - .. [1] Ulrik Brandes and Daniel Fleischer, - Centrality Measures Based on Current Flow. - Proc. 22nd Symp. Theoretical Aspects of Computer Science (STACS '05). - LNCS 3404, pp. 533-544. Springer-Verlag, 2005. - http://algo.uni-konstanz.de/publications/bf-cmbcf-05.pdf - - .. [2] Karen Stephenson and Marvin Zelen: - Rethinking centrality: Methods and examples. - Social Networks 11(1):1-37, 1989. - https://doi.org/10.1016/0378-8733(89)90016-6 - """ - import numpy as np - import scipy - if not nx.is_connected(G): - raise nx.NetworkXError("Graph not connected.") - solvername = {"full": FullInverseLaplacian, - "lu": SuperLUInverseLaplacian, - "cg": CGInverseLaplacian} - n = G.number_of_nodes() - ordering = list(reverse_cuthill_mckee_ordering(G)) - # make a copy with integer labels according to rcm ordering - # this could be done without a copy if we really wanted to - H = nx.relabel_nodes(G, dict(zip(ordering, range(n)))) - betweenness = dict.fromkeys(H, 0.0) # b[v]=0 for v in H - n = H.number_of_nodes() - L = laplacian_sparse_matrix(H, nodelist=range(n), weight=weight, - dtype=dtype, format='csc') - C2 = solvername[solver](L, width=1, dtype=dtype) # initialize solver - for v in H: - col = C2.get_row(v) - for w in H: - betweenness[v] += col[v] - 2 * col[w] - betweenness[w] += col[v] - for v in H: - betweenness[v] = 1.0 / (betweenness[v]) - return dict((ordering[k], float(v)) for k, v in betweenness.items()) - - -information_centrality = current_flow_closeness_centrality - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/degree_alg.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/degree_alg.py deleted file mode 100644 index 230a6043..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/degree_alg.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg (hagberg@lanl.gov) -# Pieter Swart (swart@lanl.gov) -# Sasha Gutfraind (ag362@cornell.edu) -"""Degree centrality measures.""" -import networkx as nx -from networkx.utils.decorators import not_implemented_for - -__all__ = ['degree_centrality', - 'in_degree_centrality', - 'out_degree_centrality'] - - -def degree_centrality(G): - """Compute the degree centrality for nodes. - - The degree centrality for a node v is the fraction of nodes it - is connected to. - - Parameters - ---------- - G : graph - A networkx graph - - Returns - ------- - nodes : dictionary - Dictionary of nodes with degree centrality as the value. - - See Also - -------- - betweenness_centrality, load_centrality, eigenvector_centrality - - Notes - ----- - The degree centrality values are normalized by dividing by the maximum - possible degree in a simple graph n-1 where n is the number of nodes in G. - - For multigraphs or graphs with self loops the maximum degree might - be higher than n-1 and values of degree centrality greater than 1 - are possible. - """ - if len(G) <= 1: - return {n: 1 for n in G} - - s = 1.0 / (len(G) - 1.0) - centrality = {n: d * s for n, d in G.degree()} - return centrality - - -@not_implemented_for('undirected') -def in_degree_centrality(G): - """Compute the in-degree centrality for nodes. - - The in-degree centrality for a node v is the fraction of nodes its - incoming edges are connected to. - - Parameters - ---------- - G : graph - A NetworkX graph - - Returns - ------- - nodes : dictionary - Dictionary of nodes with in-degree centrality as values. - - Raises - ------ - NetworkXNotImplemented: - If G is undirected. - - See Also - -------- - degree_centrality, out_degree_centrality - - Notes - ----- - The degree centrality values are normalized by dividing by the maximum - possible degree in a simple graph n-1 where n is the number of nodes in G. - - For multigraphs or graphs with self loops the maximum degree might - be higher than n-1 and values of degree centrality greater than 1 - are possible. - """ - if len(G) <= 1: - return {n: 1 for n in G} - - s = 1.0 / (len(G) - 1.0) - centrality = {n: d * s for n, d in G.in_degree()} - return centrality - - -@not_implemented_for('undirected') -def out_degree_centrality(G): - """Compute the out-degree centrality for nodes. - - The out-degree centrality for a node v is the fraction of nodes its - outgoing edges are connected to. - - Parameters - ---------- - G : graph - A NetworkX graph - - Returns - ------- - nodes : dictionary - Dictionary of nodes with out-degree centrality as values. - - Raises - ------ - NetworkXNotImplemented: - If G is undirected. - - See Also - -------- - degree_centrality, in_degree_centrality - - Notes - ----- - The degree centrality values are normalized by dividing by the maximum - possible degree in a simple graph n-1 where n is the number of nodes in G. - - For multigraphs or graphs with self loops the maximum degree might - be higher than n-1 and values of degree centrality greater than 1 - are possible. - """ - if len(G) <= 1: - return {n: 1 for n in G} - - s = 1.0 / (len(G) - 1.0) - centrality = {n: d * s for n, d in G.out_degree()} - return centrality diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/dispersion.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/dispersion.py deleted file mode 100644 index 568553a5..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/dispersion.py +++ /dev/null @@ -1,105 +0,0 @@ -from itertools import combinations - -__author__ = "\n".join(['Ben Edwards (bedwards@cs.unm.edu)', - 'Huston Hedinger (hstn@hdngr.com)', - 'Dan Schult (dschult@colgate.edu)']) - -__all__ = ['dispersion'] - - -def dispersion(G, u=None, v=None, normalized=True, alpha=1.0, b=0.0, c=0.0): - r"""Calculate dispersion between `u` and `v` in `G`. - - A link between two actors (`u` and `v`) has a high dispersion when their - mutual ties (`s` and `t`) are not well connected with each other. - - Parameters - ---------- - G : graph - A NetworkX graph. - u : node, optional - The source for the dispersion score (e.g. ego node of the network). - v : node, optional - The target of the dispersion score if specified. - normalized : bool - If True (default) normalize by the embededness of the nodes (u and v). - - Returns - ------- - nodes : dictionary - If u (v) is specified, returns a dictionary of nodes with dispersion - score for all "target" ("source") nodes. If neither u nor v is - specified, returns a dictionary of dictionaries for all nodes 'u' in the - graph with a dispersion score for each node 'v'. - - Notes - ----- - This implementation follows Lars Backstrom and Jon Kleinberg [1]_. Typical - usage would be to run dispersion on the ego network $G_u$ if $u$ were - specified. Running :func:`dispersion` with neither $u$ nor $v$ specified - can take some time to complete. - - References - ---------- - .. [1] Romantic Partnerships and the Dispersion of Social Ties: - A Network Analysis of Relationship Status on Facebook. - Lars Backstrom, Jon Kleinberg. - https://arxiv.org/pdf/1310.6753v1.pdf - - """ - - def _dispersion(G_u, u, v): - """dispersion for all nodes 'v' in a ego network G_u of node 'u'""" - u_nbrs = set(G_u[u]) - ST = set(n for n in G_u[v] if n in u_nbrs) - set_uv = set([u, v]) - # all possible ties of connections that u and b share - possib = combinations(ST, 2) - total = 0 - for (s, t) in possib: - # neighbors of s that are in G_u, not including u and v - nbrs_s = u_nbrs.intersection(G_u[s]) - set_uv - # s and t are not directly connected - if t not in nbrs_s: - # s and t do not share a connection - if nbrs_s.isdisjoint(G_u[t]): - # tick for disp(u, v) - total += 1 - # neighbors that u and v share - embededness = len(ST) - - if normalized: - if embededness + c != 0: - norm_disp = ((total + b)**alpha) / (embededness + c) - else: - norm_disp = (total + b)**alpha - dispersion = norm_disp - - else: - dispersion = total - - return dispersion - - if u is None: - # v and u are not specified - if v is None: - results = dict((n, {}) for n in G) - for u in G: - for v in G[u]: - results[u][v] = _dispersion(G, u, v) - # u is not specified, but v is - else: - results = dict.fromkeys(G[v], {}) - for u in G[v]: - results[u] = _dispersion(G, v, u) - else: - # u is specified with no target v - if v is None: - results = dict.fromkeys(G[u], {}) - for v in G[u]: - results[v] = _dispersion(G, u, v) - # both u and v are specified - else: - results = _dispersion(G, u, v) - - return results diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/eigenvector.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/eigenvector.py deleted file mode 100644 index b19f59f6..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/eigenvector.py +++ /dev/null @@ -1,244 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: -# Aric Hagberg -# Pieter Swart -# Sasha Gutfraind -"""Functions for computing eigenvector centrality.""" - -from math import sqrt - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ['eigenvector_centrality', 'eigenvector_centrality_numpy'] - - -@not_implemented_for('multigraph') -def eigenvector_centrality(G, max_iter=100, tol=1.0e-6, nstart=None, - weight=None): - r"""Compute the eigenvector centrality for the graph `G`. - - Eigenvector centrality computes the centrality for a node based on the - centrality of its neighbors. The eigenvector centrality for node $i$ is - the $i$-th element of the vector $x$ defined by the equation - - .. math:: - - Ax = \lambda x - - where $A$ is the adjacency matrix of the graph `G` with eigenvalue - $\lambda$. By virtue of the Perron–Frobenius theorem, there is a unique - solution $x$, all of whose entries are positive, if $\lambda$ is the - largest eigenvalue of the adjacency matrix $A$ ([2]_). - - Parameters - ---------- - G : graph - A networkx graph - - max_iter : integer, optional (default=100) - Maximum number of iterations in power method. - - tol : float, optional (default=1.0e-6) - Error tolerance used to check convergence in power method iteration. - - nstart : dictionary, optional (default=None) - Starting value of eigenvector iteration for each node. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with eigenvector centrality as the value. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> centrality = nx.eigenvector_centrality(G) - >>> sorted((v, '{:0.2f}'.format(c)) for v, c in centrality.items()) - [(0, '0.37'), (1, '0.60'), (2, '0.60'), (3, '0.37')] - - Raises - ------ - NetworkXPointlessConcept - If the graph `G` is the null graph. - - NetworkXError - If each value in `nstart` is zero. - - PowerIterationFailedConvergence - If the algorithm fails to converge to the specified tolerance - within the specified number of iterations of the power iteration - method. - - See Also - -------- - eigenvector_centrality_numpy - pagerank - hits - - Notes - ----- - The measure was introduced by [1]_ and is discussed in [2]_. - - The power iteration method is used to compute the eigenvector and - convergence is **not** guaranteed. Our method stops after ``max_iter`` - iterations or when the change in the computed vector between two - iterations is smaller than an error tolerance of - ``G.number_of_nodes() * tol``. This implementation uses ($A + I$) - rather than the adjacency matrix $A$ because it shifts the spectrum - to enable discerning the correct eigenvector even for networks with - multiple dominant eigenvalues. - - For directed graphs this is "left" eigenvector centrality which corresponds - to the in-edges in the graph. For out-edges eigenvector centrality - first reverse the graph with ``G.reverse()``. - - References - ---------- - .. [1] Phillip Bonacich. - "Power and Centrality: A Family of Measures." - *American Journal of Sociology* 92(5):1170–1182, 1986 - - .. [2] Mark E. J. Newman. - *Networks: An Introduction.* - Oxford University Press, USA, 2010, pp. 169. - - """ - if len(G) == 0: - raise nx.NetworkXPointlessConcept('cannot compute centrality for the' - ' null graph') - # If no initial vector is provided, start with the all-ones vector. - if nstart is None: - nstart = {v: 1 for v in G} - if all(v == 0 for v in nstart.values()): - raise nx.NetworkXError('initial vector cannot have all zero values') - # Normalize the initial vector so that each entry is in [0, 1]. This is - # guaranteed to never have a divide-by-zero error by the previous line. - nstart_sum = sum(nstart.values()) - x = {k: v / nstart_sum for k, v in nstart.items()} - nnodes = G.number_of_nodes() - # make up to max_iter iterations - for i in range(max_iter): - xlast = x - x = xlast.copy() # Start with xlast times I to iterate with (A+I) - # do the multiplication y^T = x^T A (left eigenvector) - for n in x: - for nbr in G[n]: - w = G[n][nbr].get(weight, 1) if weight else 1 - x[nbr] += xlast[n] * w - # Normalize the vector. The normalization denominator `norm` - # should never be zero by the Perron--Frobenius - # theorem. However, in case it is due to numerical error, we - # assume the norm to be one instead. - norm = sqrt(sum(z ** 2 for z in x.values())) or 1 - x = {k: v / norm for k, v in x.items()} - # Check for convergence (in the L_1 norm). - if sum(abs(x[n] - xlast[n]) for n in x) < nnodes * tol: - return x - raise nx.PowerIterationFailedConvergence(max_iter) - - -def eigenvector_centrality_numpy(G, weight=None, max_iter=50, tol=0): - r"""Compute the eigenvector centrality for the graph G. - - Eigenvector centrality computes the centrality for a node based on the - centrality of its neighbors. The eigenvector centrality for node $i$ is - - .. math:: - - Ax = \lambda x - - where $A$ is the adjacency matrix of the graph G with eigenvalue $\lambda$. - By virtue of the Perron–Frobenius theorem, there is a unique and positive - solution if $\lambda$ is the largest eigenvalue associated with the - eigenvector of the adjacency matrix $A$ ([2]_). - - Parameters - ---------- - G : graph - A networkx graph - - weight : None or string, optional (default=None) - The name of the edge attribute used as weight. - If None, all edge weights are considered equal. - - max_iter : integer, optional (default=100) - Maximum number of iterations in power method. - - tol : float, optional (default=1.0e-6) - Relative accuracy for eigenvalues (stopping criterion). - The default value of 0 implies machine precision. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with eigenvector centrality as the value. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> centrality = nx.eigenvector_centrality_numpy(G) - >>> print(['{} {:0.2f}'.format(node, centrality[node]) for node in centrality]) - ['0 0.37', '1 0.60', '2 0.60', '3 0.37'] - - See Also - -------- - eigenvector_centrality - pagerank - hits - - Notes - ----- - The measure was introduced by [1]_. - - This algorithm uses the SciPy sparse eigenvalue solver (ARPACK) to - find the largest eigenvalue/eigenvector pair. - - For directed graphs this is "left" eigenvector centrality which corresponds - to the in-edges in the graph. For out-edges eigenvector centrality - first reverse the graph with ``G.reverse()``. - - Raises - ------ - NetworkXPointlessConcept - If the graph ``G`` is the null graph. - - References - ---------- - .. [1] Phillip Bonacich: - Power and Centrality: A Family of Measures. - American Journal of Sociology 92(5):1170–1182, 1986 - http://www.leonidzhukov.net/hse/2014/socialnetworks/papers/Bonacich-Centrality.pdf - .. [2] Mark E. J. Newman: - Networks: An Introduction. - Oxford University Press, USA, 2010, pp. 169. - """ - import scipy as sp - from scipy.sparse import linalg - if len(G) == 0: - raise nx.NetworkXPointlessConcept('cannot compute centrality for the' - ' null graph') - M = nx.to_scipy_sparse_matrix(G, nodelist=list(G), weight=weight, - dtype=float) - eigenvalue, eigenvector = linalg.eigs(M.T, k=1, which='LR', - maxiter=max_iter, tol=tol) - largest = eigenvector.flatten().real - norm = sp.sign(largest.sum()) * sp.linalg.norm(largest) - return dict(zip(G, largest / norm)) - - -# fixture for pytest -def setup_module(module): - import pytest - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/flow_matrix.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/flow_matrix.py deleted file mode 100644 index ae179788..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/flow_matrix.py +++ /dev/null @@ -1,138 +0,0 @@ -# Helpers for current-flow betweenness and current-flow closness -# Lazy computations for inverse Laplacian and flow-matrix rows. -import networkx as nx - - -def flow_matrix_row(G, weight=None, dtype=float, solver='lu'): - # Generate a row of the current-flow matrix - import numpy as np - from scipy import sparse - from scipy.sparse import linalg - solvername = {"full": FullInverseLaplacian, - "lu": SuperLUInverseLaplacian, - "cg": CGInverseLaplacian} - n = G.number_of_nodes() - L = laplacian_sparse_matrix(G, nodelist=range(n), weight=weight, - dtype=dtype, format='csc') - C = solvername[solver](L, dtype=dtype) # initialize solver - w = C.w # w is the Laplacian matrix width - # row-by-row flow matrix - for u, v in sorted(sorted((u, v)) for u, v in G.edges()): - B = np.zeros(w, dtype=dtype) - c = G[u][v].get(weight, 1.0) - B[u % w] = c - B[v % w] = -c - # get only the rows needed in the inverse laplacian - # and multiply to get the flow matrix row - row = np.dot(B, C.get_rows(u, v)) - yield row, (u, v) - - -# Class to compute the inverse laplacian only for specified rows -# Allows computation of the current-flow matrix without storing entire -# inverse laplacian matrix -class InverseLaplacian(object): - def __init__(self, L, width=None, dtype=None): - global np - import numpy as np - (n, n) = L.shape - self.dtype = dtype - self.n = n - if width is None: - self.w = self.width(L) - else: - self.w = width - self.C = np.zeros((self.w, n), dtype=dtype) - self.L1 = L[1:, 1:] - self.init_solver(L) - - def init_solver(self, L): - pass - - def solve(self, r): - raise nx.NetworkXError("Implement solver") - - def solve_inverse(self, r): - raise nx.NetworkXError("Implement solver") - - def get_rows(self, r1, r2): - for r in range(r1, r2 + 1): - self.C[r % self.w, 1:] = self.solve_inverse(r) - return self.C - - def get_row(self, r): - self.C[r % self.w, 1:] = self.solve_inverse(r) - return self.C[r % self.w] - - def width(self, L): - m = 0 - for i, row in enumerate(L): - w = 0 - x, y = np.nonzero(row) - if len(y) > 0: - v = y - i - w = v.max() - v.min() + 1 - m = max(w, m) - return m - - -class FullInverseLaplacian(InverseLaplacian): - def init_solver(self, L): - self.IL = np.zeros(L.shape, dtype=self.dtype) - self.IL[1:, 1:] = np.linalg.inv(self.L1.todense()) - - def solve(self, rhs): - s = np.zeros(rhs.shape, dtype=self.dtype) - s = np.dot(self.IL, rhs) - return s - - def solve_inverse(self, r): - return self.IL[r, 1:] - - -class SuperLUInverseLaplacian(InverseLaplacian): - def init_solver(self, L): - from scipy.sparse import linalg - self.lusolve = linalg.factorized(self.L1.tocsc()) - - def solve_inverse(self, r): - rhs = np.zeros(self.n, dtype=self.dtype) - rhs[r] = 1 - return self.lusolve(rhs[1:]) - - def solve(self, rhs): - s = np.zeros(rhs.shape, dtype=self.dtype) - s[1:] = self.lusolve(rhs[1:]) - return s - - -class CGInverseLaplacian(InverseLaplacian): - def init_solver(self, L): - global linalg - from scipy.sparse import linalg - ilu = linalg.spilu(self.L1.tocsc()) - n = self.n - 1 - self.M = linalg.LinearOperator(shape=(n, n), matvec=ilu.solve) - - def solve(self, rhs): - s = np.zeros(rhs.shape, dtype=self.dtype) - s[1:] = linalg.cg(self.L1, rhs[1:], M=self.M, atol=0)[0] - return s - - def solve_inverse(self, r): - rhs = np.zeros(self.n, self.dtype) - rhs[r] = 1 - return linalg.cg(self.L1, rhs[1:], M=self.M, atol=0)[0] - - -# graph laplacian, sparse version, will move to linalg/laplacianmatrix.py -def laplacian_sparse_matrix(G, nodelist=None, weight=None, dtype=None, - format='csr'): - import numpy as np - import scipy.sparse - A = nx.to_scipy_sparse_matrix(G, nodelist=nodelist, weight=weight, - dtype=dtype, format=format) - (n, n) = A.shape - data = np.asarray(A.sum(axis=1).T) - D = scipy.sparse.spdiags(data, 0, n, n, format=format) - return D - A diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/group.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/group.py deleted file mode 100644 index cd3838d7..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/group.py +++ /dev/null @@ -1,373 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Nanda H Krishna -"""Group centrality measures.""" -from itertools import combinations - - -import networkx as nx -from networkx.utils.decorators import not_implemented_for - - -__all__ = ['group_betweenness_centrality', - 'group_closeness_centrality', - 'group_degree_centrality', - 'group_in_degree_centrality', - 'group_out_degree_centrality'] - - -def group_betweenness_centrality(G, C, normalized=True, weight=None): - r"""Compute the group betweenness centrality for a group of nodes. - - Group betweenness centrality of a group of nodes $C$ is the sum of the - fraction of all-pairs shortest paths that pass through any vertex in $C$ - - .. math:: - - c_B(C) =\sum_{s,t \in V-C; s -# -"""Functions for computing the harmonic centrality of a graph.""" -from functools import partial - -import networkx as nx - -__all__ = ['harmonic_centrality'] - - -def harmonic_centrality(G, nbunch=None, distance=None): - r"""Compute harmonic centrality for nodes. - - Harmonic centrality [1]_ of a node `u` is the sum of the reciprocal - of the shortest path distances from all other nodes to `u` - - .. math:: - - C(u) = \sum_{v \neq u} \frac{1}{d(v, u)} - - where `d(v, u)` is the shortest-path distance between `v` and `u`. - - Notice that higher values indicate higher centrality. - - Parameters - ---------- - G : graph - A NetworkX graph - - nbunch : container - Container of nodes. If provided harmonic centrality will be computed - only over the nodes in nbunch. - - distance : edge attribute key, optional (default=None) - Use the specified edge attribute as the edge distance in shortest - path calculations. If `None`, then each edge will have distance equal to 1. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with harmonic centrality as the value. - - See Also - -------- - betweenness_centrality, load_centrality, eigenvector_centrality, - degree_centrality, closeness_centrality - - Notes - ----- - If the 'distance' keyword is set to an edge attribute key then the - shortest-path length will be computed using Dijkstra's algorithm with - that edge attribute as the edge weight. - - References - ---------- - .. [1] Boldi, Paolo, and Sebastiano Vigna. "Axioms for centrality." - Internet Mathematics 10.3-4 (2014): 222-262. - """ - if G.is_directed(): - G = G.reverse() - spl = partial(nx.shortest_path_length, G, weight=distance) - return {u: sum(1 / d if d > 0 else 0 for v, d in spl(source=u).items()) - for u in G.nbunch_iter(nbunch)} diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/katz.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/katz.py deleted file mode 100644 index 8f6e80ed..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/katz.py +++ /dev/null @@ -1,343 +0,0 @@ -# coding=utf8 -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg (aric.hagberg@gmail.com) -# Pieter Swart (swart@lanl.gov) -# Sasha Gutfraind (ag362@cornell.edu) -# Vincent Gauthier (vgauthier@luxbulb.org) -"""Katz centrality.""" -from math import sqrt - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ['katz_centrality', 'katz_centrality_numpy'] - - -@not_implemented_for('multigraph') -def katz_centrality(G, alpha=0.1, beta=1.0, max_iter=1000, tol=1.0e-6, - nstart=None, normalized=True, weight=None): - r"""Compute the Katz centrality for the nodes of the graph G. - - Katz centrality computes the centrality for a node based on the centrality - of its neighbors. It is a generalization of the eigenvector centrality. The - Katz centrality for node $i$ is - - .. math:: - - x_i = \alpha \sum_{j} A_{ij} x_j + \beta, - - where $A$ is the adjacency matrix of graph G with eigenvalues $\lambda$. - - The parameter $\beta$ controls the initial centrality and - - .. math:: - - \alpha < \frac{1}{\lambda_{\max}}. - - Katz centrality computes the relative influence of a node within a - network by measuring the number of the immediate neighbors (first - degree nodes) and also all other nodes in the network that connect - to the node under consideration through these immediate neighbors. - - Extra weight can be provided to immediate neighbors through the - parameter $\beta$. Connections made with distant neighbors - are, however, penalized by an attenuation factor $\alpha$ which - should be strictly less than the inverse largest eigenvalue of the - adjacency matrix in order for the Katz centrality to be computed - correctly. More information is provided in [1]_. - - Parameters - ---------- - G : graph - A NetworkX graph. - - alpha : float - Attenuation factor - - beta : scalar or dictionary, optional (default=1.0) - Weight attributed to the immediate neighborhood. If not a scalar, the - dictionary must have an value for every node. - - max_iter : integer, optional (default=1000) - Maximum number of iterations in power method. - - tol : float, optional (default=1.0e-6) - Error tolerance used to check convergence in power method iteration. - - nstart : dictionary, optional - Starting value of Katz iteration for each node. - - normalized : bool, optional (default=True) - If True normalize the resulting values. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with Katz centrality as the value. - - Raises - ------ - NetworkXError - If the parameter `beta` is not a scalar but lacks a value for at least - one node - - PowerIterationFailedConvergence - If the algorithm fails to converge to the specified tolerance - within the specified number of iterations of the power iteration - method. - - Examples - -------- - >>> import math - >>> G = nx.path_graph(4) - >>> phi = (1 + math.sqrt(5)) / 2.0 # largest eigenvalue of adj matrix - >>> centrality = nx.katz_centrality(G, 1/phi - 0.01) - >>> for n, c in sorted(centrality.items()): - ... print("%d %0.2f" % (n, c)) - 0 0.37 - 1 0.60 - 2 0.60 - 3 0.37 - - See Also - -------- - katz_centrality_numpy - eigenvector_centrality - eigenvector_centrality_numpy - pagerank - hits - - Notes - ----- - Katz centrality was introduced by [2]_. - - This algorithm it uses the power method to find the eigenvector - corresponding to the largest eigenvalue of the adjacency matrix of ``G``. - The parameter ``alpha`` should be strictly less than the inverse of largest - eigenvalue of the adjacency matrix for the algorithm to converge. - You can use ``max(nx.adjacency_spectrum(G))`` to get $\lambda_{\max}$ the largest - eigenvalue of the adjacency matrix. - The iteration will stop after ``max_iter`` iterations or an error tolerance of - ``number_of_nodes(G) * tol`` has been reached. - - When $\alpha = 1/\lambda_{\max}$ and $\beta=0$, Katz centrality is the same - as eigenvector centrality. - - For directed graphs this finds "left" eigenvectors which corresponds - to the in-edges in the graph. For out-edges Katz centrality - first reverse the graph with ``G.reverse()``. - - References - ---------- - .. [1] Mark E. J. Newman: - Networks: An Introduction. - Oxford University Press, USA, 2010, p. 720. - .. [2] Leo Katz: - A New Status Index Derived from Sociometric Index. - Psychometrika 18(1):39–43, 1953 - http://phya.snu.ac.kr/~dkim/PRL87278701.pdf - """ - if len(G) == 0: - return {} - - nnodes = G.number_of_nodes() - - if nstart is None: - # choose starting vector with entries of 0 - x = dict([(n, 0) for n in G]) - else: - x = nstart - - try: - b = dict.fromkeys(G, float(beta)) - except (TypeError, ValueError, AttributeError): - b = beta - if set(beta) != set(G): - raise nx.NetworkXError('beta dictionary ' - 'must have a value for every node') - - # make up to max_iter iterations - for i in range(max_iter): - xlast = x - x = dict.fromkeys(xlast, 0) - # do the multiplication y^T = Alpha * x^T A - Beta - for n in x: - for nbr in G[n]: - x[nbr] += xlast[n] * G[n][nbr].get(weight, 1) - for n in x: - x[n] = alpha * x[n] + b[n] - - # check convergence - err = sum([abs(x[n] - xlast[n]) for n in x]) - if err < nnodes * tol: - if normalized: - # normalize vector - try: - s = 1.0 / sqrt(sum(v**2 for v in x.values())) - # this should never be zero? - except ZeroDivisionError: - s = 1.0 - else: - s = 1 - for n in x: - x[n] *= s - return x - raise nx.PowerIterationFailedConvergence(max_iter) - - -@not_implemented_for('multigraph') -def katz_centrality_numpy(G, alpha=0.1, beta=1.0, normalized=True, - weight=None): - r"""Compute the Katz centrality for the graph G. - - Katz centrality computes the centrality for a node based on the centrality - of its neighbors. It is a generalization of the eigenvector centrality. The - Katz centrality for node $i$ is - - .. math:: - - x_i = \alpha \sum_{j} A_{ij} x_j + \beta, - - where $A$ is the adjacency matrix of graph G with eigenvalues $\lambda$. - - The parameter $\beta$ controls the initial centrality and - - .. math:: - - \alpha < \frac{1}{\lambda_{\max}}. - - Katz centrality computes the relative influence of a node within a - network by measuring the number of the immediate neighbors (first - degree nodes) and also all other nodes in the network that connect - to the node under consideration through these immediate neighbors. - - Extra weight can be provided to immediate neighbors through the - parameter $\beta$. Connections made with distant neighbors - are, however, penalized by an attenuation factor $\alpha$ which - should be strictly less than the inverse largest eigenvalue of the - adjacency matrix in order for the Katz centrality to be computed - correctly. More information is provided in [1]_. - - Parameters - ---------- - G : graph - A NetworkX graph - - alpha : float - Attenuation factor - - beta : scalar or dictionary, optional (default=1.0) - Weight attributed to the immediate neighborhood. If not a scalar the - dictionary must have an value for every node. - - normalized : bool - If True normalize the resulting values. - - weight : None or string, optional - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with Katz centrality as the value. - - Raises - ------ - NetworkXError - If the parameter `beta` is not a scalar but lacks a value for at least - one node - - Examples - -------- - >>> import math - >>> G = nx.path_graph(4) - >>> phi = (1 + math.sqrt(5)) / 2.0 # largest eigenvalue of adj matrix - >>> centrality = nx.katz_centrality_numpy(G, 1/phi) - >>> for n, c in sorted(centrality.items()): - ... print("%d %0.2f" % (n, c)) - 0 0.37 - 1 0.60 - 2 0.60 - 3 0.37 - - See Also - -------- - katz_centrality - eigenvector_centrality_numpy - eigenvector_centrality - pagerank - hits - - Notes - ----- - Katz centrality was introduced by [2]_. - - This algorithm uses a direct linear solver to solve the above equation. - The parameter ``alpha`` should be strictly less than the inverse of largest - eigenvalue of the adjacency matrix for there to be a solution. - You can use ``max(nx.adjacency_spectrum(G))`` to get $\lambda_{\max}$ the largest - eigenvalue of the adjacency matrix. - - When $\alpha = 1/\lambda_{\max}$ and $\beta=0$, Katz centrality is the same - as eigenvector centrality. - - For directed graphs this finds "left" eigenvectors which corresponds - to the in-edges in the graph. For out-edges Katz centrality - first reverse the graph with ``G.reverse()``. - - References - ---------- - .. [1] Mark E. J. Newman: - Networks: An Introduction. - Oxford University Press, USA, 2010, p. 720. - .. [2] Leo Katz: - A New Status Index Derived from Sociometric Index. - Psychometrika 18(1):39–43, 1953 - http://phya.snu.ac.kr/~dkim/PRL87278701.pdf - """ - try: - import numpy as np - except ImportError: - raise ImportError('Requires NumPy: http://scipy.org/') - if len(G) == 0: - return {} - try: - nodelist = beta.keys() - if set(nodelist) != set(G): - raise nx.NetworkXError('beta dictionary ' - 'must have a value for every node') - b = np.array(list(beta.values()), dtype=float) - except AttributeError: - nodelist = list(G) - try: - b = np.ones((len(nodelist), 1)) * float(beta) - except (TypeError, ValueError, AttributeError): - raise nx.NetworkXError('beta must be a number') - - A = nx.adj_matrix(G, nodelist=nodelist, weight=weight).todense().T - n = A.shape[0] - centrality = np.linalg.solve(np.eye(n, n) - (alpha * A), b) - if normalized: - norm = np.sign(sum(centrality)) * np.linalg.norm(centrality) - else: - norm = 1.0 - centrality = dict(zip(nodelist, map(float, centrality / norm))) - return centrality - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/load.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/load.py deleted file mode 100644 index 3d1a6515..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/load.py +++ /dev/null @@ -1,212 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg (hagberg@lanl.gov) -# Pieter Swart (swart@lanl.gov) -# Sasha Gutfraind (ag362@cornell.edu) -"""Load centrality.""" -from operator import itemgetter - -import networkx as nx - -__all__ = ['load_centrality', 'edge_load_centrality'] - - -def newman_betweenness_centrality(G, v=None, cutoff=None, - normalized=True, weight=None): - """Compute load centrality for nodes. - - The load centrality of a node is the fraction of all shortest - paths that pass through that node. - - Parameters - ---------- - G : graph - A networkx graph. - - normalized : bool, optional (default=True) - If True the betweenness values are normalized by b=b/(n-1)(n-2) where - n is the number of nodes in G. - - weight : None or string, optional (default=None) - If None, edge weights are ignored. - Otherwise holds the name of the edge attribute used as weight. - - cutoff : bool, optional (default=None) - If specified, only consider paths of length <= cutoff. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with centrality as the value. - - See Also - -------- - betweenness_centrality() - - Notes - ----- - Load centrality is slightly different than betweenness. It was originally - introduced by [2]_. For this load algorithm see [1]_. - - References - ---------- - .. [1] Mark E. J. Newman: - Scientific collaboration networks. II. - Shortest paths, weighted networks, and centrality. - Physical Review E 64, 016132, 2001. - http://journals.aps.org/pre/abstract/10.1103/PhysRevE.64.016132 - .. [2] Kwang-Il Goh, Byungnam Kahng and Doochul Kim - Universal behavior of Load Distribution in Scale-Free Networks. - Physical Review Letters 87(27):1–4, 2001. - http://phya.snu.ac.kr/~dkim/PRL87278701.pdf - """ - if v is not None: # only one node - betweenness = 0.0 - for source in G: - ubetween = _node_betweenness(G, source, cutoff, False, weight) - betweenness += ubetween[v] if v in ubetween else 0 - if normalized: - order = G.order() - if order <= 2: - return betweenness # no normalization b=0 for all nodes - betweenness *= 1.0 / ((order - 1) * (order - 2)) - return betweenness - else: - betweenness = {}.fromkeys(G, 0.0) - for source in betweenness: - ubetween = _node_betweenness(G, source, cutoff, False, weight) - for vk in ubetween: - betweenness[vk] += ubetween[vk] - if normalized: - order = G.order() - if order <= 2: - return betweenness # no normalization b=0 for all nodes - scale = 1.0 / ((order - 1) * (order - 2)) - for v in betweenness: - betweenness[v] *= scale - return betweenness # all nodes - - -def _node_betweenness(G, source, cutoff=False, normalized=True, - weight=None): - """Node betweenness_centrality helper: - - See betweenness_centrality for what you probably want. - This actually computes "load" and not betweenness. - See https://networkx.lanl.gov/ticket/103 - - This calculates the load of each node for paths from a single source. - (The fraction of number of shortests paths from source that go - through each node.) - - To get the load for a node you need to do all-pairs shortest paths. - - If weight is not None then use Dijkstra for finding shortest paths. - """ - # get the predecessor and path length data - if weight is None: - (pred, length) = nx.predecessor(G, source, cutoff=cutoff, - return_seen=True) - else: - (pred, length) = nx.dijkstra_predecessor_and_distance(G, source, - cutoff, weight) - - # order the nodes by path length - onodes = [(l, vert) for (vert, l) in length.items()] - onodes.sort() - onodes[:] = [vert for (l, vert) in onodes if l > 0] - - # initialize betweenness - between = {}.fromkeys(length, 1.0) - - while onodes: - v = onodes.pop() - if v in pred: - num_paths = len(pred[v]) # Discount betweenness if more than - for x in pred[v]: # one shortest path. - if x == source: # stop if hit source because all remaining v - break # also have pred[v]==[source] - between[x] += between[v] / float(num_paths) - # remove source - for v in between: - between[v] -= 1 - # rescale to be between 0 and 1 - if normalized: - l = len(between) - if l > 2: - # scale by 1/the number of possible paths - scale = 1.0 / float((l - 1) * (l - 2)) - for v in between: - between[v] *= scale - return between - - -load_centrality = newman_betweenness_centrality - - -def edge_load_centrality(G, cutoff=False): - """Compute edge load. - - WARNING: This concept of edge load has not been analysed - or discussed outside of NetworkX that we know of. - It is based loosely on load_centrality in the sense that - it counts the number of shortest paths which cross each edge. - This function is for demonstration and testing purposes. - - Parameters - ---------- - G : graph - A networkx graph - - cutoff : bool, optional (default=False) - If specified, only consider paths of length <= cutoff. - - Returns - ------- - A dict keyed by edge 2-tuple to the number of shortest paths - which use that edge. Where more than one path is shortest - the count is divided equally among paths. - """ - betweenness = {} - for u, v in G.edges(): - betweenness[(u, v)] = 0.0 - betweenness[(v, u)] = 0.0 - - for source in G: - ubetween = _edge_betweenness(G, source, cutoff=cutoff) - for e, ubetweenv in ubetween.items(): - betweenness[e] += ubetweenv # cumulative total - return betweenness - - -def _edge_betweenness(G, source, nodes=None, cutoff=False): - """Edge betweenness helper.""" - # get the predecessor data - (pred, length) = nx.predecessor(G, source, cutoff=cutoff, return_seen=True) - # order the nodes by path length - onodes = [n for n, d in sorted(length.items(), key=itemgetter(1))] - # initialize betweenness, doesn't account for any edge weights - between = {} - for u, v in G.edges(nodes): - between[(u, v)] = 1.0 - between[(v, u)] = 1.0 - - while onodes: # work through all paths - v = onodes.pop() - if v in pred: - # Discount betweenness if more than one shortest path. - num_paths = len(pred[v]) - for w in pred[v]: - if w in pred: - # Discount betweenness, mult path - num_paths = len(pred[w]) - for x in pred[w]: - between[(w, x)] += between[(v, w)] / num_paths - between[(x, w)] += between[(w, v)] / num_paths - return between diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/percolation.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/percolation.py deleted file mode 100644 index 8f5e80ae..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/percolation.py +++ /dev/null @@ -1,130 +0,0 @@ -# coding=utf8 -# Copyright (C) 2018 by -# Pranay Kanwar -# All rights reserved. -# BSD license. -# -"""Percolation centrality measures.""" - -__author__ = """\n""".join(['Pranay Kanwar ']) - -import networkx as nx - -from networkx.algorithms.centrality.betweenness import\ - _single_source_dijkstra_path_basic as dijkstra -from networkx.algorithms.centrality.betweenness import\ - _single_source_shortest_path_basic as shortest_path - -__all__ = ['percolation_centrality'] - - -def percolation_centrality(G, attribute='percolation', - states=None, weight=None): - r"""Compute the percolation centrality for nodes. - - Percolation centrality of a node $v$, at a given time, is defined - as the proportion of ‘percolated paths’ that go through that node. - - This measure quantifies relative impact of nodes based on their - topological connectivity, as well as their percolation states. - - Percolation states of nodes are used to depict network percolation - scenarios (such as during infection transmission in a social network - of individuals, spreading of computer viruses on computer networks, or - transmission of disease over a network of towns) over time. In this - measure usually the percolation state is expressed as a decimal - between 0.0 and 1.0. - - When all nodes are in the same percolated state this measure is - equivalent to betweenness centrality. - - Parameters - ---------- - G : graph - A NetworkX graph. - - attribute : None or string, optional (default='percolation') - Name of the node attribute to use for percolation state, used - if `states` is None. - - states : None or dict, optional (default=None) - Specify percolation states for the nodes, nodes as keys states - as values. - - weight : None or string, optional (default=None) - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - - Returns - ------- - nodes : dictionary - Dictionary of nodes with percolation centrality as the value. - - See Also - -------- - betweenness_centrality - - Notes - ----- - The algorithm is from Mahendra Piraveenan, Mikhail Prokopenko, and - Liaquat Hossain [1]_ - Pair dependecies are calculated and accumulated using [2]_ - - For weighted graphs the edge weights must be greater than zero. - Zero edge weights can produce an infinite number of equal length - paths between pairs of nodes. - - References - ---------- - .. [1] Mahendra Piraveenan, Mikhail Prokopenko, Liaquat Hossain - Percolation Centrality: Quantifying Graph-Theoretic Impact of Nodes - during Percolation in Networks - http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0053095 - .. [2] Ulrik Brandes: - A Faster Algorithm for Betweenness Centrality. - Journal of Mathematical Sociology 25(2):163-177, 2001. - http://www.inf.uni-konstanz.de/algo/publications/b-fabc-01.pdf - """ - percolation = dict.fromkeys(G, 0.0) # b[v]=0 for v in G - - nodes = G - - if states is None: - states = nx.get_node_attributes(nodes, attribute) - - # sum of all percolation states - p_sigma_x_t = 0.0 - for v in states.values(): - p_sigma_x_t += v - - for s in nodes: - # single source shortest paths - if weight is None: # use BFS - S, P, sigma = shortest_path(G, s) - else: # use Dijkstra's algorithm - S, P, sigma = dijkstra(G, s, weight) - # accumulation - percolation = _accumulate_percolation(percolation, G, S, P, sigma, s, - states, p_sigma_x_t) - - n = len(G) - - for v in percolation: - percolation[v] *= 1 / (n - 2) - - return percolation - - -def _accumulate_percolation(percolation, G, S, P, sigma, s, - states, p_sigma_x_t): - delta = dict.fromkeys(S, 0) - while S: - w = S.pop() - coeff = (1 + delta[w]) / sigma[w] - for v in P[w]: - delta[v] += sigma[v] * coeff - if w != s: - # percolation weight - pw_s_w = states[s] / (p_sigma_x_t - states[w]) - percolation[w] += delta[w] * pw_s_w - return percolation diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/reaching.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/reaching.py deleted file mode 100644 index 45ee209c..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/reaching.py +++ /dev/null @@ -1,208 +0,0 @@ -# -*- encoding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -"""Functions for computing reaching centrality of a node or a graph.""" - -import networkx as nx - -from networkx.utils import pairwise - -__all__ = ['global_reaching_centrality', 'local_reaching_centrality'] - - -def _average_weight(G, path, weight=None): - """Returns the average weight of an edge in a weighted path. - - Parameters - ---------- - G : graph - A networkx graph. - - path: list - A list of vertices that define the path. - - weight : None or string, optional (default=None) - If None, edge weights are ignored. Then the average weight of an edge - is assumed to be the multiplicative inverse of the length of the path. - Otherwise holds the name of the edge attribute used as weight. - """ - path_length = len(path) - 1 - if path_length <= 0: - return 0 - if weight is None: - return 1 / path_length - total_weight = sum(G.edges[i, j][weight] for i, j in pairwise(path)) - return total_weight / path_length - - -def global_reaching_centrality(G, weight=None, normalized=True): - """Returns the global reaching centrality of a directed graph. - - The *global reaching centrality* of a weighted directed graph is the - average over all nodes of the difference between the local reaching - centrality of the node and the greatest local reaching centrality of - any node in the graph [1]_. For more information on the local - reaching centrality, see :func:`local_reaching_centrality`. - Informally, the local reaching centrality is the proportion of the - graph that is reachable from the neighbors of the node. - - Parameters - ---------- - G : DiGraph - A networkx DiGraph. - - weight : None or string, optional (default=None) - Attribute to use for edge weights. If ``None``, each edge weight - is assumed to be one. A higher weight implies a stronger - connection between nodes and a *shorter* path length. - - normalized : bool, optional (default=True) - Whether to normalize the edge weights by the total sum of edge - weights. - - Returns - ------- - h : float - The global reaching centrality of the graph. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.DiGraph() - >>> G.add_edge(1, 2) - >>> G.add_edge(1, 3) - >>> nx.global_reaching_centrality(G) - 1.0 - >>> G.add_edge(3, 2) - >>> nx.global_reaching_centrality(G) - 0.75 - - See also - -------- - local_reaching_centrality - - References - ---------- - .. [1] Mones, Enys, Lilla Vicsek, and Tamás Vicsek. - "Hierarchy Measure for Complex Networks." - *PLoS ONE* 7.3 (2012): e33799. - https://doi.org/10.1371/journal.pone.0033799 - """ - if nx.is_negatively_weighted(G, weight=weight): - raise nx.NetworkXError('edge weights must be positive') - total_weight = G.size(weight=weight) - if total_weight <= 0: - raise nx.NetworkXError('Size of G must be positive') - - # If provided, weights must be interpreted as connection strength - # (so higher weights are more likely to be chosen). However, the - # shortest path algorithms in NetworkX assume the provided "weight" - # is actually a distance (so edges with higher weight are less - # likely to be chosen). Therefore we need to invert the weights when - # computing shortest paths. - # - # If weight is None, we leave it as-is so that the shortest path - # algorithm can use a faster, unweighted algorithm. - if weight is not None: - def as_distance(u, v, d): return total_weight / d.get(weight, 1) - shortest_paths = nx.shortest_path(G, weight=as_distance) - else: - shortest_paths = nx.shortest_path(G) - - centrality = local_reaching_centrality - # TODO This can be trivially parallelized. - lrc = [centrality(G, node, paths=paths, weight=weight, - normalized=normalized) - for node, paths in shortest_paths.items()] - - max_lrc = max(lrc) - return sum(max_lrc - c for c in lrc) / (len(G) - 1) - - -def local_reaching_centrality(G, v, paths=None, weight=None, normalized=True): - """Returns the local reaching centrality of a node in a directed - graph. - - The *local reaching centrality* of a node in a directed graph is the - proportion of other nodes reachable from that node [1]_. - - Parameters - ---------- - G : DiGraph - A NetworkX DiGraph. - - v : node - A node in the directed graph `G`. - - paths : dictionary (default=None) - If this is not `None` it must be a dictionary representation - of single-source shortest paths, as computed by, for example, - :func:`networkx.shortest_path` with source node `v`. Use this - keyword argument if you intend to invoke this function many - times but don't want the paths to be recomputed each time. - - weight : None or string, optional (default=None) - Attribute to use for edge weights. If `None`, each edge weight - is assumed to be one. A higher weight implies a stronger - connection between nodes and a *shorter* path length. - - normalized : bool, optional (default=True) - Whether to normalize the edge weights by the total sum of edge - weights. - - Returns - ------- - h : float - The local reaching centrality of the node ``v`` in the graph - ``G``. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.DiGraph() - >>> G.add_edges_from([(1, 2), (1, 3)]) - >>> nx.local_reaching_centrality(G, 3) - 0.0 - >>> G.add_edge(3, 2) - >>> nx.local_reaching_centrality(G, 3) - 0.5 - - See also - -------- - global_reaching_centrality - - References - ---------- - .. [1] Mones, Enys, Lilla Vicsek, and Tamás Vicsek. - "Hierarchy Measure for Complex Networks." - *PLoS ONE* 7.3 (2012): e33799. - https://doi.org/10.1371/journal.pone.0033799 - """ - if paths is None: - if nx.is_negatively_weighted(G, weight=weight): - raise nx.NetworkXError('edge weights must be positive') - total_weight = G.size(weight=weight) - if total_weight <= 0: - raise nx.NetworkXError('Size of G must be positive') - if weight is not None: - # Interpret weights as lengths. - def as_distance(u, v, d): return total_weight / d.get(weight, 1) - paths = nx.shortest_path(G, source=v, weight=as_distance) - else: - paths = nx.shortest_path(G, source=v) - # If the graph is unweighted, simply return the proportion of nodes - # reachable from the source node ``v``. - if weight is None and G.is_directed(): - return (len(paths) - 1) / (len(G) - 1) - if normalized and weight is not None: - norm = G.size(weight=weight) / G.size() - else: - norm = 1 - # TODO This can be trivially parallelized. - avgw = (_average_weight(G, path, weight=weight) for path in paths.values()) - sum_avg_weight = sum(avgw) / norm - return sum_avg_weight / (len(G) - 1) diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/second_order.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/second_order.py deleted file mode 100644 index 2e9cd5e5..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/second_order.py +++ /dev/null @@ -1,145 +0,0 @@ -# -*- coding: utf-8 -*- -'''Copyright (c) 2015 – Thomson Licensing, SAS - -Redistribution and use in source and binary forms, with or without -modification, are permitted (subject to the limitations in the -disclaimer below) provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -* Neither the name of Thomson Licensing, or Technicolor, nor the names -of its contributors may be used to endorse or promote products derived -from this software without specific prior written permission. - -NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE -GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT -HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -''' - -import networkx as nx -from networkx.utils import not_implemented_for - -# Authors: Erwan Le Merrer (erwan.lemerrer@technicolor.com) -''' Second order centrality measure.''' - -__all__ = ['second_order_centrality'] - - -@not_implemented_for('directed') -def second_order_centrality(G): - """Compute the second order centrality for nodes of G. - - The second order centrality of a given node is the standard deviation of - the return times to that node of a perpetual random walk on G: - - Parameters - ---------- - G : graph - A NetworkX connected and undirected graph. - - Returns - ------- - nodes : dictionary - Dictionary keyed by node with second order centrality as the value. - - Examples - -------- - >>> G = nx.star_graph(10) - >>> soc = nx.second_order_centrality(G) - >>> print(sorted(soc.items(), key=lambda x:x[1])[0][0]) # pick first id - 0 - - Raises - ------ - NetworkXException - If the graph G is empty, non connected or has negative weights. - - See Also - -------- - betweenness_centrality - - Notes - ----- - Lower values of second order centrality indicate higher centrality. - - The algorithm is from Kermarrec, Le Merrer, Sericola and Trédan [1]_. - - This code implements the analytical version of the algorithm, i.e., - there is no simulation of a random walk process involved. The random walk - is here unbiased (corresponding to eq 6 of the paper [1]_), thus the - centrality values are the standard deviations for random walk return times - on the transformed input graph G (equal in-degree at each nodes by adding - self-loops). - - Complexity of this implementation, made to run locally on a single machine, - is O(n^3), with n the size of G, which makes it viable only for small - graphs. - - References - ---------- - .. [1] Anne-Marie Kermarrec, Erwan Le Merrer, Bruno Sericola, Gilles Trédan - "Second order centrality: Distributed assessment of nodes criticity in - complex networks", Elsevier Computer Communications 34(5):619-628, 2011. - """ - - try: - import numpy as np - except ImportError: - raise ImportError('Requires NumPy: http://scipy.org/') - - n = len(G) - - if n == 0: - raise nx.NetworkXException("Empty graph.") - if not nx.is_connected(G): - raise nx.NetworkXException("Non connected graph.") - if any(d.get('weight', 0) < 0 for u, v, d in G.edges(data=True)): - raise nx.NetworkXException("Graph has negative edge weights.") - - # balancing G for Metropolis-Hastings random walks - G = nx.DiGraph(G) - in_deg = dict(G.in_degree(weight='weight')) - d_max = max(in_deg.values()) - for i, deg in in_deg.items(): - if deg < d_max: - G.add_edge(i, i, weight=d_max-deg) - - P = nx.to_numpy_matrix(G) - P = P / P.sum(axis=1) # to transition probability matrix - - def _Qj(P, j): - P = P.copy() - P[:, j] = 0 - return P - - M = np.empty([n, n]) - - for i in range(n): - M[:, i] = np.linalg.solve(np.identity(n) - _Qj(P, i), - np.ones([n, 1])[:, 0]) # eq 3 - - return dict(zip(G.nodes, - [np.sqrt((2*np.sum(M[:, i])-n*(n+1))) for i in range(n)] - )) # eq 6 - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/subgraph_alg.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/subgraph_alg.py deleted file mode 100644 index fc197410..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/subgraph_alg.py +++ /dev/null @@ -1,324 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Subraph centrality and communicability betweenness. -""" -# Copyright (C) 2011 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -import networkx as nx -from networkx.utils import * -__author__ = "\n".join(['Aric Hagberg (hagberg@lanl.gov)', - 'Franck Kalala (franckkalala@yahoo.fr']) -__all__ = ['subgraph_centrality_exp', - 'subgraph_centrality', - 'communicability_betweenness_centrality', - 'estrada_index' - ] - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def subgraph_centrality_exp(G): - r"""Returns the subgraph centrality for each node of G. - - Subgraph centrality of a node `n` is the sum of weighted closed - walks of all lengths starting and ending at node `n`. The weights - decrease with path length. Each closed walk is associated with a - connected subgraph ([1]_). - - Parameters - ---------- - G: graph - - Returns - ------- - nodes:dictionary - Dictionary of nodes with subgraph centrality as the value. - - Raises - ------ - NetworkXError - If the graph is not undirected and simple. - - See Also - -------- - subgraph_centrality: - Alternative algorithm of the subgraph centrality for each node of G. - - Notes - ----- - This version of the algorithm exponentiates the adjacency matrix. - - The subgraph centrality of a node `u` in G can be found using - the matrix exponential of the adjacency matrix of G [1]_, - - .. math:: - - SC(u)=(e^A)_{uu} . - - References - ---------- - .. [1] Ernesto Estrada, Juan A. Rodriguez-Velazquez, - "Subgraph centrality in complex networks", - Physical Review E 71, 056103 (2005). - https://arxiv.org/abs/cond-mat/0504730 - - Examples - -------- - (Example from [1]_) - >>> G = nx.Graph([(1,2),(1,5),(1,8),(2,3),(2,8),(3,4),(3,6),(4,5),(4,7),(5,6),(6,7),(7,8)]) - >>> sc = nx.subgraph_centrality_exp(G) - >>> print(['%s %0.2f'%(node,sc[node]) for node in sorted(sc)]) - ['1 3.90', '2 3.90', '3 3.64', '4 3.71', '5 3.64', '6 3.71', '7 3.64', '8 3.90'] - """ - # alternative implementation that calculates the matrix exponential - import scipy.linalg - nodelist = list(G) # ordering of nodes in matrix - A = nx.to_numpy_array(G, nodelist) - # convert to 0-1 matrix - A[A != 0.0] = 1 - expA = scipy.linalg.expm(A) - # convert diagonal to dictionary keyed by node - sc = dict(zip(nodelist, map(float, expA.diagonal()))) - return sc - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def subgraph_centrality(G): - r"""Returns subgraph centrality for each node in G. - - Subgraph centrality of a node `n` is the sum of weighted closed - walks of all lengths starting and ending at node `n`. The weights - decrease with path length. Each closed walk is associated with a - connected subgraph ([1]_). - - Parameters - ---------- - G: graph - - Returns - ------- - nodes : dictionary - Dictionary of nodes with subgraph centrality as the value. - - Raises - ------ - NetworkXError - If the graph is not undirected and simple. - - See Also - -------- - subgraph_centrality_exp: - Alternative algorithm of the subgraph centrality for each node of G. - - Notes - ----- - This version of the algorithm computes eigenvalues and eigenvectors - of the adjacency matrix. - - Subgraph centrality of a node `u` in G can be found using - a spectral decomposition of the adjacency matrix [1]_, - - .. math:: - - SC(u)=\sum_{j=1}^{N}(v_{j}^{u})^2 e^{\lambda_{j}}, - - where `v_j` is an eigenvector of the adjacency matrix `A` of G - corresponding corresponding to the eigenvalue `\lambda_j`. - - Examples - -------- - (Example from [1]_) - >>> G = nx.Graph([(1,2),(1,5),(1,8),(2,3),(2,8),(3,4),(3,6),(4,5),(4,7),(5,6),(6,7),(7,8)]) - >>> sc = nx.subgraph_centrality(G) - >>> print(['%s %0.2f'%(node,sc[node]) for node in sorted(sc)]) - ['1 3.90', '2 3.90', '3 3.64', '4 3.71', '5 3.64', '6 3.71', '7 3.64', '8 3.90'] - - References - ---------- - .. [1] Ernesto Estrada, Juan A. Rodriguez-Velazquez, - "Subgraph centrality in complex networks", - Physical Review E 71, 056103 (2005). - https://arxiv.org/abs/cond-mat/0504730 - - """ - import numpy - import numpy.linalg - nodelist = list(G) # ordering of nodes in matrix - A = nx.to_numpy_matrix(G, nodelist) - # convert to 0-1 matrix - A[A != 0.0] = 1 - w, v = numpy.linalg.eigh(A.A) - vsquare = numpy.array(v)**2 - expw = numpy.exp(w) - xg = numpy.dot(vsquare, expw) - # convert vector dictionary keyed by node - sc = dict(zip(nodelist, map(float, xg))) - return sc - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def communicability_betweenness_centrality(G, normalized=True): - r"""Returns subgraph communicability for all pairs of nodes in G. - - Communicability betweenness measure makes use of the number of walks - connecting every pair of nodes as the basis of a betweenness centrality - measure. - - Parameters - ---------- - G: graph - - Returns - ------- - nodes : dictionary - Dictionary of nodes with communicability betweenness as the value. - - Raises - ------ - NetworkXError - If the graph is not undirected and simple. - - Notes - ----- - Let `G=(V,E)` be a simple undirected graph with `n` nodes and `m` edges, - and `A` denote the adjacency matrix of `G`. - - Let `G(r)=(V,E(r))` be the graph resulting from - removing all edges connected to node `r` but not the node itself. - - The adjacency matrix for `G(r)` is `A+E(r)`, where `E(r)` has nonzeros - only in row and column `r`. - - The subraph betweenness of a node `r` is [1]_ - - .. math:: - - \omega_{r} = \frac{1}{C}\sum_{p}\sum_{q}\frac{G_{prq}}{G_{pq}}, - p\neq q, q\neq r, - - where - `G_{prq}=(e^{A}_{pq} - (e^{A+E(r)})_{pq}` is the number of walks - involving node r, - `G_{pq}=(e^{A})_{pq}` is the number of closed walks starting - at node `p` and ending at node `q`, - and `C=(n-1)^{2}-(n-1)` is a normalization factor equal to the - number of terms in the sum. - - The resulting `\omega_{r}` takes values between zero and one. - The lower bound cannot be attained for a connected - graph, and the upper bound is attained in the star graph. - - References - ---------- - .. [1] Ernesto Estrada, Desmond J. Higham, Naomichi Hatano, - "Communicability Betweenness in Complex Networks" - Physica A 388 (2009) 764-774. - https://arxiv.org/abs/0905.4102 - - Examples - -------- - >>> G = nx.Graph([(0,1),(1,2),(1,5),(5,4),(2,4),(2,3),(4,3),(3,6)]) - >>> cbc = nx.communicability_betweenness_centrality(G) - """ - import scipy - import scipy.linalg - nodelist = list(G) # ordering of nodes in matrix - n = len(nodelist) - A = nx.to_numpy_matrix(G, nodelist) - # convert to 0-1 matrix - A[A != 0.0] = 1 - expA = scipy.linalg.expm(A.A) - mapping = dict(zip(nodelist, range(n))) - cbc = {} - for v in G: - # remove row and col of node v - i = mapping[v] - row = A[i, :].copy() - col = A[:, i].copy() - A[i, :] = 0 - A[:, i] = 0 - B = (expA - scipy.linalg.expm(A.A)) / expA - # sum with row/col of node v and diag set to zero - B[i, :] = 0 - B[:, i] = 0 - B -= scipy.diag(scipy.diag(B)) - cbc[v] = float(B.sum()) - # put row and col back - A[i, :] = row - A[:, i] = col - # rescaling - cbc = _rescale(cbc, normalized=normalized) - return cbc - - -def _rescale(cbc, normalized): - # helper to rescale betweenness centrality - if normalized is True: - order = len(cbc) - if order <= 2: - scale = None - else: - scale = 1.0 / ((order - 1.0)**2 - (order - 1.0)) - if scale is not None: - for v in cbc: - cbc[v] *= scale - return cbc - - -def estrada_index(G): - r"""Returns the Estrada index of a the graph G. - - The Estrada Index is a topological index of folding or 3D "compactness" ([1]_). - - Parameters - ---------- - G: graph - - Returns - ------- - estrada index: float - - Raises - ------ - NetworkXError - If the graph is not undirected and simple. - - Notes - ----- - Let `G=(V,E)` be a simple undirected graph with `n` nodes and let - `\lambda_{1}\leq\lambda_{2}\leq\cdots\lambda_{n}` - be a non-increasing ordering of the eigenvalues of its adjacency - matrix `A`. The Estrada index is ([1]_, [2]_) - - .. math:: - EE(G)=\sum_{j=1}^n e^{\lambda _j}. - - References - ---------- - .. [1] E. Estrada, "Characterization of 3D molecular structure", - Chem. Phys. Lett. 319, 713 (2000). - https://doi.org/10.1016/S0009-2614(00)00158-5 - .. [2] José Antonio de la Peñaa, Ivan Gutman, Juan Rada, - "Estimating the Estrada index", - Linear Algebra and its Applications. 427, 1 (2007). - https://doi.org/10.1016/j.laa.2007.06.020 - - Examples - -------- - >>> G=nx.Graph([(0,1),(1,2),(1,5),(5,4),(2,4),(2,3),(4,3),(3,6)]) - >>> ei=nx.estrada_index(G) - """ - return sum(subgraph_centrality(G).values()) - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_betweenness_centrality.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_betweenness_centrality.py deleted file mode 100644 index 59396a57..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_betweenness_centrality.py +++ /dev/null @@ -1,658 +0,0 @@ -#!/usr/bin/env python -import networkx as nx -from networkx.testing import almost_equal - -def weighted_G(): - G = nx.Graph() - G.add_edge(0, 1, weight=3) - G.add_edge(0, 2, weight=2) - G.add_edge(0, 3, weight=6) - G.add_edge(0, 4, weight=4) - G.add_edge(1, 3, weight=5) - G.add_edge(1, 5, weight=5) - G.add_edge(2, 4, weight=1) - G.add_edge(3, 4, weight=2) - G.add_edge(3, 5, weight=1) - G.add_edge(4, 5, weight=4) - return G - - -class TestBetweennessCentrality(object): - def test_K5(self): - """Betweenness centrality: K5""" - G = nx.complete_graph(5) - b = nx.betweenness_centrality(G, - weight=None, - normalized=False) - b_answer = {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_K5_endpoints(self): - """Betweenness centrality: K5 endpoints""" - G = nx.complete_graph(5) - b = nx.betweenness_centrality(G, - weight=None, - normalized=False, - endpoints=True) - b_answer = {0: 4.0, 1: 4.0, 2: 4.0, 3: 4.0, 4: 4.0} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - # normalized = True case - b = nx.betweenness_centrality(G, - weight=None, - normalized=True, - endpoints=True) - b_answer = {0: 0.4, 1: 0.4, 2: 0.4, 3: 0.4, 4: 0.4} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_P3_normalized(self): - """Betweenness centrality: P3 normalized""" - G = nx.path_graph(3) - b = nx.betweenness_centrality(G, - weight=None, - normalized=True) - b_answer = {0: 0.0, 1: 1.0, 2: 0.0} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_P3(self): - """Betweenness centrality: P3""" - G = nx.path_graph(3) - b_answer = {0: 0.0, 1: 1.0, 2: 0.0} - b = nx.betweenness_centrality(G, - weight=None, - normalized=False) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_sample_from_P3(self): - G= nx.path_graph(3) - b_answer = {0: 0.0, 1: 1.0, 2: 0.0} - b = nx.betweenness_centrality(G, - k=3, - weight=None, - normalized=False, - seed=1) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - b = nx.betweenness_centrality(G, - k=2, - weight=None, - normalized=False, - seed=1) - # python versions give different results with same seed - b_approx1 = {0: 0.0, 1: 1.5, 2: 0.0} - b_approx2 = {0: 0.0, 1: 0.75, 2: 0.0} - for n in sorted(G): - assert b[n] in (b_approx1[n], b_approx2[n]) - - def test_P3_endpoints(self): - """Betweenness centrality: P3 endpoints""" - G = nx.path_graph(3) - b_answer = {0: 2.0, 1: 3.0, 2: 2.0} - b = nx.betweenness_centrality(G, - weight=None, - normalized=False, - endpoints=True) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - # normalized = True case - b_answer = {0: 2/3, 1: 1.0, 2: 2/3} - b = nx.betweenness_centrality(G, - weight=None, - normalized=True, - endpoints=True) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_krackhardt_kite_graph(self): - """Betweenness centrality: Krackhardt kite graph""" - G = nx.krackhardt_kite_graph() - b_answer = {0: 1.667, 1: 1.667, 2: 0.000, 3: 7.333, 4: 0.000, - 5: 16.667, 6: 16.667, 7: 28.000, 8: 16.000, 9: 0.000} - for b in b_answer: - b_answer[b] /= 2 - b = nx.betweenness_centrality(G, - weight=None, - normalized=False) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=3) - - def test_krackhardt_kite_graph_normalized(self): - """Betweenness centrality: Krackhardt kite graph normalized""" - G = nx.krackhardt_kite_graph() - b_answer = {0: 0.023, 1: 0.023, 2: 0.000, 3: 0.102, 4: 0.000, - 5: 0.231, 6: 0.231, 7: 0.389, 8: 0.222, 9: 0.000} - b = nx.betweenness_centrality(G, - weight=None, - normalized=True) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=3) - - def test_florentine_families_graph(self): - """Betweenness centrality: Florentine families graph""" - G = nx.florentine_families_graph() - b_answer =\ - {'Acciaiuoli': 0.000, - 'Albizzi': 0.212, - 'Barbadori': 0.093, - 'Bischeri': 0.104, - 'Castellani': 0.055, - 'Ginori': 0.000, - 'Guadagni': 0.255, - 'Lamberteschi': 0.000, - 'Medici': 0.522, - 'Pazzi': 0.000, - 'Peruzzi': 0.022, - 'Ridolfi': 0.114, - 'Salviati': 0.143, - 'Strozzi': 0.103, - 'Tornabuoni': 0.092} - - b = nx.betweenness_centrality(G, - weight=None, - normalized=True) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=3) - - def test_les_miserables_graph(self): - """Betweenness centrality: Les Miserables graph""" - G = nx.les_miserables_graph() - b_answer = \ - {'Napoleon': 0.000, - 'Myriel': 0.177, - 'MlleBaptistine': 0.000, - 'MmeMagloire': 0.000, - 'CountessDeLo': 0.000, - 'Geborand': 0.000, - 'Champtercier': 0.000, - 'Cravatte': 0.000, - 'Count': 0.000, - 'OldMan': 0.000, - 'Valjean': 0.570, - 'Labarre': 0.000, - 'Marguerite': 0.000, - 'MmeDeR': 0.000, - 'Isabeau': 0.000, - 'Gervais': 0.000, - 'Listolier': 0.000, - 'Tholomyes': 0.041, - 'Fameuil': 0.000, - 'Blacheville': 0.000, - 'Favourite': 0.000, - 'Dahlia': 0.000, - 'Zephine': 0.000, - 'Fantine': 0.130, - 'MmeThenardier': 0.029, - 'Thenardier': 0.075, - 'Cosette': 0.024, - 'Javert': 0.054, - 'Fauchelevent': 0.026, - 'Bamatabois': 0.008, - 'Perpetue': 0.000, - 'Simplice': 0.009, - 'Scaufflaire': 0.000, - 'Woman1': 0.000, - 'Judge': 0.000, - 'Champmathieu': 0.000, - 'Brevet': 0.000, - 'Chenildieu': 0.000, - 'Cochepaille': 0.000, - 'Pontmercy': 0.007, - 'Boulatruelle': 0.000, - 'Eponine': 0.011, - 'Anzelma': 0.000, - 'Woman2': 0.000, - 'MotherInnocent': 0.000, - 'Gribier': 0.000, - 'MmeBurgon': 0.026, - 'Jondrette': 0.000, - 'Gavroche': 0.165, - 'Gillenormand': 0.020, - 'Magnon': 0.000, - 'MlleGillenormand': 0.048, - 'MmePontmercy': 0.000, - 'MlleVaubois': 0.000, - 'LtGillenormand': 0.000, - 'Marius': 0.132, - 'BaronessT': 0.000, - 'Mabeuf': 0.028, - 'Enjolras': 0.043, - 'Combeferre': 0.001, - 'Prouvaire': 0.000, - 'Feuilly': 0.001, - 'Courfeyrac': 0.005, - 'Bahorel': 0.002, - 'Bossuet': 0.031, - 'Joly': 0.002, - 'Grantaire': 0.000, - 'MotherPlutarch': 0.000, - 'Gueulemer': 0.005, - 'Babet': 0.005, - 'Claquesous': 0.005, - 'Montparnasse': 0.004, - 'Toussaint': 0.000, - 'Child1': 0.000, - 'Child2': 0.000, - 'Brujon': 0.000, - 'MmeHucheloup': 0.000} - - b = nx.betweenness_centrality(G, - weight=None, - normalized=True) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=3) - - def test_ladder_graph(self): - """Betweenness centrality: Ladder graph""" - G = nx.Graph() # ladder_graph(3) - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3), - (2, 4), (4, 5), (3, 5)]) - b_answer = {0: 1.667, 1: 1.667, 2: 6.667, - 3: 6.667, 4: 1.667, 5: 1.667} - for b in b_answer: - b_answer[b] /= 2 - b = nx.betweenness_centrality(G, - weight=None, - normalized=False) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=3) - - def test_disconnected_path(self): - """Betweenness centrality: disconnected path""" - G = nx.Graph() - nx.add_path(G, [0, 1, 2]) - nx.add_path(G, [3, 4, 5, 6]) - b_answer = {0: 0, 1: 1, 2: 0, 3: 0, 4: 2, 5: 2, 6: 0} - b = nx.betweenness_centrality(G, - weight=None, - normalized=False) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_disconnected_path_endpoints(self): - """Betweenness centrality: disconnected path endpoints""" - G = nx.Graph() - nx.add_path(G, [0, 1, 2]) - nx.add_path(G, [3, 4, 5, 6]) - b_answer = {0: 2, 1: 3, 2: 2, 3: 3, 4: 5, 5: 5, 6: 3} - b = nx.betweenness_centrality(G, - weight=None, - normalized=False, - endpoints=True) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - # normalized = True case - b = nx.betweenness_centrality(G, - weight=None, - normalized=True, - endpoints=True) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n] / 21) - - def test_directed_path(self): - """Betweenness centrality: directed path""" - G = nx.DiGraph() - nx.add_path(G, [0, 1, 2]) - b = nx.betweenness_centrality(G, - weight=None, - normalized=False) - b_answer = {0: 0.0, 1: 1.0, 2: 0.0} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_directed_path_normalized(self): - """Betweenness centrality: directed path normalized""" - G = nx.DiGraph() - nx.add_path(G, [0, 1, 2]) - b = nx.betweenness_centrality(G, - weight=None, - normalized=True) - b_answer = {0: 0.0, 1: 0.5, 2: 0.0} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - -class TestWeightedBetweennessCentrality(object): - def test_K5(self): - """Weighted betweenness centrality: K5""" - G = nx.complete_graph(5) - b = nx.betweenness_centrality(G, - weight='weight', - normalized=False) - b_answer = {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_P3_normalized(self): - """Weighted betweenness centrality: P3 normalized""" - G = nx.path_graph(3) - b = nx.betweenness_centrality(G, - weight='weight', - normalized=True) - b_answer = {0: 0.0, 1: 1.0, 2: 0.0} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_P3(self): - """Weighted betweenness centrality: P3""" - G = nx.path_graph(3) - b_answer = {0: 0.0, 1: 1.0, 2: 0.0} - b = nx.betweenness_centrality(G, - weight='weight', - normalized=False) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_krackhardt_kite_graph(self): - """Weighted betweenness centrality: Krackhardt kite graph""" - G = nx.krackhardt_kite_graph() - b_answer = {0: 1.667, 1: 1.667, 2: 0.000, 3: 7.333, 4: 0.000, - 5: 16.667, 6: 16.667, 7: 28.000, 8: 16.000, 9: 0.000} - for b in b_answer: - b_answer[b] /= 2 - - b = nx.betweenness_centrality(G, - weight='weight', - normalized=False) - - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=3) - - def test_krackhardt_kite_graph_normalized(self): - """Weighted betweenness centrality: - Krackhardt kite graph normalized - """ - G = nx.krackhardt_kite_graph() - b_answer = {0: 0.023, 1: 0.023, 2: 0.000, 3: 0.102, 4: 0.000, - 5: 0.231, 6: 0.231, 7: 0.389, 8: 0.222, 9: 0.000} - b = nx.betweenness_centrality(G, - weight='weight', - normalized=True) - - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=3) - - def test_florentine_families_graph(self): - """Weighted betweenness centrality: - Florentine families graph""" - G = nx.florentine_families_graph() - b_answer = \ - {'Acciaiuoli': 0.000, - 'Albizzi': 0.212, - 'Barbadori': 0.093, - 'Bischeri': 0.104, - 'Castellani': 0.055, - 'Ginori': 0.000, - 'Guadagni': 0.255, - 'Lamberteschi': 0.000, - 'Medici': 0.522, - 'Pazzi': 0.000, - 'Peruzzi': 0.022, - 'Ridolfi': 0.114, - 'Salviati': 0.143, - 'Strozzi': 0.103, - 'Tornabuoni': 0.092} - - b = nx.betweenness_centrality(G, - weight='weight', - normalized=True) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=3) - - def test_les_miserables_graph(self): - """Weighted betweenness centrality: Les Miserables graph""" - G = nx.les_miserables_graph() - b_answer = \ - {'Napoleon': 0.000, - 'Myriel': 0.177, - 'MlleBaptistine': 0.000, - 'MmeMagloire': 0.000, - 'CountessDeLo': 0.000, - 'Geborand': 0.000, - 'Champtercier': 0.000, - 'Cravatte': 0.000, - 'Count': 0.000, - 'OldMan': 0.000, - 'Valjean': 0.454, - 'Labarre': 0.000, - 'Marguerite': 0.009, - 'MmeDeR': 0.000, - 'Isabeau': 0.000, - 'Gervais': 0.000, - 'Listolier': 0.000, - 'Tholomyes': 0.066, - 'Fameuil': 0.000, - 'Blacheville': 0.000, - 'Favourite': 0.000, - 'Dahlia': 0.000, - 'Zephine': 0.000, - 'Fantine': 0.114, - 'MmeThenardier': 0.046, - 'Thenardier': 0.129, - 'Cosette': 0.075, - 'Javert': 0.193, - 'Fauchelevent': 0.026, - 'Bamatabois': 0.080, - 'Perpetue': 0.000, - 'Simplice': 0.001, - 'Scaufflaire': 0.000, - 'Woman1': 0.000, - 'Judge': 0.000, - 'Champmathieu': 0.000, - 'Brevet': 0.000, - 'Chenildieu': 0.000, - 'Cochepaille': 0.000, - 'Pontmercy': 0.023, - 'Boulatruelle': 0.000, - 'Eponine': 0.023, - 'Anzelma': 0.000, - 'Woman2': 0.000, - 'MotherInnocent': 0.000, - 'Gribier': 0.000, - 'MmeBurgon': 0.026, - 'Jondrette': 0.000, - 'Gavroche': 0.285, - 'Gillenormand': 0.024, - 'Magnon': 0.005, - 'MlleGillenormand': 0.036, - 'MmePontmercy': 0.005, - 'MlleVaubois': 0.000, - 'LtGillenormand': 0.015, - 'Marius': 0.072, - 'BaronessT': 0.004, - 'Mabeuf': 0.089, - 'Enjolras': 0.003, - 'Combeferre': 0.000, - 'Prouvaire': 0.000, - 'Feuilly': 0.004, - 'Courfeyrac': 0.001, - 'Bahorel': 0.007, - 'Bossuet': 0.028, - 'Joly': 0.000, - 'Grantaire': 0.036, - 'MotherPlutarch': 0.000, - 'Gueulemer': 0.025, - 'Babet': 0.015, - 'Claquesous': 0.042, - 'Montparnasse': 0.050, - 'Toussaint': 0.011, - 'Child1': 0.000, - 'Child2': 0.000, - 'Brujon': 0.002, - 'MmeHucheloup': 0.034} - - b = nx.betweenness_centrality(G, - weight='weight', - normalized=True) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=3) - - def test_ladder_graph(self): - """Weighted betweenness centrality: Ladder graph""" - G = nx.Graph() # ladder_graph(3) - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3), - (2, 4), (4, 5), (3, 5)]) - b_answer = {0: 1.667, 1: 1.667, 2: 6.667, - 3: 6.667, 4: 1.667, 5: 1.667} - for b in b_answer: - b_answer[b] /= 2 - b = nx.betweenness_centrality(G, - weight='weight', - normalized=False) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=3) - - def test_G(self): - """Weighted betweenness centrality: G""" - G = weighted_G() - b_answer = {0: 2.0, 1: 0.0, 2: 4.0, 3: 3.0, 4: 4.0, 5: 0.0} - b = nx.betweenness_centrality(G, - weight='weight', - normalized=False) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_G2(self): - """Weighted betweenness centrality: G2""" - G = nx.DiGraph() - G.add_weighted_edges_from([('s', 'u', 10), ('s', 'x', 5), - ('u', 'v', 1), ('u', 'x', 2), - ('v', 'y', 1), ('x', 'u', 3), - ('x', 'v', 5), ('x', 'y', 2), - ('y', 's', 7), ('y', 'v', 6)]) - - b_answer = {'y': 5.0, 'x': 5.0, 's': 4.0, 'u': 2.0, 'v': 2.0} - - b = nx.betweenness_centrality(G, - weight='weight', - normalized=False) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - -class TestEdgeBetweennessCentrality(object): - def test_K5(self): - """Edge betweenness centrality: K5""" - G = nx.complete_graph(5) - b = nx.edge_betweenness_centrality(G, weight=None, normalized=False) - b_answer = dict.fromkeys(G.edges(), 1) - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n]) - - def test_normalized_K5(self): - """Edge betweenness centrality: K5""" - G = nx.complete_graph(5) - b = nx.edge_betweenness_centrality(G, weight=None, normalized=True) - b_answer = dict.fromkeys(G.edges(), 1 / 10) - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n]) - - def test_C4(self): - """Edge betweenness centrality: C4""" - G = nx.cycle_graph(4) - b = nx.edge_betweenness_centrality(G, weight=None, normalized=True) - b_answer = {(0, 1): 2, (0, 3): 2, (1, 2): 2, (2, 3): 2} - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n] / 6) - - def test_P4(self): - """Edge betweenness centrality: P4""" - G = nx.path_graph(4) - b = nx.edge_betweenness_centrality(G, weight=None, normalized=False) - b_answer = {(0, 1): 3, (1, 2): 4, (2, 3): 3} - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n]) - - def test_normalized_P4(self): - """Edge betweenness centrality: P4""" - G = nx.path_graph(4) - b = nx.edge_betweenness_centrality(G, weight=None, normalized=True) - b_answer = {(0, 1): 3, (1, 2): 4, (2, 3): 3} - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n] / 6) - - def test_balanced_tree(self): - """Edge betweenness centrality: balanced tree""" - G = nx.balanced_tree(r=2, h=2) - b = nx.edge_betweenness_centrality(G, weight=None, normalized=False) - b_answer = {(0, 1): 12, (0, 2): 12, - (1, 3): 6, (1, 4): 6, (2, 5): 6, (2, 6): 6} - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n]) - - -class TestWeightedEdgeBetweennessCentrality(object): - def test_K5(self): - """Edge betweenness centrality: K5""" - G = nx.complete_graph(5) - b = nx.edge_betweenness_centrality(G, weight='weight', normalized=False) - b_answer = dict.fromkeys(G.edges(), 1) - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n]) - - def test_C4(self): - """Edge betweenness centrality: C4""" - G = nx.cycle_graph(4) - b = nx.edge_betweenness_centrality(G, weight='weight', normalized=False) - b_answer = {(0, 1): 2, (0, 3): 2, (1, 2): 2, (2, 3): 2} - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n]) - - def test_P4(self): - """Edge betweenness centrality: P4""" - G = nx.path_graph(4) - b = nx.edge_betweenness_centrality(G, weight='weight', normalized=False) - b_answer = {(0, 1): 3, (1, 2): 4, (2, 3): 3} - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n]) - - def test_balanced_tree(self): - """Edge betweenness centrality: balanced tree""" - G = nx.balanced_tree(r=2, h=2) - b = nx.edge_betweenness_centrality(G, weight='weight', normalized=False) - b_answer = {(0, 1): 12, (0, 2): 12, - (1, 3): 6, (1, 4): 6, (2, 5): 6, (2, 6): 6} - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n]) - - def test_weighted_graph(self): - eList = [(0, 1, 5), (0, 2, 4), (0, 3, 3), - (0, 4, 2), (1, 2, 4), (1, 3, 1), - (1, 4, 3), (2, 4, 5), (3, 4, 4)] - G = nx.Graph() - G.add_weighted_edges_from(eList) - b = nx.edge_betweenness_centrality(G, weight='weight', normalized=False) - b_answer = {(0, 1): 0.0, - (0, 2): 1.0, - (0, 3): 2.0, - (0, 4): 1.0, - (1, 2): 2.0, - (1, 3): 3.5, - (1, 4): 1.5, - (2, 4): 1.0, - (3, 4): 0.5} - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n]) - - def test_normalized_weighted_graph(self): - eList = [(0, 1, 5), (0, 2, 4), (0, 3, 3), - (0, 4, 2), (1, 2, 4), (1, 3, 1), - (1, 4, 3), (2, 4, 5), (3, 4, 4)] - G = nx.Graph() - G.add_weighted_edges_from(eList) - b = nx.edge_betweenness_centrality(G, weight='weight', normalized=True) - b_answer = {(0, 1): 0.0, - (0, 2): 1.0, - (0, 3): 2.0, - (0, 4): 1.0, - (1, 2): 2.0, - (1, 3): 3.5, - (1, 4): 1.5, - (2, 4): 1.0, - (3, 4): 0.5} - norm = len(G) * (len(G) - 1) / 2 - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n] / norm) diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_betweenness_centrality_subset.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_betweenness_centrality_subset.py deleted file mode 100644 index c67130b1..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_betweenness_centrality_subset.py +++ /dev/null @@ -1,224 +0,0 @@ -#!/usr/bin/env python -import networkx as nx -from networkx.testing import almost_equal - -class TestSubsetBetweennessCentrality: - - def test_K5(self): - """Betweenness Centrality Subset: K5""" - G = nx.complete_graph(5) - b = nx.betweenness_centrality_subset(G, sources=[0], targets=[1, 3], - weight=None) - b_answer = {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_P5_directed(self): - """Betweenness Centrality Subset: P5 directed""" - G = nx.DiGraph() - nx.add_path(G, range(5)) - b_answer = {0: 0, 1: 1, 2: 1, 3: 0, 4: 0, 5: 0} - b = nx.betweenness_centrality_subset(G, sources=[0], targets=[3], - weight=None) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_P5(self): - """Betweenness Centrality Subset: P5""" - G = nx.Graph() - nx.add_path(G, range(5)) - b_answer = {0: 0, 1: 0.5, 2: 0.5, 3: 0, 4: 0, 5: 0} - b = nx.betweenness_centrality_subset(G, sources=[0], targets=[3], - weight=None) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_P5_multiple_target(self): - """Betweenness Centrality Subset: P5 multiple target""" - G = nx.Graph() - nx.add_path(G, range(5)) - b_answer = {0: 0, 1: 1, 2: 1, 3: 0.5, 4: 0, 5: 0} - b = nx.betweenness_centrality_subset(G, sources=[0], targets=[3, 4], - weight=None) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_box(self): - """Betweenness Centrality Subset: box""" - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - b_answer = {0: 0, 1: 0.25, 2: 0.25, 3: 0} - b = nx.betweenness_centrality_subset(G, sources=[0], targets=[3], - weight=None) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_box_and_path(self): - """Betweenness Centrality Subset: box and path""" - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3), (3, 4), (4, 5)]) - b_answer = {0: 0, 1: 0.5, 2: 0.5, 3: 0.5, 4: 0, 5: 0} - b = nx.betweenness_centrality_subset(G, sources=[0], targets=[3, 4], - weight=None) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_box_and_path2(self): - """Betweenness Centrality Subset: box and path multiple target""" - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (1, 20), (20, 3), (3, 4)]) - b_answer = {0: 0, 1: 1.0, 2: 0.5, 20: 0.5, 3: 0.5, 4: 0} - b = nx.betweenness_centrality_subset(G, sources=[0], targets=[3, 4], - weight=None) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_diamond_multi_path(self): - """Betweenness Centrality Subset: Diamond Multi Path""" - G = nx.Graph() - G.add_edges_from([ - (1,2), - (1,3), - (1,4), - (1,5), - (1,10), - (10,11), - (11,12), - (12,9), - (2,6), - (3,6), - (4,6), - (5,7), - (7,8), - (6,8), - (8,9) - ]) - b = nx.betweenness_centrality_subset( - G, - sources=[1], - targets=[9], - weight=None - ) - - expected_b = { - 1: 0, - 2: 1./10, - 3: 1./10, - 4: 1./10, - 5: 1./10, - 6: 3./10, - 7:1./10, - 8:4./10, - 9:0, - 10:1./10, - 11:1./10, - 12:1./10, - } - - for n in sorted(G): - assert almost_equal(b[n], expected_b[n]) - - -class TestBetweennessCentralitySources: - - def test_K5(self): - """Betweenness Centrality Sources: K5""" - G = nx.complete_graph(5) - b = nx.betweenness_centrality_source(G, weight=None, normalized=False) - b_answer = {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_P3(self): - """Betweenness Centrality Sources: P3""" - G = nx.path_graph(3) - b_answer = {0: 0.0, 1: 1.0, 2: 0.0} - b = nx.betweenness_centrality_source(G, weight=None, normalized=True) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - -class TestEdgeSubsetBetweennessCentrality: - - def test_K5(self): - """Edge betweenness subset centrality: K5""" - G = nx.complete_graph(5) - b = nx.edge_betweenness_centrality_subset(G, sources=[0], - targets=[1, 3], weight=None) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(0, 3)] = b_answer[(0, 1)] = 0.5 - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n]) - - def test_P5_directed(self): - """Edge betweenness subset centrality: P5 directed""" - G = nx.DiGraph() - nx.add_path(G, range(5)) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(0, 1)] = b_answer[(1, 2)] = b_answer[(2, 3)] = 1 - b = nx.edge_betweenness_centrality_subset(G, sources=[0], targets=[3], - weight=None) - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n]) - - def test_P5(self): - """Edge betweenness subset centrality: P5""" - G = nx.Graph() - nx.add_path(G, range(5)) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(0, 1)] = b_answer[(1, 2)] = b_answer[(2, 3)] = 0.5 - b = nx.edge_betweenness_centrality_subset(G, sources=[0], targets=[3], - weight=None) - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n]) - - def test_P5_multiple_target(self): - """Edge betweenness subset centrality: P5 multiple target""" - G = nx.Graph() - nx.add_path(G, range(5)) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(0, 1)] = b_answer[(1, 2)] = b_answer[(2, 3)] = 1 - b_answer[(3, 4)] = 0.5 - b = nx.edge_betweenness_centrality_subset(G, sources=[0], - targets=[3, 4], weight=None) - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n]) - - def test_box(self): - """Edge betweenness subset centrality: box""" - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(0, 1)] = b_answer[(0, 2)] = 0.25 - b_answer[(1, 3)] = b_answer[(2, 3)] = 0.25 - b = nx.edge_betweenness_centrality_subset(G, sources=[0], targets=[3], - weight=None) - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n]) - - def test_box_and_path(self): - """Edge betweenness subset centrality: box and path""" - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3), (3, 4), (4, 5)]) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(0, 1)] = b_answer[(0, 2)] = 0.5 - b_answer[(1, 3)] = b_answer[(2, 3)] = 0.5 - b_answer[(3, 4)] = 0.5 - b = nx.edge_betweenness_centrality_subset(G, sources=[0], - targets=[3, 4], weight=None) - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n]) - - def test_box_and_path2(self): - """Edge betweenness subset centrality: box and path multiple target""" - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (1, 20), (20, 3), (3, 4)]) - b_answer = dict.fromkeys(G.edges(), 0) - b_answer[(0, 1)] = 1.0 - b_answer[(1, 20)] = b_answer[(3, 20)] = 0.5 - b_answer[(1, 2)] = b_answer[(2, 3)] = 0.5 - b_answer[(3, 4)] = 0.5 - b = nx.edge_betweenness_centrality_subset(G, sources=[0], - targets=[3, 4], weight=None) - for n in sorted(G.edges()): - assert almost_equal(b[n], b_answer[n]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_closeness_centrality.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_closeness_centrality.py deleted file mode 100644 index 6ab4e15d..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_closeness_centrality.py +++ /dev/null @@ -1,306 +0,0 @@ -""" -Tests for closeness centrality. -""" -import pytest -import networkx as nx -from networkx.testing import almost_equal - -class TestClosenessCentrality: - @classmethod - def setup_class(cls): - cls.K = nx.krackhardt_kite_graph() - cls.P3 = nx.path_graph(3) - cls.P4 = nx.path_graph(4) - cls.K5 = nx.complete_graph(5) - - cls.C4 = nx.cycle_graph(4) - cls.T = nx.balanced_tree(r=2, h=2) - cls.Gb = nx.Graph() - cls.Gb.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3), - (2, 4), (4, 5), (3, 5)]) - - F = nx.florentine_families_graph() - cls.F = F - - cls.LM = nx.les_miserables_graph() - - # Create random undirected, unweighted graph for testing incremental version - cls.undirected_G = nx.fast_gnp_random_graph(n=100, p=0.6, seed=123) - cls.undirected_G_cc = nx.closeness_centrality(cls.undirected_G) - - def test_wf_improved(self): - G = nx.union(self.P4, nx.path_graph([4, 5, 6])) - c = nx.closeness_centrality(G) - cwf = nx.closeness_centrality(G, wf_improved=False) - res = {0: 0.25, 1: 0.375, 2: 0.375, 3: 0.25, - 4: 0.222, 5: 0.333, 6: 0.222} - wf_res = {0: 0.5, 1: 0.75, 2: 0.75, 3: 0.5, - 4: 0.667, 5: 1.0, 6: 0.667} - for n in G: - assert almost_equal(c[n], res[n], places=3) - assert almost_equal(cwf[n], wf_res[n], places=3) - - def test_digraph(self): - G = nx.path_graph(3, create_using=nx.DiGraph()) - c = nx.closeness_centrality(G) - cr = nx.closeness_centrality(G.reverse()) - d = {0: 0.0, 1: 0.500, 2: 0.667} - dr = {0: 0.667, 1: 0.500, 2: 0.0} - for n in sorted(self.P3): - assert almost_equal(c[n], d[n], places=3) - assert almost_equal(cr[n], dr[n], places=3) - - def test_k5_closeness(self): - c = nx.closeness_centrality(self.K5) - d = {0: 1.000, - 1: 1.000, - 2: 1.000, - 3: 1.000, - 4: 1.000} - for n in sorted(self.K5): - assert almost_equal(c[n], d[n], places=3) - - def test_p3_closeness(self): - c = nx.closeness_centrality(self.P3) - d = {0: 0.667, - 1: 1.000, - 2: 0.667} - for n in sorted(self.P3): - assert almost_equal(c[n], d[n], places=3) - - def test_krackhardt_closeness(self): - c = nx.closeness_centrality(self.K) - d = {0: 0.529, - 1: 0.529, - 2: 0.500, - 3: 0.600, - 4: 0.500, - 5: 0.643, - 6: 0.643, - 7: 0.600, - 8: 0.429, - 9: 0.310} - for n in sorted(self.K): - assert almost_equal(c[n], d[n], places=3) - - def test_florentine_families_closeness(self): - c = nx.closeness_centrality(self.F) - d = {'Acciaiuoli': 0.368, - 'Albizzi': 0.483, - 'Barbadori': 0.4375, - 'Bischeri': 0.400, - 'Castellani': 0.389, - 'Ginori': 0.333, - 'Guadagni': 0.467, - 'Lamberteschi': 0.326, - 'Medici': 0.560, - 'Pazzi': 0.286, - 'Peruzzi': 0.368, - 'Ridolfi': 0.500, - 'Salviati': 0.389, - 'Strozzi': 0.4375, - 'Tornabuoni': 0.483} - for n in sorted(self.F): - assert almost_equal(c[n], d[n], places=3) - - def test_les_miserables_closeness(self): - c = nx.closeness_centrality(self.LM) - d = {'Napoleon': 0.302, - 'Myriel': 0.429, - 'MlleBaptistine': 0.413, - 'MmeMagloire': 0.413, - 'CountessDeLo': 0.302, - 'Geborand': 0.302, - 'Champtercier': 0.302, - 'Cravatte': 0.302, - 'Count': 0.302, - 'OldMan': 0.302, - 'Valjean': 0.644, - 'Labarre': 0.394, - 'Marguerite': 0.413, - 'MmeDeR': 0.394, - 'Isabeau': 0.394, - 'Gervais': 0.394, - 'Listolier': 0.341, - 'Tholomyes': 0.392, - 'Fameuil': 0.341, - 'Blacheville': 0.341, - 'Favourite': 0.341, - 'Dahlia': 0.341, - 'Zephine': 0.341, - 'Fantine': 0.461, - 'MmeThenardier': 0.461, - 'Thenardier': 0.517, - 'Cosette': 0.478, - 'Javert': 0.517, - 'Fauchelevent': 0.402, - 'Bamatabois': 0.427, - 'Perpetue': 0.318, - 'Simplice': 0.418, - 'Scaufflaire': 0.394, - 'Woman1': 0.396, - 'Judge': 0.404, - 'Champmathieu': 0.404, - 'Brevet': 0.404, - 'Chenildieu': 0.404, - 'Cochepaille': 0.404, - 'Pontmercy': 0.373, - 'Boulatruelle': 0.342, - 'Eponine': 0.396, - 'Anzelma': 0.352, - 'Woman2': 0.402, - 'MotherInnocent': 0.398, - 'Gribier': 0.288, - 'MmeBurgon': 0.344, - 'Jondrette': 0.257, - 'Gavroche': 0.514, - 'Gillenormand': 0.442, - 'Magnon': 0.335, - 'MlleGillenormand': 0.442, - 'MmePontmercy': 0.315, - 'MlleVaubois': 0.308, - 'LtGillenormand': 0.365, - 'Marius': 0.531, - 'BaronessT': 0.352, - 'Mabeuf': 0.396, - 'Enjolras': 0.481, - 'Combeferre': 0.392, - 'Prouvaire': 0.357, - 'Feuilly': 0.392, - 'Courfeyrac': 0.400, - 'Bahorel': 0.394, - 'Bossuet': 0.475, - 'Joly': 0.394, - 'Grantaire': 0.358, - 'MotherPlutarch': 0.285, - 'Gueulemer': 0.463, - 'Babet': 0.463, - 'Claquesous': 0.452, - 'Montparnasse': 0.458, - 'Toussaint': 0.402, - 'Child1': 0.342, - 'Child2': 0.342, - 'Brujon': 0.380, - 'MmeHucheloup': 0.353} - for n in sorted(self.LM): - assert almost_equal(c[n], d[n], places=3) - - def test_weighted_closeness(self): - edges = ([('s', 'u', 10), ('s', 'x', 5), ('u', 'v', 1), - ('u', 'x', 2), ('v', 'y', 1), ('x', 'u', 3), - ('x', 'v', 5), ('x', 'y', 2), ('y', 's', 7), ('y', 'v', 6)]) - XG = nx.Graph() - XG.add_weighted_edges_from(edges) - c = nx.closeness_centrality(XG, distance='weight') - d = {'y': 0.200, - 'x': 0.286, - 's': 0.138, - 'u': 0.235, - 'v': 0.200} - for n in sorted(XG): - assert almost_equal(c[n], d[n], places=3) - - - # - # Tests for incremental closeness centrality. - # - @staticmethod - def pick_add_edge(g): - u = nx.utils.arbitrary_element(g) - possible_nodes = set(g.nodes()) - neighbors = list(g.neighbors(u)) + [u] - possible_nodes.difference_update(neighbors) - v = nx.utils.arbitrary_element(possible_nodes) - return (u, v) - - @staticmethod - def pick_remove_edge(g): - u = nx.utils.arbitrary_element(g) - possible_nodes = list(g.neighbors(u)) - v = nx.utils.arbitrary_element(possible_nodes) - return (u, v) - - def test_directed_raises(self): - with pytest.raises(nx.NetworkXNotImplemented): - dir_G = nx.gn_graph(n=5) - prev_cc = None - edge = self.pick_add_edge(dir_G) - insert = True - nx.incremental_closeness_centrality(dir_G, edge, prev_cc, insert) - - def test_wrong_size_prev_cc_raises(self): - with pytest.raises(nx.NetworkXError): - G = self.undirected_G.copy() - edge = self.pick_add_edge(G) - insert = True - prev_cc = self.undirected_G_cc.copy() - prev_cc.pop(0) - nx.incremental_closeness_centrality(G, edge, prev_cc, insert) - - def test_wrong_nodes_prev_cc_raises(self): - with pytest.raises(nx.NetworkXError): - G = self.undirected_G.copy() - edge = self.pick_add_edge(G) - insert = True - prev_cc = self.undirected_G_cc.copy() - num_nodes = len(prev_cc) - prev_cc.pop(0) - prev_cc[num_nodes] = 0.5 - nx.incremental_closeness_centrality(G, edge, prev_cc, insert) - - def test_zero_centrality(self): - G = nx.path_graph(3) - prev_cc = nx.closeness_centrality(G) - edge = self.pick_remove_edge(G) - test_cc = nx.incremental_closeness_centrality( - G, edge, prev_cc, insertion=False) - G.remove_edges_from([edge]) - real_cc = nx.closeness_centrality(G) - shared_items = set(test_cc.items()) & set(real_cc.items()) - assert len(shared_items) == len(real_cc) - assert 0 in test_cc.values() - - def test_incremental(self): - # Check that incremental and regular give same output - G = self.undirected_G.copy() - prev_cc = None - for i in range(5): - if i % 2 == 0: - # Remove an edge - insert = False - edge = self.pick_remove_edge(G) - else: - # Add an edge - insert = True - edge = self.pick_add_edge(G) - - # start = timeit.default_timer() - test_cc = nx.incremental_closeness_centrality( - G, edge, prev_cc, insert) - # inc_elapsed = (timeit.default_timer() - start) - # print("incremental time: {}".format(inc_elapsed)) - - if insert: - G.add_edges_from([edge]) - else: - G.remove_edges_from([edge]) - - # start = timeit.default_timer() - real_cc = nx.closeness_centrality(G) - # reg_elapsed = (timeit.default_timer() - start) - # print("regular time: {}".format(reg_elapsed)) - # Example output: - # incremental time: 0.208 - # regular time: 0.276 - # incremental time: 0.00683 - # regular time: 0.260 - # incremental time: 0.0224 - # regular time: 0.278 - # incremental time: 0.00804 - # regular time: 0.208 - # incremental time: 0.00947 - # regular time: 0.188 - - assert set(test_cc.items()) == set(real_cc.items()) - - prev_cc = test_cc diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality.py deleted file mode 100644 index 46112d68..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality.py +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env python -import pytest - -import networkx as nx -from networkx.testing import almost_equal -from networkx import edge_current_flow_betweenness_centrality \ - as edge_current_flow -from networkx import approximate_current_flow_betweenness_centrality \ - as approximate_cfbc - - -np = pytest.importorskip('numpy') -npt = pytest.importorskip('numpy.testing') -scipy = pytest.importorskip('scipy') - - -class TestFlowBetweennessCentrality(object): - def test_K4_normalized(self): - """Betweenness centrality: K4""" - G = nx.complete_graph(4) - b = nx.current_flow_betweenness_centrality(G, normalized=True) - b_answer = {0: 0.25, 1: 0.25, 2: 0.25, 3: 0.25} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - G.add_edge(0, 1, weight=0.5, other=0.3) - b = nx.current_flow_betweenness_centrality(G, normalized=True, weight=None) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - wb_answer = {0: 0.2222222, 1: 0.2222222, 2: 0.30555555, 3: 0.30555555} - b = nx.current_flow_betweenness_centrality(G, normalized=True, weight='weight') - for n in sorted(G): - assert almost_equal(b[n], wb_answer[n]) - wb_answer = {0: 0.2051282, 1: 0.2051282, 2: 0.33974358, 3: 0.33974358} - b = nx.current_flow_betweenness_centrality(G, normalized=True, weight='other') - for n in sorted(G): - assert almost_equal(b[n], wb_answer[n]) - - def test_K4(self): - """Betweenness centrality: K4""" - G = nx.complete_graph(4) - for solver in ['full', 'lu', 'cg']: - b = nx.current_flow_betweenness_centrality(G, normalized=False, - solver=solver) - b_answer = {0: 0.75, 1: 0.75, 2: 0.75, 3: 0.75} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_P4_normalized(self): - """Betweenness centrality: P4 normalized""" - G = nx.path_graph(4) - b = nx.current_flow_betweenness_centrality(G, normalized=True) - b_answer = {0: 0, 1: 2. / 3, 2: 2. / 3, 3: 0} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_P4(self): - """Betweenness centrality: P4""" - G = nx.path_graph(4) - b = nx.current_flow_betweenness_centrality(G, normalized=False) - b_answer = {0: 0, 1: 2, 2: 2, 3: 0} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_star(self): - """Betweenness centrality: star """ - G = nx.Graph() - nx.add_star(G, ['a', 'b', 'c', 'd']) - b = nx.current_flow_betweenness_centrality(G, normalized=True) - b_answer = {'a': 1.0, 'b': 0.0, 'c': 0.0, 'd': 0.0} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_solvers2(self): - """Betweenness centrality: alternate solvers""" - G = nx.complete_graph(4) - for solver in ['full', 'lu', 'cg']: - b = nx.current_flow_betweenness_centrality(G, normalized=False, - solver=solver) - b_answer = {0: 0.75, 1: 0.75, 2: 0.75, 3: 0.75} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - -class TestApproximateFlowBetweennessCentrality(object): - - def test_K4_normalized(self): - "Approximate current-flow betweenness centrality: K4 normalized" - G = nx.complete_graph(4) - b = nx.current_flow_betweenness_centrality(G, normalized=True) - epsilon = 0.1 - ba = approximate_cfbc(G, normalized=True, epsilon=0.5 * epsilon) - for n in sorted(G): - npt.assert_allclose(b[n], ba[n], atol=epsilon) - - def test_K4(self): - "Approximate current-flow betweenness centrality: K4" - G = nx.complete_graph(4) - b = nx.current_flow_betweenness_centrality(G, normalized=False) - epsilon = 0.1 - ba = approximate_cfbc(G, normalized=False, epsilon=0.5 * epsilon) - for n in sorted(G): - npt.assert_allclose(b[n], ba[n], atol=epsilon * len(G)**2) - - def test_star(self): - "Approximate current-flow betweenness centrality: star" - G = nx.Graph() - nx.add_star(G, ['a', 'b', 'c', 'd']) - b = nx.current_flow_betweenness_centrality(G, normalized=True) - epsilon = 0.1 - ba = approximate_cfbc(G, normalized=True, epsilon=0.5 * epsilon) - for n in sorted(G): - npt.assert_allclose(b[n], ba[n], atol=epsilon) - - def test_grid(self): - "Approximate current-flow betweenness centrality: 2d grid" - G = nx.grid_2d_graph(4, 4) - b = nx.current_flow_betweenness_centrality(G, normalized=True) - epsilon = 0.1 - ba = approximate_cfbc(G, normalized=True, epsilon=0.5 * epsilon) - for n in sorted(G): - npt.assert_allclose(b[n], ba[n], atol=epsilon) - - def test_seed(self): - G = nx.complete_graph(4) - b = approximate_cfbc(G, normalized=False, epsilon=0.05, seed=1) - b_answer = {0: 0.75, 1: 0.75, 2: 0.75, 3: 0.75} - for n in sorted(G): - npt.assert_allclose(b[n], b_answer[n], atol=0.1) - - def test_solvers(self): - "Approximate current-flow betweenness centrality: solvers" - G = nx.complete_graph(4) - epsilon = 0.1 - for solver in ['full', 'lu', 'cg']: - b = approximate_cfbc(G, normalized=False, solver=solver, - epsilon=0.5 * epsilon) - b_answer = {0: 0.75, 1: 0.75, 2: 0.75, 3: 0.75} - for n in sorted(G): - npt.assert_allclose(b[n], b_answer[n], atol=epsilon) - - -class TestWeightedFlowBetweennessCentrality(object): - pass - - -class TestEdgeFlowBetweennessCentrality(object): - - def test_K4(self): - """Edge flow betweenness centrality: K4""" - G = nx.complete_graph(4) - b = edge_current_flow(G, normalized=True) - b_answer = dict.fromkeys(G.edges(), 0.25) - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert almost_equal(v1, v2) - - def test_K4_normalized(self): - """Edge flow betweenness centrality: K4""" - G = nx.complete_graph(4) - b = edge_current_flow(G, normalized=False) - b_answer = dict.fromkeys(G.edges(), 0.75) - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert almost_equal(v1, v2) - - def test_C4(self): - """Edge flow betweenness centrality: C4""" - G = nx.cycle_graph(4) - b = edge_current_flow(G, normalized=False) - b_answer = {(0, 1): 1.25, (0, 3): 1.25, (1, 2): 1.25, (2, 3): 1.25} - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert almost_equal(v1, v2) - - def test_P4(self): - """Edge betweenness centrality: P4""" - G = nx.path_graph(4) - b = edge_current_flow(G, normalized=False) - b_answer = {(0, 1): 1.5, (1, 2): 2.0, (2, 3): 1.5} - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert almost_equal(v1, v2) diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality_subset.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality_subset.py deleted file mode 100644 index ac448d07..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality_subset.py +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/env python -import pytest -np = pytest.importorskip('numpy') -scipy = pytest.importorskip('scipy') - -import networkx as nx -from networkx.testing import almost_equal - -from networkx import edge_current_flow_betweenness_centrality \ - as edge_current_flow - -from networkx import edge_current_flow_betweenness_centrality_subset \ - as edge_current_flow_subset - - -class TestFlowBetweennessCentrality(object): - - def test_K4_normalized(self): - """Betweenness centrality: K4""" - G = nx.complete_graph(4) - b = nx.current_flow_betweenness_centrality_subset(G, - list(G), - list(G), - normalized=True) - b_answer = nx.current_flow_betweenness_centrality(G, normalized=True) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_K4(self): - """Betweenness centrality: K4""" - G = nx.complete_graph(4) - b = nx.current_flow_betweenness_centrality_subset(G, - list(G), - list(G), - normalized=True) - b_answer = nx.current_flow_betweenness_centrality(G, normalized=True) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - # test weighted network - G.add_edge(0, 1, weight=0.5, other=0.3) - b = nx.current_flow_betweenness_centrality_subset(G, - list(G), - list(G), - normalized=True, - weight=None) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - b = nx.current_flow_betweenness_centrality_subset(G, - list(G), - list(G), - normalized=True) - b_answer = nx.current_flow_betweenness_centrality(G, normalized=True) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - b = nx.current_flow_betweenness_centrality_subset(G, - list(G), - list(G), - normalized=True, - weight='other') - b_answer = nx.current_flow_betweenness_centrality(G, normalized=True, weight='other') - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_P4_normalized(self): - """Betweenness centrality: P4 normalized""" - G = nx.path_graph(4) - b = nx.current_flow_betweenness_centrality_subset(G, - list(G), - list(G), - normalized=True) - b_answer = nx.current_flow_betweenness_centrality(G, normalized=True) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_P4(self): - """Betweenness centrality: P4""" - G = nx.path_graph(4) - b = nx.current_flow_betweenness_centrality_subset(G, - list(G), - list(G), - normalized=True) - b_answer = nx.current_flow_betweenness_centrality(G, normalized=True) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_star(self): - """Betweenness centrality: star """ - G = nx.Graph() - nx.add_star(G, ['a', 'b', 'c', 'd']) - b = nx.current_flow_betweenness_centrality_subset(G, - list(G), - list(G), - normalized=True) - b_answer = nx.current_flow_betweenness_centrality(G, normalized=True) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - -# class TestWeightedFlowBetweennessCentrality(): -# pass - - -class TestEdgeFlowBetweennessCentrality(object): - - def test_K4_normalized(self): - """Betweenness centrality: K4""" - G = nx.complete_graph(4) - b = edge_current_flow_subset(G, list(G), list(G), normalized=True) - b_answer = edge_current_flow(G, normalized=True) - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert almost_equal(v1, v2) - - def test_K4(self): - """Betweenness centrality: K4""" - G = nx.complete_graph(4) - b = edge_current_flow_subset(G, list(G), list(G), normalized=False) - b_answer = edge_current_flow(G, normalized=False) - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert almost_equal(v1, v2) - # test weighted network - G.add_edge(0, 1, weight=0.5, other=0.3) - b = edge_current_flow_subset(G, list(G), list(G), normalized=False, weight=None) - # weight is None => same as unweighted network - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert almost_equal(v1, v2) - - b = edge_current_flow_subset(G, list(G), list(G), normalized=False) - b_answer = edge_current_flow(G, normalized=False) - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert almost_equal(v1, v2) - - b = edge_current_flow_subset(G, list(G), list(G), normalized=False, weight='other') - b_answer = edge_current_flow(G, normalized=False, weight='other') - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert almost_equal(v1, v2) - - def test_C4(self): - """Edge betweenness centrality: C4""" - G = nx.cycle_graph(4) - b = edge_current_flow_subset(G, list(G), list(G), normalized=True) - b_answer = edge_current_flow(G, normalized=True) - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert almost_equal(v1, v2) - - def test_P4(self): - """Edge betweenness centrality: P4""" - G = nx.path_graph(4) - b = edge_current_flow_subset(G, list(G), list(G), normalized=True) - b_answer = edge_current_flow(G, normalized=True) - for (s, t), v1 in b_answer.items(): - v2 = b.get((s, t), b.get((t, s))) - assert almost_equal(v1, v2) diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_current_flow_closeness.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_current_flow_closeness.py deleted file mode 100644 index e3ab72e7..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_current_flow_closeness.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python -import pytest -np = pytest.importorskip('numpy') -scipy = pytest.importorskip('scipy') - -import networkx as nx -from networkx.testing import almost_equal - -class TestFlowClosenessCentrality(object): - - def test_K4(self): - """Closeness centrality: K4""" - G = nx.complete_graph(4) - b = nx.current_flow_closeness_centrality(G) - b_answer = {0: 2.0 / 3, 1: 2.0 / 3, 2: 2.0 / 3, 3: 2.0 / 3} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_P4(self): - """Closeness centrality: P4""" - G = nx.path_graph(4) - b = nx.current_flow_closeness_centrality(G) - b_answer = {0: 1.0 / 6, 1: 1.0 / 4, 2: 1.0 / 4, 3: 1.0 / 6} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_star(self): - """Closeness centrality: star """ - G = nx.Graph() - nx.add_star(G, ['a', 'b', 'c', 'd']) - b = nx.current_flow_closeness_centrality(G) - b_answer = {'a': 1.0 / 3, 'b': 0.6 / 3, 'c': 0.6 / 3, 'd': 0.6 / 3} - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - -class TestWeightedFlowClosenessCentrality(object): - pass diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_degree_centrality.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_degree_centrality.py deleted file mode 100644 index c5aef07f..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_degree_centrality.py +++ /dev/null @@ -1,101 +0,0 @@ -""" - Unit tests for degree centrality. -""" - - -import networkx as nx -from networkx.testing import almost_equal - -class TestDegreeCentrality: - def setup_method(self): - - self.K = nx.krackhardt_kite_graph() - self.P3 = nx.path_graph(3) - self.K5 = nx.complete_graph(5) - - F = nx.Graph() # Florentine families - F.add_edge('Acciaiuoli', 'Medici') - F.add_edge('Castellani', 'Peruzzi') - F.add_edge('Castellani', 'Strozzi') - F.add_edge('Castellani', 'Barbadori') - F.add_edge('Medici', 'Barbadori') - F.add_edge('Medici', 'Ridolfi') - F.add_edge('Medici', 'Tornabuoni') - F.add_edge('Medici', 'Albizzi') - F.add_edge('Medici', 'Salviati') - F.add_edge('Salviati', 'Pazzi') - F.add_edge('Peruzzi', 'Strozzi') - F.add_edge('Peruzzi', 'Bischeri') - F.add_edge('Strozzi', 'Ridolfi') - F.add_edge('Strozzi', 'Bischeri') - F.add_edge('Ridolfi', 'Tornabuoni') - F.add_edge('Tornabuoni', 'Guadagni') - F.add_edge('Albizzi', 'Ginori') - F.add_edge('Albizzi', 'Guadagni') - F.add_edge('Bischeri', 'Guadagni') - F.add_edge('Guadagni', 'Lamberteschi') - self.F = F - - G = nx.DiGraph() - G.add_edge(0, 5) - G.add_edge(1, 5) - G.add_edge(2, 5) - G.add_edge(3, 5) - G.add_edge(4, 5) - G.add_edge(5, 6) - G.add_edge(5, 7) - G.add_edge(5, 8) - self.G = G - - def test_degree_centrality_1(self): - d = nx.degree_centrality(self.K5) - exact = dict(zip(range(5), [1] * 5)) - for n, dc in d.items(): - assert almost_equal(exact[n], dc) - - def test_degree_centrality_2(self): - d = nx.degree_centrality(self.P3) - exact = {0: 0.5, 1: 1, 2: 0.5} - for n, dc in d.items(): - assert almost_equal(exact[n], dc) - - def test_degree_centrality_3(self): - d = nx.degree_centrality(self.K) - exact = {0: .444, 1: .444, 2: .333, 3: .667, 4: .333, - 5: .556, 6: .556, 7: .333, 8: .222, 9: .111} - for n, dc in d.items(): - assert almost_equal(exact[n], float("%5.3f" % dc)) - - def test_degree_centrality_4(self): - d = nx.degree_centrality(self.F) - names = sorted(self.F.nodes()) - dcs = [0.071, 0.214, 0.143, 0.214, 0.214, 0.071, 0.286, - 0.071, 0.429, 0.071, 0.214, 0.214, 0.143, 0.286, 0.214] - exact = dict(zip(names, dcs)) - for n, dc in d.items(): - assert almost_equal(exact[n], float("%5.3f" % dc)) - - def test_indegree_centrality(self): - d = nx.in_degree_centrality(self.G) - exact = {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0, - 5: 0.625, 6: 0.125, 7: 0.125, 8: 0.125} - for n, dc in d.items(): - assert almost_equal(exact[n], dc) - - def test_outdegree_centrality(self): - d = nx.out_degree_centrality(self.G) - exact = {0: 0.125, 1: 0.125, 2: 0.125, 3: 0.125, - 4: 0.125, 5: 0.375, 6: 0.0, 7: 0.0, 8: 0.0} - for n, dc in d.items(): - assert almost_equal(exact[n], dc) - - def test_small_graph_centrality(self): - G = nx.empty_graph(create_using=nx.DiGraph) - assert {} == nx.degree_centrality(G) - assert {} == nx.out_degree_centrality(G) - assert {} == nx.in_degree_centrality(G) - - G = nx.empty_graph(1, create_using=nx.DiGraph) - assert {0: 1} == nx.degree_centrality(G) - assert {0: 1} == nx.out_degree_centrality(G) - assert {0: 1} == nx.in_degree_centrality(G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_dispersion.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_dispersion.py deleted file mode 100644 index 865548f9..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_dispersion.py +++ /dev/null @@ -1,42 +0,0 @@ -import networkx as nx - - -def small_ego_G(): - """The sample network from https://arxiv.org/pdf/1310.6753v1.pdf""" - edges = [('a', 'b'), ('a', 'c'), ('b', 'c'), ('b', 'd'), - ('b', 'e'), ('b', 'f'), ('c', 'd'), ('c', 'f'), ('c', 'h'), ('d', 'f'), ('e', 'f'), - ('f', 'h'), ('h', 'j'), ('h', 'k'), ('i', 'j'), ('i', 'k'), ('j', 'k'), ('u', 'a'), - ('u', 'b'), ('u', 'c'), ('u', 'd'), ('u', 'e'), ('u', 'f'), ('u', 'g'), ('u', 'h'), - ('u', 'i'), ('u', 'j'), ('u', 'k')] - G = nx.Graph() - G.add_edges_from(edges) - - return G - - -class TestDispersion(object): - - def test_article(self): - """our algorithm matches article's""" - G = small_ego_G() - disp_uh = nx.dispersion(G, 'u', 'h', normalized=False) - disp_ub = nx.dispersion(G, 'u', 'b', normalized=False) - assert disp_uh == 4 - assert disp_ub == 1 - - def test_results_length(self): - """there is a result for every node""" - G = small_ego_G() - disp = nx.dispersion(G) - disp_Gu = nx.dispersion(G, 'u') - disp_uv = nx.dispersion(G, 'u', 'h') - assert len(disp) == len(G) - assert len(disp_Gu) == len(G) - 1 - assert type(disp_uv) is float - - def test_impossible_things(self): - G = nx.karate_club_graph() - disp = nx.dispersion(G) - for u in disp: - for v in disp[u]: - assert disp[u][v] >= 0 diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_eigenvector_centrality.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_eigenvector_centrality.py deleted file mode 100644 index 33e68146..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_eigenvector_centrality.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env python -import math -import pytest -np = pytest.importorskip('numpy') -scipy = pytest.importorskip('scipy') - - -import networkx as nx -from networkx.testing import almost_equal - -class TestEigenvectorCentrality(object): - - def test_K5(self): - """Eigenvector centrality: K5""" - G = nx.complete_graph(5) - b = nx.eigenvector_centrality(G) - v = math.sqrt(1 / 5.0) - b_answer = dict.fromkeys(G, v) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - nstart = dict([(n, 1) for n in G]) - b = nx.eigenvector_centrality(G, nstart=nstart) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - b = nx.eigenvector_centrality_numpy(G) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=3) - - def test_P3(self): - """Eigenvector centrality: P3""" - G = nx.path_graph(3) - b_answer = {0: 0.5, 1: 0.7071, 2: 0.5} - b = nx.eigenvector_centrality_numpy(G) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=4) - b = nx.eigenvector_centrality(G) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=4) - - def test_P3_unweighted(self): - """Eigenvector centrality: P3""" - G = nx.path_graph(3) - b_answer = {0: 0.5, 1: 0.7071, 2: 0.5} - b = nx.eigenvector_centrality_numpy(G, weight=None) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=4) - - def test_maxiter(self): - with pytest.raises(nx.PowerIterationFailedConvergence): - G = nx.path_graph(3) - b = nx.eigenvector_centrality(G, max_iter=0) - - -class TestEigenvectorCentralityDirected(object): - - @classmethod - def setup_class(cls): - G = nx.DiGraph() - - edges = [(1, 2), (1, 3), (2, 4), (3, 2), (3, 5), (4, 2), (4, 5), (4, 6), - (5, 6), (5, 7), (5, 8), (6, 8), (7, 1), (7, 5), - (7, 8), (8, 6), (8, 7)] - - G.add_edges_from(edges, weight=2.0) - cls.G = G.reverse() - cls.G.evc = [0.25368793, 0.19576478, 0.32817092, 0.40430835, - 0.48199885, 0.15724483, 0.51346196, 0.32475403] - - H = nx.DiGraph() - - edges = [(1, 2), (1, 3), (2, 4), (3, 2), (3, 5), (4, 2), (4, 5), (4, 6), - (5, 6), (5, 7), (5, 8), (6, 8), (7, 1), (7, 5), - (7, 8), (8, 6), (8, 7)] - - G.add_edges_from(edges) - cls.H = G.reverse() - cls.H.evc = [0.25368793, 0.19576478, 0.32817092, 0.40430835, - 0.48199885, 0.15724483, 0.51346196, 0.32475403] - - def test_eigenvector_centrality_weighted(self): - G = self.G - p = nx.eigenvector_centrality(G) - for (a, b) in zip(list(p.values()), self.G.evc): - assert almost_equal(a, b, places=4) - - def test_eigenvector_centrality_weighted_numpy(self): - G = self.G - p = nx.eigenvector_centrality_numpy(G) - for (a, b) in zip(list(p.values()), self.G.evc): - assert almost_equal(a, b) - - def test_eigenvector_centrality_unweighted(self): - G = self.H - p = nx.eigenvector_centrality(G) - for (a, b) in zip(list(p.values()), self.G.evc): - assert almost_equal(a, b, places=4) - - def test_eigenvector_centrality_unweighted_numpy(self): - G = self.H - p = nx.eigenvector_centrality_numpy(G) - for (a, b) in zip(list(p.values()), self.G.evc): - assert almost_equal(a, b) - - -class TestEigenvectorCentralityExceptions(object): - - def test_multigraph(self): - with pytest.raises(nx.NetworkXException): - e = nx.eigenvector_centrality(nx.MultiGraph()) - - def test_multigraph_numpy(self): - with pytest.raises(nx.NetworkXException): - e = nx.eigenvector_centrality_numpy(nx.MultiGraph()) - - def test_empty(self): - with pytest.raises(nx.NetworkXException): - e = nx.eigenvector_centrality(nx.Graph()) - - def test_empty_numpy(self): - with pytest.raises(nx.NetworkXException): - e = nx.eigenvector_centrality_numpy(nx.Graph()) diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_group.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_group.py deleted file mode 100644 index b4a15565..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_group.py +++ /dev/null @@ -1,156 +0,0 @@ -""" - Tests for Group Centrality Measures -""" - - -import pytest -import networkx as nx - - -class TestGroupBetweennessCentrality: - - def test_group_betweenness_single_node(self): - """ - Group betweenness centrality for single node group - """ - G = nx.path_graph(5) - C = [1] - b = nx.group_betweenness_centrality(G, C, - weight=None, normalized=False) - b_answer = 3.0 - assert b == b_answer - - def test_group_betweenness_normalized(self): - """ - Group betweenness centrality for group with more than - 1 node and normalized - """ - G = nx.path_graph(5) - C = [1, 3] - b = nx.group_betweenness_centrality(G, C, - weight=None, normalized=True) - b_answer = 1.0 - assert b == b_answer - - def test_group_betweenness_value_zero(self): - """ - Group betweenness centrality value of 0 - """ - G = nx.cycle_graph(6) - C = [0, 1, 5] - b = nx.group_betweenness_centrality(G, C, weight=None) - b_answer = 0.0 - assert b == b_answer - - def test_group_betweenness_disconnected_graph(self): - """ - Group betweenness centrality in a disconnected graph - """ - G = nx.path_graph(5) - G.remove_edge(0, 1) - C = [1] - b = nx.group_betweenness_centrality(G, C, weight=None) - b_answer = 0.0 - assert b == b_answer - - def test_group_betweenness_node_not_in_graph(self): - """ - Node(s) in C not in graph, raises NodeNotFound exception - """ - with pytest.raises(nx.NodeNotFound): - b = nx.group_betweenness_centrality(nx.path_graph(5), [6, 7, 8]) - - -class TestGroupClosenessCentrality: - - def test_group_closeness_single_node(self): - """ - Group closeness centrality for a single node group - """ - G = nx.path_graph(5) - c = nx.group_closeness_centrality(G, [1]) - c_answer = nx.closeness_centrality(G, 1) - assert c == c_answer - - def test_group_closeness_disconnected(self): - """ - Group closeness centrality for a disconnected graph - """ - G = nx.Graph() - G.add_nodes_from([1, 2, 3, 4]) - c = nx.group_closeness_centrality(G, [1, 2]) - c_answer = 0 - assert c == c_answer - - def test_group_closeness_multiple_node(self): - """ - Group closeness centrality for a group with more than - 1 node - """ - G = nx.path_graph(4) - c = nx.group_closeness_centrality(G, [1, 2]) - c_answer = 1 - assert c == c_answer - - def test_group_closeness_node_not_in_graph(self): - """ - Node(s) in S not in graph, raises NodeNotFound exception - """ - with pytest.raises(nx.NodeNotFound): - c = nx.group_closeness_centrality(nx.path_graph(5), [6, 7, 8]) - - -class TestGroupDegreeCentrality: - - def test_group_degree_centrality_single_node(self): - """ - Group degree centrality for a single node group - """ - G = nx.path_graph(4) - d = nx.group_degree_centrality(G, [1]) - d_answer = nx.degree_centrality(G)[1] - assert d == d_answer - - def test_group_degree_centrality_multiple_node(self): - """ - Group degree centrality for group with more than - 1 node - """ - G = nx.Graph() - G.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8]) - G.add_edges_from([(1, 2), (1, 3), (1, 6), (1, 7), (1, 8), - (2, 3), (2, 4), (2, 5)]) - d = nx.group_degree_centrality(G, [1, 2]) - d_answer = 1 - assert d == d_answer - - def test_group_in_degree_centrality(self): - """ - Group in-degree centrality in a DiGraph - """ - G = nx.DiGraph() - G.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8]) - G.add_edges_from([(1, 2), (1, 3), (1, 6), (1, 7), (1, 8), - (2, 3), (2, 4), (2, 5)]) - d = nx.group_in_degree_centrality(G, [1, 2]) - d_answer = 0 - assert d == d_answer - - def test_group_out_degree_centrality(self): - """ - Group out-degree centrality in a DiGraph - """ - G = nx.DiGraph() - G.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8]) - G.add_edges_from([(1, 2), (1, 3), (1, 6), (1, 7), (1, 8), - (2, 3), (2, 4), (2, 5)]) - d = nx.group_out_degree_centrality(G, [1, 2]) - d_answer = 1 - assert d == d_answer - - def test_group_degree_centrality_node_not_in_graph(self): - """ - Node(s) in S not in graph, raises NetworkXError - """ - with pytest.raises(nx.NetworkXError): - b = nx.group_degree_centrality(nx.path_graph(5), [6, 7, 8]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_harmonic_centrality.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_harmonic_centrality.py deleted file mode 100644 index 3adcfc5c..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_harmonic_centrality.py +++ /dev/null @@ -1,119 +0,0 @@ -""" -Tests for degree centrality. -""" -import networkx as nx -from networkx.algorithms.centrality import harmonic_centrality -from networkx.testing import almost_equal - -class TestClosenessCentrality: - @classmethod - def setup_class(cls): - cls.P3 = nx.path_graph(3) - cls.P4 = nx.path_graph(4) - cls.K5 = nx.complete_graph(5) - - cls.C4 = nx.cycle_graph(4) - cls.C5 = nx.cycle_graph(5) - - cls.T = nx.balanced_tree(r=2, h=2) - - cls.Gb = nx.DiGraph() - cls.Gb.add_edges_from([(0, 1), (0, 2), (0, 4), (2, 1), - (2, 3), (4, 3)]) - - def test_p3_harmonic(self): - c = harmonic_centrality(self.P3) - d = {0: 1.5, - 1: 2, - 2: 1.5} - for n in sorted(self.P3): - assert almost_equal(c[n], d[n], places=3) - - def test_p4_harmonic(self): - c = harmonic_centrality(self.P4) - d = {0: 1.8333333, - 1: 2.5, - 2: 2.5, - 3: 1.8333333} - for n in sorted(self.P4): - assert almost_equal(c[n], d[n], places=3) - - def test_clique_complete(self): - c = harmonic_centrality(self.K5) - d = {0: 4, - 1: 4, - 2: 4, - 3: 4, - 4: 4} - for n in sorted(self.P3): - assert almost_equal(c[n], d[n], places=3) - - def test_cycle_C4(self): - c = harmonic_centrality(self.C4) - d = {0: 2.5, - 1: 2.5, - 2: 2.5, - 3: 2.5, } - for n in sorted(self.C4): - assert almost_equal(c[n], d[n], places=3) - - def test_cycle_C5(self): - c = harmonic_centrality(self.C5) - d = {0: 3, - 1: 3, - 2: 3, - 3: 3, - 4: 3, - 5: 4} - for n in sorted(self.C5): - assert almost_equal(c[n], d[n], places=3) - - def test_bal_tree(self): - c = harmonic_centrality(self.T) - d = {0: 4.0, - 1: 4.1666, - 2: 4.1666, - 3: 2.8333, - 4: 2.8333, - 5: 2.8333, - 6: 2.8333} - for n in sorted(self.T): - assert almost_equal(c[n], d[n], places=3) - - def test_exampleGraph(self): - c = harmonic_centrality(self.Gb) - d = {0: 0, - 1: 2, - 2: 1, - 3: 2.5, - 4: 1} - for n in sorted(self.Gb): - assert almost_equal(c[n], d[n], places=3) - - def test_weighted_harmonic(self): - XG = nx.DiGraph() - XG.add_weighted_edges_from([('a', 'b', 10), ('d', 'c', 5), ('a', 'c', 1), - ('e', 'f', 2), ('f', 'c', 1), ('a', 'f', 3), - ]) - c = harmonic_centrality(XG, distance='weight') - d = {'a': 0, - 'b': 0.1, - 'c': 2.533, - 'd': 0, - 'e': 0, - 'f': 0.83333} - for n in sorted(XG): - assert almost_equal(c[n], d[n], places=3) - - def test_empty(self): - G = nx.DiGraph() - c = harmonic_centrality(G, distance='weight') - d = {} - assert c == d - - def test_singleton(self): - G = nx.DiGraph() - G.add_node(0) - c = harmonic_centrality(G, distance='weight') - d = {0: 0} - assert c == d diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_katz_centrality.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_katz_centrality.py deleted file mode 100644 index 102a0515..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_katz_centrality.py +++ /dev/null @@ -1,310 +0,0 @@ -# -*- coding: utf-8 -*- -import math - -import networkx as nx -from networkx.testing import almost_equal -import pytest - -class TestKatzCentrality(object): - - def test_K5(self): - """Katz centrality: K5""" - G = nx.complete_graph(5) - alpha = 0.1 - b = nx.katz_centrality(G, alpha) - v = math.sqrt(1 / 5.0) - b_answer = dict.fromkeys(G, v) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - nstart = dict([(n, 1) for n in G]) - b = nx.katz_centrality(G, alpha, nstart=nstart) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - - def test_P3(self): - """Katz centrality: P3""" - alpha = 0.1 - G = nx.path_graph(3) - b_answer = {0: 0.5598852584152165, 1: 0.6107839182711449, - 2: 0.5598852584152162} - b = nx.katz_centrality(G, alpha) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=4) - - def test_maxiter(self): - with pytest.raises(nx.PowerIterationFailedConvergence): - alpha = 0.1 - G = nx.path_graph(3) - max_iter = 0 - try: - b = nx.katz_centrality(G, alpha, max_iter=max_iter) - except nx.NetworkXError as e: - assert str(max_iter) in e.args[0], "max_iter value not in error msg" - raise # So that the decorater sees the exception. - - def test_beta_as_scalar(self): - alpha = 0.1 - beta = 0.1 - b_answer = {0: 0.5598852584152165, 1: 0.6107839182711449, - 2: 0.5598852584152162} - G = nx.path_graph(3) - b = nx.katz_centrality(G, alpha, beta) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=4) - - def test_beta_as_dict(self): - alpha = 0.1 - beta = {0: 1.0, 1: 1.0, 2: 1.0} - b_answer = {0: 0.5598852584152165, 1: 0.6107839182711449, - 2: 0.5598852584152162} - G = nx.path_graph(3) - b = nx.katz_centrality(G, alpha, beta) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=4) - - def test_multiple_alpha(self): - alpha_list = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6] - for alpha in alpha_list: - b_answer = {0.1: {0: 0.5598852584152165, 1: 0.6107839182711449, - 2: 0.5598852584152162}, - 0.2: {0: 0.5454545454545454, 1: 0.6363636363636365, - 2: 0.5454545454545454}, - 0.3: {0: 0.5333964609104419, 1: 0.6564879518897746, - 2: 0.5333964609104419}, - 0.4: {0: 0.5232045649263551, 1: 0.6726915834767423, - 2: 0.5232045649263551}, - 0.5: {0: 0.5144957746691622, 1: 0.6859943117075809, - 2: 0.5144957746691622}, - 0.6: {0: 0.5069794004195823, 1: 0.6970966755769258, - 2: 0.5069794004195823}} - G = nx.path_graph(3) - b = nx.katz_centrality(G, alpha) - for n in sorted(G): - assert almost_equal(b[n], b_answer[alpha][n], places=4) - - def test_multigraph(self): - with pytest.raises(nx.NetworkXException): - e = nx.katz_centrality(nx.MultiGraph(), 0.1) - - def test_empty(self): - e = nx.katz_centrality(nx.Graph(), 0.1) - assert e == {} - - def test_bad_beta(self): - with pytest.raises(nx.NetworkXException): - G = nx.Graph([(0, 1)]) - beta = {0: 77} - e = nx.katz_centrality(G, 0.1, beta=beta) - - def test_bad_beta_numbe(self): - with pytest.raises(nx.NetworkXException): - G = nx.Graph([(0, 1)]) - e = nx.katz_centrality(G, 0.1, beta='foo') - - -class TestKatzCentralityNumpy(object): - - @classmethod - def setup_class(cls): - global np - np = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') - - def test_K5(self): - """Katz centrality: K5""" - G = nx.complete_graph(5) - alpha = 0.1 - b = nx.katz_centrality(G, alpha) - v = math.sqrt(1 / 5.0) - b_answer = dict.fromkeys(G, v) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - nstart = dict([(n, 1) for n in G]) - b = nx.eigenvector_centrality_numpy(G) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=3) - - def test_P3(self): - """Katz centrality: P3""" - alpha = 0.1 - G = nx.path_graph(3) - b_answer = {0: 0.5598852584152165, 1: 0.6107839182711449, - 2: 0.5598852584152162} - b = nx.katz_centrality_numpy(G, alpha) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=4) - - def test_beta_as_scalar(self): - alpha = 0.1 - beta = 0.1 - b_answer = {0: 0.5598852584152165, 1: 0.6107839182711449, - 2: 0.5598852584152162} - G = nx.path_graph(3) - b = nx.katz_centrality_numpy(G, alpha, beta) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=4) - - def test_beta_as_dict(self): - alpha = 0.1 - beta = {0: 1.0, 1: 1.0, 2: 1.0} - b_answer = {0: 0.5598852584152165, 1: 0.6107839182711449, - 2: 0.5598852584152162} - G = nx.path_graph(3) - b = nx.katz_centrality_numpy(G, alpha, beta) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=4) - - def test_multiple_alpha(self): - alpha_list = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6] - for alpha in alpha_list: - b_answer = {0.1: {0: 0.5598852584152165, 1: 0.6107839182711449, - 2: 0.5598852584152162}, - 0.2: {0: 0.5454545454545454, 1: 0.6363636363636365, - 2: 0.5454545454545454}, - 0.3: {0: 0.5333964609104419, 1: 0.6564879518897746, - 2: 0.5333964609104419}, - 0.4: {0: 0.5232045649263551, 1: 0.6726915834767423, - 2: 0.5232045649263551}, - 0.5: {0: 0.5144957746691622, 1: 0.6859943117075809, - 2: 0.5144957746691622}, - 0.6: {0: 0.5069794004195823, 1: 0.6970966755769258, - 2: 0.5069794004195823}} - G = nx.path_graph(3) - b = nx.katz_centrality_numpy(G, alpha) - for n in sorted(G): - assert almost_equal(b[n], b_answer[alpha][n], places=4) - - def test_multigraph(self): - with pytest.raises(nx.NetworkXException): - e = nx.katz_centrality(nx.MultiGraph(), 0.1) - - def test_empty(self): - e = nx.katz_centrality(nx.Graph(), 0.1) - assert e == {} - - def test_bad_beta(self): - with pytest.raises(nx.NetworkXException): - G = nx.Graph([(0, 1)]) - beta = {0: 77} - e = nx.katz_centrality_numpy(G, 0.1, beta=beta) - - def test_bad_beta_numbe(self): - with pytest.raises(nx.NetworkXException): - G = nx.Graph([(0, 1)]) - e = nx.katz_centrality_numpy(G, 0.1, beta='foo') - - def test_K5_unweighted(self): - """Katz centrality: K5""" - G = nx.complete_graph(5) - alpha = 0.1 - b = nx.katz_centrality(G, alpha, weight=None) - v = math.sqrt(1 / 5.0) - b_answer = dict.fromkeys(G, v) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n]) - nstart = dict([(n, 1) for n in G]) - b = nx.eigenvector_centrality_numpy(G, weight=None) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=3) - - def test_P3_unweighted(self): - """Katz centrality: P3""" - alpha = 0.1 - G = nx.path_graph(3) - b_answer = {0: 0.5598852584152165, 1: 0.6107839182711449, - 2: 0.5598852584152162} - b = nx.katz_centrality_numpy(G, alpha, weight=None) - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=4) - - -class TestKatzCentralityDirected(object): - @classmethod - def setup_class(cls): - G = nx.DiGraph() - edges = [(1, 2), (1, 3), (2, 4), (3, 2), (3, 5), (4, 2), (4, 5), - (4, 6), (5, 6), (5, 7), (5, 8), (6, 8), (7, 1), (7, 5), - (7, 8), (8, 6), (8, 7)] - G.add_edges_from(edges, weight=2.0) - cls.G = G.reverse() - cls.G.alpha = 0.1 - cls.G.evc = [ - 0.3289589783189635, - 0.2832077296243516, - 0.3425906003685471, - 0.3970420865198392, - 0.41074871061646284, - 0.272257430756461, - 0.4201989685435462, - 0.34229059218038554, - ] - - H = nx.DiGraph(edges) - cls.H = G.reverse() - cls.H.alpha = 0.1 - cls.H.evc = [ - 0.3289589783189635, - 0.2832077296243516, - 0.3425906003685471, - 0.3970420865198392, - 0.41074871061646284, - 0.272257430756461, - 0.4201989685435462, - 0.34229059218038554, - ] - - def test_katz_centrality_weighted(self): - G = self.G - alpha = self.G.alpha - p = nx.katz_centrality(G, alpha, weight='weight') - for (a, b) in zip(list(p.values()), self.G.evc): - assert almost_equal(a, b) - - def test_katz_centrality_unweighted(self): - H = self.H - alpha = self.H.alpha - p = nx.katz_centrality(H, alpha, weight='weight') - for (a, b) in zip(list(p.values()), self.H.evc): - assert almost_equal(a, b) - - -class TestKatzCentralityDirectedNumpy(TestKatzCentralityDirected): - - @classmethod - def setup_class(cls): - global np - np = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') - - def test_katz_centrality_weighted(self): - G = self.G - alpha = self.G.alpha - p = nx.katz_centrality_numpy(G, alpha, weight='weight') - for (a, b) in zip(list(p.values()), self.G.evc): - assert almost_equal(a, b) - - def test_katz_centrality_unweighted(self): - H = self.H - alpha = self.H.alpha - p = nx.katz_centrality_numpy(H, alpha, weight='weight') - for (a, b) in zip(list(p.values()), self.H.evc): - assert almost_equal(a, b) - - -class TestKatzEigenvectorVKatz(object): - - @classmethod - def setup_class(cls): - global np - global eigvals - np = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') - from numpy.linalg import eigvals - - def test_eigenvector_v_katz_random(self): - G = nx.gnp_random_graph(10, 0.5, seed=1234) - l = float(max(eigvals(nx.adjacency_matrix(G).todense()))) - e = nx.eigenvector_centrality_numpy(G) - k = nx.katz_centrality_numpy(G, 1.0 / l) - for n in G: - assert almost_equal(e[n], k[n]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_load_centrality.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_load_centrality.py deleted file mode 100644 index 5d296999..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_load_centrality.py +++ /dev/null @@ -1,351 +0,0 @@ -#!/usr/bin/env python -import networkx as nx -from networkx.testing import almost_equal - -class TestLoadCentrality: - - @classmethod - def setup_class(cls): - - G = nx.Graph() - G.add_edge(0, 1, weight=3) - G.add_edge(0, 2, weight=2) - G.add_edge(0, 3, weight=6) - G.add_edge(0, 4, weight=4) - G.add_edge(1, 3, weight=5) - G.add_edge(1, 5, weight=5) - G.add_edge(2, 4, weight=1) - G.add_edge(3, 4, weight=2) - G.add_edge(3, 5, weight=1) - G.add_edge(4, 5, weight=4) - cls.G = G - cls.exact_weighted = {0: 4.0, 1: 0.0, 2: 8.0, 3: 6.0, 4: 8.0, 5: 0.0} - cls.K = nx.krackhardt_kite_graph() - cls.P3 = nx.path_graph(3) - cls.P4 = nx.path_graph(4) - cls.K5 = nx.complete_graph(5) - - cls.C4 = nx.cycle_graph(4) - cls.T = nx.balanced_tree(r=2, h=2) - cls.Gb = nx.Graph() - cls.Gb.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3), - (2, 4), (4, 5), (3, 5)]) - cls.F = nx.florentine_families_graph() - cls.LM = nx.les_miserables_graph() - cls.D = nx.cycle_graph(3, create_using=nx.DiGraph()) - cls.D.add_edges_from([(3, 0), (4, 3)]) - - def test_not_strongly_connected(self): - b = nx.load_centrality(self.D) - result = {0: 5. / 12, - 1: 1. / 4, - 2: 1. / 12, - 3: 1. / 4, - 4: 0.000} - for n in sorted(self.D): - assert almost_equal(result[n], b[n], places=3) - assert almost_equal(result[n], nx.load_centrality(self.D, n), places=3) - - def test_weighted_load(self): - b = nx.load_centrality(self.G, weight='weight', normalized=False) - for n in sorted(self.G): - assert b[n] == self.exact_weighted[n] - - def test_k5_load(self): - G = self.K5 - c = nx.load_centrality(G) - d = {0: 0.000, - 1: 0.000, - 2: 0.000, - 3: 0.000, - 4: 0.000} - for n in sorted(G): - assert almost_equal(c[n], d[n], places=3) - - def test_p3_load(self): - G = self.P3 - c = nx.load_centrality(G) - d = {0: 0.000, - 1: 1.000, - 2: 0.000} - for n in sorted(G): - assert almost_equal(c[n], d[n], places=3) - c = nx.load_centrality(G, v=1) - assert almost_equal(c, 1.0) - c = nx.load_centrality(G, v=1, normalized=True) - assert almost_equal(c, 1.0) - - def test_p2_load(self): - G = nx.path_graph(2) - c = nx.load_centrality(G) - d = {0: 0.000, - 1: 0.000} - for n in sorted(G): - assert almost_equal(c[n], d[n], places=3) - - def test_krackhardt_load(self): - G = self.K - c = nx.load_centrality(G) - d = {0: 0.023, - 1: 0.023, - 2: 0.000, - 3: 0.102, - 4: 0.000, - 5: 0.231, - 6: 0.231, - 7: 0.389, - 8: 0.222, - 9: 0.000} - for n in sorted(G): - assert almost_equal(c[n], d[n], places=3) - - def test_florentine_families_load(self): - G = self.F - c = nx.load_centrality(G) - d = {'Acciaiuoli': 0.000, - 'Albizzi': 0.211, - 'Barbadori': 0.093, - 'Bischeri': 0.104, - 'Castellani': 0.055, - 'Ginori': 0.000, - 'Guadagni': 0.251, - 'Lamberteschi': 0.000, - 'Medici': 0.522, - 'Pazzi': 0.000, - 'Peruzzi': 0.022, - 'Ridolfi': 0.117, - 'Salviati': 0.143, - 'Strozzi': 0.106, - 'Tornabuoni': 0.090} - for n in sorted(G): - assert almost_equal(c[n], d[n], places=3) - - def test_les_miserables_load(self): - G = self.LM - c = nx.load_centrality(G) - d = {'Napoleon': 0.000, - 'Myriel': 0.177, - 'MlleBaptistine': 0.000, - 'MmeMagloire': 0.000, - 'CountessDeLo': 0.000, - 'Geborand': 0.000, - 'Champtercier': 0.000, - 'Cravatte': 0.000, - 'Count': 0.000, - 'OldMan': 0.000, - 'Valjean': 0.567, - 'Labarre': 0.000, - 'Marguerite': 0.000, - 'MmeDeR': 0.000, - 'Isabeau': 0.000, - 'Gervais': 0.000, - 'Listolier': 0.000, - 'Tholomyes': 0.043, - 'Fameuil': 0.000, - 'Blacheville': 0.000, - 'Favourite': 0.000, - 'Dahlia': 0.000, - 'Zephine': 0.000, - 'Fantine': 0.128, - 'MmeThenardier': 0.029, - 'Thenardier': 0.075, - 'Cosette': 0.024, - 'Javert': 0.054, - 'Fauchelevent': 0.026, - 'Bamatabois': 0.008, - 'Perpetue': 0.000, - 'Simplice': 0.009, - 'Scaufflaire': 0.000, - 'Woman1': 0.000, - 'Judge': 0.000, - 'Champmathieu': 0.000, - 'Brevet': 0.000, - 'Chenildieu': 0.000, - 'Cochepaille': 0.000, - 'Pontmercy': 0.007, - 'Boulatruelle': 0.000, - 'Eponine': 0.012, - 'Anzelma': 0.000, - 'Woman2': 0.000, - 'MotherInnocent': 0.000, - 'Gribier': 0.000, - 'MmeBurgon': 0.026, - 'Jondrette': 0.000, - 'Gavroche': 0.164, - 'Gillenormand': 0.021, - 'Magnon': 0.000, - 'MlleGillenormand': 0.047, - 'MmePontmercy': 0.000, - 'MlleVaubois': 0.000, - 'LtGillenormand': 0.000, - 'Marius': 0.133, - 'BaronessT': 0.000, - 'Mabeuf': 0.028, - 'Enjolras': 0.041, - 'Combeferre': 0.001, - 'Prouvaire': 0.000, - 'Feuilly': 0.001, - 'Courfeyrac': 0.006, - 'Bahorel': 0.002, - 'Bossuet': 0.032, - 'Joly': 0.002, - 'Grantaire': 0.000, - 'MotherPlutarch': 0.000, - 'Gueulemer': 0.005, - 'Babet': 0.005, - 'Claquesous': 0.005, - 'Montparnasse': 0.004, - 'Toussaint': 0.000, - 'Child1': 0.000, - 'Child2': 0.000, - 'Brujon': 0.000, - 'MmeHucheloup': 0.000} - for n in sorted(G): - assert almost_equal(c[n], d[n], places=3) - - def test_unnormalized_k5_load(self): - G = self.K5 - c = nx.load_centrality(G, normalized=False) - d = {0: 0.000, - 1: 0.000, - 2: 0.000, - 3: 0.000, - 4: 0.000} - for n in sorted(G): - assert almost_equal(c[n], d[n], places=3) - - def test_unnormalized_p3_load(self): - G = self.P3 - c = nx.load_centrality(G, normalized=False) - d = {0: 0.000, - 1: 2.000, - 2: 0.000} - for n in sorted(G): - assert almost_equal(c[n], d[n], places=3) - - def test_unnormalized_krackhardt_load(self): - G = self.K - c = nx.load_centrality(G, normalized=False) - d = {0: 1.667, - 1: 1.667, - 2: 0.000, - 3: 7.333, - 4: 0.000, - 5: 16.667, - 6: 16.667, - 7: 28.000, - 8: 16.000, - 9: 0.000} - - for n in sorted(G): - assert almost_equal(c[n], d[n], places=3) - - def test_unnormalized_florentine_families_load(self): - G = self.F - c = nx.load_centrality(G, normalized=False) - - d = {'Acciaiuoli': 0.000, - 'Albizzi': 38.333, - 'Barbadori': 17.000, - 'Bischeri': 19.000, - 'Castellani': 10.000, - 'Ginori': 0.000, - 'Guadagni': 45.667, - 'Lamberteschi': 0.000, - 'Medici': 95.000, - 'Pazzi': 0.000, - 'Peruzzi': 4.000, - 'Ridolfi': 21.333, - 'Salviati': 26.000, - 'Strozzi': 19.333, - 'Tornabuoni': 16.333} - for n in sorted(G): - assert almost_equal(c[n], d[n], places=3) - - def test_load_betweenness_difference(self): - # Difference Between Load and Betweenness - # --------------------------------------- The smallest graph - # that shows the difference between load and betweenness is - # G=ladder_graph(3) (Graph B below) - - # Graph A and B are from Tao Zhou, Jian-Guo Liu, Bing-Hong - # Wang: Comment on "Scientific collaboration - # networks. II. Shortest paths, weighted networks, and - # centrality". https://arxiv.org/pdf/physics/0511084 - - # Notice that unlike here, their calculation adds to 1 to the - # betweennes of every node i for every path from i to every - # other node. This is exactly what it should be, based on - # Eqn. (1) in their paper: the eqn is B(v) = \sum_{s\neq t, - # s\neq v}{\frac{\sigma_{st}(v)}{\sigma_{st}}}, therefore, - # they allow v to be the target node. - - # We follow Brandes 2001, who follows Freeman 1977 that make - # the sum for betweenness of v exclude paths where v is either - # the source or target node. To agree with their numbers, we - # must additionally, remove edge (4,8) from the graph, see AC - # example following (there is a mistake in the figure in their - # paper - personal communication). - - # A = nx.Graph() - # A.add_edges_from([(0,1), (1,2), (1,3), (2,4), - # (3,5), (4,6), (4,7), (4,8), - # (5,8), (6,9), (7,9), (8,9)]) - B = nx.Graph() # ladder_graph(3) - B.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (4, 5), (3, 5)]) - c = nx.load_centrality(B, normalized=False) - d = {0: 1.750, - 1: 1.750, - 2: 6.500, - 3: 6.500, - 4: 1.750, - 5: 1.750} - for n in sorted(B): - assert almost_equal(c[n], d[n], places=3) - - def test_c4_edge_load(self): - G = self.C4 - c = nx.edge_load_centrality(G) - d = {(0, 1): 6.000, - (0, 3): 6.000, - (1, 2): 6.000, - (2, 3): 6.000} - for n in G.edges(): - assert almost_equal(c[n], d[n], places=3) - - def test_p4_edge_load(self): - G = self.P4 - c = nx.edge_load_centrality(G) - d = {(0, 1): 6.000, - (1, 2): 8.000, - (2, 3): 6.000} - for n in G.edges(): - assert almost_equal(c[n], d[n], places=3) - - def test_k5_edge_load(self): - G = self.K5 - c = nx.edge_load_centrality(G) - d = {(0, 1): 5.000, - (0, 2): 5.000, - (0, 3): 5.000, - (0, 4): 5.000, - (1, 2): 5.000, - (1, 3): 5.000, - (1, 4): 5.000, - (2, 3): 5.000, - (2, 4): 5.000, - (3, 4): 5.000} - for n in G.edges(): - assert almost_equal(c[n], d[n], places=3) - - def test_tree_edge_load(self): - G = self.T - c = nx.edge_load_centrality(G) - d = {(0, 1): 24.000, - (0, 2): 24.000, - (1, 3): 12.000, - (1, 4): 12.000, - (2, 5): 12.000, - (2, 6): 12.000} - for n in G.edges(): - assert almost_equal(c[n], d[n], places=3) diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_percolation_centrality.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_percolation_centrality.py deleted file mode 100644 index ea59b66f..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_percolation_centrality.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python -import networkx as nx -from networkx.testing import almost_equal - -def example1a_G(): - G = nx.Graph() - G.add_node(1, percolation=0.1) - G.add_node(2, percolation=0.2) - G.add_node(3, percolation=0.2) - G.add_node(4, percolation=0.2) - G.add_node(5, percolation=0.3) - G.add_node(6, percolation=0.2) - G.add_node(7, percolation=0.5) - G.add_node(8, percolation=0.5) - G.add_edges_from([(1, 4), (2, 4), (3, 4), (4, 5), (5, 6), (6, 7), (6, 8)]) - return G - - -def example1b_G(): - G = nx.Graph() - G.add_node(1, percolation=0.3) - G.add_node(2, percolation=0.5) - G.add_node(3, percolation=0.5) - G.add_node(4, percolation=0.2) - G.add_node(5, percolation=0.3) - G.add_node(6, percolation=0.2) - G.add_node(7, percolation=0.1) - G.add_node(8, percolation=0.1) - G.add_edges_from([(1, 4), (2, 4), (3, 4), (4, 5), (5, 6), (6, 7), (6, 8)]) - return G - - -class TestPercolationCentrality(object): - def test_percolation_example1a(self): - """percolation centrality: example 1a""" - G = example1a_G() - p = nx.percolation_centrality(G) - p_answer = {4: 0.625, 6: 0.667} - for n in p_answer: - assert almost_equal(p[n], p_answer[n], places=3) - - def test_percolation_example1b(self): - """percolation centrality: example 1a""" - G = example1b_G() - p = nx.percolation_centrality(G) - p_answer = {4: 0.825, 6: 0.4} - for n in p_answer: - assert almost_equal(p[n], p_answer[n], places=3) - - def test_converge_to_betweenness(self): - """percolation centrality: should converge to betweenness - centrality when all nodes are percolated the same""" - # taken from betweenness test test_florentine_families_graph - G = nx.florentine_families_graph() - b_answer =\ - {'Acciaiuoli': 0.000, - 'Albizzi': 0.212, - 'Barbadori': 0.093, - 'Bischeri': 0.104, - 'Castellani': 0.055, - 'Ginori': 0.000, - 'Guadagni': 0.255, - 'Lamberteschi': 0.000, - 'Medici': 0.522, - 'Pazzi': 0.000, - 'Peruzzi': 0.022, - 'Ridolfi': 0.114, - 'Salviati': 0.143, - 'Strozzi': 0.103, - 'Tornabuoni': 0.092} - - p_states = {k: 1.0 for k, v in b_answer.items()} - p_answer = nx.percolation_centrality(G, states=p_states) - for n in sorted(G): - assert almost_equal(p_answer[n], b_answer[n], places=3) - - p_states = {k: 0.3 for k, v in b_answer.items()} - p_answer = nx.percolation_centrality(G, states=p_states) - for n in sorted(G): - assert almost_equal(p_answer[n], b_answer[n], places=3) diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_reaching.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_reaching.py deleted file mode 100644 index 98ef5743..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_reaching.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright (C) 2015-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -"""Unit tests for the :mod:`networkx.algorithms.centrality.reaching` module.""" -import pytest - -from networkx import nx -from networkx.testing import almost_equal - -class TestGlobalReachingCentrality: - """Unit tests for the global reaching centrality function.""" - - def test_non_positive_weights(self): - with pytest.raises(nx.NetworkXError): - G = nx.DiGraph() - nx.global_reaching_centrality(G, weight='weight') - - def test_negatively_weighted(self): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - G.add_weighted_edges_from([(0, 1, -2), (1, 2, +1)]) - nx.global_reaching_centrality(G, weight='weight') - - def test_directed_star(self): - G = nx.DiGraph() - G.add_weighted_edges_from([(1, 2, 0.5), (1, 3, 0.5)]) - grc = nx.global_reaching_centrality - assert grc(G, normalized=False, weight='weight') == 0.5 - assert grc(G) == 1 - - def test_undirected_unweighted_star(self): - G = nx.star_graph(2) - grc = nx.global_reaching_centrality - assert grc(G, normalized=False, weight=None) == 0.25 - - def test_undirected_weighted_star(self): - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 1), (1, 3, 2)]) - grc = nx.global_reaching_centrality - assert grc(G, normalized=False, weight='weight') == 0.375 - - def test_cycle_directed_unweighted(self): - G = nx.DiGraph() - G.add_edge(1, 2) - G.add_edge(2, 1) - assert nx.global_reaching_centrality(G, weight=None) == 0 - - def test_cycle_undirected_unweighted(self): - G = nx.Graph() - G.add_edge(1, 2) - assert nx.global_reaching_centrality(G, weight=None) == 0 - - def test_cycle_directed_weighted(self): - G = nx.DiGraph() - G.add_weighted_edges_from([(1, 2, 1), (2, 1, 1)]) - assert nx.global_reaching_centrality(G) == 0 - - def test_cycle_undirected_weighted(self): - G = nx.Graph() - G.add_edge(1, 2, weight=1) - grc = nx.global_reaching_centrality - assert grc(G, normalized=False) == 0 - - def test_directed_weighted(self): - G = nx.DiGraph() - G.add_edge("A", "B", weight=5) - G.add_edge("B", "C", weight=1) - G.add_edge("B", "D", weight=0.25) - G.add_edge("D", "E", weight=1) - - denom = len(G) - 1 - A_local = sum([5, 3, 2.625, 2.0833333333333]) / denom - B_local = sum([1, 0.25, 0.625]) / denom - C_local = 0 - D_local = sum([1]) / denom - E_local = 0 - - local_reach_ctrs = [A_local, C_local, B_local, D_local, E_local] - max_local = max(local_reach_ctrs) - expected = sum(max_local - lrc for lrc in local_reach_ctrs) / denom - grc = nx.global_reaching_centrality - actual = grc(G, normalized=False, weight='weight') - assert almost_equal(expected, actual, places=7) - - -class TestLocalReachingCentrality: - """Unit tests for the local reaching centrality function.""" - - def test_non_positive_weights(self): - with pytest.raises(nx.NetworkXError): - G = nx.DiGraph() - G.add_weighted_edges_from([(0, 1, 0)]) - nx.local_reaching_centrality(G, 0, weight='weight') - - def test_negatively_weighted(self): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - G.add_weighted_edges_from([(0, 1, -2), (1, 2, +1)]) - nx.local_reaching_centrality(G, 0, weight='weight') - - def test_undirected_unweighted_star(self): - G = nx.star_graph(2) - grc = nx.local_reaching_centrality - assert grc(G, 1, weight=None, normalized=False) == 0.75 - - def test_undirected_weighted_star(self): - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 1), (1, 3, 2)]) - centrality = nx.local_reaching_centrality(G, 1, normalized=False, weight='weight') - assert centrality == 1.5 diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_second_order_centrality.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_second_order_centrality.py deleted file mode 100644 index 94c9e5f9..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_second_order_centrality.py +++ /dev/null @@ -1,69 +0,0 @@ -""" -Tests for second order centrality. -""" - -import pytest -np = pytest.importorskip('numpy') -scipy = pytest.importorskip('scipy') - -import networkx as nx -from networkx.testing import almost_equal - - -class TestSecondOrderCentrality(object): - - def test_empty(self): - with pytest.raises(nx.NetworkXException): - G = nx.empty_graph() - nx.second_order_centrality(G) - - def test_non_connected(self): - with pytest.raises(nx.NetworkXException): - G = nx.Graph() - G.add_node(0) - G.add_node(1) - nx.second_order_centrality(G) - - def test_non_negative_edge_weights(self): - with pytest.raises(nx.NetworkXException): - G = nx.path_graph(2) - G.add_edge(0, 1, weight=-1) - nx.second_order_centrality(G) - - def test_one_node_graph(self): - """Second order centrality: single node""" - G = nx.Graph() - G.add_node(0) - G.add_edge(0, 0) - assert nx.second_order_centrality(G)[0] == 0 - - def test_P3(self): - """Second order centrality: line graph, as defined in paper""" - G = nx.path_graph(3) - b_answer = {0: 3.741, 1: 1.414, 2: 3.741} - - b = nx.second_order_centrality(G) - - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=2) - - def test_K3(self): - """Second order centrality: complete graph, as defined in paper""" - G = nx.complete_graph(3) - b_answer = {0: 1.414, 1: 1.414, 2: 1.414} - - b = nx.second_order_centrality(G) - - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=2) - - def test_ring_graph(self): - """Second order centrality: ring graph, as defined in paper""" - G = nx.cycle_graph(5) - b_answer = {0: 4.472, 1: 4.472, 2: 4.472, - 3: 4.472, 4: 4.472} - - b = nx.second_order_centrality(G) - - for n in sorted(G): - assert almost_equal(b[n], b_answer[n], places=2) diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_subgraph.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_subgraph.py deleted file mode 100644 index 8ba68e08..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_subgraph.py +++ /dev/null @@ -1,65 +0,0 @@ -from collections import defaultdict - -import pytest -numpy = pytest.importorskip('numpy') -scipy = pytest.importorskip('scipy') - -import networkx as nx -from networkx.algorithms.centrality.subgraph_alg import * -from networkx.testing import almost_equal - -class TestSubgraph: - - def test_subgraph_centrality(self): - answer = {0: 1.5430806348152433, 1: 1.5430806348152433} - result = subgraph_centrality(nx.path_graph(2)) - for k, v in result.items(): - assert almost_equal(answer[k], result[k], places=7) - - answer1 = {'1': 1.6445956054135658, - 'Albert': 2.4368257358712189, - 'Aric': 2.4368257358712193, - 'Dan': 3.1306328496328168, - 'Franck': 2.3876142275231915} - G1 = nx.Graph([('Franck', 'Aric'), ('Aric', 'Dan'), ('Dan', 'Albert'), - ('Albert', 'Franck'), ('Dan', '1'), ('Franck', 'Albert')]) - result1 = subgraph_centrality(G1) - for k, v in result1.items(): - assert almost_equal(answer1[k], result1[k], places=7) - result1 = subgraph_centrality_exp(G1) - for k, v in result1.items(): - assert almost_equal(answer1[k], result1[k], places=7) - - def test_subgraph_centrality_big_graph(self): - g199 = nx.complete_graph(199) - g200 = nx.complete_graph(200) - - comm199 = nx.subgraph_centrality(g199) - comm199_exp = nx.subgraph_centrality_exp(g199) - - comm200 = nx.subgraph_centrality(g200) - comm200_exp = nx.subgraph_centrality_exp(g200) - - def test_communicability_betweenness_centrality(self): - answer = {0: 0.07017447951484615, 1: 0.71565598701107991, - 2: 0.71565598701107991, 3: 0.07017447951484615} - result = communicability_betweenness_centrality(nx.path_graph(4)) - for k, v in result.items(): - assert almost_equal(answer[k], result[k], places=7) - - answer1 = {'1': 0.060039074193949521, - 'Albert': 0.315470761661372, - 'Aric': 0.31547076166137211, - 'Dan': 0.68297778678316201, - 'Franck': 0.21977926617449497} - G1 = nx.Graph([('Franck', 'Aric'), - ('Aric', 'Dan'), ('Dan', 'Albert'), ('Albert', 'Franck'), - ('Dan', '1'), ('Franck', 'Albert')]) - result1 = communicability_betweenness_centrality(G1) - for k, v in result1.items(): - assert almost_equal(answer1[k], result1[k], places=7) - - def test_estrada_index(self): - answer = 1041.2470334195475 - result = estrada_index(nx.karate_club_graph()) - assert almost_equal(answer, result, places=7) diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_voterank.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_voterank.py deleted file mode 100644 index 8e080bb2..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/tests/test_voterank.py +++ /dev/null @@ -1,20 +0,0 @@ -""" - Unit tests for VoteRank. -""" - - -import networkx as nx - - -class TestVoteRankCentrality: - def test_voterank_centrality_1(self): - G = nx.Graph() - G.add_edges_from([(7, 8), (7, 5), (7, 9), (5, 0), (0, 1), (0, 2), - (0, 3), (0, 4), (1, 6), (2, 6), (3, 6), (4, 6)]) - assert [0, 7, 6] == nx.voterank(G) - - def test_voterank_centrality_2(self): - G = nx.florentine_families_graph() - d = nx.voterank(G, 4) - exact = ['Medici', 'Strozzi', 'Guadagni', 'Castellani'] - assert exact == d diff --git a/extensions/fablabchemnitz/networkx/algorithms/centrality/voterank_alg.py b/extensions/fablabchemnitz/networkx/algorithms/centrality/voterank_alg.py deleted file mode 100644 index 8eb5c501..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/centrality/voterank_alg.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (C) 2017 by -# Fredrik Erlandsson -# All rights reserved. -# BSD license. -# -"""Algorithm to compute influential seeds in a graph using voterank.""" -from networkx.utils.decorators import not_implemented_for - -__all__ = ['voterank'] -__author__ = """\n""".join(['Fredrik Erlandsson ', - 'Piotr Brodka (piotr.brodka@pwr.edu.pl']) - - -@not_implemented_for('directed') -def voterank(G, number_of_nodes=None, max_iter=10000): - """Compute a list of seeds for the nodes in the graph using VoteRank - - VoteRank [1]_ computes a ranking of the nodes in the graph G based on a voting - scheme. With VoteRank, all nodes vote for each neighbours and the node with - the highest score is elected iteratively. The voting ability of neighbors of - elected nodes will be decreased in subsequent turn. - - Parameters - ---------- - G : graph - A NetworkX graph. - - number_of_nodes : integer, optional - Number of ranked nodes to extract (default all nodes). - - max_iter : integer, optional - Maximum number of iterations to rank nodes. - - Returns - ------- - voterank : list - Ordered list of computed seeds. - - Raises - ------ - NetworkXNotImplemented: - If G is digraph. - - References - ---------- - .. [1] Zhang, J.-X. et al. (2016). - Identifying a set of influential spreaders in complex networks. - Sci. Rep. 6, 27823; doi: 10.1038/srep27823. - """ - voterank = [] - if len(G) == 0: - return voterank - if number_of_nodes is None or number_of_nodes > len(G): - number_of_nodes = len(G) - avgDegree = sum(deg for _, deg in G.degree()) / float(len(G)) - # step 1 - initiate all nodes to (0,1) (score, voting ability) - for _, v in G.nodes(data=True): - v['voterank'] = [0, 1] - # Repeat steps 1b to 4 until num_seeds are elected. - for _ in range(max_iter): - # step 1b - reset rank - for _, v in G.nodes(data=True): - v['voterank'][0] = 0 - # step 2 - vote - for n, nbr in G.edges(): - G.nodes[n]['voterank'][0] += G.nodes[nbr]['voterank'][1] - G.nodes[nbr]['voterank'][0] += G.nodes[n]['voterank'][1] - for n in voterank: - G.nodes[n]['voterank'][0] = 0 - # step 3 - select top node - n, value = max(G.nodes(data=True), - key=lambda x: x[1]['voterank'][0]) - if value['voterank'][0] == 0: - return voterank - voterank.append(n) - if len(voterank) >= number_of_nodes: - return voterank - # weaken the selected node - G.nodes[n]['voterank'] = [0, 0] - # step 4 - update voterank properties - for nbr in G.neighbors(n): - G.nodes[nbr]['voterank'][1] -= 1 / avgDegree - return voterank diff --git a/extensions/fablabchemnitz/networkx/algorithms/chains.py b/extensions/fablabchemnitz/networkx/algorithms/chains.py deleted file mode 100644 index a1e0cc8e..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/chains.py +++ /dev/null @@ -1,168 +0,0 @@ -# -*- coding: utf-8 -*- -# chains.py - functions for finding chains in a graph -# -# Copyright 2004-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Functions for finding chains in a graph.""" - -import networkx as nx -from networkx.utils import not_implemented_for - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def chain_decomposition(G, root=None): - """Returns the chain decomposition of a graph. - - The *chain decomposition* of a graph with respect a depth-first - search tree is a set of cycles or paths derived from the set of - fundamental cycles of the tree in the following manner. Consider - each fundamental cycle with respect to the given tree, represented - as a list of edges beginning with the nontree edge oriented away - from the root of the tree. For each fundamental cycle, if it - overlaps with any previous fundamental cycle, just take the initial - non-overlapping segment, which is a path instead of a cycle. Each - cycle or path is called a *chain*. For more information, see [1]_. - - Parameters - ---------- - G : undirected graph - - root : node (optional) - A node in the graph `G`. If specified, only the chain - decomposition for the connected component containing this node - will be returned. This node indicates the root of the depth-first - search tree. - - Yields - ------ - chain : list - A list of edges representing a chain. There is no guarantee on - the orientation of the edges in each chain (for example, if a - chain includes the edge joining nodes 1 and 2, the chain may - include either (1, 2) or (2, 1)). - - Raises - ------ - NodeNotFound - If `root` is not in the graph `G`. - - Notes - ----- - The worst-case running time of this implementation is linear in the - number of nodes and number of edges [1]_. - - References - ---------- - .. [1] Jens M. Schmidt (2013). "A simple test on 2-vertex- - and 2-edge-connectivity." *Information Processing Letters*, - 113, 241–244. Elsevier. - - """ - - def _dfs_cycle_forest(G, root=None): - """Builds a directed graph composed of cycles from the given graph. - - `G` is an undirected simple graph. `root` is a node in the graph - from which the depth-first search is started. - - This function returns both the depth-first search cycle graph - (as a :class:`~networkx.DiGraph`) and the list of nodes in - depth-first preorder. The depth-first search cycle graph is a - directed graph whose edges are the edges of `G` oriented toward - the root if the edge is a tree edge and away from the root if - the edge is a non-tree edge. If `root` is not specified, this - performs a depth-first search on each connected component of `G` - and returns a directed forest instead. - - If `root` is not in the graph, this raises :exc:`KeyError`. - - """ - # Create a directed graph from the depth-first search tree with - # root node `root` in which tree edges are directed toward the - # root and nontree edges are directed away from the root. For - # each node with an incident nontree edge, this creates a - # directed cycle starting with the nontree edge and returning to - # that node. - # - # The `parent` node attribute stores the parent of each node in - # the DFS tree. The `nontree` edge attribute indicates whether - # the edge is a tree edge or a nontree edge. - # - # We also store the order of the nodes found in the depth-first - # search in the `nodes` list. - H = nx.DiGraph() - nodes = [] - for u, v, d in nx.dfs_labeled_edges(G, source=root): - if d == 'forward': - # `dfs_labeled_edges()` yields (root, root, 'forward') - # if it is beginning the search on a new connected - # component. - if u == v: - H.add_node(v, parent=None) - nodes.append(v) - else: - H.add_node(v, parent=u) - H.add_edge(v, u, nontree=False) - nodes.append(v) - # `dfs_labeled_edges` considers nontree edges in both - # orientations, so we need to not add the edge if it its - # other orientation has been added. - elif d == 'nontree' and v not in H[u]: - H.add_edge(v, u, nontree=True) - else: - # Do nothing on 'reverse' edges; we only care about - # forward and nontree edges. - pass - return H, nodes - - def _build_chain(G, u, v, visited): - """Generate the chain starting from the given nontree edge. - - `G` is a DFS cycle graph as constructed by - :func:`_dfs_cycle_graph`. The edge (`u`, `v`) is a nontree edge - that begins a chain. `visited` is a set representing the nodes - in `G` that have already been visited. - - This function yields the edges in an initial segment of the - fundamental cycle of `G` starting with the nontree edge (`u`, - `v`) that includes all the edges up until the first node that - appears in `visited`. The tree edges are given by the 'parent' - node attribute. The `visited` set is updated to add each node in - an edge yielded by this function. - - """ - while v not in visited: - yield u, v - visited.add(v) - u, v = v, G.nodes[v]['parent'] - yield u, v - - # Create a directed version of H that has the DFS edges directed - # toward the root and the nontree edges directed away from the root - # (in each connected component). - H, nodes = _dfs_cycle_forest(G, root) - - # Visit the nodes again in DFS order. For each node, and for each - # nontree edge leaving that node, compute the fundamental cycle for - # that nontree edge starting with that edge. If the fundamental - # cycle overlaps with any visited nodes, just take the prefix of the - # cycle up to the point of visited nodes. - # - # We repeat this process for each connected component (implicitly, - # since `nodes` already has a list of the nodes grouped by connected - # component). - visited = set() - for u in nodes: - visited.add(u) - # For each nontree edge going out of node u... - edges = ((u, v) for u, v, d in H.out_edges(u, data='nontree') if d) - for u, v in edges: - # Create the cycle or cycle prefix starting with the - # nontree edge. - chain = list(_build_chain(H, u, v, visited)) - yield chain diff --git a/extensions/fablabchemnitz/networkx/algorithms/chordal.py b/extensions/fablabchemnitz/networkx/algorithms/chordal.py deleted file mode 100644 index f871fa14..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/chordal.py +++ /dev/null @@ -1,421 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Algorithms for chordal graphs. - -A graph is chordal if every cycle of length at least 4 has a chord -(an edge joining two nodes not adjacent in the cycle). -https://en.wikipedia.org/wiki/Chordal_graph -""" -import sys - -import networkx as nx -from networkx.algorithms.components import connected_components -from networkx.utils import arbitrary_element, not_implemented_for - -__authors__ = "\n".join(['Jesus Cerquides ', - 'Julien Klaus -# All rights reserved. -# BSD license. - -__all__ = ['is_chordal', - 'find_induced_nodes', - 'chordal_graph_cliques', - 'chordal_graph_treewidth', - 'NetworkXTreewidthBoundExceeded', - 'complete_to_chordal_graph'] - - -class NetworkXTreewidthBoundExceeded(nx.NetworkXException): - """Exception raised when a treewidth bound has been provided and it has - been exceeded""" - - -def is_chordal(G): - """Checks whether G is a chordal graph. - - A graph is chordal if every cycle of length at least 4 has a chord - (an edge joining two nodes not adjacent in the cycle). - - Parameters - ---------- - G : graph - A NetworkX graph. - - Returns - ------- - chordal : bool - True if G is a chordal graph and False otherwise. - - Raises - ------ - NetworkXError - The algorithm does not support DiGraph, MultiGraph and MultiDiGraph. - If the input graph is an instance of one of these classes, a - :exc:`NetworkXError` is raised. - - Examples - -------- - >>> import networkx as nx - >>> e=[(1,2),(1,3),(2,3),(2,4),(3,4),(3,5),(3,6),(4,5),(4,6),(5,6)] - >>> G=nx.Graph(e) - >>> nx.is_chordal(G) - True - - Notes - ----- - The routine tries to go through every node following maximum cardinality - search. It returns False when it finds that the separator for any node - is not a clique. Based on the algorithms in [1]_. - - References - ---------- - .. [1] R. E. Tarjan and M. Yannakakis, Simple linear-time algorithms - to test chordality of graphs, test acyclicity of hypergraphs, and - selectively reduce acyclic hypergraphs, SIAM J. Comput., 13 (1984), - pp. 566–579. - """ - if G.is_directed(): - raise nx.NetworkXError('Directed graphs not supported') - if G.is_multigraph(): - raise nx.NetworkXError('Multiply connected graphs not supported.') - if len(_find_chordality_breaker(G)) == 0: - return True - else: - return False - - -def find_induced_nodes(G, s, t, treewidth_bound=sys.maxsize): - """Returns the set of induced nodes in the path from s to t. - - Parameters - ---------- - G : graph - A chordal NetworkX graph - s : node - Source node to look for induced nodes - t : node - Destination node to look for induced nodes - treewith_bound: float - Maximum treewidth acceptable for the graph H. The search - for induced nodes will end as soon as the treewidth_bound is exceeded. - - Returns - ------- - Induced_nodes : Set of nodes - The set of induced nodes in the path from s to t in G - - Raises - ------ - NetworkXError - The algorithm does not support DiGraph, MultiGraph and MultiDiGraph. - If the input graph is an instance of one of these classes, a - :exc:`NetworkXError` is raised. - The algorithm can only be applied to chordal graphs. If the input - graph is found to be non-chordal, a :exc:`NetworkXError` is raised. - - Examples - -------- - >>> import networkx as nx - >>> G=nx.Graph() - >>> G = nx.generators.classic.path_graph(10) - >>> Induced_nodes = nx.find_induced_nodes(G,1,9,2) - >>> sorted(Induced_nodes) - [1, 2, 3, 4, 5, 6, 7, 8, 9] - - Notes - ----- - G must be a chordal graph and (s,t) an edge that is not in G. - - If a treewidth_bound is provided, the search for induced nodes will end - as soon as the treewidth_bound is exceeded. - - The algorithm is inspired by Algorithm 4 in [1]_. - A formal definition of induced node can also be found on that reference. - - References - ---------- - .. [1] Learning Bounded Treewidth Bayesian Networks. - Gal Elidan, Stephen Gould; JMLR, 9(Dec):2699--2731, 2008. - http://jmlr.csail.mit.edu/papers/volume9/elidan08a/elidan08a.pdf - """ - if not is_chordal(G): - raise nx.NetworkXError("Input graph is not chordal.") - - H = nx.Graph(G) - H.add_edge(s, t) - Induced_nodes = set() - triplet = _find_chordality_breaker(H, s, treewidth_bound) - while triplet: - (u, v, w) = triplet - Induced_nodes.update(triplet) - for n in triplet: - if n != s: - H.add_edge(s, n) - triplet = _find_chordality_breaker(H, s, treewidth_bound) - if Induced_nodes: - # Add t and the second node in the induced path from s to t. - Induced_nodes.add(t) - for u in G[s]: - if len(Induced_nodes & set(G[u])) == 2: - Induced_nodes.add(u) - break - return Induced_nodes - - -def chordal_graph_cliques(G): - """Returns the set of maximal cliques of a chordal graph. - - The algorithm breaks the graph in connected components and performs a - maximum cardinality search in each component to get the cliques. - - Parameters - ---------- - G : graph - A NetworkX graph - - Returns - ------- - cliques : A set containing the maximal cliques in G. - - Raises - ------ - NetworkXError - The algorithm does not support DiGraph, MultiGraph and MultiDiGraph. - If the input graph is an instance of one of these classes, a - :exc:`NetworkXError` is raised. - The algorithm can only be applied to chordal graphs. If the input - graph is found to be non-chordal, a :exc:`NetworkXError` is raised. - - Examples - -------- - >>> import networkx as nx - >>> e= [(1,2),(1,3),(2,3),(2,4),(3,4),(3,5),(3,6),(4,5),(4,6),(5,6),(7,8)] - >>> G = nx.Graph(e) - >>> G.add_node(9) - >>> setlist = nx.chordal_graph_cliques(G) - """ - if not is_chordal(G): - raise nx.NetworkXError("Input graph is not chordal.") - - cliques = set() - for C in (G.subgraph(c).copy() for c in connected_components(G)): - cliques |= _connected_chordal_graph_cliques(C) - - return cliques - - -def chordal_graph_treewidth(G): - """Returns the treewidth of the chordal graph G. - - Parameters - ---------- - G : graph - A NetworkX graph - - Returns - ------- - treewidth : int - The size of the largest clique in the graph minus one. - - Raises - ------ - NetworkXError - The algorithm does not support DiGraph, MultiGraph and MultiDiGraph. - If the input graph is an instance of one of these classes, a - :exc:`NetworkXError` is raised. - The algorithm can only be applied to chordal graphs. If the input - graph is found to be non-chordal, a :exc:`NetworkXError` is raised. - - Examples - -------- - >>> import networkx as nx - >>> e = [(1,2),(1,3),(2,3),(2,4),(3,4),(3,5),(3,6),(4,5),(4,6),(5,6),(7,8)] - >>> G = nx.Graph(e) - >>> G.add_node(9) - >>> nx.chordal_graph_treewidth(G) - 3 - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Tree_decomposition#Treewidth - """ - if not is_chordal(G): - raise nx.NetworkXError("Input graph is not chordal.") - - max_clique = -1 - for clique in nx.chordal_graph_cliques(G): - max_clique = max(max_clique, len(clique)) - return max_clique - 1 - - -def _is_complete_graph(G): - """Returns True if G is a complete graph.""" - if nx.number_of_selfloops(G) > 0: - raise nx.NetworkXError("Self loop found in _is_complete_graph()") - n = G.number_of_nodes() - if n < 2: - return True - e = G.number_of_edges() - max_edges = ((n * (n - 1)) / 2) - return e == max_edges - - -def _find_missing_edge(G): - """ Given a non-complete graph G, returns a missing edge.""" - nodes = set(G) - for u in G: - missing = nodes - set(list(G[u].keys()) + [u]) - if missing: - return (u, missing.pop()) - - -def _max_cardinality_node(G, choices, wanna_connect): - """Returns a the node in choices that has more connections in G - to nodes in wanna_connect. - """ - max_number = -1 - for x in choices: - number = len([y for y in G[x] if y in wanna_connect]) - if number > max_number: - max_number = number - max_cardinality_node = x - return max_cardinality_node - - -def _find_chordality_breaker(G, s=None, treewidth_bound=sys.maxsize): - """ Given a graph G, starts a max cardinality search - (starting from s if s is given and from an arbitrary node otherwise) - trying to find a non-chordal cycle. - - If it does find one, it returns (u,v,w) where u,v,w are the three - nodes that together with s are involved in the cycle. - """ - - unnumbered = set(G) - if s is None: - s = arbitrary_element(G) - unnumbered.remove(s) - numbered = set([s]) - current_treewidth = -1 - while unnumbered: # and current_treewidth <= treewidth_bound: - v = _max_cardinality_node(G, unnumbered, numbered) - unnumbered.remove(v) - numbered.add(v) - clique_wanna_be = set(G[v]) & numbered - sg = G.subgraph(clique_wanna_be) - if _is_complete_graph(sg): - # The graph seems to be chordal by now. We update the treewidth - current_treewidth = max(current_treewidth, len(clique_wanna_be)) - if current_treewidth > treewidth_bound: - raise nx.NetworkXTreewidthBoundExceeded( - "treewidth_bound exceeded: %s" % current_treewidth) - else: - # sg is not a clique, - # look for an edge that is not included in sg - (u, w) = _find_missing_edge(sg) - return (u, v, w) - return () - - -def _connected_chordal_graph_cliques(G): - """Returns the set of maximal cliques of a connected chordal graph.""" - if G.number_of_nodes() == 1: - x = frozenset(G.nodes()) - return set([x]) - else: - cliques = set() - unnumbered = set(G.nodes()) - v = arbitrary_element(G) - unnumbered.remove(v) - numbered = set([v]) - clique_wanna_be = set([v]) - while unnumbered: - v = _max_cardinality_node(G, unnumbered, numbered) - unnumbered.remove(v) - numbered.add(v) - new_clique_wanna_be = set(G.neighbors(v)) & numbered - sg = G.subgraph(clique_wanna_be) - if _is_complete_graph(sg): - new_clique_wanna_be.add(v) - if not new_clique_wanna_be >= clique_wanna_be: - cliques.add(frozenset(clique_wanna_be)) - clique_wanna_be = new_clique_wanna_be - else: - raise nx.NetworkXError("Input graph is not chordal.") - cliques.add(frozenset(clique_wanna_be)) - return cliques - - -@not_implemented_for('directed') -def complete_to_chordal_graph(G): - """Return a copy of G completed to a chordal graph - - Adds edges to a copy of G to create a chordal graph. A graph G=(V,E) is - called chordal if for each cycle with length bigger than 3, there exist - two non-adjacent nodes connected by an edge (called a chord). - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - Returns - ------- - H : NetworkX graph - The chordal enhancement of G - alpha : Dictionary - The elimination ordering of nodes of G - - Notes - ------ - There are different approaches to calculate the chordal - enhancement of a graph. The algorithm used here is called - MCS-M and gives at least minimal (local) triangulation of graph. Note - that this triangulation is not necessarily a global minimum. - - https://en.wikipedia.org/wiki/Chordal_graph - - References - ---------- - .. [1] Berry, Anne & Blair, Jean & Heggernes, Pinar & Peyton, Barry. (2004) - Maximum Cardinality Search for Computing Minimal Triangulations of - Graphs. Algorithmica. 39. 287-298. 10.1007/s00453-004-1084-3. - - Examples - -------- - >>> import networkx as nx - >>> from networkx.algorithms.chordal import complete_to_chordal_graph - >>> G = nx.wheel_graph(10) - >>> H,alpha = complete_to_chordal_graph(G) - """ - H = G.copy() - alpha = {node: 0 for node in H} - if nx.is_chordal(H): - return H, alpha - chords = set([]) - weight = {node: 0 for node in H.nodes()} - unnumbered_nodes = list(H.nodes()) - for i in range(len(H.nodes()), 0, -1): - # get the node in unnumbered_nodes with the maximum weight - z = max(unnumbered_nodes, key=lambda node: weight[node]) - unnumbered_nodes.remove(z) - alpha[z] = i - update_nodes = [] - for y in unnumbered_nodes: - if G.has_edge(y, z): - update_nodes.append(y) - else: - # y_weight will be bigger than node weights between y and z - y_weight = weight[y] - lower_nodes = [node for node in unnumbered_nodes - if weight[node] < y_weight] - if nx.has_path(H.subgraph(lower_nodes + [z, y]), y, z): - update_nodes.append(y) - chords.add((z, y)) - # during calculation of paths the weights should not be updated - for node in update_nodes: - weight[node] += 1 - H.add_edges_from(chords) - return H, alpha diff --git a/extensions/fablabchemnitz/networkx/algorithms/clique.py b/extensions/fablabchemnitz/networkx/algorithms/clique.py deleted file mode 100644 index e9265c24..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/clique.py +++ /dev/null @@ -1,553 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -"""Functions for finding and manipulating cliques. - -Finding the largest clique in a graph is NP-complete problem, so most of -these algorithms have an exponential running time; for more information, -see the Wikipedia article on the clique problem [1]_. - -.. [1] clique problem:: https://en.wikipedia.org/wiki/Clique_problem - -""" -from collections import deque -from itertools import chain -from itertools import combinations -from itertools import islice -try: - from itertools import ifilter as filter -except ImportError: - pass -import networkx as nx -from networkx.utils import not_implemented_for -__author__ = """Dan Schult (dschult@colgate.edu)""" -__all__ = ['find_cliques', 'find_cliques_recursive', 'make_max_clique_graph', - 'make_clique_bipartite', 'graph_clique_number', - 'graph_number_of_cliques', 'node_clique_number', - 'number_of_cliques', 'cliques_containing_node', - 'enumerate_all_cliques'] - - -@not_implemented_for('directed') -def enumerate_all_cliques(G): - """Returns all cliques in an undirected graph. - - This function returns an iterator over cliques, each of which is a - list of nodes. The iteration is ordered by cardinality of the - cliques: first all cliques of size one, then all cliques of size - two, etc. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - Returns - ------- - iterator - An iterator over cliques, each of which is a list of nodes in - `G`. The cliques are ordered according to size. - - Notes - ----- - To obtain a list of all cliques, use - `list(enumerate_all_cliques(G))`. However, be aware that in the - worst-case, the length of this list can be exponential in the number - of nodes in the graph (for example, when the graph is the complete - graph). This function avoids storing all cliques in memory by only - keeping current candidate node lists in memory during its search. - - The implementation is adapted from the algorithm by Zhang, et - al. (2005) [1]_ to output all cliques discovered. - - This algorithm ignores self-loops and parallel edges, since cliques - are not conventionally defined with such edges. - - References - ---------- - .. [1] Yun Zhang, Abu-Khzam, F.N., Baldwin, N.E., Chesler, E.J., - Langston, M.A., Samatova, N.F., - "Genome-Scale Computational Approaches to Memory-Intensive - Applications in Systems Biology". - *Supercomputing*, 2005. Proceedings of the ACM/IEEE SC 2005 - Conference, pp. 12, 12--18 Nov. 2005. - . - - """ - index = {} - nbrs = {} - for u in G: - index[u] = len(index) - # Neighbors of u that appear after u in the iteration order of G. - nbrs[u] = {v for v in G[u] if v not in index} - - queue = deque(([u], sorted(nbrs[u], key=index.__getitem__)) for u in G) - # Loop invariants: - # 1. len(base) is nondecreasing. - # 2. (base + cnbrs) is sorted with respect to the iteration order of G. - # 3. cnbrs is a set of common neighbors of nodes in base. - while queue: - base, cnbrs = map(list, queue.popleft()) - yield base - for i, u in enumerate(cnbrs): - # Use generators to reduce memory consumption. - queue.append((chain(base, [u]), - filter(nbrs[u].__contains__, - islice(cnbrs, i + 1, None)))) - - -@not_implemented_for('directed') -def find_cliques(G): - """Returns all maximal cliques in an undirected graph. - - For each node *v*, a *maximal clique for v* is a largest complete - subgraph containing *v*. The largest maximal clique is sometimes - called the *maximum clique*. - - This function returns an iterator over cliques, each of which is a - list of nodes. It is an iterative implementation, so should not - suffer from recursion depth issues. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - Returns - ------- - iterator - An iterator over maximal cliques, each of which is a list of - nodes in `G`. The order of cliques is arbitrary. - - See Also - -------- - find_cliques_recursive - A recursive version of the same algorithm. - - Notes - ----- - To obtain a list of all maximal cliques, use - `list(find_cliques(G))`. However, be aware that in the worst-case, - the length of this list can be exponential in the number of nodes in - the graph. This function avoids storing all cliques in memory by - only keeping current candidate node lists in memory during its search. - - This implementation is based on the algorithm published by Bron and - Kerbosch (1973) [1]_, as adapted by Tomita, Tanaka and Takahashi - (2006) [2]_ and discussed in Cazals and Karande (2008) [3]_. It - essentially unrolls the recursion used in the references to avoid - issues of recursion stack depth (for a recursive implementation, see - :func:`find_cliques_recursive`). - - This algorithm ignores self-loops and parallel edges, since cliques - are not conventionally defined with such edges. - - References - ---------- - .. [1] Bron, C. and Kerbosch, J. - "Algorithm 457: finding all cliques of an undirected graph". - *Communications of the ACM* 16, 9 (Sep. 1973), 575--577. - - - .. [2] Etsuji Tomita, Akira Tanaka, Haruhisa Takahashi, - "The worst-case time complexity for generating all maximal - cliques and computational experiments", - *Theoretical Computer Science*, Volume 363, Issue 1, - Computing and Combinatorics, - 10th Annual International Conference on - Computing and Combinatorics (COCOON 2004), 25 October 2006, Pages 28--42 - - - .. [3] F. Cazals, C. Karande, - "A note on the problem of reporting maximal cliques", - *Theoretical Computer Science*, - Volume 407, Issues 1--3, 6 November 2008, Pages 564--568, - - - """ - if len(G) == 0: - return - - adj = {u: {v for v in G[u] if v != u} for u in G} - Q = [None] - - subg = set(G) - cand = set(G) - u = max(subg, key=lambda u: len(cand & adj[u])) - ext_u = cand - adj[u] - stack = [] - - try: - while True: - if ext_u: - q = ext_u.pop() - cand.remove(q) - Q[-1] = q - adj_q = adj[q] - subg_q = subg & adj_q - if not subg_q: - yield Q[:] - else: - cand_q = cand & adj_q - if cand_q: - stack.append((subg, cand, ext_u)) - Q.append(None) - subg = subg_q - cand = cand_q - u = max(subg, key=lambda u: len(cand & adj[u])) - ext_u = cand - adj[u] - else: - Q.pop() - subg, cand, ext_u = stack.pop() - except IndexError: - pass - - -# TODO Should this also be not implemented for directed graphs? -def find_cliques_recursive(G): - """Returns all maximal cliques in a graph. - - For each node *v*, a *maximal clique for v* is a largest complete - subgraph containing *v*. The largest maximal clique is sometimes - called the *maximum clique*. - - This function returns an iterator over cliques, each of which is a - list of nodes. It is a recursive implementation, so may suffer from - recursion depth issues. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - iterator - An iterator over maximal cliques, each of which is a list of - nodes in `G`. The order of cliques is arbitrary. - - See Also - -------- - find_cliques - An iterative version of the same algorithm. - - Notes - ----- - To obtain a list of all maximal cliques, use - `list(find_cliques_recursive(G))`. However, be aware that in the - worst-case, the length of this list can be exponential in the number - of nodes in the graph. This function avoids storing all cliques in memory - by only keeping current candidate node lists in memory during its search. - - This implementation is based on the algorithm published by Bron and - Kerbosch (1973) [1]_, as adapted by Tomita, Tanaka and Takahashi - (2006) [2]_ and discussed in Cazals and Karande (2008) [3]_. For a - non-recursive implementation, see :func:`find_cliques`. - - This algorithm ignores self-loops and parallel edges, since cliques - are not conventionally defined with such edges. - - References - ---------- - .. [1] Bron, C. and Kerbosch, J. - "Algorithm 457: finding all cliques of an undirected graph". - *Communications of the ACM* 16, 9 (Sep. 1973), 575--577. - - - .. [2] Etsuji Tomita, Akira Tanaka, Haruhisa Takahashi, - "The worst-case time complexity for generating all maximal - cliques and computational experiments", - *Theoretical Computer Science*, Volume 363, Issue 1, - Computing and Combinatorics, - 10th Annual International Conference on - Computing and Combinatorics (COCOON 2004), 25 October 2006, Pages 28--42 - - - .. [3] F. Cazals, C. Karande, - "A note on the problem of reporting maximal cliques", - *Theoretical Computer Science*, - Volume 407, Issues 1--3, 6 November 2008, Pages 564--568, - - - """ - if len(G) == 0: - return iter([]) - - adj = {u: {v for v in G[u] if v != u} for u in G} - Q = [] - - def expand(subg, cand): - u = max(subg, key=lambda u: len(cand & adj[u])) - for q in cand - adj[u]: - cand.remove(q) - Q.append(q) - adj_q = adj[q] - subg_q = subg & adj_q - if not subg_q: - yield Q[:] - else: - cand_q = cand & adj_q - if cand_q: - for clique in expand(subg_q, cand_q): - yield clique - Q.pop() - - return expand(set(G), set(G)) - - -def make_max_clique_graph(G, create_using=None): - """Returns the maximal clique graph of the given graph. - - The nodes of the maximal clique graph of `G` are the cliques of - `G` and an edge joins two cliques if the cliques are not disjoint. - - Parameters - ---------- - G : NetworkX graph - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - NetworkX graph - A graph whose nodes are the cliques of `G` and whose edges - join two cliques if they are not disjoint. - - Notes - ----- - This function behaves like the following code:: - - import networkx as nx - G = nx.make_clique_bipartite(G) - cliques = [v for v in G.nodes() if G.nodes[v]['bipartite'] == 0] - G = nx.bipartite.project(G, cliques) - G = nx.relabel_nodes(G, {-v: v - 1 for v in G}) - - It should be faster, though, since it skips all the intermediate - steps. - - """ - if create_using is None: - B = G.__class__() - else: - B = nx.empty_graph(0, create_using) - cliques = list(enumerate(set(c) for c in find_cliques(G))) - # Add a numbered node for each clique. - B.add_nodes_from(i for i, c in cliques) - # Join cliques by an edge if they share a node. - clique_pairs = combinations(cliques, 2) - B.add_edges_from((i, j) for (i, c1), (j, c2) in clique_pairs if c1 & c2) - return B - - -def make_clique_bipartite(G, fpos=None, create_using=None, name=None): - """Returns the bipartite clique graph corresponding to `G`. - - In the returned bipartite graph, the "bottom" nodes are the nodes of - `G` and the "top" nodes represent the maximal cliques of `G`. - There is an edge from node *v* to clique *C* in the returned graph - if and only if *v* is an element of *C*. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - fpos : bool - If True or not None, the returned graph will have an - additional attribute, `pos`, a dictionary mapping node to - position in the Euclidean plane. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - NetworkX graph - A bipartite graph whose "bottom" set is the nodes of the graph - `G`, whose "top" set is the cliques of `G`, and whose edges - join nodes of `G` to the cliques that contain them. - - The nodes of the graph `G` have the node attribute - 'bipartite' set to 1 and the nodes representing cliques - have the node attribute 'bipartite' set to 0, as is the - convention for bipartite graphs in NetworkX. - - """ - B = nx.empty_graph(0, create_using) - B.clear() - # The "bottom" nodes in the bipartite graph are the nodes of the - # original graph, G. - B.add_nodes_from(G, bipartite=1) - for i, cl in enumerate(find_cliques(G)): - # The "top" nodes in the bipartite graph are the cliques. These - # nodes get negative numbers as labels. - name = -i - 1 - B.add_node(name, bipartite=0) - B.add_edges_from((v, name) for v in cl) - return B - - -def graph_clique_number(G, cliques=None): - """Returns the clique number of the graph. - - The *clique number* of a graph is the size of the largest clique in - the graph. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - cliques : list - A list of cliques, each of which is itself a list of nodes. If - not specified, the list of all cliques will be computed, as by - :func:`find_cliques`. - - Returns - ------- - int - The size of the largest clique in `G`. - - Notes - ----- - You should provide `cliques` if you have already computed the list - of maximal cliques, in order to avoid an exponential time search for - maximal cliques. - - """ - if cliques is None: - cliques = find_cliques(G) - if len(G.nodes) < 1: - return 0 - return max([len(c) for c in cliques] or [1]) - - -def graph_number_of_cliques(G, cliques=None): - """Returns the number of maximal cliques in the graph. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - cliques : list - A list of cliques, each of which is itself a list of nodes. If - not specified, the list of all cliques will be computed, as by - :func:`find_cliques`. - - Returns - ------- - int - The number of maximal cliques in `G`. - - Notes - ----- - You should provide `cliques` if you have already computed the list - of maximal cliques, in order to avoid an exponential time search for - maximal cliques. - - """ - if cliques is None: - cliques = list(find_cliques(G)) - return len(cliques) - - -def node_clique_number(G, nodes=None, cliques=None): - """ Returns the size of the largest maximal clique containing - each given node. - - Returns a single or list depending on input nodes. - Optional list of cliques can be input if already computed. - """ - if cliques is None: - if nodes is not None: - # Use ego_graph to decrease size of graph - if isinstance(nodes, list): - d = {} - for n in nodes: - H = nx.ego_graph(G, n) - d[n] = max((len(c) for c in find_cliques(H))) - else: - H = nx.ego_graph(G, nodes) - d = max((len(c) for c in find_cliques(H))) - return d - # nodes is None--find all cliques - cliques = list(find_cliques(G)) - - if nodes is None: - nodes = list(G.nodes()) # none, get entire graph - - if not isinstance(nodes, list): # check for a list - v = nodes - # assume it is a single value - d = max([len(c) for c in cliques if v in c]) - else: - d = {} - for v in nodes: - d[v] = max([len(c) for c in cliques if v in c]) - return d - - # if nodes is None: # none, use entire graph - # nodes=G.nodes() - # elif not isinstance(nodes, list): # check for a list - # nodes=[nodes] # assume it is a single value - - # if cliques is None: - # cliques=list(find_cliques(G)) - # d={} - # for v in nodes: - # d[v]=max([len(c) for c in cliques if v in c]) - - # if nodes in G: - # return d[v] #return single value - # return d - - -def number_of_cliques(G, nodes=None, cliques=None): - """Returns the number of maximal cliques for each node. - - Returns a single or list depending on input nodes. - Optional list of cliques can be input if already computed. - """ - if cliques is None: - cliques = list(find_cliques(G)) - - if nodes is None: - nodes = list(G.nodes()) # none, get entire graph - - if not isinstance(nodes, list): # check for a list - v = nodes - # assume it is a single value - numcliq = len([1 for c in cliques if v in c]) - else: - numcliq = {} - for v in nodes: - numcliq[v] = len([1 for c in cliques if v in c]) - return numcliq - - -def cliques_containing_node(G, nodes=None, cliques=None): - """Returns a list of cliques containing the given node. - - Returns a single list or list of lists depending on input nodes. - Optional list of cliques can be input if already computed. - """ - if cliques is None: - cliques = list(find_cliques(G)) - - if nodes is None: - nodes = list(G.nodes()) # none, get entire graph - - if not isinstance(nodes, list): # check for a list - v = nodes - # assume it is a single value - vcliques = [c for c in cliques if v in c] - else: - vcliques = {} - for v in nodes: - vcliques[v] = [c for c in cliques if v in c] - return vcliques diff --git a/extensions/fablabchemnitz/networkx/algorithms/cluster.py b/extensions/fablabchemnitz/networkx/algorithms/cluster.py deleted file mode 100644 index 203d5068..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/cluster.py +++ /dev/null @@ -1,538 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -"""Algorithms to characterize the number of triangles in a graph.""" - -from itertools import chain -from itertools import combinations -from collections import Counter - -import networkx as nx -from networkx.utils import not_implemented_for - -__author__ = """\n""".join(['Aric Hagberg ', - 'Dan Schult (dschult@colgate.edu)', - 'Pieter Swart (swart@lanl.gov)', - 'Jordi Torrents ']) - -__all__ = ['triangles', 'average_clustering', 'clustering', 'transitivity', - 'square_clustering', 'generalized_degree'] - - -@not_implemented_for('directed') -def triangles(G, nodes=None): - """Compute the number of triangles. - - Finds the number of triangles that include a node as one vertex. - - Parameters - ---------- - G : graph - A networkx graph - nodes : container of nodes, optional (default= all nodes in G) - Compute triangles for nodes in this container. - - Returns - ------- - out : dictionary - Number of triangles keyed by node label. - - Examples - -------- - >>> G=nx.complete_graph(5) - >>> print(nx.triangles(G,0)) - 6 - >>> print(nx.triangles(G)) - {0: 6, 1: 6, 2: 6, 3: 6, 4: 6} - >>> print(list(nx.triangles(G,(0,1)).values())) - [6, 6] - - Notes - ----- - When computing triangles for the entire graph each triangle is counted - three times, once at each node. Self loops are ignored. - - """ - # If `nodes` represents a single node in the graph, return only its number - # of triangles. - if nodes in G: - return next(_triangles_and_degree_iter(G, nodes))[2] // 2 - # Otherwise, `nodes` represents an iterable of nodes, so return a - # dictionary mapping node to number of triangles. - return {v: t // 2 for v, d, t, _ in _triangles_and_degree_iter(G, nodes)} - - -@not_implemented_for('multigraph') -def _triangles_and_degree_iter(G, nodes=None): - """ Return an iterator of (node, degree, triangles, generalized degree). - - This double counts triangles so you may want to divide by 2. - See degree(), triangles() and generalized_degree() for definitions - and details. - - """ - if nodes is None: - nodes_nbrs = G.adj.items() - else: - nodes_nbrs = ((n, G[n]) for n in G.nbunch_iter(nodes)) - - for v, v_nbrs in nodes_nbrs: - vs = set(v_nbrs) - {v} - gen_degree = Counter(len(vs & (set(G[w]) - {w})) for w in vs) - ntriangles = sum(k * val for k, val in gen_degree.items()) - yield (v, len(vs), ntriangles, gen_degree) - - -@not_implemented_for('multigraph') -def _weighted_triangles_and_degree_iter(G, nodes=None, weight='weight'): - """ Return an iterator of (node, degree, weighted_triangles). - - Used for weighted clustering. - - """ - if weight is None or G.number_of_edges() == 0: - max_weight = 1 - else: - max_weight = max(d.get(weight, 1) for u, v, d in G.edges(data=True)) - if nodes is None: - nodes_nbrs = G.adj.items() - else: - nodes_nbrs = ((n, G[n]) for n in G.nbunch_iter(nodes)) - - def wt(u, v): - return G[u][v].get(weight, 1) / max_weight - - for i, nbrs in nodes_nbrs: - inbrs = set(nbrs) - {i} - weighted_triangles = 0 - seen = set() - for j in inbrs: - seen.add(j) - # This prevents double counting. - jnbrs = set(G[j]) - seen - # Only compute the edge weight once, before the inner inner - # loop. - wij = wt(i, j) - weighted_triangles += sum((wij * wt(j, k) * wt(k, i)) ** (1 / 3) - for k in inbrs & jnbrs) - yield (i, len(inbrs), 2 * weighted_triangles) - - -@not_implemented_for('multigraph') -def _directed_triangles_and_degree_iter(G, nodes=None): - """ Return an iterator of - (node, total_degree, reciprocal_degree, directed_triangles). - - Used for directed clustering. - - """ - nodes_nbrs = ((n, G._pred[n], G._succ[n]) for n in G.nbunch_iter(nodes)) - - for i, preds, succs in nodes_nbrs: - ipreds = set(preds) - {i} - isuccs = set(succs) - {i} - - directed_triangles = 0 - for j in chain(ipreds, isuccs): - jpreds = set(G._pred[j]) - {j} - jsuccs = set(G._succ[j]) - {j} - directed_triangles += sum((1 for k in - chain((ipreds & jpreds), - (ipreds & jsuccs), - (isuccs & jpreds), - (isuccs & jsuccs)))) - dtotal = len(ipreds) + len(isuccs) - dbidirectional = len(ipreds & isuccs) - yield (i, dtotal, dbidirectional, directed_triangles) - - -@not_implemented_for('multigraph') -def _directed_weighted_triangles_and_degree_iter(G, nodes=None, weight = 'weight'): - """ Return an iterator of - (node, total_degree, reciprocal_degree, directed_weighted_triangles). - - Used for directed weighted clustering. - - """ - if weight is None or G.number_of_edges() == 0: - max_weight = 1 - else: - max_weight = max(d.get(weight, 1) for u, v, d in G.edges(data=True)) - - nodes_nbrs = ((n, G._pred[n], G._succ[n]) for n in G.nbunch_iter(nodes)) - - def wt(u, v): - return G[u][v].get(weight, 1) / max_weight - - for i, preds, succs in nodes_nbrs: - ipreds = set(preds) - {i} - isuccs = set(succs) - {i} - - directed_triangles = 0 - for j in ipreds: - jpreds = set(G._pred[j]) - {j} - jsuccs = set(G._succ[j]) - {j} - directed_triangles += sum((wt(j, i) * wt(k, i) * wt(k, j))**(1 / 3) - for k in ipreds & jpreds) - directed_triangles += sum((wt(j, i) * wt(k, i) * wt(j, k))**(1 / 3) - for k in ipreds & jsuccs) - directed_triangles += sum((wt(j, i) * wt(i, k) * wt(k, j))**(1 / 3) - for k in isuccs & jpreds) - directed_triangles += sum((wt(j, i) * wt(i, k) * wt(j, k))**(1 / 3) - for k in isuccs & jsuccs) - - for j in isuccs: - jpreds = set(G._pred[j]) - {j} - jsuccs = set(G._succ[j]) - {j} - directed_triangles += sum((wt(i, j) * wt(k, i) * wt(k, j))**(1 / 3) - for k in ipreds & jpreds) - directed_triangles += sum((wt(i, j) * wt(k, i) * wt(j, k))**(1 / 3) - for k in ipreds & jsuccs) - directed_triangles += sum((wt(i, j) * wt(i, k) * wt(k, j))**(1 / 3) - for k in isuccs & jpreds) - directed_triangles += sum((wt(i, j) * wt(i, k) * wt(j, k))**(1 / 3) - for k in isuccs & jsuccs) - - dtotal = len(ipreds) + len(isuccs) - dbidirectional = len(ipreds & isuccs) - yield (i, dtotal, dbidirectional, directed_triangles) - - -def average_clustering(G, nodes=None, weight=None, count_zeros=True): - r"""Compute the average clustering coefficient for the graph G. - - The clustering coefficient for the graph is the average, - - .. math:: - - C = \frac{1}{n}\sum_{v \in G} c_v, - - where :math:`n` is the number of nodes in `G`. - - Parameters - ---------- - G : graph - - nodes : container of nodes, optional (default=all nodes in G) - Compute average clustering for nodes in this container. - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used as a weight. - If None, then each edge has weight 1. - - count_zeros : bool - If False include only the nodes with nonzero clustering in the average. - - Returns - ------- - avg : float - Average clustering - - Examples - -------- - >>> G=nx.complete_graph(5) - >>> print(nx.average_clustering(G)) - 1.0 - - Notes - ----- - This is a space saving routine; it might be faster - to use the clustering function to get a list and then take the average. - - Self loops are ignored. - - References - ---------- - .. [1] Generalizations of the clustering coefficient to weighted - complex networks by J. Saramäki, M. Kivelä, J.-P. Onnela, - K. Kaski, and J. Kertész, Physical Review E, 75 027105 (2007). - http://jponnela.com/web_documents/a9.pdf - .. [2] Marcus Kaiser, Mean clustering coefficients: the role of isolated - nodes and leafs on clustering measures for small-world networks. - https://arxiv.org/abs/0802.2512 - """ - c = clustering(G, nodes, weight=weight).values() - if not count_zeros: - c = [v for v in c if v > 0] - return sum(c) / len(c) - - -def clustering(G, nodes=None, weight=None): - r"""Compute the clustering coefficient for nodes. - - For unweighted graphs, the clustering of a node :math:`u` - is the fraction of possible triangles through that node that exist, - - .. math:: - - c_u = \frac{2 T(u)}{deg(u)(deg(u)-1)}, - - where :math:`T(u)` is the number of triangles through node :math:`u` and - :math:`deg(u)` is the degree of :math:`u`. - - For weighted graphs, there are several ways to define clustering [1]_. - the one used here is defined - as the geometric average of the subgraph edge weights [2]_, - - .. math:: - - c_u = \frac{1}{deg(u)(deg(u)-1))} - \sum_{vw} (\hat{w}_{uv} \hat{w}_{uw} \hat{w}_{vw})^{1/3}. - - The edge weights :math:`\hat{w}_{uv}` are normalized by the maximum weight - in the network :math:`\hat{w}_{uv} = w_{uv}/\max(w)`. - - The value of :math:`c_u` is assigned to 0 if :math:`deg(u) < 2`. - - For directed graphs, the clustering is similarly defined as the fraction - of all possible directed triangles or geometric average of the subgraph - edge weights for unweighted and weighted directed graph respectively [3]_. - - .. math:: - - c_u = \frac{1}{deg^{tot}(u)(deg^{tot}(u)-1) - 2deg^{\leftrightarrow}(u)} - T(u), - - where :math:`T(u)` is the number of directed triangles through node - :math:`u`, :math:`deg^{tot}(u)` is the sum of in degree and out degree of - :math:`u` and :math:`deg^{\leftrightarrow}(u)` is the reciprocal degree of - :math:`u`. - - Parameters - ---------- - G : graph - - nodes : container of nodes, optional (default=all nodes in G) - Compute clustering for nodes in this container. - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used as a weight. - If None, then each edge has weight 1. - - Returns - ------- - out : float, or dictionary - Clustering coefficient at specified nodes - - Examples - -------- - >>> G=nx.complete_graph(5) - >>> print(nx.clustering(G,0)) - 1.0 - >>> print(nx.clustering(G)) - {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0, 4: 1.0} - - Notes - ----- - Self loops are ignored. - - References - ---------- - .. [1] Generalizations of the clustering coefficient to weighted - complex networks by J. Saramäki, M. Kivelä, J.-P. Onnela, - K. Kaski, and J. Kertész, Physical Review E, 75 027105 (2007). - http://jponnela.com/web_documents/a9.pdf - .. [2] Intensity and coherence of motifs in weighted complex - networks by J. P. Onnela, J. Saramäki, J. Kertész, and K. Kaski, - Physical Review E, 71(6), 065103 (2005). - .. [3] Clustering in complex directed networks by G. Fagiolo, - Physical Review E, 76(2), 026107 (2007). - """ - if G.is_directed(): - if weight is not None: - td_iter = _directed_weighted_triangles_and_degree_iter( - G, nodes, weight) - clusterc = {v: 0 if t == 0 else t / ((dt * (dt - 1) - 2 * db) * 2) - for v, dt, db, t in td_iter} - else: - td_iter = _directed_triangles_and_degree_iter(G, nodes) - clusterc = {v: 0 if t == 0 else t / ((dt * (dt - 1) - 2 * db) * 2) - for v, dt, db, t in td_iter} - else: - if weight is not None: - td_iter = _weighted_triangles_and_degree_iter(G, nodes, weight) - clusterc = {v: 0 if t == 0 else t / (d * (d - 1)) for - v, d, t in td_iter} - else: - td_iter = _triangles_and_degree_iter(G, nodes) - clusterc = {v: 0 if t == 0 else t / (d * (d - 1)) for - v, d, t, _ in td_iter} - if nodes in G: - # Return the value of the sole entry in the dictionary. - return clusterc[nodes] - return clusterc - - -def transitivity(G): - r"""Compute graph transitivity, the fraction of all possible triangles - present in G. - - Possible triangles are identified by the number of "triads" - (two edges with a shared vertex). - - The transitivity is - - .. math:: - - T = 3\frac{\#triangles}{\#triads}. - - Parameters - ---------- - G : graph - - Returns - ------- - out : float - Transitivity - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> print(nx.transitivity(G)) - 1.0 - """ - triangles = sum(t for v, d, t, _ in _triangles_and_degree_iter(G)) - contri = sum(d * (d - 1) for v, d, t, _ in _triangles_and_degree_iter(G)) - return 0 if triangles == 0 else triangles / contri - - -def square_clustering(G, nodes=None): - r""" Compute the squares clustering coefficient for nodes. - - For each node return the fraction of possible squares that exist at - the node [1]_ - - .. math:: - C_4(v) = \frac{ \sum_{u=1}^{k_v} - \sum_{w=u+1}^{k_v} q_v(u,w) }{ \sum_{u=1}^{k_v} - \sum_{w=u+1}^{k_v} [a_v(u,w) + q_v(u,w)]}, - - where :math:`q_v(u,w)` are the number of common neighbors of :math:`u` and - :math:`w` other than :math:`v` (ie squares), and :math:`a_v(u,w) = (k_u - - (1+q_v(u,w)+\theta_{uv}))(k_w - (1+q_v(u,w)+\theta_{uw}))`, where - :math:`\theta_{uw} = 1` if :math:`u` and :math:`w` are connected and 0 - otherwise. - - Parameters - ---------- - G : graph - - nodes : container of nodes, optional (default=all nodes in G) - Compute clustering for nodes in this container. - - Returns - ------- - c4 : dictionary - A dictionary keyed by node with the square clustering coefficient value. - - Examples - -------- - >>> G=nx.complete_graph(5) - >>> print(nx.square_clustering(G,0)) - 1.0 - >>> print(nx.square_clustering(G)) - {0: 1.0, 1: 1.0, 2: 1.0, 3: 1.0, 4: 1.0} - - Notes - ----- - While :math:`C_3(v)` (triangle clustering) gives the probability that - two neighbors of node v are connected with each other, :math:`C_4(v)` is - the probability that two neighbors of node v share a common - neighbor different from v. This algorithm can be applied to both - bipartite and unipartite networks. - - References - ---------- - .. [1] Pedro G. Lind, Marta C. González, and Hans J. Herrmann. 2005 - Cycles and clustering in bipartite networks. - Physical Review E (72) 056127. - """ - if nodes is None: - node_iter = G - else: - node_iter = G.nbunch_iter(nodes) - clustering = {} - for v in node_iter: - clustering[v] = 0 - potential = 0 - for u, w in combinations(G[v], 2): - squares = len((set(G[u]) & set(G[w])) - set([v])) - clustering[v] += squares - degm = squares + 1 - if w in G[u]: - degm += 1 - potential += (len(G[u]) - degm) * (len(G[w]) - degm) + squares - if potential > 0: - clustering[v] /= potential - if nodes in G: - # Return the value of the sole entry in the dictionary. - return clustering[nodes] - return clustering - - -@not_implemented_for('directed') -def generalized_degree(G, nodes=None): - r""" Compute the generalized degree for nodes. - - For each node, the generalized degree shows how many edges of given - triangle multiplicity the node is connected to. The triangle multiplicity - of an edge is the number of triangles an edge participates in. The - generalized degree of node :math:`i` can be written as a vector - :math:`\mathbf{k}_i=(k_i^{(0)}, \dotsc, k_i^{(N-2)})` where - :math:`k_i^{(j)}` is the number of edges attached to node :math:`i` that - participate in :math:`j` triangles. - - Parameters - ---------- - G : graph - - nodes : container of nodes, optional (default=all nodes in G) - Compute the generalized degree for nodes in this container. - - Returns - ------- - out : Counter, or dictionary of Counters - Generalized degree of specified nodes. The Counter is keyed by edge - triangle multiplicity. - - Examples - -------- - >>> G=nx.complete_graph(5) - >>> print(nx.generalized_degree(G,0)) - Counter({3: 4}) - >>> print(nx.generalized_degree(G)) - {0: Counter({3: 4}), 1: Counter({3: 4}), 2: Counter({3: 4}), 3: Counter({3: 4}), 4: Counter({3: 4})} - - To recover the number of triangles attached to a node: - - >>> k1 = nx.generalized_degree(G,0) - >>> sum([k*v for k,v in k1.items()])/2 == nx.triangles(G,0) - True - - Notes - ----- - In a network of N nodes, the highest triangle multiplicty an edge can have - is N-2. - - The return value does not include a `zero` entry if no edges of a - particular triangle multiplicity are present. - - The number of triangles node :math:`i` is attached to can be recovered from - the generalized degree :math:`\mathbf{k}_i=(k_i^{(0)}, \dotsc, - k_i^{(N-2)})` by :math:`(k_i^{(1)}+2k_i^{(2)}+\dotsc +(N-2)k_i^{(N-2)})/2`. - - References - ---------- - .. [1] Networks with arbitrary edge multiplicities by V. Zlatić, - D. Garlaschelli and G. Caldarelli, EPL (Europhysics Letters), - Volume 97, Number 2 (2012). - https://iopscience.iop.org/article/10.1209/0295-5075/97/28005 - """ - if nodes in G: - return next(_triangles_and_degree_iter(G, nodes))[3] - return {v: gd for v, d, t, gd in _triangles_and_degree_iter(G, nodes)} diff --git a/extensions/fablabchemnitz/networkx/algorithms/coloring/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/coloring/__init__.py deleted file mode 100644 index 69b082ff..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/coloring/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from networkx.algorithms.coloring.greedy_coloring import * -from networkx.algorithms.coloring.equitable_coloring import equitable_color -__all__ = ['greedy_color', 'equitable_color'] diff --git a/extensions/fablabchemnitz/networkx/algorithms/coloring/equitable_coloring.py b/extensions/fablabchemnitz/networkx/algorithms/coloring/equitable_coloring.py deleted file mode 100644 index 9e737a75..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/coloring/equitable_coloring.py +++ /dev/null @@ -1,474 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2018 by -# Utkarsh Upadhyay -# All rights reserved. -# BSD license. -""" -Equitable coloring of graphs with bounded degree. -""" - -import networkx as nx -from collections import defaultdict - -__all__ = ['equitable_color'] - - -def is_coloring(G, coloring): - """Determine if the coloring is a valid coloring for the graph G.""" - # Verify that the coloring is valid. - for (s, d) in G.edges: - if coloring[s] == coloring[d]: - return False - return True - - -def is_equitable(G, coloring, num_colors=None): - """Determines if the coloring is valid and equitable for the graph G.""" - - if not is_coloring(G, coloring): - return False - - # Verify whether it is equitable. - color_set_size = defaultdict(int) - for color in coloring.values(): - color_set_size[color] += 1 - - if num_colors is not None: - for color in range(num_colors): - if color not in color_set_size: - # These colors do not have any vertices attached to them. - color_set_size[color] = 0 - - # If there are more than 2 distinct values, the coloring cannot be equitable - all_set_sizes = set(color_set_size.values()) - if len(all_set_sizes) == 0 and num_colors is None: # Was an empty graph - return True - elif len(all_set_sizes) == 1: - return True - elif len(all_set_sizes) == 2: - a, b = list(all_set_sizes) - return abs(a - b) <= 1 - else: # len(all_set_sizes) > 2: - return False - - -def make_C_from_F(F): - C = defaultdict(lambda: []) - for node, color in F.items(): - C[color].append(node) - - return C - - -def make_N_from_L_C(L, C): - nodes = L.keys() - colors = C.keys() - return {(node, color): sum(1 for v in L[node] if v in C[color]) - for node in nodes for color in colors} - - -def make_H_from_C_N(C, N): - return {(c1, c2): sum(1 for node in C[c1] if N[(node, c2)] == 0) - for c1 in C.keys() for c2 in C.keys()} - - -def change_color(u, X, Y, N, H, F, C, L): - """Change the color of 'u' from X to Y and update N, H, F, C.""" - assert F[u] == X and X != Y - - # Change the class of 'u' from X to Y - F[u] = Y - - for k in C.keys(): - # 'u' witnesses an edge from k -> Y instead of from k -> X now. - if N[u, k] == 0: - H[(X, k)] -= 1 - H[(Y, k)] += 1 - - for v in L[u]: - # 'v' has lost a neighbor in X and gained one in Y - N[(v, X)] -= 1 - N[(v, Y)] += 1 - - if N[(v, X)] == 0: - # 'v' witnesses F[v] -> X - H[(F[v], X)] += 1 - - if N[(v, Y)] == 1: - # 'v' no longer witnesses F[v] -> Y - H[(F[v], Y)] -= 1 - - C[X].remove(u) - C[Y].append(u) - - -def move_witnesses(src_color, dst_color, N, H, F, C, T_cal, L): - """Move witness along a path from src_color to dst_color.""" - X = src_color - while X != dst_color: - Y = T_cal[X] - # Move _any_ witness from X to Y = T_cal[X] - w = [x for x in C[X] if N[(x, Y)] == 0][0] - change_color(w, X, Y, N=N, H=H, F=F, C=C, L=L) - X = Y - - -def pad_graph(G, num_colors): - """Add a disconnected complete clique K_p such that the number of nodes in - the graph becomes a multiple of `num_colors`. - - Assumes that the graph's nodes are labelled using integers. - - Returns the number of nodes with each color. - """ - - n_ = len(G) - r = num_colors - 1 - - # Ensure that the number of nodes in G is a multiple of (r + 1) - s = n_ // (r + 1) - if n_ != s * (r + 1): - p = (r + 1) - n_ % (r + 1) - s += 1 - - # Complete graph K_p between (imaginary) nodes [n_, ... , n_ + p] - K = nx.relabel_nodes(nx.complete_graph(p), - {idx: idx + n_ for idx in range(p)}) - G.add_edges_from(K.edges) - - return s - - -def procedure_P(V_minus, V_plus, N, H, F, C, L, excluded_colors=None): - """Procedure P as described in the paper.""" - - if excluded_colors is None: - excluded_colors = set() - - A_cal = set() - T_cal = {} - R_cal = [] - - # BFS to determine A_cal, i.e. colors reachable from V- - reachable = [V_minus] - marked = set(reachable) - idx = 0 - - while idx < len(reachable): - pop = reachable[idx] - idx += 1 - - A_cal.add(pop) - R_cal.append(pop) - - # TODO: Checking whether a color has been visited can be made faster by - # using a look-up table instead of testing for membership in a set by a - # logarithmic factor. - next_layer = [] - for k in C.keys(): - if H[(k, pop)] > 0 and \ - k not in A_cal and \ - k not in excluded_colors and \ - k not in marked: - next_layer.append(k) - - for dst in next_layer: - # Record that `dst` can reach `pop` - T_cal[dst] = pop - - marked.update(next_layer) - reachable.extend(next_layer) - - # Variables for the algorithm - b = (len(C) - len(A_cal)) - - if V_plus in A_cal: - # Easy case: V+ is in A_cal - # Move one node from V+ to V- using T_cal to find the parents. - move_witnesses(V_plus, V_minus, N=N, H=H, F=F, C=C, T_cal=T_cal, L=L) - else: - # If there is a solo edge, we can resolve the situation by - # moving witnesses from B to A, making G[A] equitable and then - # recursively balancing G[B - w] with a different V_minus and - # but the same V_plus. - - A_0 = set() - A_cal_0 = set() - num_terminal_sets_found = 0 - made_equitable = False - - for W_1 in R_cal[::-1]: - - for v in C[W_1]: - X = None - - for U in C.keys(): - if N[(v, U)] == 0 and U in A_cal and U != W_1: - X = U - - # v does not witness an edge in H[A_cal] - if X is None: - continue - - for U in C.keys(): - # Note: Departing from the paper here. - if N[(v, U)] >= 1 and U not in A_cal: - X_prime = U - w = v - - # Finding the solo neighbor of w in X_prime - y_candidates = [node for node in L[w] - if F[node] == X_prime and N[(node, W_1)] == 1] - - if len(y_candidates) > 0: - y = y_candidates[0] - W = W_1 - - # Move w from W to X, now X has one extra node. - change_color(w, W, X, N=N, H=H, F=F, C=C, L=L) - - # Move witness from X to V_minus, making the coloring - # equitable. - move_witnesses(src_color=X, dst_color=V_minus, - N=N, H=H, F=F, C=C, T_cal=T_cal, L=L) - - # Move y from X_prime to W, making W the correct size. - change_color(y, X_prime, W, N=N, H=H, F=F, C=C, L=L) - - # Then call the procedure on G[B - y] - procedure_P(V_minus=X_prime, V_plus=V_plus, - N=N, H=H, C=C, F=F, L=L, - excluded_colors=excluded_colors.union(A_cal)) - made_equitable = True - break - - if made_equitable: - break - else: - # No node in W_1 was found such that - # it had a solo-neighbor. - A_cal_0.add(W_1) - A_0.update(C[W_1]) - num_terminal_sets_found += 1 - - if num_terminal_sets_found == b: - # Otherwise, construct the maximal independent set and find - # a pair of z_1, z_2 as in Case II. - - # BFS to determine B_cal': the set of colors reachable from V+ - B_cal_prime = set() - T_cal_prime = {} - - reachable = [V_plus] - marked = set(reachable) - idx = 0 - while idx < len(reachable): - pop = reachable[idx] - idx += 1 - - B_cal_prime.add(pop) - - # No need to check for excluded_colors here because - # they only exclude colors from A_cal - next_layer = [k for k in C.keys() - if H[(pop, k)] > 0 and - k not in B_cal_prime and - k not in marked] - - for dst in next_layer: - T_cal_prime[pop] = dst - - marked.update(next_layer) - reachable.extend(next_layer) - - # Construct the independent set of G[B'] - I_set = set() - I_covered = set() - W_covering = {} - - B_prime = [node for k in B_cal_prime for node in C[k]] - - # Add the nodes in V_plus to I first. - for z in C[V_plus] + B_prime: - if z in I_covered or F[z] not in B_cal_prime: - continue - - I_set.add(z) - I_covered.add(z) - I_covered.update([nbr for nbr in L[z]]) - - for w in L[z]: - if F[w] in A_cal_0 and N[(z, F[w])] == 1: - if w not in W_covering: - W_covering[w] = z - else: - # Found z1, z2 which have the same solo - # neighbor in some W - z_1 = W_covering[w] - # z_2 = z - - Z = F[z_1] - W = F[w] - - # shift nodes along W, V- - move_witnesses(W, V_minus, - N=N, H=H, F=F, C=C, - T_cal=T_cal, L=L) - - # shift nodes along V+ to Z - move_witnesses(V_plus, Z, - N=N, H=H, F=F, C=C, - T_cal=T_cal_prime, L=L) - - # change color of z_1 to W - change_color(z_1, Z, W, - N=N, H=H, F=F, C=C, L=L) - - # change color of w to some color in B_cal - W_plus = [k for k in C.keys() - if N[(w, k)] == 0 and - k not in A_cal][0] - change_color(w, W, W_plus, - N=N, H=H, F=F, C=C, L=L) - - # recurse with G[B \cup W*] - excluded_colors.update([ - k for k in C.keys() - if k != W and k not in B_cal_prime - ]) - procedure_P(V_minus=W, V_plus=W_plus, - N=N, H=H, C=C, F=F, L=L, - excluded_colors=excluded_colors) - - made_equitable = True - break - - if made_equitable: - break - else: - assert False, "Must find a w which is the solo neighbor " \ - "of two vertices in B_cal_prime." - - if made_equitable: - break - - -def equitable_color(G, num_colors): - """Provides equitable (r + 1)-coloring for nodes of G in O(r * n^2) time - if deg(G) <= r. The algorithm is described in [1]_. - - Attempts to color a graph using r colors, where no neighbors of a node - can have same color as the node itself and the number of nodes with each - color differ by at most 1. - - Parameters - ---------- - G : networkX graph - The nodes of this graph will be colored. - - num_colors : number of colors to use - This number must be at least one more than the maximum degree of nodes - in the graph. - - Returns - ------- - A dictionary with keys representing nodes and values representing - corresponding coloring. - - Examples - -------- - >>> G = nx.cycle_graph(4) - >>> d = nx.coloring.equitable_color(G, num_colors=3) - >>> nx.algorithms.coloring.equitable_coloring.is_equitable(G, d) - True - - Raises - ------ - NetworkXAlgorithmError - If the maximum degree of the graph ``G`` is greater than - ``num_colors``. - - References - ---------- - .. [1] Kierstead, H. A., Kostochka, A. V., Mydlarz, M., & Szemerédi, E. - (2010). A fast algorithm for equitable coloring. Combinatorica, 30(2), - 217-224. - """ - - # Map nodes to integers for simplicity later. - nodes_to_int = {} - int_to_nodes = {} - - for idx, node in enumerate(G.nodes): - nodes_to_int[node] = idx - int_to_nodes[idx] = node - - G = nx.relabel_nodes(G, nodes_to_int, copy=True) - - # Basic graph statistics and sanity check. - if len(G.nodes) > 0: - r_ = max([G.degree(node) for node in G.nodes]) - else: - r_ = 0 - - if r_ >= num_colors: - raise nx.NetworkXAlgorithmError( - 'Graph has maximum degree {}, needs {} (> {}) colors for guaranteed coloring.' - .format(r_, r_ + 1, num_colors) - ) - - # Ensure that the number of nodes in G is a multiple of (r + 1) - pad_graph(G, num_colors) - - # Starting the algorithm. - # L = {node: list(G.neighbors(node)) for node in G.nodes} - L_ = {node: [] for node in G.nodes} - - # Arbitrary equitable allocation of colors to nodes. - F = {node: idx % num_colors for idx, node in enumerate(G.nodes)} - - C = make_C_from_F(F) - - # The neighborhood is empty initially. - N = make_N_from_L_C(L_, C) - - # Currently all nodes witness all edges. - H = make_H_from_C_N(C, N) - - # Start of algorithm. - edges_seen = set() - - for u in sorted(G.nodes): - for v in sorted(G.neighbors(u)): - - # Do not double count edges if (v, u) has already been seen. - if (v, u) in edges_seen: - continue - - edges_seen.add((u, v)) - - L_[u].append(v) - L_[v].append(u) - - N[(u, F[v])] += 1 - N[(v, F[u])] += 1 - - if F[u] != F[v]: - # Were 'u' and 'v' witnesses for F[u] -> F[v] or F[v] -> F[u]? - if N[(u, F[v])] == 1: - H[F[u], F[v]] -= 1 # u cannot witness an edge between F[u], F[v] - - if N[(v, F[u])] == 1: - H[F[v], F[u]] -= 1 # v cannot witness an edge between F[v], F[u] - - if N[(u, F[u])] != 0: - # Find the first color where 'u' does not have any neighbors. - Y = [k for k in C.keys() if N[(u, k)] == 0][0] - X = F[u] - change_color(u, X, Y, N=N, H=H, F=F, C=C, L=L_) - - # Procedure P - procedure_P(V_minus=X, V_plus=Y, - N=N, H=H, F=F, C=C, L=L_) - - return {int_to_nodes[x]: F[x] for x in int_to_nodes} diff --git a/extensions/fablabchemnitz/networkx/algorithms/coloring/greedy_coloring.py b/extensions/fablabchemnitz/networkx/algorithms/coloring/greedy_coloring.py deleted file mode 100644 index c8319bf1..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/coloring/greedy_coloring.py +++ /dev/null @@ -1,362 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2014 by -# Christian Olsson -# Jan Aagaard Meier -# Henrik Haugbølle -# Arya McCarthy -# All rights reserved. -# BSD license. -""" -Greedy graph coloring using various strategies. -""" -from collections import defaultdict, deque -import itertools - -import networkx as nx -from networkx.utils import arbitrary_element -from networkx.utils import py_random_state -from . import greedy_coloring_with_interchange as _interchange - -__all__ = ['greedy_color', 'strategy_connected_sequential', - 'strategy_connected_sequential_bfs', - 'strategy_connected_sequential_dfs', 'strategy_independent_set', - 'strategy_largest_first', 'strategy_random_sequential', - 'strategy_saturation_largest_first', 'strategy_smallest_last'] - - -def strategy_largest_first(G, colors): - """Returns a list of the nodes of ``G`` in decreasing order by - degree. - - ``G`` is a NetworkX graph. ``colors`` is ignored. - - """ - return sorted(G, key=G.degree, reverse=True) - - -@py_random_state(2) -def strategy_random_sequential(G, colors, seed=None): - """Returns a random permutation of the nodes of ``G`` as a list. - - ``G`` is a NetworkX graph. ``colors`` is ignored. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - """ - nodes = list(G) - seed.shuffle(nodes) - return nodes - - -def strategy_smallest_last(G, colors): - """Returns a deque of the nodes of ``G``, "smallest" last. - - Specifically, the degrees of each node are tracked in a bucket queue. - From this, the node of minimum degree is repeatedly popped from the - graph, updating its neighbors' degrees. - - ``G`` is a NetworkX graph. ``colors`` is ignored. - - This implementation of the strategy runs in $O(n + m)$ time - (ignoring polylogarithmic factors), where $n$ is the number of nodes - and $m$ is the number of edges. - - This strategy is related to :func:`strategy_independent_set`: if we - interpret each node removed as an independent set of size one, then - this strategy chooses an independent set of size one instead of a - maximal independent set. - - """ - H = G.copy() - result = deque() - - # Build initial degree list (i.e. the bucket queue data structure) - degrees = defaultdict(set) # set(), for fast random-access removals - lbound = float('inf') - for node, d in H.degree(): - degrees[d].add(node) - lbound = min(lbound, d) # Lower bound on min-degree. - - def find_min_degree(): - # Save time by starting the iterator at `lbound`, not 0. - # The value that we find will be our new `lbound`, which we set later. - return next(d for d in itertools.count(lbound) if d in degrees) - - for _ in G: - # Pop a min-degree node and add it to the list. - min_degree = find_min_degree() - u = degrees[min_degree].pop() - if not degrees[min_degree]: # Clean up the degree list. - del degrees[min_degree] - result.appendleft(u) - - # Update degrees of removed node's neighbors. - for v in H[u]: - degree = H.degree(v) - degrees[degree].remove(v) - if not degrees[degree]: # Clean up the degree list. - del degrees[degree] - degrees[degree - 1].add(v) - - # Finally, remove the node. - H.remove_node(u) - lbound = min_degree - 1 # Subtract 1 in case of tied neighbors. - - return result - - -def _maximal_independent_set(G): - """Returns a maximal independent set of nodes in ``G`` by repeatedly - choosing an independent node of minimum degree (with respect to the - subgraph of unchosen nodes). - - """ - result = set() - remaining = set(G) - while remaining: - G = G.subgraph(remaining) - v = min(remaining, key=G.degree) - result.add(v) - remaining -= set(G[v]) | {v} - return result - - -def strategy_independent_set(G, colors): - """Uses a greedy independent set removal strategy to determine the - colors. - - This function updates ``colors`` **in-place** and return ``None``, - unlike the other strategy functions in this module. - - This algorithm repeatedly finds and removes a maximal independent - set, assigning each node in the set an unused color. - - ``G`` is a NetworkX graph. - - This strategy is related to :func:`strategy_smallest_last`: in that - strategy, an independent set of size one is chosen at each step - instead of a maximal independent set. - - """ - remaining_nodes = set(G) - while len(remaining_nodes) > 0: - nodes = _maximal_independent_set(G.subgraph(remaining_nodes)) - remaining_nodes -= nodes - for v in nodes: - yield v - - -def strategy_connected_sequential_bfs(G, colors): - """Returns an iterable over nodes in ``G`` in the order given by a - breadth-first traversal. - - The generated sequence has the property that for each node except - the first, at least one neighbor appeared earlier in the sequence. - - ``G`` is a NetworkX graph. ``colors`` is ignored. - - """ - return strategy_connected_sequential(G, colors, 'bfs') - - -def strategy_connected_sequential_dfs(G, colors): - """Returns an iterable over nodes in ``G`` in the order given by a - depth-first traversal. - - The generated sequence has the property that for each node except - the first, at least one neighbor appeared earlier in the sequence. - - ``G`` is a NetworkX graph. ``colors`` is ignored. - - """ - return strategy_connected_sequential(G, colors, 'dfs') - - -def strategy_connected_sequential(G, colors, traversal='bfs'): - """Returns an iterable over nodes in ``G`` in the order given by a - breadth-first or depth-first traversal. - - ``traversal`` must be one of the strings ``'dfs'`` or ``'bfs'``, - representing depth-first traversal or breadth-first traversal, - respectively. - - The generated sequence has the property that for each node except - the first, at least one neighbor appeared earlier in the sequence. - - ``G`` is a NetworkX graph. ``colors`` is ignored. - - """ - if traversal == 'bfs': - traverse = nx.bfs_edges - elif traversal == 'dfs': - traverse = nx.dfs_edges - else: - raise nx.NetworkXError("Please specify one of the strings 'bfs' or" - " 'dfs' for connected sequential ordering") - for component in nx.connected_components(G): - source = arbitrary_element(component) - # Yield the source node, then all the nodes in the specified - # traversal order. - yield source - for (_, end) in traverse(G.subgraph(component), source): - yield end - - -def strategy_saturation_largest_first(G, colors): - """Iterates over all the nodes of ``G`` in "saturation order" (also - known as "DSATUR"). - - ``G`` is a NetworkX graph. ``colors`` is a dictionary mapping nodes of - ``G`` to colors, for those nodes that have already been colored. - - """ - distinct_colors = {v: set() for v in G} - for i in range(len(G)): - # On the first time through, simply choose the node of highest degree. - if i == 0: - node = max(G, key=G.degree) - yield node - # Add the color 0 to the distinct colors set for each - # neighbors of that node. - for v in G[node]: - distinct_colors[v].add(0) - else: - # Compute the maximum saturation and the set of nodes that - # achieve that saturation. - saturation = {v: len(c) for v, c in distinct_colors.items() - if v not in colors} - # Yield the node with the highest saturation, and break ties by - # degree. - node = max(saturation, key=lambda v: (saturation[v], G.degree(v))) - yield node - # Update the distinct color sets for the neighbors. - color = colors[node] - for v in G[node]: - distinct_colors[v].add(color) - - -#: Dictionary mapping name of a strategy as a string to the strategy function. -STRATEGIES = { - 'largest_first': strategy_largest_first, - 'random_sequential': strategy_random_sequential, - 'smallest_last': strategy_smallest_last, - 'independent_set': strategy_independent_set, - 'connected_sequential_bfs': strategy_connected_sequential_bfs, - 'connected_sequential_dfs': strategy_connected_sequential_dfs, - 'connected_sequential': strategy_connected_sequential, - 'saturation_largest_first': strategy_saturation_largest_first, - 'DSATUR': strategy_saturation_largest_first, -} - - -def greedy_color(G, strategy='largest_first', interchange=False): - """Color a graph using various strategies of greedy graph coloring. - - Attempts to color a graph using as few colors as possible, where no - neighbours of a node can have same color as the node itself. The - given strategy determines the order in which nodes are colored. - - The strategies are described in [1]_, and smallest-last is based on - [2]_. - - Parameters - ---------- - G : NetworkX graph - - strategy : string or function(G, colors) - A function (or a string representing a function) that provides - the coloring strategy, by returning nodes in the ordering they - should be colored. ``G`` is the graph, and ``colors`` is a - dictionary of the currently assigned colors, keyed by nodes. The - function must return an iterable over all the nodes in ``G``. - - If the strategy function is an iterator generator (that is, a - function with ``yield`` statements), keep in mind that the - ``colors`` dictionary will be updated after each ``yield``, since - this function chooses colors greedily. - - If ``strategy`` is a string, it must be one of the following, - each of which represents one of the built-in strategy functions. - - * ``'largest_first'`` - * ``'random_sequential'`` - * ``'smallest_last'`` - * ``'independent_set'`` - * ``'connected_sequential_bfs'`` - * ``'connected_sequential_dfs'`` - * ``'connected_sequential'`` (alias for the previous strategy) - * ``'saturation_largest_first'`` - * ``'DSATUR'`` (alias for the previous strategy) - - interchange: bool - Will use the color interchange algorithm described by [3]_ if set - to ``True``. - - Note that ``saturation_largest_first`` and ``independent_set`` - do not work with interchange. Furthermore, if you use - interchange with your own strategy function, you cannot rely - on the values in the ``colors`` argument. - - Returns - ------- - A dictionary with keys representing nodes and values representing - corresponding coloring. - - Examples - -------- - >>> G = nx.cycle_graph(4) - >>> d = nx.coloring.greedy_color(G, strategy='largest_first') - >>> d in [{0: 0, 1: 1, 2: 0, 3: 1}, {0: 1, 1: 0, 2: 1, 3: 0}] - True - - Raises - ------ - NetworkXPointlessConcept - If ``strategy`` is ``saturation_largest_first`` or - ``independent_set`` and ``interchange`` is ``True``. - - References - ---------- - .. [1] Adrian Kosowski, and Krzysztof Manuszewski, - Classical Coloring of Graphs, Graph Colorings, 2-19, 2004. - ISBN 0-8218-3458-4. - .. [2] David W. Matula, and Leland L. Beck, "Smallest-last - ordering and clustering and graph coloring algorithms." *J. ACM* 30, - 3 (July 1983), 417–427. - .. [3] Maciej M. Sysło, Marsingh Deo, Janusz S. Kowalik, - Discrete Optimization Algorithms with Pascal Programs, 415-424, 1983. - ISBN 0-486-45353-7. - - """ - if len(G) == 0: - return {} - # Determine the strategy provided by the caller. - strategy = STRATEGIES.get(strategy, strategy) - if not callable(strategy): - raise nx.NetworkXError('strategy must be callable or a valid string. ' - '{0} not valid.'.format(strategy)) - # Perform some validation on the arguments before executing any - # strategy functions. - if interchange: - if strategy is strategy_independent_set: - msg = 'interchange cannot be used with independent_set' - raise nx.NetworkXPointlessConcept(msg) - if strategy is strategy_saturation_largest_first: - msg = ('interchange cannot be used with' - ' saturation_largest_first') - raise nx.NetworkXPointlessConcept(msg) - colors = {} - nodes = strategy(G, colors) - if interchange: - return _interchange.greedy_coloring_with_interchange(G, nodes) - for u in nodes: - # Set to keep track of colors of neighbours - neighbour_colors = {colors[v] for v in G[u] if v in colors} - # Find the first unused color. - for color in itertools.count(): - if color not in neighbour_colors: - break - # Assign the new color to the current node. - colors[u] = color - return colors diff --git a/extensions/fablabchemnitz/networkx/algorithms/coloring/greedy_coloring_with_interchange.py b/extensions/fablabchemnitz/networkx/algorithms/coloring/greedy_coloring_with_interchange.py deleted file mode 100644 index 465590a0..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/coloring/greedy_coloring_with_interchange.py +++ /dev/null @@ -1,179 +0,0 @@ -import itertools - -__all__ = ['greedy_coloring_with_interchange'] - - -class Node(object): - - __slots__ = ['node_id', 'color', 'adj_list', 'adj_color'] - - def __init__(self, node_id, n): - self.node_id = node_id - self.color = -1 - self.adj_list = None - self.adj_color = [None for _ in range(n)] - - def __repr__(self): - return "Node_id: {0}, Color: {1}, Adj_list: ({2}), \ - adj_color: ({3})".format( - self.node_id, self.color, self.adj_list, self.adj_color) - - def assign_color(self, adj_entry, color): - adj_entry.col_prev = None - adj_entry.col_next = self.adj_color[color] - self.adj_color[color] = adj_entry - if adj_entry.col_next is not None: - adj_entry.col_next.col_prev = adj_entry - - def clear_color(self, adj_entry, color): - if adj_entry.col_prev is None: - self.adj_color[color] = adj_entry.col_next - else: - adj_entry.col_prev.col_next = adj_entry.col_next - if adj_entry.col_next is not None: - adj_entry.col_next.col_prev = adj_entry.col_prev - - def iter_neighbors(self): - adj_node = self.adj_list - while adj_node is not None: - yield adj_node - adj_node = adj_node.next - - def iter_neighbors_color(self, color): - adj_color_node = self.adj_color[color] - while adj_color_node is not None: - yield adj_color_node.node_id - adj_color_node = adj_color_node.col_next - - -class AdjEntry(object): - - __slots__ = ['node_id', 'next', 'mate', 'col_next', 'col_prev'] - - def __init__(self, node_id): - self.node_id = node_id - self.next = None - self.mate = None - self.col_next = None - self.col_prev = None - - def __repr__(self): - return "Node_id: {0}, Next: ({1}), Mate: ({2}), \ - col_next: ({3}), col_prev: ({4})".format( - self.node_id, - self.next, - self.mate.node_id, - None if self.col_next is None else self.col_next.node_id, - None if self.col_prev is None else self.col_prev.node_id - ) - - -def greedy_coloring_with_interchange(original_graph, nodes): - """ - This procedure is an adaption of the algorithm described by [1]_, - and is an implementation of coloring with interchange. Please be - advised, that the datastructures used are rather complex because - they are optimized to minimize the time spent identifying - subcomponents of the graph, which are possible candidates for color - interchange. - - References - ---------- - .. [1] Maciej M. Syslo, Marsingh Deo, Janusz S. Kowalik, - Discrete Optimization Algorithms with Pascal Programs, 415-424, 1983. - ISBN 0-486-45353-7. - """ - n = len(original_graph) - - graph = {node_id: Node(node_id, n) for node_id in original_graph} - - for (node1, node2) in original_graph.edges(): - adj_entry1 = AdjEntry(node2) - adj_entry2 = AdjEntry(node1) - adj_entry1.mate = adj_entry2 - adj_entry2.mate = adj_entry1 - node1_head = graph[node1].adj_list - adj_entry1.next = node1_head - graph[node1].adj_list = adj_entry1 - node2_head = graph[node2].adj_list - adj_entry2.next = node2_head - graph[node2].adj_list = adj_entry2 - - k = 0 - for node in nodes: - # Find the smallest possible, unused color - neighbors = graph[node].iter_neighbors() - col_used = {graph[adj_node.node_id].color for adj_node in neighbors} - col_used.discard(-1) - k1 = next(itertools.dropwhile( - lambda x: x in col_used, itertools.count())) - - # k1 is now the lowest available color - if k1 > k: - connected = True - visited = set() - col1 = -1 - col2 = -1 - while connected and col1 < k: - col1 += 1 - neighbor_cols = ( - graph[node].iter_neighbors_color(col1)) - col1_adj = [it for it in neighbor_cols] - - col2 = col1 - while connected and col2 < k: - col2 += 1 - visited = set(col1_adj) - frontier = list(col1_adj) - i = 0 - while i < len(frontier): - search_node = frontier[i] - i += 1 - col_opp = ( - col2 if graph[search_node].color == col1 else col1) - neighbor_cols = ( - graph[search_node].iter_neighbors_color(col_opp)) - - for neighbor in neighbor_cols: - if neighbor not in visited: - visited.add(neighbor) - frontier.append(neighbor) - - # Search if node is not adj to any col2 vertex - connected = len(visited.intersection( - graph[node].iter_neighbors_color(col2))) > 0 - - # If connected is false then we can swap !!! - if not connected: - # Update all the nodes in the component - for search_node in visited: - graph[search_node].color = ( - col2 if graph[search_node].color == col1 else col1) - col2_adj = graph[search_node].adj_color[col2] - graph[search_node].adj_color[col2] = ( - graph[search_node].adj_color[col1]) - graph[search_node].adj_color[col1] = col2_adj - - # Update all the neighboring nodes - for search_node in visited: - col = graph[search_node].color - col_opp = col1 if col == col2 else col2 - for adj_node in graph[search_node].iter_neighbors(): - if graph[adj_node.node_id].color != col_opp: - # Direct reference to entry - adj_mate = adj_node.mate - graph[adj_node.node_id].clear_color( - adj_mate, col_opp) - graph[adj_node.node_id].assign_color(adj_mate, col) - k1 = col1 - - # We can color this node color k1 - graph[node].color = k1 - k = max(k1, k) - - # Update the neighbors of this node - for adj_node in graph[node].iter_neighbors(): - adj_mate = adj_node.mate - graph[adj_node.node_id].assign_color(adj_mate, k1) - - return {node.node_id: node.color for node in graph.values()} diff --git a/extensions/fablabchemnitz/networkx/algorithms/coloring/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/coloring/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/coloring/tests/test_coloring.py b/extensions/fablabchemnitz/networkx/algorithms/coloring/tests/test_coloring.py deleted file mode 100644 index 77574b9e..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/coloring/tests/test_coloring.py +++ /dev/null @@ -1,717 +0,0 @@ -# -*- coding: utf-8 -*- -"""Greedy coloring test suite. - -""" - -__author__ = "\n".join(["Christian Olsson ", - "Jan Aagaard Meier ", - "Henrik Haugbølle ", - "Jake VanderPlas "]) - -import networkx as nx -import pytest - - -is_coloring = nx.algorithms.coloring.equitable_coloring.is_coloring -is_equitable = nx.algorithms.coloring.equitable_coloring.is_equitable - - -ALL_STRATEGIES = [ - 'largest_first', - 'random_sequential', - 'smallest_last', - 'independent_set', - 'connected_sequential_bfs', - 'connected_sequential_dfs', - 'connected_sequential', - 'saturation_largest_first', - 'DSATUR', -] - -# List of strategies where interchange=True results in an error -INTERCHANGE_INVALID = [ - 'independent_set', - 'saturation_largest_first', - 'DSATUR' -] - - -class TestColoring: - def test_basic_cases(self): - def check_basic_case(graph_func, n_nodes, strategy, interchange): - graph = graph_func() - coloring = nx.coloring.greedy_color(graph, - strategy=strategy, - interchange=interchange) - assert verify_length(coloring, n_nodes) - assert verify_coloring(graph, coloring) - - for graph_func, n_nodes in BASIC_TEST_CASES.items(): - for interchange in [True, False]: - for strategy in ALL_STRATEGIES: - check_basic_case(graph_func, n_nodes, strategy, False) - if strategy not in INTERCHANGE_INVALID: - check_basic_case(graph_func, n_nodes, strategy, True) - - def test_special_cases(self): - def check_special_case(strategy, graph_func, interchange, colors): - graph = graph_func() - coloring = nx.coloring.greedy_color(graph, - strategy=strategy, - interchange=interchange) - if not hasattr(colors, '__len__'): - colors = [colors] - assert any(verify_length(coloring, n_colors) - for n_colors in colors) - assert verify_coloring(graph, coloring) - - for strategy, arglist in SPECIAL_TEST_CASES.items(): - for args in arglist: - check_special_case(strategy, args[0], args[1], args[2]) - - def test_interchange_invalid(self): - graph = one_node_graph() - for strategy in INTERCHANGE_INVALID: - pytest.raises(nx.NetworkXPointlessConcept, - nx.coloring.greedy_color, - graph, strategy=strategy, interchange=True) - - def test_bad_inputs(self): - graph = one_node_graph() - pytest.raises(nx.NetworkXError, nx.coloring.greedy_color, - graph, strategy='invalid strategy') - - def test_strategy_as_function(self): - graph = lf_shc() - colors_1 = nx.coloring.greedy_color(graph, - 'largest_first') - colors_2 = nx.coloring.greedy_color(graph, - nx.coloring.strategy_largest_first) - assert colors_1 == colors_2 - - def test_seed_argument(self): - graph = lf_shc() - rs = nx.coloring.strategy_random_sequential - c1 = nx.coloring.greedy_color(graph, lambda g, c: rs(g, c, seed=1)) - for u, v in graph.edges: - assert c1[u] != c1[v] - - def test_is_coloring(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2)]) - coloring = {0: 0, 1: 1, 2: 0} - assert is_coloring(G, coloring) - - coloring[0] = 1 - assert not is_coloring(G, coloring) - assert not is_equitable(G, coloring) - - def test_is_equitable(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2)]) - coloring = {0: 0, 1: 1, 2: 0} - assert is_equitable(G, coloring) - - G.add_edges_from([(2, 3), (2, 4), (2, 5)]) - coloring[3] = 1 - coloring[4] = 1 - coloring[5] = 1 - assert is_coloring(G, coloring) - assert not is_equitable(G, coloring) - - def test_num_colors(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (0, 3)]) - pytest.raises(nx.NetworkXAlgorithmError, - nx.coloring.equitable_color, G, 2) - - def test_equitable_color(self): - G = nx.fast_gnp_random_graph(n=10, p=0.2, seed=42) - coloring = nx.coloring.equitable_color(G, max_degree(G) + 1) - assert is_equitable(G, coloring) - - def test_equitable_color_empty(self): - G = nx.empty_graph() - coloring = nx.coloring.equitable_color(G, max_degree(G) + 1) - assert is_equitable(G, coloring) - - def test_equitable_color_large(self): - G = nx.fast_gnp_random_graph(100, 0.1, seed=42) - coloring = nx.coloring.equitable_color(G, max_degree(G) + 1) - assert is_equitable(G, coloring, num_colors=max_degree(G) + 1) - - def test_case_V_plus_not_in_A_cal(self): - # Hand crafted case to avoid the easy case. - L = { - 0: [2, 5], - 1: [3, 4], - 2: [0, 8], - 3: [1, 7], - 4: [1, 6], - 5: [0, 6], - 6: [4, 5], - 7: [3], - 8: [2], - } - - F = { - # Color 0 - 0: 0, - 1: 0, - - # Color 1 - 2: 1, - 3: 1, - 4: 1, - 5: 1, - - # Color 2 - 6: 2, - 7: 2, - 8: 2, - } - - C = nx.algorithms.coloring.equitable_coloring.make_C_from_F(F) - N = nx.algorithms.coloring.equitable_coloring.make_N_from_L_C(L, C) - H = nx.algorithms.coloring.equitable_coloring.make_H_from_C_N(C, N) - - nx.algorithms.coloring.equitable_coloring.procedure_P( - V_minus=0, V_plus=1, N=N, H=H, F=F, C=C, L=L - ) - check_state(L=L, N=N, H=H, F=F, C=C) - - def test_cast_no_solo(self): - L = { - 0: [8, 9], - 1: [10, 11], - - 2: [8], - 3: [9], - 4: [10, 11], - - 5: [8], - 6: [9], - 7: [10, 11], - - 8: [0, 2, 5], - 9: [0, 3, 6], - 10: [1, 4, 7], - 11: [1, 4, 7], - } - - F = { - 0: 0, - 1: 0, - - 2: 2, - 3: 2, - 4: 2, - - 5: 3, - 6: 3, - 7: 3, - - 8: 1, - 9: 1, - 10: 1, - 11: 1, - } - - C = nx.algorithms.coloring.equitable_coloring.make_C_from_F(F) - N = nx.algorithms.coloring.equitable_coloring.make_N_from_L_C(L, C) - H = nx.algorithms.coloring.equitable_coloring.make_H_from_C_N(C, N) - - nx.algorithms.coloring.equitable_coloring.procedure_P( - V_minus=0, V_plus=1, N=N, H=H, F=F, C=C, L=L - ) - check_state(L=L, N=N, H=H, F=F, C=C) - - def test_hard_prob(self): - # Tests for two levels of recursion. - num_colors, s = 5, 5 - - G = nx.Graph() - G.add_edges_from( - [(0, 10), (0, 11), (0, 12), (0, 23), (10, 4), (10, 9), - (10, 20), (11, 4), (11, 8), (11, 16), (12, 9), (12, 22), - (12, 23), (23, 7), (1, 17), (1, 18), (1, 19), (1, 24), - (17, 5), (17, 13), (17, 22), (18, 5), (19, 5), (19, 6), - (19, 8), (24, 7), (24, 16), (2, 4), (2, 13), (2, 14), - (2, 15), (4, 6), (13, 5), (13, 21), (14, 6), (14, 15), - (15, 6), (15, 21), (3, 16), (3, 20), (3, 21), (3, 22), - (16, 8), (20, 8), (21, 9), (22, 7)] - ) - F = {node: node // s for node in range(num_colors * s)} - F[s - 1] = num_colors - 1 - - params = make_params_from_graph(G=G, F=F) - - nx.algorithms.coloring.equitable_coloring.procedure_P( - V_minus=0, V_plus=num_colors - 1, **params - ) - check_state(**params) - - def test_hardest_prob(self): - # Tests for two levels of recursion. - num_colors, s = 10, 4 - - G = nx.Graph() - G.add_edges_from( - [(0, 19), (0, 24), (0, 29), (0, 30), (0, 35), (19, 3), (19, 7), - (19, 9), (19, 15), (19, 21), (19, 24), (19, 30), (19, 38), - (24, 5), (24, 11), (24, 13), (24, 20), (24, 30), (24, 37), - (24, 38), (29, 6), (29, 10), (29, 13), (29, 15), (29, 16), - (29, 17), (29, 20), (29, 26), (30, 6), (30, 10), (30, 15), - (30, 22), (30, 23), (30, 39), (35, 6), (35, 9), (35, 14), - (35, 18), (35, 22), (35, 23), (35, 25), (35, 27), (1, 20), - (1, 26), (1, 31), (1, 34), (1, 38), (20, 4), (20, 8), (20, 14), - (20, 18), (20, 28), (20, 33), (26, 7), (26, 10), (26, 14), - (26, 18), (26, 21), (26, 32), (26, 39), (31, 5), (31, 8), - (31, 13), (31, 16), (31, 17), (31, 21), (31, 25), (31, 27), - (34, 7), (34, 8), (34, 13), (34, 18), (34, 22), (34, 23), - (34, 25), (34, 27), (38, 4), (38, 9), (38, 12), (38, 14), - (38, 21), (38, 27), (2, 3), (2, 18), (2, 21), (2, 28), (2, 32), - (2, 33), (2, 36), (2, 37), (2, 39), (3, 5), (3, 9), (3, 13), - (3, 22), (3, 23), (3, 25), (3, 27), (18, 6), (18, 11), (18, 15), - (18, 39), (21, 4), (21, 10), (21, 14), (21, 36), (28, 6), - (28, 10), (28, 14), (28, 16), (28, 17), (28, 25), (28, 27), - (32, 5), (32, 10), (32, 12), (32, 16), (32, 17), (32, 22), - (32, 23), (33, 7), (33, 10), (33, 12), (33, 16), (33, 17), - (33, 25), (33, 27), (36, 5), (36, 8), (36, 15), (36, 16), - (36, 17), (36, 25), (36, 27), (37, 5), (37, 11), (37, 15), - (37, 16), (37, 17), (37, 22), (37, 23), (39, 7), (39, 8), - (39, 15), (39, 22), (39, 23)] - ) - F = {node: node // s for node in range(num_colors * s)} - F[s - 1] = num_colors - 1 # V- = 0, V+ = num_colors - 1 - - params = make_params_from_graph(G=G, F=F) - - nx.algorithms.coloring.equitable_coloring.procedure_P( - V_minus=0, V_plus=num_colors - 1, **params - ) - check_state(**params) - - -# ############################ Utility functions ############################ -def verify_coloring(graph, coloring): - for node in graph.nodes(): - if node not in coloring: - return False - - color = coloring[node] - for neighbor in graph.neighbors(node): - if coloring[neighbor] == color: - return False - - return True - - -def verify_length(coloring, expected): - coloring = dict_to_sets(coloring) - return len(coloring) == expected - - -def dict_to_sets(colors): - if len(colors) == 0: - return [] - - k = max(colors.values()) + 1 - sets = [set() for _ in range(k)] - - for (node, color) in colors.items(): - sets[color].add(node) - - return sets - -# ############################ Graph Generation ############################ - - -def empty_graph(): - return nx.Graph() - - -def one_node_graph(): - graph = nx.Graph() - graph.add_nodes_from([1]) - return graph - - -def two_node_graph(): - graph = nx.Graph() - graph.add_nodes_from([1, 2]) - graph.add_edges_from([(1, 2)]) - return graph - - -def three_node_clique(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3]) - graph.add_edges_from([(1, 2), (1, 3), (2, 3)]) - return graph - - -def disconnected(): - graph = nx.Graph() - graph.add_edges_from([ - (1, 2), - (2, 3), - (4, 5), - (5, 6) - ]) - return graph - - -def rs_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4]) - graph.add_edges_from([ - (1, 2), - (2, 3), - (3, 4) - ]) - return graph - - -def slf_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7]) - graph.add_edges_from([ - (1, 2), - (1, 5), - (1, 6), - (2, 3), - (2, 7), - (3, 4), - (3, 7), - (4, 5), - (4, 6), - (5, 6) - ]) - return graph - - -def slf_hc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8]) - graph.add_edges_from([ - (1, 2), - (1, 3), - (1, 4), - (1, 5), - (2, 3), - (2, 4), - (2, 6), - (5, 7), - (5, 8), - (6, 7), - (6, 8), - (7, 8) - ]) - return graph - - -def lf_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6]) - graph.add_edges_from([ - (6, 1), - (1, 4), - (4, 3), - (3, 2), - (2, 5) - ]) - return graph - - -def lf_hc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7]) - graph.add_edges_from([ - (1, 7), - (1, 6), - (1, 3), - (1, 4), - (7, 2), - (2, 6), - (2, 3), - (2, 5), - (5, 3), - (5, 4), - (4, 3) - ]) - return graph - - -def sl_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6]) - graph.add_edges_from([ - (1, 2), - (1, 3), - (2, 3), - (1, 4), - (2, 5), - (3, 6), - (4, 5), - (4, 6), - (5, 6) - ]) - return graph - - -def sl_hc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8]) - graph.add_edges_from([ - (1, 2), - (1, 3), - (1, 5), - (1, 7), - (2, 3), - (2, 4), - (2, 8), - (8, 4), - (8, 6), - (8, 7), - (7, 5), - (7, 6), - (3, 4), - (4, 6), - (6, 5), - (5, 3) - ]) - return graph - - -def gis_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4]) - graph.add_edges_from([ - (1, 2), - (2, 3), - (3, 4) - ]) - return graph - - -def gis_hc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6]) - graph.add_edges_from([ - (1, 5), - (2, 5), - (3, 6), - (4, 6), - (5, 6) - ]) - return graph - - -def cs_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5]) - graph.add_edges_from([ - (1, 2), - (1, 5), - (2, 3), - (2, 4), - (2, 5), - (3, 4), - (4, 5) - ]) - return graph - - -def rsi_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6]) - graph.add_edges_from([ - (1, 2), - (1, 5), - (1, 6), - (2, 3), - (3, 4), - (4, 5), - (4, 6), - (5, 6) - ]) - return graph - - -def lfi_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7]) - graph.add_edges_from([ - (1, 2), - (1, 5), - (1, 6), - (2, 3), - (2, 7), - (3, 4), - (3, 7), - (4, 5), - (4, 6), - (5, 6) - ]) - return graph - - -def lfi_hc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8, 9]) - graph.add_edges_from([ - (1, 2), - (1, 5), - (1, 6), - (1, 7), - (2, 3), - (2, 8), - (2, 9), - (3, 4), - (3, 8), - (3, 9), - (4, 5), - (4, 6), - (4, 7), - (5, 6) - ]) - return graph - - -def sli_shc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7]) - graph.add_edges_from([ - (1, 2), - (1, 3), - (1, 5), - (1, 7), - (2, 3), - (2, 6), - (3, 4), - (4, 5), - (4, 6), - (5, 7), - (6, 7) - ]) - return graph - - -def sli_hc(): - graph = nx.Graph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8, 9]) - graph.add_edges_from([ - (1, 2), - (1, 3), - (1, 4), - (1, 5), - (2, 3), - (2, 7), - (2, 8), - (2, 9), - (3, 6), - (3, 7), - (3, 9), - (4, 5), - (4, 6), - (4, 8), - (4, 9), - (5, 6), - (5, 7), - (5, 8), - (6, 7), - (6, 9), - (7, 8), - (8, 9) - ]) - return graph - - -# -------------------------------------------------------------------------- -# Basic tests for all strategies -# For each basic graph function, specify the number of expected colors. -BASIC_TEST_CASES = {empty_graph: 0, - one_node_graph: 1, - two_node_graph: 2, - disconnected: 2, - three_node_clique: 3} - - -# -------------------------------------------------------------------------- -# Special test cases. Each strategy has a list of tuples of the form -# (graph function, interchange, valid # of colors) -SPECIAL_TEST_CASES = { - 'random_sequential': [ - (rs_shc, False, (2, 3)), - (rs_shc, True, 2), - (rsi_shc, True, (3, 4))], - 'saturation_largest_first': [ - (slf_shc, False, (3, 4)), - (slf_hc, False, 4)], - 'largest_first': [ - (lf_shc, False, (2, 3)), - (lf_hc, False, 4), - (lf_shc, True, 2), - (lf_hc, True, 3), - (lfi_shc, True, (3, 4)), - (lfi_hc, True, 4)], - 'smallest_last': [ - (sl_shc, False, (3, 4)), - (sl_hc, False, 5), - (sl_shc, True, 3), - (sl_hc, True, 4), - (sli_shc, True, (3, 4)), - (sli_hc, True, 5)], - 'independent_set': [ - (gis_shc, False, (2, 3)), - (gis_hc, False, 3)], - 'connected_sequential': [ - (cs_shc, False, (3, 4)), - (cs_shc, True, 3)], - 'connected_sequential_dfs': [ - (cs_shc, False, (3, 4))], -} - - -# -------------------------------------------------------------------------- -# Helper functions to test -# (graph function, interchange, valid # of colors) - - -def check_state(L, N, H, F, C): - s = len(C[0]) - num_colors = len(C.keys()) - - assert all(u in L[v] for u in L.keys() for v in L[u]) - assert all(F[u] != F[v] for u in L.keys() for v in L[u]) - assert all(len(L[u]) < num_colors for u in L.keys()) - assert all(len(C[x]) == s for x in C) - assert all(H[(c1, c2)] >= 0 for c1 in C.keys() for c2 in C.keys()) - assert all(N[(u, F[u])] == 0 for u in F.keys()) - - -def max_degree(G): - """Get the maximum degree of any node in G.""" - return max([G.degree(node) for node in G.nodes]) if len(G.nodes) > 0 else 0 - - -def make_params_from_graph(G, F): - """Returns {N, L, H, C} from the given graph.""" - num_nodes = len(G) - L = {u: [] for u in range(num_nodes)} - for (u, v) in G.edges: - L[u].append(v) - L[v].append(u) - - C = nx.algorithms.coloring.equitable_coloring.make_C_from_F(F) - N = nx.algorithms.coloring.equitable_coloring.make_N_from_L_C(L, C) - H = nx.algorithms.coloring.equitable_coloring.make_H_from_C_N(C, N) - - return { - 'N': N, - 'F': F, - 'C': C, - 'H': H, - 'L': L, - } diff --git a/extensions/fablabchemnitz/networkx/algorithms/communicability_alg.py b/extensions/fablabchemnitz/networkx/algorithms/communicability_alg.py deleted file mode 100644 index 2cd2a4ae..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/communicability_alg.py +++ /dev/null @@ -1,177 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Communicability. -""" -# Copyright (C) 2011 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# Previously coded as communicability centrality -# All rights reserved. -# BSD license. -import networkx as nx -from networkx.utils import * -__author__ = "\n".join(['Aric Hagberg (hagberg@lanl.gov)', - 'Franck Kalala (franckkalala@yahoo.fr']) -__all__ = ['communicability', - 'communicability_exp', - ] - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def communicability(G): - r"""Returns communicability between all pairs of nodes in G. - - The communicability between pairs of nodes in G is the sum of - closed walks of different lengths starting at node u and ending at node v. - - Parameters - ---------- - G: graph - - Returns - ------- - comm: dictionary of dictionaries - Dictionary of dictionaries keyed by nodes with communicability - as the value. - - Raises - ------ - NetworkXError - If the graph is not undirected and simple. - - See Also - -------- - communicability_exp: - Communicability between all pairs of nodes in G using spectral - decomposition. - communicability_betweenness_centrality: - Communicability betweeness centrality for each node in G. - - Notes - ----- - This algorithm uses a spectral decomposition of the adjacency matrix. - Let G=(V,E) be a simple undirected graph. Using the connection between - the powers of the adjacency matrix and the number of walks in the graph, - the communicability between nodes `u` and `v` based on the graph spectrum - is [1]_ - - .. math:: - C(u,v)=\sum_{j=1}^{n}\phi_{j}(u)\phi_{j}(v)e^{\lambda_{j}}, - - where `\phi_{j}(u)` is the `u\rm{th}` element of the `j\rm{th}` orthonormal - eigenvector of the adjacency matrix associated with the eigenvalue - `\lambda_{j}`. - - References - ---------- - .. [1] Ernesto Estrada, Naomichi Hatano, - "Communicability in complex networks", - Phys. Rev. E 77, 036111 (2008). - https://arxiv.org/abs/0707.0756 - - Examples - -------- - >>> G = nx.Graph([(0,1),(1,2),(1,5),(5,4),(2,4),(2,3),(4,3),(3,6)]) - >>> c = nx.communicability(G) - """ - import numpy - import scipy.linalg - nodelist = list(G) # ordering of nodes in matrix - A = nx.to_numpy_array(G, nodelist) - # convert to 0-1 matrix - A[A != 0.0] = 1 - w, vec = numpy.linalg.eigh(A) - expw = numpy.exp(w) - mapping = dict(zip(nodelist, range(len(nodelist)))) - c = {} - # computing communicabilities - for u in G: - c[u] = {} - for v in G: - s = 0 - p = mapping[u] - q = mapping[v] - for j in range(len(nodelist)): - s += vec[:, j][p] * vec[:, j][q] * expw[j] - c[u][v] = float(s) - return c - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def communicability_exp(G): - r"""Returns communicability between all pairs of nodes in G. - - Communicability between pair of node (u,v) of node in G is the sum of - closed walks of different lengths starting at node u and ending at node v. - - Parameters - ---------- - G: graph - - Returns - ------- - comm: dictionary of dictionaries - Dictionary of dictionaries keyed by nodes with communicability - as the value. - - Raises - ------ - NetworkXError - If the graph is not undirected and simple. - - See Also - -------- - communicability: - Communicability between pairs of nodes in G. - communicability_betweenness_centrality: - Communicability betweeness centrality for each node in G. - - Notes - ----- - This algorithm uses matrix exponentiation of the adjacency matrix. - - Let G=(V,E) be a simple undirected graph. Using the connection between - the powers of the adjacency matrix and the number of walks in the graph, - the communicability between nodes u and v is [1]_, - - .. math:: - C(u,v) = (e^A)_{uv}, - - where `A` is the adjacency matrix of G. - - References - ---------- - .. [1] Ernesto Estrada, Naomichi Hatano, - "Communicability in complex networks", - Phys. Rev. E 77, 036111 (2008). - https://arxiv.org/abs/0707.0756 - - Examples - -------- - >>> G = nx.Graph([(0,1),(1,2),(1,5),(5,4),(2,4),(2,3),(4,3),(3,6)]) - >>> c = nx.communicability_exp(G) - """ - import scipy.linalg - nodelist = list(G) # ordering of nodes in matrix - A = nx.to_numpy_array(G, nodelist) - # convert to 0-1 matrix - A[A != 0.0] = 1 - # communicability matrix - expA = scipy.linalg.expm(A) - mapping = dict(zip(nodelist, range(len(nodelist)))) - c = {} - for u in G: - c[u] = {} - for v in G: - c[u][v] = float(expA[mapping[u], mapping[v]]) - return c - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/community/__init__.py deleted file mode 100644 index be6f87af..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Functions for computing and measuring community structure. - -The functions in this class are not imported into the top-level -:mod:`networkx` namespace. You can access these functions by importing -the :mod:`networkx.algorithms.community` module, then accessing the -functions as attributes of ``community``. For example:: - - >>> import networkx as nx - >>> from networkx.algorithms import community - >>> G = nx.barbell_graph(5, 1) - >>> communities_generator = community.girvan_newman(G) - >>> top_level_communities = next(communities_generator) - >>> next_level_communities = next(communities_generator) - >>> sorted(map(sorted, next_level_communities)) - [[0, 1, 2, 3, 4], [5], [6, 7, 8, 9, 10]] - -""" -from networkx.algorithms.community.asyn_fluid import * -from networkx.algorithms.community.centrality import * -from networkx.algorithms.community.kclique import * -from networkx.algorithms.community.kernighan_lin import * -from networkx.algorithms.community.label_propagation import * -from networkx.algorithms.community.modularity_max import * -from networkx.algorithms.community.quality import * -from networkx.algorithms.community.community_utils import * diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/asyn_fluid.py b/extensions/fablabchemnitz/networkx/algorithms/community/asyn_fluid.py deleted file mode 100644 index 86892e86..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/asyn_fluid.py +++ /dev/null @@ -1,150 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2017-2019 -# All rights reserved. -# BSD license. -# Author: Ferran Parés -"""Asynchronous Fluid Communities algorithm for community detection.""" - -from collections import Counter -from networkx.exception import NetworkXError -from networkx.algorithms.components import is_connected -from networkx.utils import groups -from networkx.utils import not_implemented_for -from networkx.utils import py_random_state - -__all__ = ['asyn_fluidc'] - - -@py_random_state(3) -@not_implemented_for('directed', 'multigraph') -def asyn_fluidc(G, k, max_iter=100, seed=None): - """Returns communities in `G` as detected by Fluid Communities algorithm. - - The asynchronous fluid communities algorithm is described in - [1]_. The algorithm is based on the simple idea of fluids interacting - in an environment, expanding and pushing each other. It's initialization is - random, so found communities may vary on different executions. - - The algorithm proceeds as follows. First each of the initial k communities - is initialized in a random vertex in the graph. Then the algorithm iterates - over all vertices in a random order, updating the community of each vertex - based on its own community and the communities of its neighbours. This - process is performed several times until convergence. - At all times, each community has a total density of 1, which is equally - distributed among the vertices it contains. If a vertex changes of - community, vertex densities of affected communities are adjusted - immediately. When a complete iteration over all vertices is done, such that - no vertex changes the community it belongs to, the algorithm has converged - and returns. - - This is the original version of the algorithm described in [1]_. - Unfortunately, it does not support weighted graphs yet. - - Parameters - ---------- - G : Graph - - k : integer - The number of communities to be found. - - max_iter : integer - The number of maximum iterations allowed. By default 15. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - communities : iterable - Iterable of communities given as sets of nodes. - - Notes - ----- - k variable is not an optional argument. - - References - ---------- - .. [1] Parés F., Garcia-Gasulla D. et al. "Fluid Communities: A - Competitive and Highly Scalable Community Detection Algorithm". - [https://arxiv.org/pdf/1703.09307.pdf]. - """ - # Initial checks - if not isinstance(k, int): - raise NetworkXError("k must be an integer.") - if not k > 0: - raise NetworkXError("k must be greater than 0.") - if not is_connected(G): - raise NetworkXError("Fluid Communities require connected Graphs.") - if len(G) < k: - raise NetworkXError("k cannot be bigger than the number of nodes.") - # Initialization - max_density = 1.0 - vertices = list(G) - seed.shuffle(vertices) - communities = {n: i for i, n in enumerate(vertices[:k])} - density = {} - com_to_numvertices = {} - for vertex in communities.keys(): - com_to_numvertices[communities[vertex]] = 1 - density[communities[vertex]] = max_density - # Set up control variables and start iterating - iter_count = 0 - cont = True - while cont: - cont = False - iter_count += 1 - # Loop over all vertices in graph in a random order - vertices = list(G) - seed.shuffle(vertices) - for vertex in vertices: - # Updating rule - com_counter = Counter() - # Take into account self vertex community - try: - com_counter.update({communities[vertex]: - density[communities[vertex]]}) - except KeyError: - pass - # Gather neighbour vertex communities - for v in G[vertex]: - try: - com_counter.update({communities[v]: - density[communities[v]]}) - except KeyError: - continue - # Check which is the community with highest density - new_com = -1 - if len(com_counter.keys()) > 0: - max_freq = max(com_counter.values()) - best_communities = [com for com, freq in com_counter.items() - if (max_freq - freq) < 0.0001] - # If actual vertex com in best communities, it is preserved - try: - if communities[vertex] in best_communities: - new_com = communities[vertex] - except KeyError: - pass - # If vertex community changes... - if new_com == -1: - # Set flag of non-convergence - cont = True - # Randomly chose a new community from candidates - new_com = seed.choice(best_communities) - # Update previous community status - try: - com_to_numvertices[communities[vertex]] -= 1 - density[communities[vertex]] = max_density / \ - com_to_numvertices[communities[vertex]] - except KeyError: - pass - # Update new community status - communities[vertex] = new_com - com_to_numvertices[communities[vertex]] += 1 - density[communities[vertex]] = max_density / \ - com_to_numvertices[communities[vertex]] - # If maximum iterations reached --> output actual results - if iter_count > max_iter: - break - # Return results by grouping communities as list of vertices - return iter(groups(communities).values()) diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/centrality.py b/extensions/fablabchemnitz/networkx/algorithms/community/centrality.py deleted file mode 100644 index 036b4a26..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/centrality.py +++ /dev/null @@ -1,177 +0,0 @@ -# -*- coding: utf-8 -*- -# centrality.py - functions for computing communities using centrality notions -# -# Copyright 2015, 2016 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Functions for computing communities based on centrality notions.""" - -import networkx as nx - -__all__ = ['girvan_newman'] - - -def girvan_newman(G, most_valuable_edge=None): - """Finds communities in a graph using the Girvan–Newman method. - - Parameters - ---------- - G : NetworkX graph - - most_valuable_edge : function - Function that takes a graph as input and outputs an edge. The - edge returned by this function will be recomputed and removed at - each iteration of the algorithm. - - If not specified, the edge with the highest - :func:`networkx.edge_betweenness_centrality` will be used. - - Returns - ------- - iterator - Iterator over tuples of sets of nodes in `G`. Each set of node - is a community, each tuple is a sequence of communities at a - particular level of the algorithm. - - Examples - -------- - To get the first pair of communities:: - - >>> G = nx.path_graph(10) - >>> comp = girvan_newman(G) - >>> tuple(sorted(c) for c in next(comp)) - ([0, 1, 2, 3, 4], [5, 6, 7, 8, 9]) - - To get only the first *k* tuples of communities, use - :func:`itertools.islice`:: - - >>> import itertools - >>> G = nx.path_graph(8) - >>> k = 2 - >>> comp = girvan_newman(G) - >>> for communities in itertools.islice(comp, k): - ... print(tuple(sorted(c) for c in communities)) # doctest: +SKIP - ... - ([0, 1, 2, 3], [4, 5, 6, 7]) - ([0, 1], [2, 3], [4, 5, 6, 7]) - - To stop getting tuples of communities once the number of communities - is greater than *k*, use :func:`itertools.takewhile`:: - - >>> import itertools - >>> G = nx.path_graph(8) - >>> k = 4 - >>> comp = girvan_newman(G) - >>> limited = itertools.takewhile(lambda c: len(c) <= k, comp) - >>> for communities in limited: - ... print(tuple(sorted(c) for c in communities)) # doctest: +SKIP - ... - ([0, 1, 2, 3], [4, 5, 6, 7]) - ([0, 1], [2, 3], [4, 5, 6, 7]) - ([0, 1], [2, 3], [4, 5], [6, 7]) - - To just choose an edge to remove based on the weight:: - - >>> from operator import itemgetter - >>> G = nx.path_graph(10) - >>> edges = G.edges() - >>> nx.set_edge_attributes(G, {(u, v): v for u, v in edges}, 'weight') - >>> def heaviest(G): - ... u, v, w = max(G.edges(data='weight'), key=itemgetter(2)) - ... return (u, v) - ... - >>> comp = girvan_newman(G, most_valuable_edge=heaviest) - >>> tuple(sorted(c) for c in next(comp)) - ([0, 1, 2, 3, 4, 5, 6, 7, 8], [9]) - - To utilize edge weights when choosing an edge with, for example, the - highest betweenness centrality:: - - >>> from networkx import edge_betweenness_centrality as betweenness - >>> def most_central_edge(G): - ... centrality = betweenness(G, weight='weight') - ... return max(centrality, key=centrality.get) - ... - >>> G = nx.path_graph(10) - >>> comp = girvan_newman(G, most_valuable_edge=most_central_edge) - >>> tuple(sorted(c) for c in next(comp)) - ([0, 1, 2, 3, 4], [5, 6, 7, 8, 9]) - - To specify a different ranking algorithm for edges, use the - `most_valuable_edge` keyword argument:: - - >>> from networkx import edge_betweenness_centrality - >>> from random import random - >>> def most_central_edge(G): - ... centrality = edge_betweenness_centrality(G) - ... max_cent = max(centrality.values()) - ... # Scale the centrality values so they are between 0 and 1, - ... # and add some random noise. - ... centrality = {e: c / max_cent for e, c in centrality.items()} - ... # Add some random noise. - ... centrality = {e: c + random() for e, c in centrality.items()} - ... return max(centrality, key=centrality.get) - ... - >>> G = nx.path_graph(10) - >>> comp = girvan_newman(G, most_valuable_edge=most_central_edge) - - Notes - ----- - The Girvan–Newman algorithm detects communities by progressively - removing edges from the original graph. The algorithm removes the - "most valuable" edge, traditionally the edge with the highest - betweenness centrality, at each step. As the graph breaks down into - pieces, the tightly knit community structure is exposed and the - result can be depicted as a dendrogram. - - """ - # If the graph is already empty, simply return its connected - # components. - if G.number_of_edges() == 0: - yield tuple(nx.connected_components(G)) - return - # If no function is provided for computing the most valuable edge, - # use the edge betweenness centrality. - if most_valuable_edge is None: - def most_valuable_edge(G): - """Returns the edge with the highest betweenness centrality - in the graph `G`. - - """ - # We have guaranteed that the graph is non-empty, so this - # dictionary will never be empty. - betweenness = nx.edge_betweenness_centrality(G) - return max(betweenness, key=betweenness.get) - # The copy of G here must include the edge weight data. - g = G.copy().to_undirected() - # Self-loops must be removed because their removal has no effect on - # the connected components of the graph. - g.remove_edges_from(nx.selfloop_edges(g)) - while g.number_of_edges() > 0: - yield _without_most_central_edges(g, most_valuable_edge) - - -def _without_most_central_edges(G, most_valuable_edge): - """Returns the connected components of the graph that results from - repeatedly removing the most "valuable" edge in the graph. - - `G` must be a non-empty graph. This function modifies the graph `G` - in-place; that is, it removes edges on the graph `G`. - - `most_valuable_edge` is a function that takes the graph `G` as input - (or a subgraph with one or more edges of `G` removed) and returns an - edge. That edge will be removed and this process will be repeated - until the number of connected components in the graph increases. - - """ - original_num_components = nx.number_connected_components(G) - num_new_components = original_num_components - while num_new_components <= original_num_components: - edge = most_valuable_edge(G) - G.remove_edge(*edge) - new_components = tuple(nx.connected_components(G)) - num_new_components = len(new_components) - return new_components diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/community_utils.py b/extensions/fablabchemnitz/networkx/algorithms/community/community_utils.py deleted file mode 100644 index fa9d39cd..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/community_utils.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- -# -# utils.py - helper functions for community-finding algorithms -# -# Copyright 2011 Ben Edwards . -# Copyright 2011 Aric Hagberg . -# Copyright 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Helper functions for community-finding algorithms.""" - -__all__ = ['is_partition'] - - -def is_partition(G, communities): - """Returns *True* if `communities` is a partition of the nodes of `G`. - - A partition of a universe set is a family of pairwise disjoint sets - whose union is the entire universe set. - - Parameters - ---------- - G : NetworkX graph. - - communities : list or iterable of sets of nodes - If not a list, the iterable is converted internally to a list. - If it is an iterator it is exhausted. - - """ - # Alternate implementation: - # return all(sum(1 if v in c else 0 for c in communities) == 1 for v in G) - if not isinstance(communities, list): - communities = list(communities) - nodes = set(n for c in communities for n in c if n in G) - - return len(G) == len(nodes) == sum(len(c) for c in communities) diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/kclique.py b/extensions/fablabchemnitz/networkx/algorithms/community/kclique.py deleted file mode 100644 index 45220440..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/kclique.py +++ /dev/null @@ -1,85 +0,0 @@ -#-*- coding: utf-8 -*- -# Copyright (C) 2011 by -# Conrad Lee -# Aric Hagberg -# All rights reserved. -# BSD license. -from collections import defaultdict -import networkx as nx -__author__ = """\n""".join(['Conrad Lee ', - 'Aric Hagberg ']) -__all__ = ['k_clique_communities'] - - -def k_clique_communities(G, k, cliques=None): - """Find k-clique communities in graph using the percolation method. - - A k-clique community is the union of all cliques of size k that - can be reached through adjacent (sharing k-1 nodes) k-cliques. - - Parameters - ---------- - G : NetworkX graph - - k : int - Size of smallest clique - - cliques: list or generator - Precomputed cliques (use networkx.find_cliques(G)) - - Returns - ------- - Yields sets of nodes, one for each k-clique community. - - Examples - -------- - >>> from networkx.algorithms.community import k_clique_communities - >>> G = nx.complete_graph(5) - >>> K5 = nx.convert_node_labels_to_integers(G,first_label=2) - >>> G.add_edges_from(K5.edges()) - >>> c = list(k_clique_communities(G, 4)) - >>> sorted(list(c[0])) - [0, 1, 2, 3, 4, 5, 6] - >>> list(k_clique_communities(G, 6)) - [] - - References - ---------- - .. [1] Gergely Palla, Imre Derényi, Illés Farkas1, and Tamás Vicsek, - Uncovering the overlapping community structure of complex networks - in nature and society Nature 435, 814-818, 2005, - doi:10.1038/nature03607 - """ - if k < 2: - raise nx.NetworkXError("k=%d, k must be greater than 1." % k) - if cliques is None: - cliques = nx.find_cliques(G) - cliques = [frozenset(c) for c in cliques if len(c) >= k] - - # First index which nodes are in which cliques - membership_dict = defaultdict(list) - for clique in cliques: - for node in clique: - membership_dict[node].append(clique) - - # For each clique, see which adjacent cliques percolate - perc_graph = nx.Graph() - perc_graph.add_nodes_from(cliques) - for clique in cliques: - for adj_clique in _get_adjacent_cliques(clique, membership_dict): - if len(clique.intersection(adj_clique)) >= (k - 1): - perc_graph.add_edge(clique, adj_clique) - - # Connected components of clique graph with perc edges - # are the percolated cliques - for component in nx.connected_components(perc_graph): - yield(frozenset.union(*component)) - - -def _get_adjacent_cliques(clique, membership_dict): - adjacent_cliques = set() - for n in clique: - for adj_clique in membership_dict[n]: - if clique != adj_clique: - adjacent_cliques.add(adj_clique) - return adjacent_cliques diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/kernighan_lin.py b/extensions/fablabchemnitz/networkx/algorithms/community/kernighan_lin.py deleted file mode 100644 index ba3fea17..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/kernighan_lin.py +++ /dev/null @@ -1,174 +0,0 @@ -# -*- coding: utf-8 -*- -# -# kernighan_lin.py - Kernighan–Lin bipartition algorithm -# -# Copyright 2011 Ben Edwards . -# Copyright 2011 Aric Hagberg . -# Copyright 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Functions for computing the Kernighan–Lin bipartition algorithm.""" - -from collections import defaultdict -from itertools import islice -from operator import itemgetter - -import networkx as nx -from networkx.utils import not_implemented_for, py_random_state -from networkx.algorithms.community.community_utils import is_partition - -__all__ = ['kernighan_lin_bisection'] - - -def _compute_delta(G, A, B, weight): - # helper to compute initial swap deltas for a pass - delta = defaultdict(float) - for u, v, d in G.edges(data=True): - w = d.get(weight, 1) - if u in A: - if v in A: - delta[u] -= w - delta[v] -= w - elif v in B: - delta[u] += w - delta[v] += w - elif u in B: - if v in A: - delta[u] += w - delta[v] += w - elif v in B: - delta[u] -= w - delta[v] -= w - return delta - - -def _update_delta(delta, G, A, B, u, v, weight): - # helper to update swap deltas during single pass - for _, nbr, d in G.edges(u, data=True): - w = d.get(weight, 1) - if nbr in A: - delta[nbr] += 2 * w - if nbr in B: - delta[nbr] -= 2 * w - for _, nbr, d in G.edges(v, data=True): - w = d.get(weight, 1) - if nbr in A: - delta[nbr] -= 2 * w - if nbr in B: - delta[nbr] += 2 * w - return delta - - -def _kernighan_lin_pass(G, A, B, weight): - # do a single iteration of Kernighan–Lin algorithm - # returns list of (g_i,u_i,v_i) for i node pairs u_i,v_i - multigraph = G.is_multigraph() - delta = _compute_delta(G, A, B, weight) - swapped = set() - gains = [] - while len(swapped) < len(G): - gain = [] - for u in A - swapped: - for v in B - swapped: - try: - if multigraph: - w = sum(d.get(weight, 1) for d in G[u][v].values()) - else: - w = G[u][v].get(weight, 1) - except KeyError: - w = 0 - gain.append((delta[u] + delta[v] - 2 * w, u, v)) - if len(gain) == 0: - break - maxg, u, v = max(gain, key=itemgetter(0)) - swapped |= {u, v} - gains.append((maxg, u, v)) - delta = _update_delta(delta, G, A - swapped, B - swapped, u, v, weight) - return gains - - -@py_random_state(4) -@not_implemented_for('directed') -def kernighan_lin_bisection(G, partition=None, max_iter=10, weight='weight', - seed=None): - """Partition a graph into two blocks using the Kernighan–Lin - algorithm. - - This algorithm paritions a network into two sets by iteratively - swapping pairs of nodes to reduce the edge cut between the two sets. - - Parameters - ---------- - G : graph - - partition : tuple - Pair of iterables containing an initial partition. If not - specified, a random balanced partition is used. - - max_iter : int - Maximum number of times to attempt swaps to find an - improvemement before giving up. - - weight : key - Edge data key to use as weight. If None, the weights are all - set to one. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - Only used if partition is None - - Returns - ------- - partition : tuple - A pair of sets of nodes representing the bipartition. - - Raises - ------- - NetworkXError - If partition is not a valid partition of the nodes of the graph. - - References - ---------- - .. [1] Kernighan, B. W.; Lin, Shen (1970). - "An efficient heuristic procedure for partitioning graphs." - *Bell Systems Technical Journal* 49: 291--307. - Oxford University Press 2011. - - """ - # If no partition is provided, split the nodes randomly into a - # balanced partition. - if partition is None: - nodes = list(G) - seed.shuffle(nodes) - h = len(nodes) // 2 - partition = (nodes[:h], nodes[h:]) - # Make a copy of the partition as a pair of sets. - try: - A, B = set(partition[0]), set(partition[1]) - except: - raise ValueError('partition must be two sets') - if not is_partition(G, (A, B)): - raise nx.NetworkXError('partition invalid') - for i in range(max_iter): - # `gains` is a list of triples of the form (g, u, v) for each - # node pair (u, v), where `g` is the gain of that node pair. - gains = _kernighan_lin_pass(G, A, B, weight) - csum = list(nx.utils.accumulate(g for g, u, v in gains)) - max_cgain = max(csum) - if max_cgain <= 0: - break - # Get the node pairs up to the index of the maximum cumulative - # gain, and collect each `u` into `anodes` and each `v` into - # `bnodes`, for each pair `(u, v)`. - index = csum.index(max_cgain) - nodesets = islice(zip(*gains[:index + 1]), 1, 3) - anodes, bnodes = (set(s) for s in nodesets) - A |= bnodes - A -= anodes - B |= anodes - B -= bnodes - return A, B diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/label_propagation.py b/extensions/fablabchemnitz/networkx/algorithms/community/label_propagation.py deleted file mode 100644 index 18553790..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/label_propagation.py +++ /dev/null @@ -1,202 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2015-2019 Aitor Almeida -# All rights reserved. -# BSD license. -# -# Author: Aitor Almeida -""" -Label propagation community detection algorithms. -""" -from collections import Counter - -import networkx as nx -from networkx.utils import groups -from networkx.utils import not_implemented_for -from networkx.utils import py_random_state - -__all__ = ['label_propagation_communities', 'asyn_lpa_communities'] - - -@py_random_state(2) -def asyn_lpa_communities(G, weight=None, seed=None): - """Returns communities in `G` as detected by asynchronous label - propagation. - - The asynchronous label propagation algorithm is described in - [1]_. The algorithm is probabilistic and the found communities may - vary on different executions. - - The algorithm proceeds as follows. After initializing each node with - a unique label, the algorithm repeatedly sets the label of a node to - be the label that appears most frequently among that nodes - neighbors. The algorithm halts when each node has the label that - appears most frequently among its neighbors. The algorithm is - asynchronous because each node is updated without waiting for - updates on the remaining nodes. - - This generalized version of the algorithm in [1]_ accepts edge - weights. - - Parameters - ---------- - G : Graph - - weight : string - The edge attribute representing the weight of an edge. - If None, each edge is assumed to have weight one. In this - algorithm, the weight of an edge is used in determining the - frequency with which a label appears among the neighbors of a - node: a higher weight means the label appears more often. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - communities : iterable - Iterable of communities given as sets of nodes. - - Notes - ------ - Edge weight attributes must be numerical. - - References - ---------- - .. [1] Raghavan, Usha Nandini, Réka Albert, and Soundar Kumara. "Near - linear time algorithm to detect community structures in large-scale - networks." Physical Review E 76.3 (2007): 036106. - """ - - labels = {n: i for i, n in enumerate(G)} - cont = True - while cont: - cont = False - nodes = list(G) - seed.shuffle(nodes) - # Calculate the label for each node - for node in nodes: - if len(G[node]) < 1: - continue - - # Get label frequencies. Depending on the order they are processed - # in some nodes with be in t and others in t-1, making the - # algorithm asynchronous. - label_freq = Counter() - for v in G[node]: - label_freq.update({labels[v]: G.edges[node, v][weight] - if weight else 1}) - # Choose the label with the highest frecuency. If more than 1 label - # has the highest frecuency choose one randomly. - max_freq = max(label_freq.values()) - best_labels = [label for label, freq in label_freq.items() - if freq == max_freq] - - # Continue until all nodes have a majority label - if labels[node] not in best_labels: - labels[node] = seed.choice(best_labels) - cont = True - - # TODO In Python 3.3 or later, this should be `yield from ...`. - return iter(groups(labels).values()) - - -@not_implemented_for('directed') -def label_propagation_communities(G): - """Generates community sets determined by label propagation - - Finds communities in `G` using a semi-synchronous label propagation - method[1]_. This method combines the advantages of both the synchronous - and asynchronous models. Not implemented for directed graphs. - - Parameters - ---------- - G : graph - An undirected NetworkX graph. - - Yields - ------ - communities : generator - Yields sets of the nodes in each community. - - Raises - ------ - NetworkXNotImplemented - If the graph is directed - - References - ---------- - .. [1] Cordasco, G., & Gargano, L. (2010, December). Community detection - via semi-synchronous label propagation algorithms. In Business - Applications of Social Network Analysis (BASNA), 2010 IEEE International - Workshop on (pp. 1-8). IEEE. - """ - coloring = _color_network(G) - # Create a unique label for each node in the graph - labeling = {v: k for k, v in enumerate(G)} - while not _labeling_complete(labeling, G): - # Update the labels of every node with the same color. - for color, nodes in coloring.items(): - for n in nodes: - _update_label(n, labeling, G) - - for label in set(labeling.values()): - yield set((x for x in labeling if labeling[x] == label)) - - -def _color_network(G): - """Colors the network so that neighboring nodes all have distinct colors. - - Returns a dict keyed by color to a set of nodes with that color. - """ - coloring = dict() # color => set(node) - colors = nx.coloring.greedy_color(G) - for node, color in colors.items(): - if color in coloring: - coloring[color].add(node) - else: - coloring[color] = set([node]) - return coloring - - -def _labeling_complete(labeling, G): - """Determines whether or not LPA is done. - - Label propagation is complete when all nodes have a label that is - in the set of highest frequency labels amongst its neighbors. - - Nodes with no neighbors are considered complete. - """ - return all(labeling[v] in _most_frequent_labels(v, labeling, G) - for v in G if len(G[v]) > 0) - - -def _most_frequent_labels(node, labeling, G): - """Returns a set of all labels with maximum frequency in `labeling`. - - Input `labeling` should be a dict keyed by node to labels. - """ - if not G[node]: - # Nodes with no neighbors are themselves a community and are labeled - # accordingly, hence the immediate if statement. - return {labeling[node]} - - # Compute the frequencies of all neighbours of node - freqs = Counter(labeling[q] for q in G[node]) - max_freq = max(freqs.values()) - return {label for label, freq in freqs.items() if freq == max_freq} - - -def _update_label(node, labeling, G): - """Updates the label of a node using the Prec-Max tie breaking algorithm - - The algorithm is explained in: 'Community Detection via Semi-Synchronous - Label Propagation Algorithms' Cordasco and Gargano, 2011 - """ - high_labels = _most_frequent_labels(node, labeling, G) - if len(high_labels) == 1: - labeling[node] = high_labels.pop() - elif len(high_labels) > 1: - # Prec-Max - if labeling[node] not in high_labels: - labeling[node] = max(high_labels) diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/modularity_max.py b/extensions/fablabchemnitz/networkx/algorithms/community/modularity_max.py deleted file mode 100644 index ba413564..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/modularity_max.py +++ /dev/null @@ -1,281 +0,0 @@ -# modularity_max.py - functions for finding communities based on modularity -# -# Copyright 2018 Edward L. Platt -# -# This file is part of NetworkX -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -# -# Authors: -# Edward L. Platt -# -# TODO: -# - Alter equations for weighted case -# - Write tests for weighted case -"""Functions for detecting communities based on modularity. -""" - -import networkx as nx -from networkx.algorithms.community.quality import modularity - -from networkx.utils.mapped_queue import MappedQueue - -__all__ = [ - 'greedy_modularity_communities', - '_naive_greedy_modularity_communities'] - - -def greedy_modularity_communities(G, weight=None): - """Find communities in graph using Clauset-Newman-Moore greedy modularity - maximization. This method currently supports the Graph class and does not - consider edge weights. - - Greedy modularity maximization begins with each node in its own community - and joins the pair of communities that most increases modularity until no - such pair exists. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - Yields sets of nodes, one for each community. - - Examples - -------- - >>> from networkx.algorithms.community import greedy_modularity_communities - >>> G = nx.karate_club_graph() - >>> c = list(greedy_modularity_communities(G)) - >>> sorted(c[0]) - [8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33] - - References - ---------- - .. [1] M. E. J Newman 'Networks: An Introduction', page 224 - Oxford University Press 2011. - .. [2] Clauset, A., Newman, M. E., & Moore, C. - "Finding community structure in very large networks." - Physical Review E 70(6), 2004. - """ - - # Count nodes and edges - N = len(G.nodes()) - m = sum([d.get('weight', 1) for u, v, d in G.edges(data=True)]) - q0 = 1.0 / (2.0*m) - - # Map node labels to contiguous integers - label_for_node = dict((i, v) for i, v in enumerate(G.nodes())) - node_for_label = dict((label_for_node[i], i) for i in range(N)) - - # Calculate degrees - k_for_label = G.degree(G.nodes(), weight=weight) - k = [k_for_label[label_for_node[i]] for i in range(N)] - - # Initialize community and merge lists - communities = dict((i, frozenset([i])) for i in range(N)) - merges = [] - - # Initial modularity - partition = [[label_for_node[x] for x in c] for c in communities.values()] - q_cnm = modularity(G, partition) - - # Initialize data structures - # CNM Eq 8-9 (Eq 8 was missing a factor of 2 (from A_ij + A_ji) - # a[i]: fraction of edges within community i - # dq_dict[i][j]: dQ for merging community i, j - # dq_heap[i][n] : (-dq, i, j) for communitiy i nth largest dQ - # H[n]: (-dq, i, j) for community with nth largest max_j(dQ_ij) - a = [k[i]*q0 for i in range(N)] - dq_dict = dict( - (i, dict( - (j, 2*q0 - 2*k[i]*k[j]*q0*q0) - for j in [ - node_for_label[u] - for u in G.neighbors(label_for_node[i])] - if j != i)) - for i in range(N)) - dq_heap = [ - MappedQueue([ - (-dq, i, j) - for j, dq in dq_dict[i].items()]) - for i in range(N)] - H = MappedQueue([ - dq_heap[i].h[0] - for i in range(N) - if len(dq_heap[i]) > 0]) - - # Merge communities until we can't improve modularity - while len(H) > 1: - # Find best merge - # Remove from heap of row maxes - # Ties will be broken by choosing the pair with lowest min community id - try: - dq, i, j = H.pop() - except IndexError: - break - dq = -dq - # Remove best merge from row i heap - dq_heap[i].pop() - # Push new row max onto H - if len(dq_heap[i]) > 0: - H.push(dq_heap[i].h[0]) - # If this element was also at the root of row j, we need to remove the - # duplicate entry from H - if dq_heap[j].h[0] == (-dq, j, i): - H.remove((-dq, j, i)) - # Remove best merge from row j heap - dq_heap[j].remove((-dq, j, i)) - # Push new row max onto H - if len(dq_heap[j]) > 0: - H.push(dq_heap[j].h[0]) - else: - # Duplicate wasn't in H, just remove from row j heap - dq_heap[j].remove((-dq, j, i)) - # Stop when change is non-positive - if dq <= 0: - break - - # Perform merge - communities[j] = frozenset(communities[i] | communities[j]) - del communities[i] - merges.append((i, j, dq)) - # New modularity - q_cnm += dq - # Get list of communities connected to merged communities - i_set = set(dq_dict[i].keys()) - j_set = set(dq_dict[j].keys()) - all_set = (i_set | j_set) - set([i, j]) - both_set = i_set & j_set - # Merge i into j and update dQ - for k in all_set: - # Calculate new dq value - if k in both_set: - dq_jk = dq_dict[j][k] + dq_dict[i][k] - elif k in j_set: - dq_jk = dq_dict[j][k] - 2.0*a[i]*a[k] - else: - # k in i_set - dq_jk = dq_dict[i][k] - 2.0*a[j]*a[k] - # Update rows j and k - for row, col in [(j, k), (k, j)]: - # Save old value for finding heap index - if k in j_set: - d_old = (-dq_dict[row][col], row, col) - else: - d_old = None - # Update dict for j,k only (i is removed below) - dq_dict[row][col] = dq_jk - # Save old max of per-row heap - if len(dq_heap[row]) > 0: - d_oldmax = dq_heap[row].h[0] - else: - d_oldmax = None - # Add/update heaps - d = (-dq_jk, row, col) - if d_old is None: - # We're creating a new nonzero element, add to heap - dq_heap[row].push(d) - else: - # Update existing element in per-row heap - dq_heap[row].update(d_old, d) - # Update heap of row maxes if necessary - if d_oldmax is None: - # No entries previously in this row, push new max - H.push(d) - else: - # We've updated an entry in this row, has the max changed? - if dq_heap[row].h[0] != d_oldmax: - H.update(d_oldmax, dq_heap[row].h[0]) - - # Remove row/col i from matrix - i_neighbors = dq_dict[i].keys() - for k in i_neighbors: - # Remove from dict - dq_old = dq_dict[k][i] - del dq_dict[k][i] - # Remove from heaps if we haven't already - if k != j: - # Remove both row and column - for row, col in [(k, i), (i, k)]: - # Check if replaced dq is row max - d_old = (-dq_old, row, col) - if dq_heap[row].h[0] == d_old: - # Update per-row heap and heap of row maxes - dq_heap[row].remove(d_old) - H.remove(d_old) - # Update row max - if len(dq_heap[row]) > 0: - H.push(dq_heap[row].h[0]) - else: - # Only update per-row heap - dq_heap[row].remove(d_old) - - del dq_dict[i] - # Mark row i as deleted, but keep placeholder - dq_heap[i] = MappedQueue() - # Merge i into j and update a - a[j] += a[i] - a[i] = 0 - - communities = [ - frozenset([label_for_node[i] for i in c]) - for c in communities.values()] - return sorted(communities, key=len, reverse=True) - - -def _naive_greedy_modularity_communities(G): - """Find communities in graph using the greedy modularity maximization. - This implementation is O(n^4), much slower than alternatives, but it is - provided as an easy-to-understand reference implementation. - """ - # First create one community for each node - communities = list([frozenset([u]) for u in G.nodes()]) - # Track merges - merges = [] - # Greedily merge communities until no improvement is possible - old_modularity = None - new_modularity = modularity(G, communities) - while old_modularity is None or new_modularity > old_modularity: - # Save modularity for comparison - old_modularity = new_modularity - # Find best pair to merge - trial_communities = list(communities) - to_merge = None - for i, u in enumerate(communities): - for j, v in enumerate(communities): - # Skip i=j and empty communities - if j <= i or len(u) == 0 or len(v) == 0: - continue - # Merge communities u and v - trial_communities[j] = u | v - trial_communities[i] = frozenset([]) - trial_modularity = modularity(G, trial_communities) - if trial_modularity >= new_modularity: - # Check if strictly better or tie - if trial_modularity > new_modularity: - # Found new best, save modularity and group indexes - new_modularity = trial_modularity - to_merge = (i, j, new_modularity - old_modularity) - elif ( - to_merge and - min(i, j) < min(to_merge[0], to_merge[1]) - ): - # Break ties by choosing pair with lowest min id - new_modularity = trial_modularity - to_merge = (i, j, new_modularity - old_modularity) - # Un-merge - trial_communities[i] = u - trial_communities[j] = v - if to_merge is not None: - # If the best merge improves modularity, use it - merges.append(to_merge) - i, j, dq = to_merge - u, v = communities[i], communities[j] - communities[j] = u | v - communities[i] = frozenset([]) - # Remove empty communities and sort - communities = [c for c in communities if len(c) > 0] - for com in sorted(communities, key=lambda x: len(x), reverse=True): - yield com diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/quality.py b/extensions/fablabchemnitz/networkx/algorithms/community/quality.py deleted file mode 100644 index fdd0c542..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/quality.py +++ /dev/null @@ -1,325 +0,0 @@ -# quality.py - functions for measuring partitions of a graph -# -# Copyright 2015-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Functions for measuring the quality of a partition (into -communities). - -""" - -from functools import wraps -from itertools import product - -import networkx as nx -from networkx import NetworkXError -from networkx.utils import not_implemented_for -from networkx.algorithms.community.community_utils import is_partition - -__all__ = ['coverage', 'modularity', 'performance'] - - -class NotAPartition(NetworkXError): - """Raised if a given collection is not a partition. - - """ - def __init__(self, G, collection): - msg = '{} is not a valid partition of the graph {}' - msg = msg.format(G, collection) - super(NotAPartition, self).__init__(msg) - - -def require_partition(func): - """Decorator to check that a valid partition is input to a function - - Raises :exc:`networkx.NetworkXError` if the partition is not valid. - - This decorator should be used on functions whose first two arguments - are a graph and a partition of the nodes of that graph (in that - order):: - - >>> @require_partition - ... def foo(G, partition): - ... print('partition is valid!') - ... - >>> G = nx.complete_graph(5) - >>> partition = [{0, 1}, {2, 3}, {4}] - >>> foo(G, partition) - partition is valid! - >>> partition = [{0}, {2, 3}, {4}] - >>> foo(G, partition) # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - NetworkXError: `partition` is not a valid partition of the nodes of G - >>> partition = [{0, 1}, {1, 2, 3}, {4}] - >>> foo(G, partition) # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - NetworkXError: `partition` is not a valid partition of the nodes of G - - """ - @wraps(func) - def new_func(*args, **kw): - # Here we assume that the first two arguments are (G, partition). - if not is_partition(*args[:2]): - raise nx.NetworkXError('`partition` is not a valid partition of' - ' the nodes of G') - return func(*args, **kw) - return new_func - - -def intra_community_edges(G, partition): - """Returns the number of intra-community edges for a partition of `G`. - - Parameters - ---------- - G : NetworkX graph. - - partition : iterable of sets of nodes - This must be a partition of the nodes of `G`. - - The "intra-community edges" are those edges joining a pair of nodes - in the same block of the partition. - - """ - return sum(G.subgraph(block).size() for block in partition) - - -def inter_community_edges(G, partition): - """Returns the number of inter-community edges for a prtition of `G`. - according to the given - partition of the nodes of `G`. - - Parameters - ---------- - G : NetworkX graph. - - partition : iterable of sets of nodes - This must be a partition of the nodes of `G`. - - The *inter-community edges* are those edges joining a pair of nodes - in different blocks of the partition. - - Implementation note: this function creates an intermediate graph - that may require the same amount of memory as that of `G`. - - """ - # Alternate implementation that does not require constructing a new - # graph object (but does require constructing an affiliation - # dictionary): - # - # aff = dict(chain.from_iterable(((v, block) for v in block) - # for block in partition)) - # return sum(1 for u, v in G.edges() if aff[u] != aff[v]) - # - MG = nx.MultiDiGraph if G.is_directed() else nx.MultiGraph - return nx.quotient_graph(G, partition, create_using=MG).size() - - -def inter_community_non_edges(G, partition): - """Returns the number of inter-community non-edges according to the - given partition of the nodes of `G`. - - `G` must be a NetworkX graph. - - `partition` must be a partition of the nodes of `G`. - - A *non-edge* is a pair of nodes (undirected if `G` is undirected) - that are not adjacent in `G`. The *inter-community non-edges* are - those non-edges on a pair of nodes in different blocks of the - partition. - - Implementation note: this function creates two intermediate graphs, - which may require up to twice the amount of memory as required to - store `G`. - - """ - # Alternate implementation that does not require constructing two - # new graph objects (but does require constructing an affiliation - # dictionary): - # - # aff = dict(chain.from_iterable(((v, block) for v in block) - # for block in partition)) - # return sum(1 for u, v in nx.non_edges(G) if aff[u] != aff[v]) - # - return inter_community_edges(nx.complement(G), partition) - - -@not_implemented_for('multigraph') -@require_partition -def performance(G, partition): - """Returns the performance of a partition. - - The *performance* of a partition is the ratio of the number of - intra-community edges plus inter-community non-edges with the total - number of potential edges. - - Parameters - ---------- - G : NetworkX graph - A simple graph (directed or undirected). - - partition : sequence - Partition of the nodes of `G`, represented as a sequence of - sets of nodes. Each block of the partition represents a - community. - - Returns - ------- - float - The performance of the partition, as defined above. - - Raises - ------ - NetworkXError - If `partition` is not a valid partition of the nodes of `G`. - - References - ---------- - .. [1] Santo Fortunato. - "Community Detection in Graphs". - *Physical Reports*, Volume 486, Issue 3--5 pp. 75--174 - - - """ - # Compute the number of intra-community edges and inter-community - # edges. - intra_edges = intra_community_edges(G, partition) - inter_edges = inter_community_non_edges(G, partition) - # Compute the number of edges in the complete graph (directed or - # undirected, as it depends on `G`) on `n` nodes. - # - # (If `G` is an undirected graph, we divide by two since we have - # double-counted each potential edge. We use integer division since - # `total_pairs` is guaranteed to be even.) - n = len(G) - total_pairs = n * (n - 1) - if not G.is_directed(): - total_pairs //= 2 - return (intra_edges + inter_edges) / total_pairs - - -@require_partition -def coverage(G, partition): - """Returns the coverage of a partition. - - The *coverage* of a partition is the ratio of the number of - intra-community edges to the total number of edges in the graph. - - Parameters - ---------- - G : NetworkX graph - - partition : sequence - Partition of the nodes of `G`, represented as a sequence of - sets of nodes. Each block of the partition represents a - community. - - Returns - ------- - float - The coverage of the partition, as defined above. - - Raises - ------ - NetworkXError - If `partition` is not a valid partition of the nodes of `G`. - - Notes - ----- - If `G` is a multigraph, the multiplicity of edges is counted. - - References - ---------- - .. [1] Santo Fortunato. - "Community Detection in Graphs". - *Physical Reports*, Volume 486, Issue 3--5 pp. 75--174 - - - """ - intra_edges = intra_community_edges(G, partition) - total_edges = G.number_of_edges() - return intra_edges / total_edges - - -def modularity(G, communities, weight='weight'): - r"""Returns the modularity of the given partition of the graph. - - Modularity is defined in [1]_ as - - .. math:: - - Q = \frac{1}{2m} \sum_{ij} \left( A_{ij} - \frac{k_ik_j}{2m}\right) - \delta(c_i,c_j) - - where $m$ is the number of edges, $A$ is the adjacency matrix of - `G`, $k_i$ is the degree of $i$ and $\delta(c_i, c_j)$ - is 1 if $i$ and $j$ are in the same community and 0 otherwise. - - Parameters - ---------- - G : NetworkX Graph - - communities : list or iterable of set of nodes - These node sets must represent a partition of G's nodes. - - Returns - ------- - Q : float - The modularity of the paritition. - - Raises - ------ - NotAPartition - If `communities` is not a partition of the nodes of `G`. - - Examples - -------- - >>> import networkx.algorithms.community as nx_comm - >>> G = nx.barbell_graph(3, 0) - >>> nx_comm.modularity(G, [{0, 1, 2}, {3, 4, 5}]) - 0.35714285714285704 - >>> nx_comm.modularity(G, nx_comm.label_propagation_communities(G)) - 0.35714285714285704 - - References - ---------- - .. [1] M. E. J. Newman *Networks: An Introduction*, page 224. - Oxford University Press, 2011. - - """ - if not isinstance(communities, list): - communities = list(communities) - if not is_partition(G, communities): - raise NotAPartition(G, communities) - - multigraph = G.is_multigraph() - directed = G.is_directed() - m = G.size(weight=weight) - if directed: - out_degree = dict(G.out_degree(weight=weight)) - in_degree = dict(G.in_degree(weight=weight)) - norm = 1 / m - else: - out_degree = dict(G.degree(weight=weight)) - in_degree = out_degree - norm = 1 / (2 * m) - - def val(u, v): - try: - if multigraph: - w = sum(d.get(weight, 1) for k, d in G[u][v].items()) - else: - w = G[u][v].get(weight, 1) - except KeyError: - w = 0 - # Double count self-loops if the graph is undirected. - if u == v and not directed: - w *= 2 - return w - in_degree[u] * out_degree[v] * norm - - Q = sum(val(u, v) for c in communities for u, v in product(c, repeat=2)) - return Q * norm diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/community/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_asyn_fluid.py b/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_asyn_fluid.py deleted file mode 100644 index a18e5678..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_asyn_fluid.py +++ /dev/null @@ -1,129 +0,0 @@ -import pytest -from networkx import Graph, NetworkXError -from networkx.algorithms.community.asyn_fluid import * - - -def test_exceptions(): - test = Graph() - test.add_node('a') - pytest.raises(NetworkXError, asyn_fluidc, test, 'hi') - pytest.raises(NetworkXError, asyn_fluidc, test, -1) - pytest.raises(NetworkXError, asyn_fluidc, test, 3) - test.add_node('b') - pytest.raises(NetworkXError, asyn_fluidc, test, 1) - - -def test_single_node(): - test = Graph() - - test.add_node('a') - - # ground truth - ground_truth = set([frozenset(['a'])]) - - communities = asyn_fluidc(test, 1) - result = {frozenset(c) for c in communities} - assert result == ground_truth - - -def test_two_nodes(): - test = Graph() - - test.add_edge('a', 'b') - - # ground truth - ground_truth = set([frozenset(['a']), frozenset(['b'])]) - - communities = asyn_fluidc(test, 2) - result = {frozenset(c) for c in communities} - assert result == ground_truth - - -def test_two_clique_communities(): - test = Graph() - - # c1 - test.add_edge('a', 'b') - test.add_edge('a', 'c') - test.add_edge('b', 'c') - - # connection - test.add_edge('c', 'd') - - # c2 - test.add_edge('d', 'e') - test.add_edge('d', 'f') - test.add_edge('f', 'e') - - # ground truth - ground_truth = set([frozenset(['a', 'c', 'b']), - frozenset(['e', 'd', 'f'])]) - - communities = asyn_fluidc(test, 2, seed=7) - result = {frozenset(c) for c in communities} - assert result == ground_truth - - -def five_clique_ring(): - """Not auto-tested (not named test_...) due to cross-version seed issues - python3.4 in particular gives different results. - """ - test = Graph() - - # c1 - test.add_edge('1a', '1b') - test.add_edge('1a', '1c') - test.add_edge('1a', '1d') - test.add_edge('1b', '1c') - test.add_edge('1b', '1d') - test.add_edge('1c', '1d') - - # c2 - test.add_edge('2a', '2b') - test.add_edge('2a', '2c') - test.add_edge('2a', '2d') - test.add_edge('2b', '2c') - test.add_edge('2b', '2d') - test.add_edge('2c', '2d') - - # c3 - test.add_edge('3a', '3b') - test.add_edge('3a', '3c') - test.add_edge('3a', '3d') - test.add_edge('3b', '3c') - test.add_edge('3b', '3d') - test.add_edge('3c', '3d') - - # c4 - test.add_edge('4a', '4b') - test.add_edge('4a', '4c') - test.add_edge('4a', '4d') - test.add_edge('4b', '4c') - test.add_edge('4b', '4d') - test.add_edge('4c', '4d') - - # c5 - test.add_edge('5a', '5b') - test.add_edge('5a', '5c') - test.add_edge('5a', '5d') - test.add_edge('5b', '5c') - test.add_edge('5b', '5d') - test.add_edge('5c', '5d') - - # connections - test.add_edge('1a', '2c') - test.add_edge('2a', '3c') - test.add_edge('3a', '4c') - test.add_edge('4a', '5c') - test.add_edge('5a', '1c') - - # ground truth - ground_truth = set([frozenset(['1a', '1b', '1c', '1d']), - frozenset(['2a', '2b', '2c', '2d']), - frozenset(['3a', '3b', '3c', '3d']), - frozenset(['4a', '4b', '4c', '4d']), - frozenset(['5a', '5b', '5c', '5d'])]) - - communities = asyn_fluidc(test, 5, seed=9) - result = {frozenset(c) for c in communities} - assert result == ground_truth diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_centrality.py b/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_centrality.py deleted file mode 100644 index 85d0e807..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_centrality.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- coding: utf-8 -*- -# test_centrality.py - unit tests for algorithms.community.centrality -# -# Copyright 2015, 2016 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.community.centrality` -module. - -""" -from operator import itemgetter - - -import networkx as nx -from networkx.algorithms.community import girvan_newman - - -def set_of_sets(iterable): - return set(map(frozenset, iterable)) - - -def validate_communities(result, expected): - assert set_of_sets(result) == set_of_sets(expected) - - -def validate_possible_communities(result, *expected): - assert any(set_of_sets(result) == set_of_sets(p) for p in expected) - - -class TestGirvanNewman(object): - """Unit tests for the - :func:`networkx.algorithms.community.centrality.girvan_newman` - function. - - """ - - def test_no_edges(self): - G = nx.empty_graph(3) - communities = list(girvan_newman(G)) - assert len(communities) == 1 - validate_communities(communities[0], [{0}, {1}, {2}]) - - def test_undirected(self): - # Start with the graph .-.-.-. - G = nx.path_graph(4) - communities = list(girvan_newman(G)) - assert len(communities) == 3 - # After one removal, we get the graph .-. .-. - validate_communities(communities[0], [{0, 1}, {2, 3}]) - # After the next, we get the graph .-. . ., but there are two - # symmetric possible versions. - validate_possible_communities(communities[1], [{0}, {1}, {2, 3}], - [{0, 1}, {2}, {3}]) - # After the last removal, we always get the empty graph. - validate_communities(communities[2], [{0}, {1}, {2}, {3}]) - - def test_directed(self): - G = nx.DiGraph(nx.path_graph(4)) - communities = list(girvan_newman(G)) - assert len(communities) == 3 - validate_communities(communities[0], [{0, 1}, {2, 3}]) - validate_possible_communities(communities[1], [{0}, {1}, {2, 3}], - [{0, 1}, {2}, {3}]) - validate_communities(communities[2], [{0}, {1}, {2}, {3}]) - - def test_selfloops(self): - G = nx.path_graph(4) - G.add_edge(0, 0) - G.add_edge(2, 2) - communities = list(girvan_newman(G)) - assert len(communities) == 3 - validate_communities(communities[0], [{0, 1}, {2, 3}]) - validate_possible_communities(communities[1], [{0}, {1}, {2, 3}], - [{0, 1}, {2}, {3}]) - validate_communities(communities[2], [{0}, {1}, {2}, {3}]) - - def test_most_valuable_edge(self): - G = nx.Graph() - G.add_weighted_edges_from([(0, 1, 3), (1, 2, 2), (2, 3, 1)]) - # Let the most valuable edge be the one with the highest weight. - - def heaviest(G): return max(G.edges(data='weight'), key=itemgetter(2))[:2] - communities = list(girvan_newman(G, heaviest)) - assert len(communities) == 3 - validate_communities(communities[0], [{0}, {1, 2, 3}]) - validate_communities(communities[1], [{0}, {1}, {2, 3}]) - validate_communities(communities[2], [{0}, {1}, {2}, {3}]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_kclique.py b/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_kclique.py deleted file mode 100644 index 03a598a5..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_kclique.py +++ /dev/null @@ -1,65 +0,0 @@ -from itertools import combinations - -import pytest - -import networkx as nx -from networkx.algorithms.community import k_clique_communities - - -def test_overlapping_K5(): - G = nx.Graph() - G.add_edges_from(combinations(range(5), 2)) # Add a five clique - G.add_edges_from(combinations(range(2, 7), 2)) # Add another five clique - c = list(k_clique_communities(G, 4)) - assert c == [frozenset(range(7))] - c = set(k_clique_communities(G, 5)) - assert c == {frozenset(range(5)), frozenset(range(2, 7))} - - -def test_isolated_K5(): - G = nx.Graph() - G.add_edges_from(combinations(range(0, 5), 2)) # Add a five clique - G.add_edges_from(combinations(range(5, 10), 2)) # Add another five clique - c = set(k_clique_communities(G, 5)) - assert c == {frozenset(range(5)), frozenset(range(5, 10))} - - -class TestZacharyKarateClub(object): - - def setup(self): - self.G = nx.karate_club_graph() - - def _check_communities(self, k, expected): - communities = set(k_clique_communities(self.G, k)) - assert communities == expected - - def test_k2(self): - # clique percolation with k=2 is just connected components - expected = {frozenset(self.G)} - self._check_communities(2, expected) - - def test_k3(self): - comm1 = [0, 1, 2, 3, 7, 8, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, - 26, 27, 28, 29, 30, 31, 32, 33] - comm2 = [0, 4, 5, 6, 10, 16] - comm3 = [24, 25, 31] - expected = {frozenset(comm1), frozenset(comm2), frozenset(comm3)} - self._check_communities(3, expected) - - def test_k4(self): - expected = {frozenset([0, 1, 2, 3, 7, 13]), frozenset([8, 32, 30, 33]), - frozenset([32, 33, 29, 23])} - self._check_communities(4, expected) - - def test_k5(self): - expected = {frozenset([0, 1, 2, 3, 7, 13])} - self._check_communities(5, expected) - - def test_k6(self): - expected = set() - self._check_communities(6, expected) - - -def test_bad_k(): - with pytest.raises(nx.NetworkXError): - list(k_clique_communities(nx.Graph(), 1)) diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_kernighan_lin.py b/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_kernighan_lin.py deleted file mode 100644 index 73c4aba4..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_kernighan_lin.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- encoding: utf-8 -*- -# test_kernighan_lin.py - unit tests for Kernighan–Lin bipartition algorithm -# -# Copyright 2011 Ben Edwards . -# Copyright 2011 Aric Hagberg . -# Copyright 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.community.kernighan_lin` -module. - -""" -import pytest - -import networkx as nx -from networkx.algorithms.community import kernighan_lin_bisection - - -def assert_partition_equal(x, y): - assert set(map(frozenset, x)) == set(map(frozenset, y)) - - -def test_partition(): - G = nx.barbell_graph(3, 0) - C = kernighan_lin_bisection(G) - assert_partition_equal(C, [{0, 1, 2}, {3, 4, 5}]) - - -def test_seed_argument(): - G = nx.barbell_graph(3, 0) - C = kernighan_lin_bisection(G, seed=1) - assert_partition_equal(C, [{0, 1, 2}, {3, 4, 5}]) - - -def test_non_disjoint_partition(): - with pytest.raises(nx.NetworkXError): - G = nx.barbell_graph(3, 0) - partition = ({0, 1, 2}, {2, 3, 4, 5}) - kernighan_lin_bisection(G, partition) - - -def test_too_many_blocks(): - with pytest.raises(nx.NetworkXError): - G = nx.barbell_graph(3, 0) - partition = ({0, 1}, {2}, {3, 4, 5}) - kernighan_lin_bisection(G, partition) - - -def test_multigraph(): - G = nx.cycle_graph(4) - M = nx.MultiGraph(G.edges()) - M.add_edges_from(G.edges()) - M.remove_edge(1, 2) - A, B = kernighan_lin_bisection(M) - assert_partition_equal([A, B], [{0, 1}, {2, 3}]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_label_propagation.py b/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_label_propagation.py deleted file mode 100644 index 32586884..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_label_propagation.py +++ /dev/null @@ -1,152 +0,0 @@ -from itertools import chain -from itertools import combinations - -import pytest - -import networkx as nx -from networkx.algorithms.community import label_propagation_communities -from networkx.algorithms.community import asyn_lpa_communities - - -def test_directed_not_supported(): - with pytest.raises(nx.NetworkXNotImplemented): - # not supported for directed graphs - test = nx.DiGraph() - test.add_edge('a', 'b') - test.add_edge('a', 'c') - test.add_edge('b', 'd') - result = label_propagation_communities(test) - - -def test_one_node(): - test = nx.Graph() - test.add_node('a') - - # The expected communities are: - ground_truth = set([frozenset(['a'])]) - - communities = label_propagation_communities(test) - result = {frozenset(c) for c in communities} - assert result == ground_truth - - -def test_unconnected_communities(): - test = nx.Graph() - # community 1 - test.add_edge('a', 'c') - test.add_edge('a', 'd') - test.add_edge('d', 'c') - # community 2 - test.add_edge('b', 'e') - test.add_edge('e', 'f') - test.add_edge('f', 'b') - - # The expected communities are: - ground_truth = set([frozenset(['a', 'c', 'd']), - frozenset(['b', 'e', 'f'])]) - - communities = label_propagation_communities(test) - result = {frozenset(c) for c in communities} - assert result == ground_truth - - -def test_connected_communities(): - test = nx.Graph() - # community 1 - test.add_edge('a', 'b') - test.add_edge('c', 'a') - test.add_edge('c', 'b') - test.add_edge('d', 'a') - test.add_edge('d', 'b') - test.add_edge('d', 'c') - test.add_edge('e', 'a') - test.add_edge('e', 'b') - test.add_edge('e', 'c') - test.add_edge('e', 'd') - # community 2 - test.add_edge('1', '2') - test.add_edge('3', '1') - test.add_edge('3', '2') - test.add_edge('4', '1') - test.add_edge('4', '2') - test.add_edge('4', '3') - test.add_edge('5', '1') - test.add_edge('5', '2') - test.add_edge('5', '3') - test.add_edge('5', '4') - # edge between community 1 and 2 - test.add_edge('a', '1') - # community 3 - test.add_edge('x', 'y') - # community 4 with only a single node - test.add_node('z') - - # The expected communities are: - ground_truth1 = set([frozenset(['a', 'b', 'c', 'd', 'e']), - frozenset(['1', '2', '3', '4', '5']), - frozenset(['x', 'y']), - frozenset(['z'])]) - ground_truth2 = set([frozenset(['a', 'b', 'c', 'd', 'e', - '1', '2', '3', '4', '5']), - frozenset(['x', 'y']), - frozenset(['z'])]) - ground_truth = (ground_truth1, ground_truth2) - - communities = label_propagation_communities(test) - result = {frozenset(c) for c in communities} - assert result in ground_truth - - -def test_termination(): - # ensure termination of asyn_lpa_communities in two cases - # that led to an endless loop in a previous version - test1 = nx.karate_club_graph() - test2 = nx.caveman_graph(2, 10) - test2.add_edges_from([(0, 20), (20, 10)]) - asyn_lpa_communities(test1) - asyn_lpa_communities(test2) - - -class TestAsynLpaCommunities(object): - def _check_communities(self, G, expected): - """Checks that the communities computed from the given graph ``G`` - using the :func:`~networkx.asyn_lpa_communities` function match - the set of nodes given in ``expected``. - - ``expected`` must be a :class:`set` of :class:`frozenset` - instances, each element of which is a node in the graph. - - """ - communities = asyn_lpa_communities(G) - result = {frozenset(c) for c in communities} - assert result == expected - - def test_null_graph(self): - G = nx.null_graph() - ground_truth = set() - self._check_communities(G, ground_truth) - - def test_single_node(self): - G = nx.empty_graph(1) - ground_truth = {frozenset([0])} - self._check_communities(G, ground_truth) - - def test_simple_communities(self): - # This graph is the disjoint union of two triangles. - G = nx.Graph(['ab', 'ac', 'bc', 'de', 'df', 'fe']) - ground_truth = {frozenset('abc'), frozenset('def')} - self._check_communities(G, ground_truth) - - def test_seed_argument(self): - G = nx.Graph(['ab', 'ac', 'bc', 'de', 'df', 'fe']) - ground_truth = {frozenset('abc'), frozenset('def')} - communities = asyn_lpa_communities(G, seed=1) - result = {frozenset(c) for c in communities} - assert result == ground_truth - - def test_several_communities(self): - # This graph is the disjoint union of five triangles. - ground_truth = {frozenset(range(3 * i, 3 * (i + 1))) for i in range(5)} - edges = chain.from_iterable(combinations(c, 2) for c in ground_truth) - G = nx.Graph(edges) - self._check_communities(G, ground_truth) diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_modularity_max.py b/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_modularity_max.py deleted file mode 100644 index 77a0cfc5..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_modularity_max.py +++ /dev/null @@ -1,40 +0,0 @@ - - -import networkx as nx -from networkx.algorithms.community import ( - greedy_modularity_communities, - _naive_greedy_modularity_communities) - - -class TestCNM(object): - - def setup(self): - self.G = nx.karate_club_graph() - - def _check_communities(self, expected): - communities = set(greedy_modularity_communities(self.G)) - assert communities == expected - - def test_karate_club(self): - john_a = frozenset([ - 8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]) - mr_hi = frozenset([0, 4, 5, 6, 10, 11, 16, 19]) - overlap = frozenset([1, 2, 3, 7, 9, 12, 13, 17, 21]) - self._check_communities({john_a, overlap, mr_hi}) - - -class TestNaive(object): - - def setup(self): - self.G = nx.karate_club_graph() - - def _check_communities(self, expected): - communities = set(_naive_greedy_modularity_communities(self.G)) - assert communities == expected - - def test_karate_club(self): - john_a = frozenset([ - 8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]) - mr_hi = frozenset([0, 4, 5, 6, 10, 11, 16, 19]) - overlap = frozenset([1, 2, 3, 7, 9, 12, 13, 17, 21]) - self._check_communities({john_a, overlap, mr_hi}) diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_quality.py b/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_quality.py deleted file mode 100644 index eda7bb35..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_quality.py +++ /dev/null @@ -1,75 +0,0 @@ -# test_quality.py - unit tests for the quality module -# -# Copyright 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.community.quality` -module. - -""" - -import networkx as nx -from networkx import barbell_graph -from networkx.algorithms.community import coverage -from networkx.algorithms.community import modularity -from networkx.algorithms.community import performance -from networkx.algorithms.community.quality import inter_community_edges -from networkx.testing import almost_equal - -class TestPerformance(object): - """Unit tests for the :func:`performance` function.""" - - def test_bad_partition(self): - """Tests that a poor partition has a low performance measure.""" - G = barbell_graph(3, 0) - partition = [{0, 1, 4}, {2, 3, 5}] - assert almost_equal(8 / 15, performance(G, partition)) - - def test_good_partition(self): - """Tests that a good partition has a high performance measure. - - """ - G = barbell_graph(3, 0) - partition = [{0, 1, 2}, {3, 4, 5}] - assert almost_equal(14 / 15, performance(G, partition)) - - -class TestCoverage(object): - """Unit tests for the :func:`coverage` function.""" - - def test_bad_partition(self): - """Tests that a poor partition has a low coverage measure.""" - G = barbell_graph(3, 0) - partition = [{0, 1, 4}, {2, 3, 5}] - assert almost_equal(3 / 7, coverage(G, partition)) - - def test_good_partition(self): - """Tests that a good partition has a high coverage measure.""" - G = barbell_graph(3, 0) - partition = [{0, 1, 2}, {3, 4, 5}] - assert almost_equal(6 / 7, coverage(G, partition)) - - -def test_modularity(): - G = nx.barbell_graph(3, 0) - C = [{0, 1, 4}, {2, 3, 5}] - assert almost_equal(-16 / (14 ** 2), modularity(G, C)) - C = [{0, 1, 2}, {3, 4, 5}] - assert almost_equal((35 * 2) / (14 ** 2), modularity(G, C)) - - -def test_inter_community_edges_with_digraphs(): - G = nx.complete_graph(2, create_using=nx.DiGraph()) - partition = [{0}, {1}] - assert inter_community_edges(G, partition) == 2 - - G = nx.complete_graph(10, create_using=nx.DiGraph()) - partition = [{0}, {1, 2}, {3, 4, 5}, {6, 7, 8, 9}] - assert inter_community_edges(G, partition) == 70 - - G = nx.cycle_graph(4, create_using=nx.DiGraph()) - partition = [{0, 1}, {2, 3}] - assert inter_community_edges(G, partition) == 2 diff --git a/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_utils.py b/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_utils.py deleted file mode 100644 index 6a05d610..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/community/tests/test_utils.py +++ /dev/null @@ -1,37 +0,0 @@ -# test_utils.py - unit tests for the community utils module -# -# Copyright 2016 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.community.utils` module. - -""" - -import networkx as nx -from networkx.algorithms.community import is_partition - - -def test_is_partition(): - G = nx.empty_graph(3) - assert is_partition(G, [{0, 1}, {2}]) - assert is_partition(G, ({0, 1}, {2})) - assert is_partition(G, ([0, 1], [2])) - assert is_partition(G, [[0, 1], [2]]) - - -def test_not_covering(): - G = nx.empty_graph(3) - assert not is_partition(G, [{0}, {1}]) - - -def test_not_disjoint(): - G = nx.empty_graph(3) - assert not is_partition(G, [{0, 1}, {1, 2}]) - - -def test_not_node(): - G = nx.empty_graph(3) - assert not is_partition(G, [{0, 1}, {3}]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/components/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/components/__init__.py deleted file mode 100644 index f9ae2cab..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/components/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -from .connected import * -from .strongly_connected import * -from .weakly_connected import * -from .attracting import * -from .biconnected import * -from .semiconnected import * diff --git a/extensions/fablabchemnitz/networkx/algorithms/components/attracting.py b/extensions/fablabchemnitz/networkx/algorithms/components/attracting.py deleted file mode 100644 index 87c9ba70..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/components/attracting.py +++ /dev/null @@ -1,120 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Christopher Ellison -"""Attracting components.""" -import warnings as _warnings -import networkx as nx -from networkx.utils.decorators import not_implemented_for - -__all__ = ['number_attracting_components', - 'attracting_components', - 'is_attracting_component', - ] - - -@not_implemented_for('undirected') -def attracting_components(G): - """Generates the attracting components in `G`. - - An attracting component in a directed graph `G` is a strongly connected - component with the property that a random walker on the graph will never - leave the component, once it enters the component. - - The nodes in attracting components can also be thought of as recurrent - nodes. If a random walker enters the attractor containing the node, then - the node will be visited infinitely often. - - To obtain induced subgraphs on each component use: - ``(G.subgraph(c).copy() for c in attracting_components(G))`` - - Parameters - ---------- - G : DiGraph, MultiDiGraph - The graph to be analyzed. - - Returns - ------- - attractors : generator of sets - A generator of sets of nodes, one for each attracting component of G. - - Raises - ------ - NetworkXNotImplemented : - If the input graph is undirected. - - See Also - -------- - number_attracting_components - is_attracting_component - - """ - scc = list(nx.strongly_connected_components(G)) - cG = nx.condensation(G, scc) - for n in cG: - if cG.out_degree(n) == 0: - yield scc[n] - - -@not_implemented_for('undirected') -def number_attracting_components(G): - """Returns the number of attracting components in `G`. - - Parameters - ---------- - G : DiGraph, MultiDiGraph - The graph to be analyzed. - - Returns - ------- - n : int - The number of attracting components in G. - - Raises - ------ - NetworkXNotImplemented : - If the input graph is undirected. - - See Also - -------- - attracting_components - is_attracting_component - - """ - return sum(1 for ac in attracting_components(G)) - - -@not_implemented_for('undirected') -def is_attracting_component(G): - """Returns True if `G` consists of a single attracting component. - - Parameters - ---------- - G : DiGraph, MultiDiGraph - The graph to be analyzed. - - Returns - ------- - attracting : bool - True if `G` has a single attracting component. Otherwise, False. - - Raises - ------ - NetworkXNotImplemented : - If the input graph is undirected. - - See Also - -------- - attracting_components - number_attracting_components - - """ - ac = list(attracting_components(G)) - if len(ac) == 1: - return len(ac[0]) == len(G) - return False diff --git a/extensions/fablabchemnitz/networkx/algorithms/components/biconnected.py b/extensions/fablabchemnitz/networkx/algorithms/components/biconnected.py deleted file mode 100644 index d9e2572d..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/components/biconnected.py +++ /dev/null @@ -1,392 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2011-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Jordi Torrents (jtorrents@milnou.net) -# Dan Schult (dschult@colgate.edu) -# Aric Hagberg (aric.hagberg@gmail.com) -"""Biconnected components and articulation points.""" -import warnings as _warnings -from itertools import chain -import networkx as nx -from networkx.utils.decorators import not_implemented_for - -__all__ = [ - 'biconnected_components', - 'biconnected_component_edges', - 'is_biconnected', - 'articulation_points', -] - - -@not_implemented_for('directed') -def is_biconnected(G): - """Returns True if the graph is biconnected, False otherwise. - - A graph is biconnected if, and only if, it cannot be disconnected by - removing only one node (and all edges incident on that node). If - removing a node increases the number of disconnected components - in the graph, that node is called an articulation point, or cut - vertex. A biconnected graph has no articulation points. - - Parameters - ---------- - G : NetworkX Graph - An undirected graph. - - Returns - ------- - biconnected : bool - True if the graph is biconnected, False otherwise. - - Raises - ------ - NetworkXNotImplemented : - If the input graph is not undirected. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> print(nx.is_biconnected(G)) - False - >>> G.add_edge(0, 3) - >>> print(nx.is_biconnected(G)) - True - - See Also - -------- - biconnected_components - articulation_points - biconnected_component_edges - is_strongly_connected - is_weakly_connected - is_connected - is_semiconnected - - Notes - ----- - The algorithm to find articulation points and biconnected - components is implemented using a non-recursive depth-first-search - (DFS) that keeps track of the highest level that back edges reach - in the DFS tree. A node `n` is an articulation point if, and only - if, there exists a subtree rooted at `n` such that there is no - back edge from any successor of `n` that links to a predecessor of - `n` in the DFS tree. By keeping track of all the edges traversed - by the DFS we can obtain the biconnected components because all - edges of a bicomponent will be traversed consecutively between - articulation points. - - References - ---------- - .. [1] Hopcroft, J.; Tarjan, R. (1973). - "Efficient algorithms for graph manipulation". - Communications of the ACM 16: 372–378. doi:10.1145/362248.362272 - - """ - bcc = list(biconnected_components(G)) - if len(bcc) == 1: - return len(bcc[0]) == len(G) - return False # Multiple bicomponents or No bicomponents (empty graph?) -# if len(bcc) == 0: # No bicomponents (it could be an empty graph) -# return False -# return len(bcc[0]) == len(G) - - -@not_implemented_for('directed') -def biconnected_component_edges(G): - """Returns a generator of lists of edges, one list for each biconnected - component of the input graph. - - Biconnected components are maximal subgraphs such that the removal of a - node (and all edges incident on that node) will not disconnect the - subgraph. Note that nodes may be part of more than one biconnected - component. Those nodes are articulation points, or cut vertices. - However, each edge belongs to one, and only one, biconnected component. - - Notice that by convention a dyad is considered a biconnected component. - - Parameters - ---------- - G : NetworkX Graph - An undirected graph. - - Returns - ------- - edges : generator of lists - Generator of lists of edges, one list for each bicomponent. - - Raises - ------ - NetworkXNotImplemented : - If the input graph is not undirected. - - Examples - -------- - >>> G = nx.barbell_graph(4, 2) - >>> print(nx.is_biconnected(G)) - False - >>> bicomponents_edges = list(nx.biconnected_component_edges(G)) - >>> len(bicomponents_edges) - 5 - >>> G.add_edge(2, 8) - >>> print(nx.is_biconnected(G)) - True - >>> bicomponents_edges = list(nx.biconnected_component_edges(G)) - >>> len(bicomponents_edges) - 1 - - See Also - -------- - is_biconnected, - biconnected_components, - articulation_points, - - Notes - ----- - The algorithm to find articulation points and biconnected - components is implemented using a non-recursive depth-first-search - (DFS) that keeps track of the highest level that back edges reach - in the DFS tree. A node `n` is an articulation point if, and only - if, there exists a subtree rooted at `n` such that there is no - back edge from any successor of `n` that links to a predecessor of - `n` in the DFS tree. By keeping track of all the edges traversed - by the DFS we can obtain the biconnected components because all - edges of a bicomponent will be traversed consecutively between - articulation points. - - References - ---------- - .. [1] Hopcroft, J.; Tarjan, R. (1973). - "Efficient algorithms for graph manipulation". - Communications of the ACM 16: 372–378. doi:10.1145/362248.362272 - - """ - for comp in _biconnected_dfs(G, components=True): - yield comp - - -@not_implemented_for('directed') -def biconnected_components(G): - """Returns a generator of sets of nodes, one set for each biconnected - component of the graph - - Biconnected components are maximal subgraphs such that the removal of a - node (and all edges incident on that node) will not disconnect the - subgraph. Note that nodes may be part of more than one biconnected - component. Those nodes are articulation points, or cut vertices. The - removal of articulation points will increase the number of connected - components of the graph. - - Notice that by convention a dyad is considered a biconnected component. - - Parameters - ---------- - G : NetworkX Graph - An undirected graph. - - Returns - ------- - nodes : generator - Generator of sets of nodes, one set for each biconnected component. - - Raises - ------ - NetworkXNotImplemented : - If the input graph is not undirected. - - See Also - -------- - k_components : this function is a special case where k=2 - bridge_components : similar to this function, but is defined using - 2-edge-connectivity instead of 2-node-connectivity. - - - Examples - -------- - >>> G = nx.lollipop_graph(5, 1) - >>> print(nx.is_biconnected(G)) - False - >>> bicomponents = list(nx.biconnected_components(G)) - >>> len(bicomponents) - 2 - >>> G.add_edge(0, 5) - >>> print(nx.is_biconnected(G)) - True - >>> bicomponents = list(nx.biconnected_components(G)) - >>> len(bicomponents) - 1 - - You can generate a sorted list of biconnected components, largest - first, using sort. - - >>> G.remove_edge(0, 5) - >>> [len(c) for c in sorted(nx.biconnected_components(G), key=len, reverse=True)] - [5, 2] - - If you only want the largest connected component, it's more - efficient to use max instead of sort. - - >>> Gc = max(nx.biconnected_components(G), key=len) - - To create the components as subgraphs use: - ``(G.subgraph(c).copy() for c in biconnected_components(G))`` - - See Also - -------- - is_biconnected - articulation_points - biconnected_component_edges - - Notes - ----- - The algorithm to find articulation points and biconnected - components is implemented using a non-recursive depth-first-search - (DFS) that keeps track of the highest level that back edges reach - in the DFS tree. A node `n` is an articulation point if, and only - if, there exists a subtree rooted at `n` such that there is no - back edge from any successor of `n` that links to a predecessor of - `n` in the DFS tree. By keeping track of all the edges traversed - by the DFS we can obtain the biconnected components because all - edges of a bicomponent will be traversed consecutively between - articulation points. - - References - ---------- - .. [1] Hopcroft, J.; Tarjan, R. (1973). - "Efficient algorithms for graph manipulation". - Communications of the ACM 16: 372–378. doi:10.1145/362248.362272 - - """ - for comp in _biconnected_dfs(G, components=True): - yield set(chain.from_iterable(comp)) - - -@not_implemented_for('directed') -def articulation_points(G): - """Yield the articulation points, or cut vertices, of a graph. - - An articulation point or cut vertex is any node whose removal (along with - all its incident edges) increases the number of connected components of - a graph. An undirected connected graph without articulation points is - biconnected. Articulation points belong to more than one biconnected - component of a graph. - - Notice that by convention a dyad is considered a biconnected component. - - Parameters - ---------- - G : NetworkX Graph - An undirected graph. - - Yields - ------ - node - An articulation point in the graph. - - Raises - ------ - NetworkXNotImplemented : - If the input graph is not undirected. - - Examples - -------- - - >>> G = nx.barbell_graph(4, 2) - >>> print(nx.is_biconnected(G)) - False - >>> len(list(nx.articulation_points(G))) - 4 - >>> G.add_edge(2, 8) - >>> print(nx.is_biconnected(G)) - True - >>> len(list(nx.articulation_points(G))) - 0 - - See Also - -------- - is_biconnected - biconnected_components - biconnected_component_edges - - Notes - ----- - The algorithm to find articulation points and biconnected - components is implemented using a non-recursive depth-first-search - (DFS) that keeps track of the highest level that back edges reach - in the DFS tree. A node `n` is an articulation point if, and only - if, there exists a subtree rooted at `n` such that there is no - back edge from any successor of `n` that links to a predecessor of - `n` in the DFS tree. By keeping track of all the edges traversed - by the DFS we can obtain the biconnected components because all - edges of a bicomponent will be traversed consecutively between - articulation points. - - References - ---------- - .. [1] Hopcroft, J.; Tarjan, R. (1973). - "Efficient algorithms for graph manipulation". - Communications of the ACM 16: 372–378. doi:10.1145/362248.362272 - - """ - seen = set() - for articulation in _biconnected_dfs(G, components=False): - if articulation not in seen: - seen.add(articulation) - yield articulation - - -@not_implemented_for('directed') -def _biconnected_dfs(G, components=True): - # depth-first search algorithm to generate articulation points - # and biconnected components - visited = set() - for start in G: - if start in visited: - continue - discovery = {start: 0} # time of first discovery of node during search - low = {start: 0} - root_children = 0 - visited.add(start) - edge_stack = [] - stack = [(start, start, iter(G[start]))] - while stack: - grandparent, parent, children = stack[-1] - try: - child = next(children) - if grandparent == child: - continue - if child in visited: - if discovery[child] <= discovery[parent]: # back edge - low[parent] = min(low[parent], discovery[child]) - if components: - edge_stack.append((parent, child)) - else: - low[child] = discovery[child] = len(discovery) - visited.add(child) - stack.append((parent, child, iter(G[child]))) - if components: - edge_stack.append((parent, child)) - except StopIteration: - stack.pop() - if len(stack) > 1: - if low[parent] >= discovery[grandparent]: - if components: - ind = edge_stack.index((grandparent, parent)) - yield edge_stack[ind:] - edge_stack = edge_stack[:ind] - else: - yield grandparent - low[grandparent] = min(low[parent], low[grandparent]) - elif stack: # length 1 so grandparent is root - root_children += 1 - if components: - ind = edge_stack.index((grandparent, parent)) - yield edge_stack[ind:] - if not components: - # root node is articulation point if it has more than 1 child - if root_children > 1: - yield start diff --git a/extensions/fablabchemnitz/networkx/algorithms/components/connected.py b/extensions/fablabchemnitz/networkx/algorithms/components/connected.py deleted file mode 100644 index 16b6d693..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/components/connected.py +++ /dev/null @@ -1,197 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Eben Kenah -# Aric Hagberg (hagberg@lanl.gov) -# Christopher Ellison -"""Connected components.""" -import warnings as _warnings -import networkx as nx -from networkx.utils.decorators import not_implemented_for -from ...utils import arbitrary_element - -__all__ = [ - 'number_connected_components', - 'connected_components', - 'is_connected', - 'node_connected_component', -] - - -@not_implemented_for('directed') -def connected_components(G): - """Generate connected components. - - Parameters - ---------- - G : NetworkX graph - An undirected graph - - Returns - ------- - comp : generator of sets - A generator of sets of nodes, one for each component of G. - - Raises - ------ - NetworkXNotImplemented: - If G is directed. - - Examples - -------- - Generate a sorted list of connected components, largest first. - - >>> G = nx.path_graph(4) - >>> nx.add_path(G, [10, 11, 12]) - >>> [len(c) for c in sorted(nx.connected_components(G), key=len, reverse=True)] - [4, 3] - - If you only want the largest connected component, it's more - efficient to use max instead of sort. - - >>> largest_cc = max(nx.connected_components(G), key=len) - - To create the induced subgraph of each component use: - >>> S = [G.subgraph(c).copy() for c in connected_components(G)] - - See Also - -------- - strongly_connected_components - weakly_connected_components - - Notes - ----- - For undirected graphs only. - - """ - seen = set() - for v in G: - if v not in seen: - c = set(_plain_bfs(G, v)) - yield c - seen.update(c) - - -def number_connected_components(G): - """Returns the number of connected components. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - Returns - ------- - n : integer - Number of connected components - - See Also - -------- - connected_components - number_weakly_connected_components - number_strongly_connected_components - - Notes - ----- - For undirected graphs only. - - """ - return sum(1 for cc in connected_components(G)) - - -@not_implemented_for('directed') -def is_connected(G): - """Returns True if the graph is connected, False otherwise. - - Parameters - ---------- - G : NetworkX Graph - An undirected graph. - - Returns - ------- - connected : bool - True if the graph is connected, false otherwise. - - Raises - ------ - NetworkXNotImplemented: - If G is directed. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> print(nx.is_connected(G)) - True - - See Also - -------- - is_strongly_connected - is_weakly_connected - is_semiconnected - is_biconnected - connected_components - - Notes - ----- - For undirected graphs only. - - """ - if len(G) == 0: - raise nx.NetworkXPointlessConcept('Connectivity is undefined ', - 'for the null graph.') - return sum(1 for node in _plain_bfs(G, arbitrary_element(G))) == len(G) - - -@not_implemented_for('directed') -def node_connected_component(G, n): - """Returns the set of nodes in the component of graph containing node n. - - Parameters - ---------- - G : NetworkX Graph - An undirected graph. - - n : node label - A node in G - - Returns - ------- - comp : set - A set of nodes in the component of G containing node n. - - Raises - ------ - NetworkXNotImplemented: - If G is directed. - - See Also - -------- - connected_components - - Notes - ----- - For undirected graphs only. - - """ - return set(_plain_bfs(G, n)) - - -def _plain_bfs(G, source): - """A fast BFS node generator""" - G_adj = G.adj - seen = set() - nextlevel = {source} - while nextlevel: - thislevel = nextlevel - nextlevel = set() - for v in thislevel: - if v not in seen: - yield v - seen.add(v) - nextlevel.update(G_adj[v]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/components/semiconnected.py b/extensions/fablabchemnitz/networkx/algorithms/components/semiconnected.py deleted file mode 100644 index 8170221b..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/components/semiconnected.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: ysitu (ysitu@users.noreply.github.com) -"""Semiconnectedness.""" -import networkx as nx -from networkx.utils import not_implemented_for, pairwise - -__all__ = ['is_semiconnected'] - - -@not_implemented_for('undirected') -def is_semiconnected(G, topo_order=None): - """Returns True if the graph is semiconnected, False otherwise. - - A graph is semiconnected if, and only if, for any pair of nodes, either one - is reachable from the other, or they are mutually reachable. - - Parameters - ---------- - G : NetworkX graph - A directed graph. - - topo_order: list or tuple, optional - A topological order for G (if None, the function will compute one) - - Returns - ------- - semiconnected : bool - True if the graph is semiconnected, False otherwise. - - Raises - ------ - NetworkXNotImplemented : - If the input graph is undirected. - - NetworkXPointlessConcept : - If the graph is empty. - - Examples - -------- - >>> G=nx.path_graph(4,create_using=nx.DiGraph()) - >>> print(nx.is_semiconnected(G)) - True - >>> G=nx.DiGraph([(1, 2), (3, 2)]) - >>> print(nx.is_semiconnected(G)) - False - - See Also - -------- - is_strongly_connected - is_weakly_connected - is_connected - is_biconnected - """ - if len(G) == 0: - raise nx.NetworkXPointlessConcept( - 'Connectivity is undefined for the null graph.') - - if not nx.is_weakly_connected(G): - return False - - G = nx.condensation(G) - if topo_order is None: - topo_order = nx.topological_sort(G) - - return all(G.has_edge(u, v) for u, v in pairwise(topo_order)) diff --git a/extensions/fablabchemnitz/networkx/algorithms/components/strongly_connected.py b/extensions/fablabchemnitz/networkx/algorithms/components/strongly_connected.py deleted file mode 100644 index 935e2a66..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/components/strongly_connected.py +++ /dev/null @@ -1,399 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Eben Kenah -# Aric Hagberg (hagberg@lanl.gov) -# Christopher Ellison -# Ben Edwards (bedwards@cs.unm.edu) -"""Strongly connected components.""" -import warnings as _warnings -import networkx as nx -from networkx.utils.decorators import not_implemented_for - -__all__ = ['number_strongly_connected_components', - 'strongly_connected_components', - 'is_strongly_connected', - 'strongly_connected_components_recursive', - 'kosaraju_strongly_connected_components', - 'condensation'] - - -@not_implemented_for('undirected') -def strongly_connected_components(G): - """Generate nodes in strongly connected components of graph. - - Parameters - ---------- - G : NetworkX Graph - A directed graph. - - Returns - ------- - comp : generator of sets - A generator of sets of nodes, one for each strongly connected - component of G. - - Raises - ------ - NetworkXNotImplemented : - If G is undirected. - - Examples - -------- - Generate a sorted list of strongly connected components, largest first. - - >>> G = nx.cycle_graph(4, create_using=nx.DiGraph()) - >>> nx.add_cycle(G, [10, 11, 12]) - >>> [len(c) for c in sorted(nx.strongly_connected_components(G), - ... key=len, reverse=True)] - [4, 3] - - If you only want the largest component, it's more efficient to - use max instead of sort. - - >>> largest = max(nx.strongly_connected_components(G), key=len) - - See Also - -------- - connected_components - weakly_connected_components - kosaraju_strongly_connected_components - - Notes - ----- - Uses Tarjan's algorithm[1]_ with Nuutila's modifications[2]_. - Nonrecursive version of algorithm. - - References - ---------- - .. [1] Depth-first search and linear graph algorithms, R. Tarjan - SIAM Journal of Computing 1(2):146-160, (1972). - - .. [2] On finding the strongly connected components in a directed graph. - E. Nuutila and E. Soisalon-Soinen - Information Processing Letters 49(1): 9-14, (1994).. - - """ - preorder = {} - lowlink = {} - scc_found = set() - scc_queue = [] - i = 0 # Preorder counter - for source in G: - if source not in scc_found: - queue = [source] - while queue: - v = queue[-1] - if v not in preorder: - i = i + 1 - preorder[v] = i - done = True - for w in G[v]: - if w not in preorder: - queue.append(w) - done = False - break - if done: - lowlink[v] = preorder[v] - for w in G[v]: - if w not in scc_found: - if preorder[w] > preorder[v]: - lowlink[v] = min([lowlink[v], lowlink[w]]) - else: - lowlink[v] = min([lowlink[v], preorder[w]]) - queue.pop() - if lowlink[v] == preorder[v]: - scc = {v} - while scc_queue and preorder[scc_queue[-1]] > preorder[v]: - k = scc_queue.pop() - scc.add(k) - scc_found.update(scc) - yield scc - else: - scc_queue.append(v) - - -@not_implemented_for('undirected') -def kosaraju_strongly_connected_components(G, source=None): - """Generate nodes in strongly connected components of graph. - - Parameters - ---------- - G : NetworkX Graph - A directed graph. - - Returns - ------- - comp : generator of sets - A genrator of sets of nodes, one for each strongly connected - component of G. - - Raises - ------ - NetworkXNotImplemented: - If G is undirected. - - Examples - -------- - Generate a sorted list of strongly connected components, largest first. - - >>> G = nx.cycle_graph(4, create_using=nx.DiGraph()) - >>> nx.add_cycle(G, [10, 11, 12]) - >>> [len(c) for c in sorted(nx.kosaraju_strongly_connected_components(G), - ... key=len, reverse=True)] - [4, 3] - - If you only want the largest component, it's more efficient to - use max instead of sort. - - >>> largest = max(nx.kosaraju_strongly_connected_components(G), key=len) - - See Also - -------- - strongly_connected_components - - Notes - ----- - Uses Kosaraju's algorithm. - - """ - with nx.utils.reversed(G): - post = list(nx.dfs_postorder_nodes(G, source=source)) - - seen = set() - while post: - r = post.pop() - if r in seen: - continue - c = nx.dfs_preorder_nodes(G, r) - new = {v for v in c if v not in seen} - yield new - seen.update(new) - - -@not_implemented_for('undirected') -def strongly_connected_components_recursive(G): - """Generate nodes in strongly connected components of graph. - - Recursive version of algorithm. - - Parameters - ---------- - G : NetworkX Graph - A directed graph. - - Returns - ------- - comp : generator of sets - A generator of sets of nodes, one for each strongly connected - component of G. - - Raises - ------ - NetworkXNotImplemented : - If G is undirected. - - Examples - -------- - Generate a sorted list of strongly connected components, largest first. - - >>> G = nx.cycle_graph(4, create_using=nx.DiGraph()) - >>> nx.add_cycle(G, [10, 11, 12]) - >>> [len(c) for c in sorted(nx.strongly_connected_components_recursive(G), - ... key=len, reverse=True)] - [4, 3] - - If you only want the largest component, it's more efficient to - use max instead of sort. - - >>> largest = max(nx.strongly_connected_components_recursive(G), key=len) - - To create the induced subgraph of the components use: - >>> S = [G.subgraph(c).copy() for c in nx.weakly_connected_components(G)] - - See Also - -------- - connected_components - - Notes - ----- - Uses Tarjan's algorithm[1]_ with Nuutila's modifications[2]_. - - References - ---------- - .. [1] Depth-first search and linear graph algorithms, R. Tarjan - SIAM Journal of Computing 1(2):146-160, (1972). - - .. [2] On finding the strongly connected components in a directed graph. - E. Nuutila and E. Soisalon-Soinen - Information Processing Letters 49(1): 9-14, (1994).. - - """ - def visit(v, cnt): - root[v] = cnt - visited[v] = cnt - cnt += 1 - stack.append(v) - for w in G[v]: - if w not in visited: - for c in visit(w, cnt): - yield c - if w not in component: - root[v] = min(root[v], root[w]) - if root[v] == visited[v]: - component[v] = root[v] - tmpc = {v} # hold nodes in this component - while stack[-1] != v: - w = stack.pop() - component[w] = root[v] - tmpc.add(w) - stack.remove(v) - yield tmpc - - visited = {} - component = {} - root = {} - cnt = 0 - stack = [] - for source in G: - if source not in visited: - for c in visit(source, cnt): - yield c - - -@not_implemented_for('undirected') -def number_strongly_connected_components(G): - """Returns number of strongly connected components in graph. - - Parameters - ---------- - G : NetworkX graph - A directed graph. - - Returns - ------- - n : integer - Number of strongly connected components - - Raises - ------ - NetworkXNotImplemented: - If G is undirected. - - See Also - -------- - strongly_connected_components - number_connected_components - number_weakly_connected_components - - Notes - ----- - For directed graphs only. - """ - return sum(1 for scc in strongly_connected_components(G)) - - -@not_implemented_for('undirected') -def is_strongly_connected(G): - """Test directed graph for strong connectivity. - - A directed graph is strongly connected if and only if every vertex in - the graph is reachable from every other vertex. - - Parameters - ---------- - G : NetworkX Graph - A directed graph. - - Returns - ------- - connected : bool - True if the graph is strongly connected, False otherwise. - - Raises - ------ - NetworkXNotImplemented: - If G is undirected. - - See Also - -------- - is_weakly_connected - is_semiconnected - is_connected - is_biconnected - strongly_connected_components - - Notes - ----- - For directed graphs only. - """ - if len(G) == 0: - raise nx.NetworkXPointlessConcept( - """Connectivity is undefined for the null graph.""") - - return len(list(strongly_connected_components(G))[0]) == len(G) - - -@not_implemented_for('undirected') -def condensation(G, scc=None): - """Returns the condensation of G. - - The condensation of G is the graph with each of the strongly connected - components contracted into a single node. - - Parameters - ---------- - G : NetworkX DiGraph - A directed graph. - - scc: list or generator (optional, default=None) - Strongly connected components. If provided, the elements in - `scc` must partition the nodes in `G`. If not provided, it will be - calculated as scc=nx.strongly_connected_components(G). - - Returns - ------- - C : NetworkX DiGraph - The condensation graph C of G. The node labels are integers - corresponding to the index of the component in the list of - strongly connected components of G. C has a graph attribute named - 'mapping' with a dictionary mapping the original nodes to the - nodes in C to which they belong. Each node in C also has a node - attribute 'members' with the set of original nodes in G that - form the SCC that the node in C represents. - - Raises - ------ - NetworkXNotImplemented: - If G is undirected. - - Notes - ----- - After contracting all strongly connected components to a single node, - the resulting graph is a directed acyclic graph. - - """ - if scc is None: - scc = nx.strongly_connected_components(G) - mapping = {} - members = {} - C = nx.DiGraph() - # Add mapping dict as graph attribute - C.graph['mapping'] = mapping - if len(G) == 0: - return C - for i, component in enumerate(scc): - members[i] = component - mapping.update((n, i) for n in component) - number_of_components = i + 1 - C.add_nodes_from(range(number_of_components)) - C.add_edges_from((mapping[u], mapping[v]) for u, v in G.edges() - if mapping[u] != mapping[v]) - # Add a list of members (ie original nodes) to each node (ie scc) in C. - nx.set_node_attributes(C, members, 'members') - return C diff --git a/extensions/fablabchemnitz/networkx/algorithms/components/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/components/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_attracting.py b/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_attracting.py deleted file mode 100644 index e6befd35..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_attracting.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -import pytest -import networkx as nx -from networkx import NetworkXNotImplemented - - -class TestAttractingComponents(object): - @classmethod - def setup_class(cls): - cls.G1 = nx.DiGraph() - cls.G1.add_edges_from([(5, 11), (11, 2), (11, 9), (11, 10), - (7, 11), (7, 8), (8, 9), (3, 8), (3, 10)]) - cls.G2 = nx.DiGraph() - cls.G2.add_edges_from([(0, 1), (0, 2), (1, 1), (1, 2), (2, 1)]) - - cls.G3 = nx.DiGraph() - cls.G3.add_edges_from([(0, 1), (1, 2), (2, 1), (0, 3), (3, 4), (4, 3)]) - - cls.G4 = nx.DiGraph() - - def test_attracting_components(self): - ac = list(nx.attracting_components(self.G1)) - assert {2} in ac - assert {9} in ac - assert {10} in ac - - ac = list(nx.attracting_components(self.G2)) - ac = [tuple(sorted(x)) for x in ac] - assert ac == [(1, 2)] - - ac = list(nx.attracting_components(self.G3)) - ac = [tuple(sorted(x)) for x in ac] - assert (1, 2) in ac - assert (3, 4) in ac - assert len(ac) == 2 - - ac = list(nx.attracting_components(self.G4)) - assert ac == [] - - def test_number_attacting_components(self): - assert nx.number_attracting_components(self.G1) == 3 - assert nx.number_attracting_components(self.G2) == 1 - assert nx.number_attracting_components(self.G3) == 2 - assert nx.number_attracting_components(self.G4) == 0 - - def test_is_attracting_component(self): - assert not nx.is_attracting_component(self.G1) - assert not nx.is_attracting_component(self.G2) - assert not nx.is_attracting_component(self.G3) - g2 = self.G3.subgraph([1, 2]) - assert nx.is_attracting_component(g2) - assert not nx.is_attracting_component(self.G4) - - def test_connected_raise(self): - G = nx.Graph() - pytest.raises(NetworkXNotImplemented, nx.attracting_components, G) - pytest.raises(NetworkXNotImplemented, nx.number_attracting_components, G) - pytest.raises(NetworkXNotImplemented, nx.is_attracting_component, G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_biconnected.py b/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_biconnected.py deleted file mode 100644 index beb766f8..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_biconnected.py +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env python -import pytest -import networkx as nx -from networkx import NetworkXNotImplemented - - -def assert_components_edges_equal(x, y): - sx = {frozenset([frozenset(e) for e in c]) for c in x} - sy = {frozenset([frozenset(e) for e in c]) for c in y} - assert sx == sy - - -def assert_components_equal(x, y): - sx = {frozenset(c) for c in x} - sy = {frozenset(c) for c in y} - assert sx == sy - - -def test_barbell(): - G = nx.barbell_graph(8, 4) - nx.add_path(G, [7, 20, 21, 22]) - nx.add_cycle(G, [22, 23, 24, 25]) - pts = set(nx.articulation_points(G)) - assert pts == {7, 8, 9, 10, 11, 12, 20, 21, 22} - - answer = [ - {12, 13, 14, 15, 16, 17, 18, 19}, - {0, 1, 2, 3, 4, 5, 6, 7}, - {22, 23, 24, 25}, - {11, 12}, - {10, 11}, - {9, 10}, - {8, 9}, - {7, 8}, - {21, 22}, - {20, 21}, - {7, 20}, - ] - assert_components_equal(list(nx.biconnected_components(G)), answer) - - G.add_edge(2, 17) - pts = set(nx.articulation_points(G)) - assert pts == {7, 20, 21, 22} - - -def test_articulation_points_repetitions(): - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (1, 3)]) - assert list(nx.articulation_points(G)) == [1] - - -def test_articulation_points_cycle(): - G = nx.cycle_graph(3) - nx.add_cycle(G, [1, 3, 4]) - pts = set(nx.articulation_points(G)) - assert pts == {1} - - -def test_is_biconnected(): - G = nx.cycle_graph(3) - assert nx.is_biconnected(G) - nx.add_cycle(G, [1, 3, 4]) - assert not nx.is_biconnected(G) - - -def test_empty_is_biconnected(): - G = nx.empty_graph(5) - assert not nx.is_biconnected(G) - G.add_edge(0, 1) - assert not nx.is_biconnected(G) - - -def test_biconnected_components_cycle(): - G = nx.cycle_graph(3) - nx.add_cycle(G, [1, 3, 4]) - answer = [{0, 1, 2}, {1, 3, 4}] - assert_components_equal(list(nx.biconnected_components(G)), answer) - - -def test_biconnected_components1(): - # graph example from - # http://www.ibluemojo.com/school/articul_algorithm.html - edges = [ - (0, 1), (0, 5), (0, 6), (0, 14), (1, 5), (1, 6), (1, 14), (2, 4), - (2, 10), (3, 4), (3, 15), (4, 6), (4, 7), (4, 10), (5, 14), (6, 14), - (7, 9), (8, 9), (8, 12), (8, 13), (10, 15), (11, 12), (11, 13), (12, 13) - ] - G = nx.Graph(edges) - pts = set(nx.articulation_points(G)) - assert pts == {4, 6, 7, 8, 9} - comps = list(nx.biconnected_component_edges(G)) - answer = [ - [(3, 4), (15, 3), (10, 15), (10, 4), (2, 10), (4, 2)], - [(13, 12), (13, 8), (11, 13), (12, 11), (8, 12)], - [(9, 8)], - [(7, 9)], - [(4, 7)], - [(6, 4)], - [(14, 0), (5, 1), (5, 0), (14, 5), (14, 1), (6, 14), (6, 0), (1, 6), (0, 1)], - ] - assert_components_edges_equal(comps, answer) - - -def test_biconnected_components2(): - G = nx.Graph() - nx.add_cycle(G, 'ABC') - nx.add_cycle(G, 'CDE') - nx.add_cycle(G, 'FIJHG') - nx.add_cycle(G, 'GIJ') - G.add_edge('E', 'G') - comps = list(nx.biconnected_component_edges(G)) - answer = [ - [tuple('GF'), tuple('FI'), tuple('IG'), tuple('IJ'), - tuple('JG'), tuple('JH'), tuple('HG')], - [tuple('EG')], - [tuple('CD'), tuple('DE'), tuple('CE')], - [tuple('AB'), tuple('BC'), tuple('AC')] - ] - assert_components_edges_equal(comps, answer) - - -def test_biconnected_davis(): - D = nx.davis_southern_women_graph() - bcc = list(nx.biconnected_components(D))[0] - assert set(D) == bcc # All nodes in a giant bicomponent - # So no articulation points - assert len(list(nx.articulation_points(D))) == 0 - - -def test_biconnected_karate(): - K = nx.karate_club_graph() - answer = [{0, 1, 2, 3, 7, 8, 9, 12, 13, 14, 15, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33}, - {0, 4, 5, 6, 10, 16}, - {0, 11}] - bcc = list(nx.biconnected_components(K)) - assert_components_equal(bcc, answer) - assert set(nx.articulation_points(K)) == {0} - - -def test_biconnected_eppstein(): - # tests from http://www.ics.uci.edu/~eppstein/PADS/Biconnectivity.py - G1 = nx.Graph({ - 0: [1, 2, 5], - 1: [0, 5], - 2: [0, 3, 4], - 3: [2, 4, 5, 6], - 4: [2, 3, 5, 6], - 5: [0, 1, 3, 4], - 6: [3, 4], - }) - G2 = nx.Graph({ - 0: [2, 5], - 1: [3, 8], - 2: [0, 3, 5], - 3: [1, 2, 6, 8], - 4: [7], - 5: [0, 2], - 6: [3, 8], - 7: [4], - 8: [1, 3, 6], - }) - assert nx.is_biconnected(G1) - assert not nx.is_biconnected(G2) - answer_G2 = [{1, 3, 6, 8}, {0, 2, 5}, {2, 3}, {4, 7}] - bcc = list(nx.biconnected_components(G2)) - assert_components_equal(bcc, answer_G2) - - -def test_null_graph(): - G = nx.Graph() - assert not nx.is_biconnected(G) - assert list(nx.biconnected_components(G)) == [] - assert list(nx.biconnected_component_edges(G)) == [] - assert list(nx.articulation_points(G)) == [] - - -def test_connected_raise(): - DG = nx.DiGraph() - pytest.raises(NetworkXNotImplemented, nx.biconnected_components, DG) - pytest.raises(NetworkXNotImplemented, nx.biconnected_component_edges, DG) - pytest.raises(NetworkXNotImplemented, nx.articulation_points, DG) - pytest.raises(NetworkXNotImplemented, nx.is_biconnected, DG) diff --git a/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_connected.py b/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_connected.py deleted file mode 100644 index 97107626..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_connected.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python -import pytest -import networkx as nx -from networkx import convert_node_labels_to_integers as cnlti -from networkx import NetworkXNotImplemented - - -class TestConnected: - - @classmethod - def setup_class(cls): - G1 = cnlti(nx.grid_2d_graph(2, 2), first_label=0, ordering="sorted") - G2 = cnlti(nx.lollipop_graph(3, 3), first_label=4, ordering="sorted") - G3 = cnlti(nx.house_graph(), first_label=10, ordering="sorted") - cls.G = nx.union(G1, G2) - cls.G = nx.union(cls.G, G3) - cls.DG = nx.DiGraph([(1, 2), (1, 3), (2, 3)]) - cls.grid = cnlti(nx.grid_2d_graph(4, 4), first_label=1) - - cls.gc = [] - G = nx.DiGraph() - G.add_edges_from([(1, 2), (2, 3), (2, 8), (3, 4), (3, 7), (4, 5), - (5, 3), (5, 6), (7, 4), (7, 6), (8, 1), (8, 7)]) - C = [[3, 4, 5, 7], [1, 2, 8], [6]] - cls.gc.append((G, C)) - - G = nx.DiGraph() - G.add_edges_from([(1, 2), (1, 3), (1, 4), (4, 2), (3, 4), (2, 3)]) - C = [[2, 3, 4], [1]] - cls.gc.append((G, C)) - - G = nx.DiGraph() - G.add_edges_from([(1, 2), (2, 3), (3, 2), (2, 1)]) - C = [[1, 2, 3]] - cls.gc.append((G, C)) - - # Eppstein's tests - G = nx.DiGraph({0: [1], 1: [2, 3], 2: [4, 5], 3: [4, 5], 4: [6], 5: [], 6: []}) - C = [[0], [1], [2], [3], [4], [5], [6]] - cls.gc.append((G, C)) - - G = nx.DiGraph({0: [1], 1: [2, 3, 4], 2: [0, 3], 3: [4], 4: [3]}) - C = [[0, 1, 2], [3, 4]] - cls.gc.append((G, C)) - - G = nx.DiGraph() - C = [] - cls.gc.append((G, C)) - - def test_connected_components(self): - cc = nx.connected_components - G = self.G - C = { - frozenset([0, 1, 2, 3]), - frozenset([4, 5, 6, 7, 8, 9]), - frozenset([10, 11, 12, 13, 14]) - } - assert {frozenset(g) for g in cc(G)} == C - - def test_number_connected_components(self): - ncc = nx.number_connected_components - assert ncc(self.G) == 3 - - def test_number_connected_components2(self): - ncc = nx.number_connected_components - assert ncc(self.grid) == 1 - - def test_connected_components2(self): - cc = nx.connected_components - G = self.grid - C = {frozenset([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])} - assert {frozenset(g) for g in cc(G)} == C - - def test_node_connected_components(self): - ncc = nx.node_connected_component - G = self.grid - C = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} - assert ncc(G, 1) == C - - def test_is_connected(self): - assert nx.is_connected(self.grid) - G = nx.Graph() - G.add_nodes_from([1, 2]) - assert not nx.is_connected(G) - - def test_connected_raise(self): - pytest.raises(NetworkXNotImplemented, nx.connected_components, self.DG) - pytest.raises(NetworkXNotImplemented, nx.number_connected_components, self.DG) - pytest.raises(NetworkXNotImplemented, nx.node_connected_component, self.DG, 1) - pytest.raises(NetworkXNotImplemented, nx.is_connected, self.DG) - pytest.raises(nx.NetworkXPointlessConcept, nx.is_connected, nx.Graph()) diff --git a/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_semiconnected.py b/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_semiconnected.py deleted file mode 100644 index 35a7c090..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_semiconnected.py +++ /dev/null @@ -1,53 +0,0 @@ -from itertools import chain -import networkx as nx -import pytest - -class TestIsSemiconnected(object): - - def test_undirected(self): - pytest.raises(nx.NetworkXNotImplemented, nx.is_semiconnected, - nx.Graph()) - pytest.raises(nx.NetworkXNotImplemented, nx.is_semiconnected, - nx.MultiGraph()) - - def test_empty(self): - pytest.raises(nx.NetworkXPointlessConcept, nx.is_semiconnected, - nx.DiGraph()) - pytest.raises(nx.NetworkXPointlessConcept, nx.is_semiconnected, - nx.MultiDiGraph()) - - def test_single_node_graph(self): - G = nx.DiGraph() - G.add_node(0) - assert nx.is_semiconnected(G) - - def test_path(self): - G = nx.path_graph(100, create_using=nx.DiGraph()) - assert nx.is_semiconnected(G) - G.add_edge(100, 99) - assert not nx.is_semiconnected(G) - - def test_cycle(self): - G = nx.cycle_graph(100, create_using=nx.DiGraph()) - assert nx.is_semiconnected(G) - G = nx.path_graph(100, create_using=nx.DiGraph()) - G.add_edge(0, 99) - assert nx.is_semiconnected(G) - - def test_tree(self): - G = nx.DiGraph() - G.add_edges_from(chain.from_iterable([(i, 2 * i + 1), (i, 2 * i + 2)] - for i in range(100))) - assert not nx.is_semiconnected(G) - - def test_dumbbell(self): - G = nx.cycle_graph(100, create_using=nx.DiGraph()) - G.add_edges_from((i + 100, (i + 1) % 100 + 100) for i in range(100)) - assert not nx.is_semiconnected(G) # G is disconnected. - G.add_edge(100, 99) - assert nx.is_semiconnected(G) - - def test_alternating_path(self): - G = nx.DiGraph(chain.from_iterable([(i, i - 1), (i, i + 1)] - for i in range(0, 100, 2))) - assert not nx.is_semiconnected(G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_strongly_connected.py b/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_strongly_connected.py deleted file mode 100644 index c1dbbd8d..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_strongly_connected.py +++ /dev/null @@ -1,175 +0,0 @@ -#!/usr/bin/env python -import pytest -import networkx as nx -from networkx import NetworkXNotImplemented - - -class TestStronglyConnected: - - @classmethod - def setup_class(cls): - cls.gc = [] - G = nx.DiGraph() - G.add_edges_from([(1, 2), (2, 3), (2, 8), (3, 4), (3, 7), (4, 5), - (5, 3), (5, 6), (7, 4), (7, 6), (8, 1), (8, 7)]) - C = {frozenset([3, 4, 5, 7]), frozenset([1, 2, 8]), frozenset([6])} - cls.gc.append((G, C)) - - G = nx.DiGraph() - G.add_edges_from([(1, 2), (1, 3), (1, 4), (4, 2), (3, 4), (2, 3)]) - C = {frozenset([2, 3, 4]), frozenset([1])} - cls.gc.append((G, C)) - - G = nx.DiGraph() - G.add_edges_from([(1, 2), (2, 3), (3, 2), (2, 1)]) - C = {frozenset([1, 2, 3])} - cls.gc.append((G, C)) - - # Eppstein's tests - G = nx.DiGraph({0: [1], 1: [2, 3], 2: [4, 5], 3: [4, 5], 4: [6], 5: [], 6: []}) - C = { - frozenset([0]), - frozenset([1]), - frozenset([2]), - frozenset([3]), - frozenset([4]), - frozenset([5]), - frozenset([6]), - } - cls.gc.append((G, C)) - - G = nx.DiGraph({0: [1], 1: [2, 3, 4], 2: [0, 3], 3: [4], 4: [3]}) - C = {frozenset([0, 1, 2]), frozenset([3, 4])} - cls.gc.append((G, C)) - - def test_tarjan(self): - scc = nx.strongly_connected_components - for G, C in self.gc: - assert {frozenset(g) for g in scc(G)} == C - - def test_tarjan_recursive(self): - scc = nx.strongly_connected_components_recursive - for G, C in self.gc: - assert {frozenset(g) for g in scc(G)} == C - - def test_kosaraju(self): - scc = nx.kosaraju_strongly_connected_components - for G, C in self.gc: - assert {frozenset(g) for g in scc(G)} == C - - def test_number_strongly_connected_components(self): - ncc = nx.number_strongly_connected_components - for G, C in self.gc: - assert ncc(G) == len(C) - - def test_is_strongly_connected(self): - for G, C in self.gc: - if len(C) == 1: - assert nx.is_strongly_connected(G) - else: - assert not nx.is_strongly_connected(G) - - def test_contract_scc1(self): - G = nx.DiGraph() - G.add_edges_from([ - (1, 2), (2, 3), (2, 11), (2, 12), (3, 4), (4, 3), (4, 5), (5, 6), - (6, 5), (6, 7), (7, 8), (7, 9), (7, 10), (8, 9), (9, 7), (10, 6), - (11, 2), (11, 4), (11, 6), (12, 6), (12, 11), - ]) - scc = list(nx.strongly_connected_components(G)) - cG = nx.condensation(G, scc) - # DAG - assert nx.is_directed_acyclic_graph(cG) - # nodes - assert sorted(cG.nodes()) == [0, 1, 2, 3] - # edges - mapping = {} - for i, component in enumerate(scc): - for n in component: - mapping[n] = i - edge = (mapping[2], mapping[3]) - assert cG.has_edge(*edge) - edge = (mapping[2], mapping[5]) - assert cG.has_edge(*edge) - edge = (mapping[3], mapping[5]) - assert cG.has_edge(*edge) - - def test_contract_scc_isolate(self): - # Bug found and fixed in [1687]. - G = nx.DiGraph() - G.add_edge(1, 2) - G.add_edge(2, 1) - scc = list(nx.strongly_connected_components(G)) - cG = nx.condensation(G, scc) - assert list(cG.nodes()) == [0] - assert list(cG.edges()) == [] - - def test_contract_scc_edge(self): - G = nx.DiGraph() - G.add_edge(1, 2) - G.add_edge(2, 1) - G.add_edge(2, 3) - G.add_edge(3, 4) - G.add_edge(4, 3) - scc = list(nx.strongly_connected_components(G)) - cG = nx.condensation(G, scc) - assert sorted(cG.nodes()) == [0, 1] - if 1 in scc[0]: - edge = (0, 1) - else: - edge = (1, 0) - assert list(cG.edges()) == [edge] - - def test_condensation_mapping_and_members(self): - G, C = self.gc[1] - C = sorted(C, key=len, reverse=True) - cG = nx.condensation(G) - mapping = cG.graph['mapping'] - assert all(n in G for n in mapping) - assert all(0 == cN for n, cN in mapping.items() if n in C[0]) - assert all(1 == cN for n, cN in mapping.items() if n in C[1]) - for n, d in cG.nodes(data=True): - assert set(C[n]) == cG.nodes[n]['members'] - - def test_null_graph(self): - G = nx.DiGraph() - assert list(nx.strongly_connected_components(G)) == [] - assert list(nx.kosaraju_strongly_connected_components(G)) == [] - assert list(nx.strongly_connected_components_recursive(G)) == [] - assert len(nx.condensation(G)) == 0 - pytest.raises(nx.NetworkXPointlessConcept, nx.is_strongly_connected, nx.DiGraph()) - - def test_connected_raise(self): - G = nx.Graph() - pytest.raises(NetworkXNotImplemented, nx.strongly_connected_components, G) - pytest.raises(NetworkXNotImplemented, nx.kosaraju_strongly_connected_components, G) - pytest.raises(NetworkXNotImplemented, nx.strongly_connected_components_recursive, G) - pytest.raises(NetworkXNotImplemented, nx.is_strongly_connected, G) - pytest.raises(nx.NetworkXPointlessConcept, nx.is_strongly_connected, nx.DiGraph()) - pytest.raises(NetworkXNotImplemented, nx.condensation, G) - -# Commented out due to variability on Travis-CI hardware/operating systems -# def test_linear_time(self): -# # See Issue #2831 -# count = 100 # base case -# dg = nx.DiGraph() -# dg.add_nodes_from([0, 1]) -# for i in range(2, count): -# dg.add_node(i) -# dg.add_edge(i, 1) -# dg.add_edge(0, i) -# t = time.time() -# ret = tuple(nx.strongly_connected_components(dg)) -# dt = time.time() - t -# -# count = 200 -# dg = nx.DiGraph() -# dg.add_nodes_from([0, 1]) -# for i in range(2, count): -# dg.add_node(i) -# dg.add_edge(i, 1) -# dg.add_edge(0, i) -# t = time.time() -# ret = tuple(nx.strongly_connected_components(dg)) -# dt2 = time.time() - t -# assert_less(dt2, dt * 2.3) # should be 2 times longer for this graph diff --git a/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_weakly_connected.py b/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_weakly_connected.py deleted file mode 100644 index ab534641..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/components/tests/test_weakly_connected.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python -import pytest -import networkx as nx -from networkx import NetworkXNotImplemented - - -class TestWeaklyConnected: - - @classmethod - def setup_class(cls): - cls.gc = [] - G = nx.DiGraph() - G.add_edges_from([(1, 2), (2, 3), (2, 8), (3, 4), (3, 7), (4, 5), - (5, 3), (5, 6), (7, 4), (7, 6), (8, 1), (8, 7)]) - C = [[3, 4, 5, 7], [1, 2, 8], [6]] - cls.gc.append((G, C)) - - G = nx.DiGraph() - G.add_edges_from([(1, 2), (1, 3), (1, 4), (4, 2), (3, 4), (2, 3)]) - C = [[2, 3, 4], [1]] - cls.gc.append((G, C)) - - G = nx.DiGraph() - G.add_edges_from([(1, 2), (2, 3), (3, 2), (2, 1)]) - C = [[1, 2, 3]] - cls.gc.append((G, C)) - - # Eppstein's tests - G = nx.DiGraph({0: [1], 1: [2, 3], 2: [4, 5], 3: [4, 5], 4: [6], 5: [], 6: []}) - C = [[0], [1], [2], [3], [4], [5], [6]] - cls.gc.append((G, C)) - - G = nx.DiGraph({0: [1], 1: [2, 3, 4], 2: [0, 3], 3: [4], 4: [3]}) - C = [[0, 1, 2], [3, 4]] - cls.gc.append((G, C)) - - def test_weakly_connected_components(self): - for G, C in self.gc: - U = G.to_undirected() - w = {frozenset(g) for g in nx.weakly_connected_components(G)} - c = {frozenset(g) for g in nx.connected_components(U)} - assert w == c - - def test_number_weakly_connected_components(self): - for G, C in self.gc: - U = G.to_undirected() - w = nx.number_weakly_connected_components(G) - c = nx.number_connected_components(U) - assert w == c - - def test_is_weakly_connected(self): - for G, C in self.gc: - U = G.to_undirected() - assert nx.is_weakly_connected(G) == nx.is_connected(U) - - def test_null_graph(self): - G = nx.DiGraph() - assert list(nx.weakly_connected_components(G)) == [] - assert nx.number_weakly_connected_components(G) == 0 - pytest.raises(nx.NetworkXPointlessConcept, nx.is_weakly_connected, G) - - def test_connected_raise(self): - G = nx.Graph() - pytest.raises(NetworkXNotImplemented, nx.weakly_connected_components, G) - pytest.raises(NetworkXNotImplemented, nx.number_weakly_connected_components, G) - pytest.raises(NetworkXNotImplemented, nx.is_weakly_connected, G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/components/weakly_connected.py b/extensions/fablabchemnitz/networkx/algorithms/components/weakly_connected.py deleted file mode 100644 index e77f05e1..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/components/weakly_connected.py +++ /dev/null @@ -1,176 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg (hagberg@lanl.gov) -# Christopher Ellison -"""Weakly connected components.""" -import warnings as _warnings -import networkx as nx -from networkx.utils.decorators import not_implemented_for - -__all__ = [ - 'number_weakly_connected_components', - 'weakly_connected_components', - 'is_weakly_connected', -] - - -@not_implemented_for('undirected') -def weakly_connected_components(G): - """Generate weakly connected components of G. - - Parameters - ---------- - G : NetworkX graph - A directed graph - - Returns - ------- - comp : generator of sets - A generator of sets of nodes, one for each weakly connected - component of G. - - Raises - ------ - NetworkXNotImplemented: - If G is undirected. - - Examples - -------- - Generate a sorted list of weakly connected components, largest first. - - >>> G = nx.path_graph(4, create_using=nx.DiGraph()) - >>> nx.add_path(G, [10, 11, 12]) - >>> [len(c) for c in sorted(nx.weakly_connected_components(G), - ... key=len, reverse=True)] - [4, 3] - - If you only want the largest component, it's more efficient to - use max instead of sort: - - >>> largest_cc = max(nx.weakly_connected_components(G), key=len) - - See Also - -------- - connected_components - strongly_connected_components - - Notes - ----- - For directed graphs only. - - """ - seen = set() - for v in G: - if v not in seen: - c = set(_plain_bfs(G, v)) - yield c - seen.update(c) - - -@not_implemented_for('undirected') -def number_weakly_connected_components(G): - """Returns the number of weakly connected components in G. - - Parameters - ---------- - G : NetworkX graph - A directed graph. - - Returns - ------- - n : integer - Number of weakly connected components - - Raises - ------ - NetworkXNotImplemented: - If G is undirected. - - See Also - -------- - weakly_connected_components - number_connected_components - number_strongly_connected_components - - Notes - ----- - For directed graphs only. - - """ - return sum(1 for wcc in weakly_connected_components(G)) - - -@not_implemented_for('undirected') -def is_weakly_connected(G): - """Test directed graph for weak connectivity. - - A directed graph is weakly connected if and only if the graph - is connected when the direction of the edge between nodes is ignored. - - Note that if a graph is strongly connected (i.e. the graph is connected - even when we account for directionality), it is by definition weakly - connected as well. - - Parameters - ---------- - G : NetworkX Graph - A directed graph. - - Returns - ------- - connected : bool - True if the graph is weakly connected, False otherwise. - - Raises - ------ - NetworkXNotImplemented: - If G is undirected. - - See Also - -------- - is_strongly_connected - is_semiconnected - is_connected - is_biconnected - weakly_connected_components - - Notes - ----- - For directed graphs only. - - """ - if len(G) == 0: - raise nx.NetworkXPointlessConcept( - """Connectivity is undefined for the null graph.""") - - return len(list(weakly_connected_components(G))[0]) == len(G) - - -def _plain_bfs(G, source): - """A fast BFS node generator - - The direction of the edge between nodes is ignored. - - For directed graphs only. - - """ - Gsucc = G.succ - Gpred = G.pred - - seen = set() - nextlevel = {source} - while nextlevel: - thislevel = nextlevel - nextlevel = set() - for v in thislevel: - if v not in seen: - yield v - seen.add(v) - nextlevel.update(Gsucc[v]) - nextlevel.update(Gpred[v]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/__init__.py deleted file mode 100644 index fd77d4a3..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -"""Connectivity and cut algorithms -""" -from .connectivity import * -from .cuts import * -from .edge_augmentation import * -from .edge_kcomponents import * -from .disjoint_paths import * -from .kcomponents import * -from .kcutsets import * -from .stoerwagner import * -from .utils import * - -__all__ = sum([connectivity.__all__, - cuts.__all__, - edge_augmentation.__all__, - edge_kcomponents.__all__, - disjoint_paths.__all__, - kcomponents.__all__, - kcutsets.__all__, - stoerwagner.__all__, - utils.__all__, - ], []) diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/connectivity.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/connectivity.py deleted file mode 100644 index 036181da..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/connectivity.py +++ /dev/null @@ -1,819 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Flow based connectivity algorithms -""" - -import itertools -from operator import itemgetter - -import networkx as nx -# Define the default maximum flow function to use in all flow based -# connectivity algorithms. -from networkx.algorithms.flow import boykov_kolmogorov -from networkx.algorithms.flow import dinitz -from networkx.algorithms.flow import edmonds_karp -from networkx.algorithms.flow import shortest_augmenting_path -from networkx.algorithms.flow import build_residual_network -default_flow_func = edmonds_karp - -from .utils import (build_auxiliary_node_connectivity, - build_auxiliary_edge_connectivity) - -__author__ = '\n'.join(['Jordi Torrents ']) - -__all__ = ['average_node_connectivity', - 'local_node_connectivity', - 'node_connectivity', - 'local_edge_connectivity', - 'edge_connectivity', - 'all_pairs_node_connectivity'] - - -def local_node_connectivity(G, s, t, flow_func=None, auxiliary=None, - residual=None, cutoff=None): - r"""Computes local node connectivity for nodes s and t. - - Local node connectivity for two non adjacent nodes s and t is the - minimum number of nodes that must be removed (along with their incident - edges) to disconnect them. - - This is a flow based implementation of node connectivity. We compute the - maximum flow on an auxiliary digraph build from the original input - graph (see below for details). - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - s : node - Source node - - t : node - Target node - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The choice - of the default function may change from version to version and - should not be relied on. Default value: None. - - auxiliary : NetworkX DiGraph - Auxiliary digraph to compute flow based node connectivity. It has - to have a graph attribute called mapping with a dictionary mapping - node names in G and in the auxiliary digraph. If provided - it will be reused instead of recreated. Default value: None. - - residual : NetworkX DiGraph - Residual network to compute maximum flow. If provided it will be - reused instead of recreated. Default value: None. - - cutoff : integer, float - If specified, the maximum flow algorithm will terminate when the - flow value reaches or exceeds the cutoff. This is only for the - algorithms that support the cutoff parameter: :meth:`edmonds_karp` - and :meth:`shortest_augmenting_path`. Other algorithms will ignore - this parameter. Default value: None. - - Returns - ------- - K : integer - local node connectivity for nodes s and t - - Examples - -------- - This function is not imported in the base NetworkX namespace, so you - have to explicitly import it from the connectivity package: - - >>> from networkx.algorithms.connectivity import local_node_connectivity - - We use in this example the platonic icosahedral graph, which has node - connectivity 5. - - >>> G = nx.icosahedral_graph() - >>> local_node_connectivity(G, 0, 6) - 5 - - If you need to compute local connectivity on several pairs of - nodes in the same graph, it is recommended that you reuse the - data structures that NetworkX uses in the computation: the - auxiliary digraph for node connectivity, and the residual - network for the underlying maximum flow computation. - - Example of how to compute local node connectivity among - all pairs of nodes of the platonic icosahedral graph reusing - the data structures. - - >>> import itertools - >>> # You also have to explicitly import the function for - >>> # building the auxiliary digraph from the connectivity package - >>> from networkx.algorithms.connectivity import ( - ... build_auxiliary_node_connectivity) - ... - >>> H = build_auxiliary_node_connectivity(G) - >>> # And the function for building the residual network from the - >>> # flow package - >>> from networkx.algorithms.flow import build_residual_network - >>> # Note that the auxiliary digraph has an edge attribute named capacity - >>> R = build_residual_network(H, 'capacity') - >>> result = dict.fromkeys(G, dict()) - >>> # Reuse the auxiliary digraph and the residual network by passing them - >>> # as parameters - >>> for u, v in itertools.combinations(G, 2): - ... k = local_node_connectivity(G, u, v, auxiliary=H, residual=R) - ... result[u][v] = k - ... - >>> all(result[u][v] == 5 for u, v in itertools.combinations(G, 2)) - True - - You can also use alternative flow algorithms for computing node - connectivity. For instance, in dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better than - the default :meth:`edmonds_karp` which is faster for sparse - networks with highly skewed degree distributions. Alternative flow - functions have to be explicitly imported from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> local_node_connectivity(G, 0, 6, flow_func=shortest_augmenting_path) - 5 - - Notes - ----- - This is a flow based implementation of node connectivity. We compute the - maximum flow using, by default, the :meth:`edmonds_karp` algorithm (see: - :meth:`maximum_flow`) on an auxiliary digraph build from the original - input graph: - - For an undirected graph G having `n` nodes and `m` edges we derive a - directed graph H with `2n` nodes and `2m+n` arcs by replacing each - original node `v` with two nodes `v_A`, `v_B` linked by an (internal) - arc in H. Then for each edge (`u`, `v`) in G we add two arcs - (`u_B`, `v_A`) and (`v_B`, `u_A`) in H. Finally we set the attribute - capacity = 1 for each arc in H [1]_ . - - For a directed graph G having `n` nodes and `m` arcs we derive a - directed graph H with `2n` nodes and `m+n` arcs by replacing each - original node `v` with two nodes `v_A`, `v_B` linked by an (internal) - arc (`v_A`, `v_B`) in H. Then for each arc (`u`, `v`) in G we add one arc - (`u_B`, `v_A`) in H. Finally we set the attribute capacity = 1 for - each arc in H. - - This is equal to the local node connectivity because the value of - a maximum s-t-flow is equal to the capacity of a minimum s-t-cut. - - See also - -------- - :meth:`local_edge_connectivity` - :meth:`node_connectivity` - :meth:`minimum_node_cut` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - References - ---------- - .. [1] Kammer, Frank and Hanjo Taubig. Graph Connectivity. in Brandes and - Erlebach, 'Network Analysis: Methodological Foundations', Lecture - Notes in Computer Science, Volume 3418, Springer-Verlag, 2005. - http://www.informatik.uni-augsburg.de/thi/personen/kammer/Graph_Connectivity.pdf - - """ - if flow_func is None: - flow_func = default_flow_func - - if auxiliary is None: - H = build_auxiliary_node_connectivity(G) - else: - H = auxiliary - - mapping = H.graph.get('mapping', None) - if mapping is None: - raise nx.NetworkXError('Invalid auxiliary digraph.') - - kwargs = dict(flow_func=flow_func, residual=residual) - if flow_func is shortest_augmenting_path: - kwargs['cutoff'] = cutoff - kwargs['two_phase'] = True - elif flow_func is edmonds_karp: - kwargs['cutoff'] = cutoff - elif flow_func is dinitz: - kwargs['cutoff'] = cutoff - elif flow_func is boykov_kolmogorov: - kwargs['cutoff'] = cutoff - - return nx.maximum_flow_value(H, '%sB' % mapping[s], '%sA' % mapping[t], **kwargs) - - -def node_connectivity(G, s=None, t=None, flow_func=None): - r"""Returns node connectivity for a graph or digraph G. - - Node connectivity is equal to the minimum number of nodes that - must be removed to disconnect G or render it trivial. If source - and target nodes are provided, this function returns the local node - connectivity: the minimum number of nodes that must be removed to break - all paths from source to target in G. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - s : node - Source node. Optional. Default value: None. - - t : node - Target node. Optional. Default value: None. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The - choice of the default function may change from version - to version and should not be relied on. Default value: None. - - Returns - ------- - K : integer - Node connectivity of G, or local node connectivity if source - and target are provided. - - Examples - -------- - >>> # Platonic icosahedral graph is 5-node-connected - >>> G = nx.icosahedral_graph() - >>> nx.node_connectivity(G) - 5 - - You can use alternative flow algorithms for the underlying maximum - flow computation. In dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better - than the default :meth:`edmonds_karp`, which is faster for - sparse networks with highly skewed degree distributions. Alternative - flow functions have to be explicitly imported from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> nx.node_connectivity(G, flow_func=shortest_augmenting_path) - 5 - - If you specify a pair of nodes (source and target) as parameters, - this function returns the value of local node connectivity. - - >>> nx.node_connectivity(G, 3, 7) - 5 - - If you need to perform several local computations among different - pairs of nodes on the same graph, it is recommended that you reuse - the data structures used in the maximum flow computations. See - :meth:`local_node_connectivity` for details. - - Notes - ----- - This is a flow based implementation of node connectivity. The - algorithm works by solving $O((n-\delta-1+\delta(\delta-1)/2))$ - maximum flow problems on an auxiliary digraph. Where $\delta$ - is the minimum degree of G. For details about the auxiliary - digraph and the computation of local node connectivity see - :meth:`local_node_connectivity`. This implementation is based - on algorithm 11 in [1]_. - - See also - -------- - :meth:`local_node_connectivity` - :meth:`edge_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - References - ---------- - .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms. - http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf - - """ - if (s is not None and t is None) or (s is None and t is not None): - raise nx.NetworkXError('Both source and target must be specified.') - - # Local node connectivity - if s is not None and t is not None: - if s not in G: - raise nx.NetworkXError('node %s not in graph' % s) - if t not in G: - raise nx.NetworkXError('node %s not in graph' % t) - return local_node_connectivity(G, s, t, flow_func=flow_func) - - # Global node connectivity - if G.is_directed(): - if not nx.is_weakly_connected(G): - return 0 - iter_func = itertools.permutations - # It is necessary to consider both predecessors - # and successors for directed graphs - - def neighbors(v): - return itertools.chain.from_iterable([G.predecessors(v), - G.successors(v)]) - else: - if not nx.is_connected(G): - return 0 - iter_func = itertools.combinations - neighbors = G.neighbors - - # Reuse the auxiliary digraph and the residual network - H = build_auxiliary_node_connectivity(G) - R = build_residual_network(H, 'capacity') - kwargs = dict(flow_func=flow_func, auxiliary=H, residual=R) - - # Pick a node with minimum degree - # Node connectivity is bounded by degree. - v, K = min(G.degree(), key=itemgetter(1)) - # compute local node connectivity with all its non-neighbors nodes - for w in set(G) - set(neighbors(v)) - set([v]): - kwargs['cutoff'] = K - K = min(K, local_node_connectivity(G, v, w, **kwargs)) - # Also for non adjacent pairs of neighbors of v - for x, y in iter_func(neighbors(v), 2): - if y in G[x]: - continue - kwargs['cutoff'] = K - K = min(K, local_node_connectivity(G, x, y, **kwargs)) - - return K - - -def average_node_connectivity(G, flow_func=None): - r"""Returns the average connectivity of a graph G. - - The average connectivity `\bar{\kappa}` of a graph G is the average - of local node connectivity over all pairs of nodes of G [1]_ . - - .. math:: - - \bar{\kappa}(G) = \frac{\sum_{u,v} \kappa_{G}(u,v)}{{n \choose 2}} - - Parameters - ---------- - - G : NetworkX graph - Undirected graph - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See :meth:`local_node_connectivity` - for details. The choice of the default function may change from - version to version and should not be relied on. Default value: None. - - Returns - ------- - K : float - Average node connectivity - - See also - -------- - :meth:`local_node_connectivity` - :meth:`node_connectivity` - :meth:`edge_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - References - ---------- - .. [1] Beineke, L., O. Oellermann, and R. Pippert (2002). The average - connectivity of a graph. Discrete mathematics 252(1-3), 31-45. - http://www.sciencedirect.com/science/article/pii/S0012365X01001807 - - """ - if G.is_directed(): - iter_func = itertools.permutations - else: - iter_func = itertools.combinations - - # Reuse the auxiliary digraph and the residual network - H = build_auxiliary_node_connectivity(G) - R = build_residual_network(H, 'capacity') - kwargs = dict(flow_func=flow_func, auxiliary=H, residual=R) - - num, den = 0, 0 - for u, v in iter_func(G, 2): - num += local_node_connectivity(G, u, v, **kwargs) - den += 1 - - if den == 0: # Null Graph - return 0 - return num / den - - -def all_pairs_node_connectivity(G, nbunch=None, flow_func=None): - """Compute node connectivity between all pairs of nodes of G. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - nbunch: container - Container of nodes. If provided node connectivity will be computed - only over pairs of nodes in nbunch. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The - choice of the default function may change from version - to version and should not be relied on. Default value: None. - - Returns - ------- - all_pairs : dict - A dictionary with node connectivity between all pairs of nodes - in G, or in nbunch if provided. - - See also - -------- - :meth:`local_node_connectivity` - :meth:`edge_connectivity` - :meth:`local_edge_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - """ - if nbunch is None: - nbunch = G - else: - nbunch = set(nbunch) - - directed = G.is_directed() - if directed: - iter_func = itertools.permutations - else: - iter_func = itertools.combinations - - all_pairs = {n: {} for n in nbunch} - - # Reuse auxiliary digraph and residual network - H = build_auxiliary_node_connectivity(G) - mapping = H.graph['mapping'] - R = build_residual_network(H, 'capacity') - kwargs = dict(flow_func=flow_func, auxiliary=H, residual=R) - - for u, v in iter_func(nbunch, 2): - K = local_node_connectivity(G, u, v, **kwargs) - all_pairs[u][v] = K - if not directed: - all_pairs[v][u] = K - - return all_pairs - - -def local_edge_connectivity(G, s, t, flow_func=None, auxiliary=None, - residual=None, cutoff=None): - r"""Returns local edge connectivity for nodes s and t in G. - - Local edge connectivity for two nodes s and t is the minimum number - of edges that must be removed to disconnect them. - - This is a flow based implementation of edge connectivity. We compute the - maximum flow on an auxiliary digraph build from the original - network (see below for details). This is equal to the local edge - connectivity because the value of a maximum s-t-flow is equal to the - capacity of a minimum s-t-cut (Ford and Fulkerson theorem) [1]_ . - - Parameters - ---------- - G : NetworkX graph - Undirected or directed graph - - s : node - Source node - - t : node - Target node - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The - choice of the default function may change from version - to version and should not be relied on. Default value: None. - - auxiliary : NetworkX DiGraph - Auxiliary digraph for computing flow based edge connectivity. If - provided it will be reused instead of recreated. Default value: None. - - residual : NetworkX DiGraph - Residual network to compute maximum flow. If provided it will be - reused instead of recreated. Default value: None. - - cutoff : integer, float - If specified, the maximum flow algorithm will terminate when the - flow value reaches or exceeds the cutoff. This is only for the - algorithms that support the cutoff parameter: :meth:`edmonds_karp` - and :meth:`shortest_augmenting_path`. Other algorithms will ignore - this parameter. Default value: None. - - Returns - ------- - K : integer - local edge connectivity for nodes s and t. - - Examples - -------- - This function is not imported in the base NetworkX namespace, so you - have to explicitly import it from the connectivity package: - - >>> from networkx.algorithms.connectivity import local_edge_connectivity - - We use in this example the platonic icosahedral graph, which has edge - connectivity 5. - - >>> G = nx.icosahedral_graph() - >>> local_edge_connectivity(G, 0, 6) - 5 - - If you need to compute local connectivity on several pairs of - nodes in the same graph, it is recommended that you reuse the - data structures that NetworkX uses in the computation: the - auxiliary digraph for edge connectivity, and the residual - network for the underlying maximum flow computation. - - Example of how to compute local edge connectivity among - all pairs of nodes of the platonic icosahedral graph reusing - the data structures. - - >>> import itertools - >>> # You also have to explicitly import the function for - >>> # building the auxiliary digraph from the connectivity package - >>> from networkx.algorithms.connectivity import ( - ... build_auxiliary_edge_connectivity) - >>> H = build_auxiliary_edge_connectivity(G) - >>> # And the function for building the residual network from the - >>> # flow package - >>> from networkx.algorithms.flow import build_residual_network - >>> # Note that the auxiliary digraph has an edge attribute named capacity - >>> R = build_residual_network(H, 'capacity') - >>> result = dict.fromkeys(G, dict()) - >>> # Reuse the auxiliary digraph and the residual network by passing them - >>> # as parameters - >>> for u, v in itertools.combinations(G, 2): - ... k = local_edge_connectivity(G, u, v, auxiliary=H, residual=R) - ... result[u][v] = k - >>> all(result[u][v] == 5 for u, v in itertools.combinations(G, 2)) - True - - You can also use alternative flow algorithms for computing edge - connectivity. For instance, in dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better than - the default :meth:`edmonds_karp` which is faster for sparse - networks with highly skewed degree distributions. Alternative flow - functions have to be explicitly imported from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> local_edge_connectivity(G, 0, 6, flow_func=shortest_augmenting_path) - 5 - - Notes - ----- - This is a flow based implementation of edge connectivity. We compute the - maximum flow using, by default, the :meth:`edmonds_karp` algorithm on an - auxiliary digraph build from the original input graph: - - If the input graph is undirected, we replace each edge (`u`,`v`) with - two reciprocal arcs (`u`, `v`) and (`v`, `u`) and then we set the attribute - 'capacity' for each arc to 1. If the input graph is directed we simply - add the 'capacity' attribute. This is an implementation of algorithm 1 - in [1]_. - - The maximum flow in the auxiliary network is equal to the local edge - connectivity because the value of a maximum s-t-flow is equal to the - capacity of a minimum s-t-cut (Ford and Fulkerson theorem). - - See also - -------- - :meth:`edge_connectivity` - :meth:`local_node_connectivity` - :meth:`node_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - References - ---------- - .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms. - http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf - - """ - if flow_func is None: - flow_func = default_flow_func - - if auxiliary is None: - H = build_auxiliary_edge_connectivity(G) - else: - H = auxiliary - - kwargs = dict(flow_func=flow_func, residual=residual) - if flow_func is shortest_augmenting_path: - kwargs['cutoff'] = cutoff - kwargs['two_phase'] = True - elif flow_func is edmonds_karp: - kwargs['cutoff'] = cutoff - elif flow_func is dinitz: - kwargs['cutoff'] = cutoff - elif flow_func is boykov_kolmogorov: - kwargs['cutoff'] = cutoff - - return nx.maximum_flow_value(H, s, t, **kwargs) - - -def edge_connectivity(G, s=None, t=None, flow_func=None, cutoff=None): - r"""Returns the edge connectivity of the graph or digraph G. - - The edge connectivity is equal to the minimum number of edges that - must be removed to disconnect G or render it trivial. If source - and target nodes are provided, this function returns the local edge - connectivity: the minimum number of edges that must be removed to - break all paths from source to target in G. - - Parameters - ---------- - G : NetworkX graph - Undirected or directed graph - - s : node - Source node. Optional. Default value: None. - - t : node - Target node. Optional. Default value: None. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The - choice of the default function may change from version - to version and should not be relied on. Default value: None. - - cutoff : integer, float - If specified, the maximum flow algorithm will terminate when the - flow value reaches or exceeds the cutoff. This is only for the - algorithms that support the cutoff parameter: :meth:`edmonds_karp` - and :meth:`shortest_augmenting_path`. Other algorithms will ignore - this parameter. Default value: None. - - Returns - ------- - K : integer - Edge connectivity for G, or local edge connectivity if source - and target were provided - - Examples - -------- - >>> # Platonic icosahedral graph is 5-edge-connected - >>> G = nx.icosahedral_graph() - >>> nx.edge_connectivity(G) - 5 - - You can use alternative flow algorithms for the underlying - maximum flow computation. In dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better - than the default :meth:`edmonds_karp`, which is faster for - sparse networks with highly skewed degree distributions. - Alternative flow functions have to be explicitly imported - from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> nx.edge_connectivity(G, flow_func=shortest_augmenting_path) - 5 - - If you specify a pair of nodes (source and target) as parameters, - this function returns the value of local edge connectivity. - - >>> nx.edge_connectivity(G, 3, 7) - 5 - - If you need to perform several local computations among different - pairs of nodes on the same graph, it is recommended that you reuse - the data structures used in the maximum flow computations. See - :meth:`local_edge_connectivity` for details. - - Notes - ----- - This is a flow based implementation of global edge connectivity. - For undirected graphs the algorithm works by finding a 'small' - dominating set of nodes of G (see algorithm 7 in [1]_ ) and - computing local maximum flow (see :meth:`local_edge_connectivity`) - between an arbitrary node in the dominating set and the rest of - nodes in it. This is an implementation of algorithm 6 in [1]_ . - For directed graphs, the algorithm does n calls to the maximum - flow function. This is an implementation of algorithm 8 in [1]_ . - - See also - -------- - :meth:`local_edge_connectivity` - :meth:`local_node_connectivity` - :meth:`node_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - :meth:`k_edge_components` - :meth:`k_edge_subgraphs` - - References - ---------- - .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms. - http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf - - """ - if (s is not None and t is None) or (s is None and t is not None): - raise nx.NetworkXError('Both source and target must be specified.') - - # Local edge connectivity - if s is not None and t is not None: - if s not in G: - raise nx.NetworkXError('node %s not in graph' % s) - if t not in G: - raise nx.NetworkXError('node %s not in graph' % t) - return local_edge_connectivity(G, s, t, flow_func=flow_func, - cutoff=cutoff) - - # Global edge connectivity - # reuse auxiliary digraph and residual network - H = build_auxiliary_edge_connectivity(G) - R = build_residual_network(H, 'capacity') - kwargs = dict(flow_func=flow_func, auxiliary=H, residual=R) - - if G.is_directed(): - # Algorithm 8 in [1] - if not nx.is_weakly_connected(G): - return 0 - - # initial value for \lambda is minimum degree - L = min(d for n, d in G.degree()) - nodes = list(G) - n = len(nodes) - - if cutoff is not None: - L = min(cutoff, L) - - for i in range(n): - kwargs['cutoff'] = L - try: - L = min(L, local_edge_connectivity(G, nodes[i], nodes[i + 1], - **kwargs)) - except IndexError: # last node! - L = min(L, local_edge_connectivity(G, nodes[i], nodes[0], - **kwargs)) - return L - else: # undirected - # Algorithm 6 in [1] - if not nx.is_connected(G): - return 0 - - # initial value for \lambda is minimum degree - L = min(d for n, d in G.degree()) - - if cutoff is not None: - L = min(cutoff, L) - - # A dominating set is \lambda-covering - # We need a dominating set with at least two nodes - for node in G: - D = nx.dominating_set(G, start_with=node) - v = D.pop() - if D: - break - else: - # in complete graphs the dominating sets will always be of one node - # thus we return min degree - return L - - for w in D: - kwargs['cutoff'] = L - L = min(L, local_edge_connectivity(G, v, w, **kwargs)) - - return L diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/cuts.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/cuts.py deleted file mode 100644 index 7e78b9b2..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/cuts.py +++ /dev/null @@ -1,604 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Flow based cut algorithms -""" -import itertools -import networkx as nx - -# Define the default maximum flow function to use in all flow based -# cut algorithms. -from networkx.algorithms.flow import edmonds_karp -from networkx.algorithms.flow import build_residual_network -default_flow_func = edmonds_karp - -from .utils import (build_auxiliary_node_connectivity, - build_auxiliary_edge_connectivity) - -__author__ = '\n'.join(['Jordi Torrents ']) - -__all__ = ['minimum_st_node_cut', - 'minimum_node_cut', - 'minimum_st_edge_cut', - 'minimum_edge_cut'] - - -def minimum_st_edge_cut(G, s, t, flow_func=None, auxiliary=None, - residual=None): - """Returns the edges of the cut-set of a minimum (s, t)-cut. - - This function returns the set of edges of minimum cardinality that, - if removed, would destroy all paths among source and target in G. - Edge weights are not considered. See :meth:`minimum_cut` for - computing minimum cuts considering edge weights. - - Parameters - ---------- - G : NetworkX graph - - s : node - Source node for the flow. - - t : node - Sink node for the flow. - - auxiliary : NetworkX DiGraph - Auxiliary digraph to compute flow based node connectivity. It has - to have a graph attribute called mapping with a dictionary mapping - node names in G and in the auxiliary digraph. If provided - it will be reused instead of recreated. Default value: None. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See :meth:`node_connectivity` for - details. The choice of the default function may change from version - to version and should not be relied on. Default value: None. - - residual : NetworkX DiGraph - Residual network to compute maximum flow. If provided it will be - reused instead of recreated. Default value: None. - - Returns - ------- - cutset : set - Set of edges that, if removed from the graph, will disconnect it. - - See also - -------- - :meth:`minimum_cut` - :meth:`minimum_node_cut` - :meth:`minimum_edge_cut` - :meth:`stoer_wagner` - :meth:`node_connectivity` - :meth:`edge_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Examples - -------- - This function is not imported in the base NetworkX namespace, so you - have to explicitly import it from the connectivity package: - - >>> from networkx.algorithms.connectivity import minimum_st_edge_cut - - We use in this example the platonic icosahedral graph, which has edge - connectivity 5. - - >>> G = nx.icosahedral_graph() - >>> len(minimum_st_edge_cut(G, 0, 6)) - 5 - - If you need to compute local edge cuts on several pairs of - nodes in the same graph, it is recommended that you reuse the - data structures that NetworkX uses in the computation: the - auxiliary digraph for edge connectivity, and the residual - network for the underlying maximum flow computation. - - Example of how to compute local edge cuts among all pairs of - nodes of the platonic icosahedral graph reusing the data - structures. - - >>> import itertools - >>> # You also have to explicitly import the function for - >>> # building the auxiliary digraph from the connectivity package - >>> from networkx.algorithms.connectivity import ( - ... build_auxiliary_edge_connectivity) - >>> H = build_auxiliary_edge_connectivity(G) - >>> # And the function for building the residual network from the - >>> # flow package - >>> from networkx.algorithms.flow import build_residual_network - >>> # Note that the auxiliary digraph has an edge attribute named capacity - >>> R = build_residual_network(H, 'capacity') - >>> result = dict.fromkeys(G, dict()) - >>> # Reuse the auxiliary digraph and the residual network by passing them - >>> # as parameters - >>> for u, v in itertools.combinations(G, 2): - ... k = len(minimum_st_edge_cut(G, u, v, auxiliary=H, residual=R)) - ... result[u][v] = k - >>> all(result[u][v] == 5 for u, v in itertools.combinations(G, 2)) - True - - You can also use alternative flow algorithms for computing edge - cuts. For instance, in dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better than - the default :meth:`edmonds_karp` which is faster for sparse - networks with highly skewed degree distributions. Alternative flow - functions have to be explicitly imported from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> len(minimum_st_edge_cut(G, 0, 6, flow_func=shortest_augmenting_path)) - 5 - - """ - if flow_func is None: - flow_func = default_flow_func - - if auxiliary is None: - H = build_auxiliary_edge_connectivity(G) - else: - H = auxiliary - - kwargs = dict(capacity='capacity', flow_func=flow_func, residual=residual) - - cut_value, partition = nx.minimum_cut(H, s, t, **kwargs) - reachable, non_reachable = partition - # Any edge in the original graph linking the two sets in the - # partition is part of the edge cutset - cutset = set() - for u, nbrs in ((n, G[n]) for n in reachable): - cutset.update((u, v) for v in nbrs if v in non_reachable) - - return cutset - - -def minimum_st_node_cut(G, s, t, flow_func=None, auxiliary=None, residual=None): - r"""Returns a set of nodes of minimum cardinality that disconnect source - from target in G. - - This function returns the set of nodes of minimum cardinality that, - if removed, would destroy all paths among source and target in G. - - Parameters - ---------- - G : NetworkX graph - - s : node - Source node. - - t : node - Target node. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The choice - of the default function may change from version to version and - should not be relied on. Default value: None. - - auxiliary : NetworkX DiGraph - Auxiliary digraph to compute flow based node connectivity. It has - to have a graph attribute called mapping with a dictionary mapping - node names in G and in the auxiliary digraph. If provided - it will be reused instead of recreated. Default value: None. - - residual : NetworkX DiGraph - Residual network to compute maximum flow. If provided it will be - reused instead of recreated. Default value: None. - - Returns - ------- - cutset : set - Set of nodes that, if removed, would destroy all paths between - source and target in G. - - Examples - -------- - This function is not imported in the base NetworkX namespace, so you - have to explicitly import it from the connectivity package: - - >>> from networkx.algorithms.connectivity import minimum_st_node_cut - - We use in this example the platonic icosahedral graph, which has node - connectivity 5. - - >>> G = nx.icosahedral_graph() - >>> len(minimum_st_node_cut(G, 0, 6)) - 5 - - If you need to compute local st cuts between several pairs of - nodes in the same graph, it is recommended that you reuse the - data structures that NetworkX uses in the computation: the - auxiliary digraph for node connectivity and node cuts, and the - residual network for the underlying maximum flow computation. - - Example of how to compute local st node cuts reusing the data - structures: - - >>> # You also have to explicitly import the function for - >>> # building the auxiliary digraph from the connectivity package - >>> from networkx.algorithms.connectivity import ( - ... build_auxiliary_node_connectivity) - >>> H = build_auxiliary_node_connectivity(G) - >>> # And the function for building the residual network from the - >>> # flow package - >>> from networkx.algorithms.flow import build_residual_network - >>> # Note that the auxiliary digraph has an edge attribute named capacity - >>> R = build_residual_network(H, 'capacity') - >>> # Reuse the auxiliary digraph and the residual network by passing them - >>> # as parameters - >>> len(minimum_st_node_cut(G, 0, 6, auxiliary=H, residual=R)) - 5 - - You can also use alternative flow algorithms for computing minimum st - node cuts. For instance, in dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better than - the default :meth:`edmonds_karp` which is faster for sparse - networks with highly skewed degree distributions. Alternative flow - functions have to be explicitly imported from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> len(minimum_st_node_cut(G, 0, 6, flow_func=shortest_augmenting_path)) - 5 - - Notes - ----- - This is a flow based implementation of minimum node cut. The algorithm - is based in solving a number of maximum flow computations to determine - the capacity of the minimum cut on an auxiliary directed network that - corresponds to the minimum node cut of G. It handles both directed - and undirected graphs. This implementation is based on algorithm 11 - in [1]_. - - See also - -------- - :meth:`minimum_node_cut` - :meth:`minimum_edge_cut` - :meth:`stoer_wagner` - :meth:`node_connectivity` - :meth:`edge_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - References - ---------- - .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms. - http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf - - """ - if auxiliary is None: - H = build_auxiliary_node_connectivity(G) - else: - H = auxiliary - - mapping = H.graph.get('mapping', None) - if mapping is None: - raise nx.NetworkXError('Invalid auxiliary digraph.') - if G.has_edge(s, t) or G.has_edge(t, s): - return [] - kwargs = dict(flow_func=flow_func, residual=residual, auxiliary=H) - - # The edge cut in the auxiliary digraph corresponds to the node cut in the - # original graph. - edge_cut = minimum_st_edge_cut(H, '%sB' % mapping[s], '%sA' % mapping[t], - **kwargs) - # Each node in the original graph maps to two nodes of the auxiliary graph - node_cut = set(H.nodes[node]['id'] for edge in edge_cut for node in edge) - return node_cut - set([s, t]) - - -def minimum_node_cut(G, s=None, t=None, flow_func=None): - r"""Returns a set of nodes of minimum cardinality that disconnects G. - - If source and target nodes are provided, this function returns the - set of nodes of minimum cardinality that, if removed, would destroy - all paths among source and target in G. If not, it returns a set - of nodes of minimum cardinality that disconnects G. - - Parameters - ---------- - G : NetworkX graph - - s : node - Source node. Optional. Default value: None. - - t : node - Target node. Optional. Default value: None. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The - choice of the default function may change from version - to version and should not be relied on. Default value: None. - - Returns - ------- - cutset : set - Set of nodes that, if removed, would disconnect G. If source - and target nodes are provided, the set contains the nodes that - if removed, would destroy all paths between source and target. - - Examples - -------- - >>> # Platonic icosahedral graph has node connectivity 5 - >>> G = nx.icosahedral_graph() - >>> node_cut = nx.minimum_node_cut(G) - >>> len(node_cut) - 5 - - You can use alternative flow algorithms for the underlying maximum - flow computation. In dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better - than the default :meth:`edmonds_karp`, which is faster for - sparse networks with highly skewed degree distributions. Alternative - flow functions have to be explicitly imported from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> node_cut == nx.minimum_node_cut(G, flow_func=shortest_augmenting_path) - True - - If you specify a pair of nodes (source and target) as parameters, - this function returns a local st node cut. - - >>> len(nx.minimum_node_cut(G, 3, 7)) - 5 - - If you need to perform several local st cuts among different - pairs of nodes on the same graph, it is recommended that you reuse - the data structures used in the maximum flow computations. See - :meth:`minimum_st_node_cut` for details. - - Notes - ----- - This is a flow based implementation of minimum node cut. The algorithm - is based in solving a number of maximum flow computations to determine - the capacity of the minimum cut on an auxiliary directed network that - corresponds to the minimum node cut of G. It handles both directed - and undirected graphs. This implementation is based on algorithm 11 - in [1]_. - - See also - -------- - :meth:`minimum_st_node_cut` - :meth:`minimum_cut` - :meth:`minimum_edge_cut` - :meth:`stoer_wagner` - :meth:`node_connectivity` - :meth:`edge_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - References - ---------- - .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms. - http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf - - """ - if (s is not None and t is None) or (s is None and t is not None): - raise nx.NetworkXError('Both source and target must be specified.') - - # Local minimum node cut. - if s is not None and t is not None: - if s not in G: - raise nx.NetworkXError('node %s not in graph' % s) - if t not in G: - raise nx.NetworkXError('node %s not in graph' % t) - return minimum_st_node_cut(G, s, t, flow_func=flow_func) - - # Global minimum node cut. - # Analog to the algorithm 11 for global node connectivity in [1]. - if G.is_directed(): - if not nx.is_weakly_connected(G): - raise nx.NetworkXError('Input graph is not connected') - iter_func = itertools.permutations - - def neighbors(v): - return itertools.chain.from_iterable([G.predecessors(v), - G.successors(v)]) - else: - if not nx.is_connected(G): - raise nx.NetworkXError('Input graph is not connected') - iter_func = itertools.combinations - neighbors = G.neighbors - - # Reuse the auxiliary digraph and the residual network. - H = build_auxiliary_node_connectivity(G) - R = build_residual_network(H, 'capacity') - kwargs = dict(flow_func=flow_func, auxiliary=H, residual=R) - - # Choose a node with minimum degree. - v = min(G, key=G.degree) - # Initial node cutset is all neighbors of the node with minimum degree. - min_cut = set(G[v]) - # Compute st node cuts between v and all its non-neighbors nodes in G. - for w in set(G) - set(neighbors(v)) - set([v]): - this_cut = minimum_st_node_cut(G, v, w, **kwargs) - if len(min_cut) >= len(this_cut): - min_cut = this_cut - # Also for non adjacent pairs of neighbors of v. - for x, y in iter_func(neighbors(v), 2): - if y in G[x]: - continue - this_cut = minimum_st_node_cut(G, x, y, **kwargs) - if len(min_cut) >= len(this_cut): - min_cut = this_cut - - return min_cut - - -def minimum_edge_cut(G, s=None, t=None, flow_func=None): - r"""Returns a set of edges of minimum cardinality that disconnects G. - - If source and target nodes are provided, this function returns the - set of edges of minimum cardinality that, if removed, would break - all paths among source and target in G. If not, it returns a set of - edges of minimum cardinality that disconnects G. - - Parameters - ---------- - G : NetworkX graph - - s : node - Source node. Optional. Default value: None. - - t : node - Target node. Optional. Default value: None. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The - choice of the default function may change from version - to version and should not be relied on. Default value: None. - - Returns - ------- - cutset : set - Set of edges that, if removed, would disconnect G. If source - and target nodes are provided, the set contains the edges that - if removed, would destroy all paths between source and target. - - Examples - -------- - >>> # Platonic icosahedral graph has edge connectivity 5 - >>> G = nx.icosahedral_graph() - >>> len(nx.minimum_edge_cut(G)) - 5 - - You can use alternative flow algorithms for the underlying - maximum flow computation. In dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better - than the default :meth:`edmonds_karp`, which is faster for - sparse networks with highly skewed degree distributions. - Alternative flow functions have to be explicitly imported - from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> len(nx.minimum_edge_cut(G, flow_func=shortest_augmenting_path)) - 5 - - If you specify a pair of nodes (source and target) as parameters, - this function returns the value of local edge connectivity. - - >>> nx.edge_connectivity(G, 3, 7) - 5 - - If you need to perform several local computations among different - pairs of nodes on the same graph, it is recommended that you reuse - the data structures used in the maximum flow computations. See - :meth:`local_edge_connectivity` for details. - - Notes - ----- - This is a flow based implementation of minimum edge cut. For - undirected graphs the algorithm works by finding a 'small' dominating - set of nodes of G (see algorithm 7 in [1]_) and computing the maximum - flow between an arbitrary node in the dominating set and the rest of - nodes in it. This is an implementation of algorithm 6 in [1]_. For - directed graphs, the algorithm does n calls to the max flow function. - The function raises an error if the directed graph is not weakly - connected and returns an empty set if it is weakly connected. - It is an implementation of algorithm 8 in [1]_. - - See also - -------- - :meth:`minimum_st_edge_cut` - :meth:`minimum_node_cut` - :meth:`stoer_wagner` - :meth:`node_connectivity` - :meth:`edge_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - References - ---------- - .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms. - http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf - - """ - if (s is not None and t is None) or (s is None and t is not None): - raise nx.NetworkXError('Both source and target must be specified.') - - # reuse auxiliary digraph and residual network - H = build_auxiliary_edge_connectivity(G) - R = build_residual_network(H, 'capacity') - kwargs = dict(flow_func=flow_func, residual=R, auxiliary=H) - - # Local minimum edge cut if s and t are not None - if s is not None and t is not None: - if s not in G: - raise nx.NetworkXError('node %s not in graph' % s) - if t not in G: - raise nx.NetworkXError('node %s not in graph' % t) - return minimum_st_edge_cut(H, s, t, **kwargs) - - # Global minimum edge cut - # Analog to the algorithm for global edge connectivity - if G.is_directed(): - # Based on algorithm 8 in [1] - if not nx.is_weakly_connected(G): - raise nx.NetworkXError('Input graph is not connected') - - # Initial cutset is all edges of a node with minimum degree - node = min(G, key=G.degree) - min_cut = set(G.edges(node)) - nodes = list(G) - n = len(nodes) - for i in range(n): - try: - this_cut = minimum_st_edge_cut(H, nodes[i], nodes[i + 1], **kwargs) - if len(this_cut) <= len(min_cut): - min_cut = this_cut - except IndexError: # Last node! - this_cut = minimum_st_edge_cut(H, nodes[i], nodes[0], **kwargs) - if len(this_cut) <= len(min_cut): - min_cut = this_cut - - return min_cut - - else: # undirected - # Based on algorithm 6 in [1] - if not nx.is_connected(G): - raise nx.NetworkXError('Input graph is not connected') - - # Initial cutset is all edges of a node with minimum degree - node = min(G, key=G.degree) - min_cut = set(G.edges(node)) - # A dominating set is \lambda-covering - # We need a dominating set with at least two nodes - for node in G: - D = nx.dominating_set(G, start_with=node) - v = D.pop() - if D: - break - else: - # in complete graphs the dominating set will always be of one node - # thus we return min_cut, which now contains the edges of a node - # with minimum degree - return min_cut - for w in D: - this_cut = minimum_st_edge_cut(H, v, w, **kwargs) - if len(this_cut) <= len(min_cut): - min_cut = this_cut - - return min_cut diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/disjoint_paths.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/disjoint_paths.py deleted file mode 100644 index 4f87eb2a..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/disjoint_paths.py +++ /dev/null @@ -1,414 +0,0 @@ -# disjoint_paths.py - Flow based node and edge disjoint paths. -# -# Copyright 2017-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -# -# Author: Jordi Torrents -"""Flow based node and edge disjoint paths.""" -import networkx as nx -from networkx.exception import NetworkXNoPath -# Define the default maximum flow function to use for the undelying -# maximum flow computations -from networkx.algorithms.flow import edmonds_karp -from networkx.algorithms.flow import preflow_push -from networkx.algorithms.flow import shortest_augmenting_path -default_flow_func = edmonds_karp -# Functions to build auxiliary data structures. -from networkx.algorithms.flow import build_residual_network -from .utils import build_auxiliary_node_connectivity -from .utils import build_auxiliary_edge_connectivity - -try: - from itertools import filterfalse as _filterfalse -except ImportError: # Python 2 - def _filterfalse(predicate, iterable): - # https://docs.python.org/3/library/itertools.html - # filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8 - if predicate is None: - predicate = bool - for x in iterable: - if not predicate(x): - yield x - -__all__ = [ - 'edge_disjoint_paths', - 'node_disjoint_paths', -] - - -def edge_disjoint_paths(G, s, t, flow_func=None, cutoff=None, auxiliary=None, - residual=None): - """Returns the edges disjoint paths between source and target. - - Edge disjoint paths are paths that do not share any edge. The - number of edge disjoint paths between source and target is equal - to their edge connectivity. - - Parameters - ---------- - G : NetworkX graph - - s : node - Source node for the flow. - - t : node - Sink node for the flow. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. The choice of the default function - may change from version to version and should not be relied on. - Default value: None. - - cutoff : int - Maximum number of paths to yield. Some of the maximum flow - algorithms, such as :meth:`edmonds_karp` (the default) and - :meth:`shortest_augmenting_path` support the cutoff parameter, - and will terminate when the flow value reaches or exceeds the - cutoff. Other algorithms will ignore this parameter. - Default value: None. - - auxiliary : NetworkX DiGraph - Auxiliary digraph to compute flow based edge connectivity. It has - to have a graph attribute called mapping with a dictionary mapping - node names in G and in the auxiliary digraph. If provided - it will be reused instead of recreated. Default value: None. - - residual : NetworkX DiGraph - Residual network to compute maximum flow. If provided it will be - reused instead of recreated. Default value: None. - - Returns - ------- - paths : generator - A generator of edge independent paths. - - Raises - ------ - NetworkXNoPath : exception - If there is no path between source and target. - - NetworkXError : exception - If source or target are not in the graph G. - - See also - -------- - :meth:`node_disjoint_paths` - :meth:`edge_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Examples - -------- - We use in this example the platonic icosahedral graph, which has node - edge connectivity 5, thus there are 5 edge disjoint paths between any - pair of nodes. - - >>> G = nx.icosahedral_graph() - >>> len(list(nx.edge_disjoint_paths(G, 0, 6))) - 5 - - - If you need to compute edge disjoint paths on several pairs of - nodes in the same graph, it is recommended that you reuse the - data structures that NetworkX uses in the computation: the - auxiliary digraph for edge connectivity, and the residual - network for the underlying maximum flow computation. - - Example of how to compute edge disjoint paths among all pairs of - nodes of the platonic icosahedral graph reusing the data - structures. - - >>> import itertools - >>> # You also have to explicitly import the function for - >>> # building the auxiliary digraph from the connectivity package - >>> from networkx.algorithms.connectivity import ( - ... build_auxiliary_edge_connectivity) - >>> H = build_auxiliary_edge_connectivity(G) - >>> # And the function for building the residual network from the - >>> # flow package - >>> from networkx.algorithms.flow import build_residual_network - >>> # Note that the auxiliary digraph has an edge attribute named capacity - >>> R = build_residual_network(H, 'capacity') - >>> result = {n: {} for n in G} - >>> # Reuse the auxiliary digraph and the residual network by passing them - >>> # as arguments - >>> for u, v in itertools.combinations(G, 2): - ... k = len(list(nx.edge_disjoint_paths(G, u, v, auxiliary=H, residual=R))) - ... result[u][v] = k - >>> all(result[u][v] == 5 for u, v in itertools.combinations(G, 2)) - True - - You can also use alternative flow algorithms for computing edge disjoint - paths. For instance, in dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better than - the default :meth:`edmonds_karp` which is faster for sparse - networks with highly skewed degree distributions. Alternative flow - functions have to be explicitly imported from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> len(list(nx.edge_disjoint_paths(G, 0, 6, flow_func=shortest_augmenting_path))) - 5 - - Notes - ----- - This is a flow based implementation of edge disjoint paths. We compute - the maximum flow between source and target on an auxiliary directed - network. The saturated edges in the residual network after running the - maximum flow algorithm correspond to edge disjoint paths between source - and target in the original network. This function handles both directed - and undirected graphs, and can use all flow algorithms from NetworkX flow - package. - - """ - if s not in G: - raise nx.NetworkXError('node %s not in graph' % s) - if t not in G: - raise nx.NetworkXError('node %s not in graph' % t) - - if flow_func is None: - flow_func = default_flow_func - - if auxiliary is None: - H = build_auxiliary_edge_connectivity(G) - else: - H = auxiliary - - # Maximum possible edge disjoint paths - possible = min(H.out_degree(s), H.in_degree(t)) - if not possible: - raise NetworkXNoPath - - if cutoff is None: - cutoff = possible - else: - cutoff = min(cutoff, possible) - - # Compute maximum flow between source and target. Flow functions in - # NetworkX return a residual network. - kwargs = dict(capacity='capacity', residual=residual, cutoff=cutoff, - value_only=True) - if flow_func is preflow_push: - del kwargs['cutoff'] - if flow_func is shortest_augmenting_path: - kwargs['two_phase'] = True - R = flow_func(H, s, t, **kwargs) - - if R.graph['flow_value'] == 0: - raise NetworkXNoPath - - # Saturated edges in the residual network form the edge disjoint paths - # between source and target - cutset = [(u, v) for u, v, d in R.edges(data=True) - if d['capacity'] == d['flow'] and d['flow'] > 0] - # This is equivalent of what flow.utils.build_flow_dict returns, but - # only for the nodes with saturated edges and without reporting 0 flows. - flow_dict = {n: {} for edge in cutset for n in edge} - for u, v in cutset: - flow_dict[u][v] = 1 - - # Rebuild the edge disjoint paths from the flow dictionary. - paths_found = 0 - for v in list(flow_dict[s]): - if paths_found >= cutoff: - # preflow_push does not support cutoff: we have to - # keep track of the paths founds and stop at cutoff. - break - path = [s] - if v == t: - path.append(v) - yield path - continue - u = v - while u != t: - path.append(u) - try: - u, _ = flow_dict[u].popitem() - except KeyError: - break - else: - path.append(t) - yield path - paths_found += 1 - - -def node_disjoint_paths(G, s, t, flow_func=None, cutoff=None, auxiliary=None, - residual=None): - r"""Computes node disjoint paths between source and target. - - Node dijoint paths are paths that only share their first and last - nodes. The number of node independent paths between two nodes is - equal to their local node connectivity. - - Parameters - ---------- - G : NetworkX graph - - s : node - Source node. - - t : node - Target node. - - flow_func : function - A function for computing the maximum flow among a pair of nodes. - The function has to accept at least three parameters: a Digraph, - a source node, and a target node. And return a residual network - that follows NetworkX conventions (see :meth:`maximum_flow` for - details). If flow_func is None, the default maximum flow function - (:meth:`edmonds_karp`) is used. See below for details. The choice - of the default function may change from version to version and - should not be relied on. Default value: None. - - cutoff : int - Maximum number of paths to yield. Some of the maximum flow - algorithms, such as :meth:`edmonds_karp` (the default) and - :meth:`shortest_augmenting_path` support the cutoff parameter, - and will terminate when the flow value reaches or exceeds the - cutoff. Other algorithms will ignore this parameter. - Default value: None. - - auxiliary : NetworkX DiGraph - Auxiliary digraph to compute flow based node connectivity. It has - to have a graph attribute called mapping with a dictionary mapping - node names in G and in the auxiliary digraph. If provided - it will be reused instead of recreated. Default value: None. - - residual : NetworkX DiGraph - Residual network to compute maximum flow. If provided it will be - reused instead of recreated. Default value: None. - - Returns - ------- - paths : generator - Generator of node disjoint paths. - - Raises - ------ - NetworkXNoPath : exception - If there is no path between source and target. - - NetworkXError : exception - If source or target are not in the graph G. - - Examples - -------- - We use in this example the platonic icosahedral graph, which has node - node connectivity 5, thus there are 5 node disjoint paths between any - pair of non neighbor nodes. - - >>> G = nx.icosahedral_graph() - >>> len(list(nx.node_disjoint_paths(G, 0, 6))) - 5 - - If you need to compute node disjoint paths between several pairs of - nodes in the same graph, it is recommended that you reuse the - data structures that NetworkX uses in the computation: the - auxiliary digraph for node connectivity and node cuts, and the - residual network for the underlying maximum flow computation. - - Example of how to compute node disjoint paths reusing the data - structures: - - >>> # You also have to explicitly import the function for - >>> # building the auxiliary digraph from the connectivity package - >>> from networkx.algorithms.connectivity import ( - ... build_auxiliary_node_connectivity) - >>> H = build_auxiliary_node_connectivity(G) - >>> # And the function for building the residual network from the - >>> # flow package - >>> from networkx.algorithms.flow import build_residual_network - >>> # Note that the auxiliary digraph has an edge attribute named capacity - >>> R = build_residual_network(H, 'capacity') - >>> # Reuse the auxiliary digraph and the residual network by passing them - >>> # as arguments - >>> len(list(nx.node_disjoint_paths(G, 0, 6, auxiliary=H, residual=R))) - 5 - - You can also use alternative flow algorithms for computing node disjoint - paths. For instance, in dense networks the algorithm - :meth:`shortest_augmenting_path` will usually perform better than - the default :meth:`edmonds_karp` which is faster for sparse - networks with highly skewed degree distributions. Alternative flow - functions have to be explicitly imported from the flow package. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> len(list(nx.node_disjoint_paths(G, 0, 6, flow_func=shortest_augmenting_path))) - 5 - - Notes - ----- - This is a flow based implementation of node disjoint paths. We compute - the maximum flow between source and target on an auxiliary directed - network. The saturated edges in the residual network after running the - maximum flow algorithm correspond to node disjoint paths between source - and target in the original network. This function handles both directed - and undirected graphs, and can use all flow algorithms from NetworkX flow - package. - - See also - -------- - :meth:`edge_disjoint_paths` - :meth:`node_connectivity` - :meth:`maximum_flow` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - """ - if s not in G: - raise nx.NetworkXError('node %s not in graph' % s) - if t not in G: - raise nx.NetworkXError('node %s not in graph' % t) - - if auxiliary is None: - H = build_auxiliary_node_connectivity(G) - else: - H = auxiliary - - mapping = H.graph.get('mapping', None) - if mapping is None: - raise nx.NetworkXError('Invalid auxiliary digraph.') - - # Maximum possible edge disjoint paths - possible = min(H.out_degree('%sB' % mapping[s]), - H.in_degree('%sA' % mapping[t])) - if not possible: - raise NetworkXNoPath - - if cutoff is None: - cutoff = possible - else: - cutoff = min(cutoff, possible) - - kwargs = dict(flow_func=flow_func, residual=residual, auxiliary=H, - cutoff=cutoff) - - # The edge disjoint paths in the auxiliary digraph correspond to the node - # disjoint paths in the original graph. - paths_edges = edge_disjoint_paths(H, '%sB' % mapping[s], '%sA' % mapping[t], - **kwargs) - for path in paths_edges: - # Each node in the original graph maps to two nodes in auxiliary graph - yield list(_unique_everseen(H.nodes[node]['id'] for node in path)) - - -def _unique_everseen(iterable): - # Adapted from https://docs.python.org/3/library/itertools.html examples - "List unique elements, preserving order. Remember all elements ever seen." - # unique_everseen('AAAABBBCCDAABBB') --> A B C D - seen = set() - seen_add = seen.add - for element in _filterfalse(seen.__contains__, iterable): - seen_add(element) - yield element diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/edge_augmentation.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/edge_augmentation.py deleted file mode 100644 index a7f16aaa..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/edge_augmentation.py +++ /dev/null @@ -1,1288 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Jon Crall (erotemic@gmail.com) -""" -Algorithms for finding k-edge-augmentations - -A k-edge-augmentation is a set of edges, that once added to a graph, ensures -that the graph is k-edge-connected; i.e. the graph cannot be disconnected -unless k or more edges are removed. Typically, the goal is to find the -augmentation with minimum weight. In general, it is not guaranteed that a -k-edge-augmentation exists. - -See Also --------- -:mod:`edge_kcomponents` : algorithms for finding k-edge-connected components -:mod:`connectivity` : algorithms for determening edge connectivity. -""" -import math -import sys -import itertools as it -import networkx as nx -from networkx.utils import not_implemented_for, py_random_state -from collections import defaultdict, namedtuple - -__all__ = [ - 'k_edge_augmentation', - 'is_k_edge_connected', - 'is_locally_k_edge_connected', -] - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def is_k_edge_connected(G, k): - """Tests to see if a graph is k-edge-connected. - - Is it impossible to disconnect the graph by removing fewer than k edges? - If so, then G is k-edge-connected. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - k : integer - edge connectivity to test for - - Returns - ------- - boolean - True if G is k-edge-connected. - - See Also - -------- - :func:`is_locally_k_edge_connected` - - Example - ------- - >>> G = nx.barbell_graph(10, 0) - >>> nx.is_k_edge_connected(G, k=1) - True - >>> nx.is_k_edge_connected(G, k=2) - False - """ - if k < 1: - raise ValueError('k must be positive, not {}'.format(k)) - # First try to quickly determine if G is not k-edge-connected - if G.number_of_nodes() < k + 1: - return False - elif any(d < k for n, d in G.degree()): - return False - else: - # Otherwise perform the full check - if k == 1: - return nx.is_connected(G) - elif k == 2: - return not nx.has_bridges(G) - else: - return nx.edge_connectivity(G, cutoff=k) >= k - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def is_locally_k_edge_connected(G, s, t, k): - """Tests to see if an edge in a graph is locally k-edge-connected. - - Is it impossible to disconnect s and t by removing fewer than k edges? - If so, then s and t are locally k-edge-connected in G. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - s : node - Source node - - t : node - Target node - - k : integer - local edge connectivity for nodes s and t - - Returns - ------- - boolean - True if s and t are locally k-edge-connected in G. - - See Also - -------- - :func:`is_k_edge_connected` - - Example - ------- - >>> from networkx.algorithms.connectivity import is_locally_k_edge_connected - >>> G = nx.barbell_graph(10, 0) - >>> is_locally_k_edge_connected(G, 5, 15, k=1) - True - >>> is_locally_k_edge_connected(G, 5, 15, k=2) - False - >>> is_locally_k_edge_connected(G, 1, 5, k=2) - True - """ - if k < 1: - raise ValueError('k must be positive, not {}'.format(k)) - - # First try to quickly determine s, t is not k-locally-edge-connected in G - if G.degree(s) < k or G.degree(t) < k: - return False - else: - # Otherwise perform the full check - if k == 1: - return nx.has_path(G, s, t) - else: - localk = nx.connectivity.local_edge_connectivity(G, s, t, cutoff=k) - return localk >= k - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def k_edge_augmentation(G, k, avail=None, weight=None, partial=False): - """Finds set of edges to k-edge-connect G. - - Adding edges from the augmentation to G make it impossible to disconnect G - unless k or more edges are removed. This function uses the most efficient - function available (depending on the value of k and if the problem is - weighted or unweighted) to search for a minimum weight subset of available - edges that k-edge-connects G. In general, finding a k-edge-augmentation is - NP-hard, so solutions are not garuenteed to be minimal. Furthermore, a - k-edge-augmentation may not exist. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - k : integer - Desired edge connectivity - - avail : dict or a set of 2 or 3 tuples - The available edges that can be used in the augmentation. - - If unspecified, then all edges in the complement of G are available. - Otherwise, each item is an available edge (with an optional weight). - - In the unweighted case, each item is an edge ``(u, v)``. - - In the weighted case, each item is a 3-tuple ``(u, v, d)`` or a dict - with items ``(u, v): d``. The third item, ``d``, can be a dictionary - or a real number. If ``d`` is a dictionary ``d[weight]`` - correspondings to the weight. - - weight : string - key to use to find weights if ``avail`` is a set of 3-tuples where the - third item in each tuple is a dictionary. - - partial : boolean - If partial is True and no feasible k-edge-augmentation exists, then all - a partial k-edge-augmentation is generated. Adding the edges in a - partial augmentation to G, minimizes the number of k-edge-connected - components and maximizes the edge connectivity between those - components. For details, see :func:`partial_k_edge_augmentation`. - - Yields - ------ - edge : tuple - Edges that, once added to G, would cause G to become k-edge-connected. - If partial is False, an error is raised if this is not possible. - Otherwise, generated edges form a partial augmentation, which - k-edge-connects any part of G where it is possible, and maximally - connects the remaining parts. - - Raises - ------ - NetworkXUnfeasible: - If partial is False and no k-edge-augmentation exists. - - NetworkXNotImplemented: - If the input graph is directed or a multigraph. - - ValueError: - If k is less than 1 - - Notes - ----- - When k=1 this returns an optimal solution. - - When k=2 and ``avail`` is None, this returns an optimal solution. - Otherwise when k=2, this returns a 2-approximation of the optimal solution. - - For k>3, this problem is NP-hard and this uses a randomized algorithm that - produces a feasible solution, but provides no guarantees on the - solution weight. - - Example - ------- - >>> # Unweighted cases - >>> G = nx.path_graph((1, 2, 3, 4)) - >>> G.add_node(5) - >>> sorted(nx.k_edge_augmentation(G, k=1)) - [(1, 5)] - >>> sorted(nx.k_edge_augmentation(G, k=2)) - [(1, 5), (5, 4)] - >>> sorted(nx.k_edge_augmentation(G, k=3)) - [(1, 4), (1, 5), (2, 5), (3, 5), (4, 5)] - >>> complement = list(nx.k_edge_augmentation(G, k=5, partial=True)) - >>> G.add_edges_from(complement) - >>> nx.edge_connectivity(G) - 4 - - Example - ------- - >>> # Weighted cases - >>> G = nx.path_graph((1, 2, 3, 4)) - >>> G.add_node(5) - >>> # avail can be a tuple with a dict - >>> avail = [(1, 5, {'weight': 11}), (2, 5, {'weight': 10})] - >>> sorted(nx.k_edge_augmentation(G, k=1, avail=avail, weight='weight')) - [(2, 5)] - >>> # or avail can be a 3-tuple with a real number - >>> avail = [(1, 5, 11), (2, 5, 10), (4, 3, 1), (4, 5, 51)] - >>> sorted(nx.k_edge_augmentation(G, k=2, avail=avail)) - [(1, 5), (2, 5), (4, 5)] - >>> # or avail can be a dict - >>> avail = {(1, 5): 11, (2, 5): 10, (4, 3): 1, (4, 5): 51} - >>> sorted(nx.k_edge_augmentation(G, k=2, avail=avail)) - [(1, 5), (2, 5), (4, 5)] - >>> # If augmentation is infeasible, then a partial solution can be found - >>> avail = {(1, 5): 11} - >>> sorted(nx.k_edge_augmentation(G, k=2, avail=avail, partial=True)) - [(1, 5)] - """ - try: - if k <= 0: - raise ValueError('k must be a positive integer, not {}'.format(k)) - elif G.number_of_nodes() < k + 1: - msg = 'impossible to {} connect in graph with less than {} nodes' - raise nx.NetworkXUnfeasible(msg.format(k, k + 1)) - elif avail is not None and len(avail) == 0: - if not nx.is_k_edge_connected(G, k): - raise nx.NetworkXUnfeasible('no available edges') - aug_edges = [] - elif k == 1: - aug_edges = one_edge_augmentation(G, avail=avail, weight=weight, - partial=partial) - elif k == 2: - aug_edges = bridge_augmentation(G, avail=avail, weight=weight) - else: - # raise NotImplementedError( - # 'not implemented for k>2. k={}'.format(k)) - aug_edges = greedy_k_edge_augmentation( - G, k=k, avail=avail, weight=weight, seed=0) - # Do eager evaulation so we can catch any exceptions - # Before executing partial code. - for edge in list(aug_edges): - yield edge - except nx.NetworkXUnfeasible: - if partial: - # Return all available edges - if avail is None: - aug_edges = complement_edges(G) - else: - # If we can't k-edge-connect the entire graph, try to - # k-edge-connect as much as possible - aug_edges = partial_k_edge_augmentation(G, k=k, avail=avail, - weight=weight) - for edge in aug_edges: - yield edge - else: - raise - - -def partial_k_edge_augmentation(G, k, avail, weight=None): - """Finds augmentation that k-edge-connects as much of the graph as possible. - - When a k-edge-augmentation is not possible, we can still try to find a - small set of edges that partially k-edge-connects as much of the graph as - possible. All possible edges are generated between remaining parts. - This minimizes the number of k-edge-connected subgraphs in the resulting - graph and maxmizes the edge connectivity between those subgraphs. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - k : integer - Desired edge connectivity - - avail : dict or a set of 2 or 3 tuples - For more details, see :func:`k_edge_augmentation`. - - weight : string - key to use to find weights if ``avail`` is a set of 3-tuples. - For more details, see :func:`k_edge_augmentation`. - - Yields - ------ - edge : tuple - Edges in the partial augmentation of G. These edges k-edge-connect any - part of G where it is possible, and maximally connects the remaining - parts. In other words, all edges from avail are generated except for - those within subgraphs that have already become k-edge-connected. - - Notes - ----- - Construct H that augments G with all edges in avail. - Find the k-edge-subgraphs of H. - For each k-edge-subgraph, if the number of nodes is more than k, then find - the k-edge-augmentation of that graph and add it to the solution. Then add - all edges in avail between k-edge subgraphs to the solution. - - See Also - -------- - :func:`k_edge_augmentation` - - Example - ------- - >>> G = nx.path_graph((1, 2, 3, 4, 5, 6, 7)) - >>> G.add_node(8) - >>> avail = [(1, 3), (1, 4), (1, 5), (2, 4), (2, 5), (3, 5), (1, 8)] - >>> sorted(partial_k_edge_augmentation(G, k=2, avail=avail)) - [(1, 5), (1, 8)] - """ - def _edges_between_disjoint(H, only1, only2): - """ finds edges between disjoint nodes """ - only1_adj = {u: set(H.adj[u]) for u in only1} - for u, neighbs in only1_adj.items(): - # Find the neighbors of u in only1 that are also in only2 - neighbs12 = neighbs.intersection(only2) - for v in neighbs12: - yield (u, v) - - avail_uv, avail_w = _unpack_available_edges(avail, weight=weight, G=G) - - # Find which parts of the graph can be k-edge-connected - H = G.copy() - H.add_edges_from( - ((u, v, {'weight': w, 'generator': (u, v)}) - for (u, v), w in zip(avail, avail_w))) - k_edge_subgraphs = list(nx.k_edge_subgraphs(H, k=k)) - - # Generate edges to k-edge-connect internal subgraphs - for nodes in k_edge_subgraphs: - if len(nodes) > 1: - # Get the k-edge-connected subgraph - C = H.subgraph(nodes).copy() - # Find the internal edges that were available - sub_avail = { - d['generator']: d['weight'] - for (u, v, d) in C.edges(data=True) - if 'generator' in d - } - # Remove potential augmenting edges - C.remove_edges_from(sub_avail.keys()) - # Find a subset of these edges that makes the compoment - # k-edge-connected and ignore the rest - for edge in nx.k_edge_augmentation(C, k=k, avail=sub_avail): - yield edge - - # Generate all edges between CCs that could not be k-edge-connected - for cc1, cc2 in it.combinations(k_edge_subgraphs, 2): - for (u, v) in _edges_between_disjoint(H, cc1, cc2): - d = H.get_edge_data(u, v) - edge = d.get('generator', None) - if edge is not None: - yield edge - - -@not_implemented_for('multigraph') -@not_implemented_for('directed') -def one_edge_augmentation(G, avail=None, weight=None, partial=False): - """Finds minimum weight set of edges to connect G. - - Equivalent to :func:`k_edge_augmentation` when k=1. Adding the resulting - edges to G will make it 1-edge-connected. The solution is optimal for both - weighted and non-weighted variants. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - avail : dict or a set of 2 or 3 tuples - For more details, see :func:`k_edge_augmentation`. - - weight : string - key to use to find weights if ``avail`` is a set of 3-tuples. - For more details, see :func:`k_edge_augmentation`. - - partial : boolean - If partial is True and no feasible k-edge-augmentation exists, then the - augmenting edges minimize the number of connected components. - - Yields - ------ - edge : tuple - Edges in the one-augmentation of G - - Raises - ------ - NetworkXUnfeasible: - If partial is False and no one-edge-augmentation exists. - - Notes - ----- - Uses either :func:`unconstrained_one_edge_augmentation` or - :func:`weighted_one_edge_augmentation` depending on whether ``avail`` is - specified. Both algorithms are based on finding a minimum spanning tree. - As such both algorithms find optimal solutions and run in linear time. - - See Also - -------- - :func:`k_edge_augmentation` - """ - if avail is None: - return unconstrained_one_edge_augmentation(G) - else: - return weighted_one_edge_augmentation(G, avail=avail, weight=weight, - partial=partial) - - -@not_implemented_for('multigraph') -@not_implemented_for('directed') -def bridge_augmentation(G, avail=None, weight=None): - """Finds the a set of edges that bridge connects G. - - Equivalent to :func:`k_edge_augmentation` when k=2, and partial=False. - Adding the resulting edges to G will make it 2-edge-connected. If no - constraints are specified the returned set of edges is minimum an optimal, - otherwise the solution is approximated. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - avail : dict or a set of 2 or 3 tuples - For more details, see :func:`k_edge_augmentation`. - - weight : string - key to use to find weights if ``avail`` is a set of 3-tuples. - For more details, see :func:`k_edge_augmentation`. - - Yields - ------ - edge : tuple - Edges in the bridge-augmentation of G - - Raises - ------ - NetworkXUnfeasible: - If no bridge-augmentation exists. - - Notes - ----- - If there are no constraints the solution can be computed in linear time - using :func:`unconstrained_bridge_augmentation`. Otherwise, the problem - becomes NP-hard and is the solution is approximated by - :func:`weighted_bridge_augmentation`. - - See Also - -------- - :func:`k_edge_augmentation` - """ - if G.number_of_nodes() < 3: - raise nx.NetworkXUnfeasible( - 'impossible to bridge connect less than 3 nodes') - if avail is None: - return unconstrained_bridge_augmentation(G) - else: - return weighted_bridge_augmentation(G, avail, weight=weight) - - -# --- Algorithms and Helpers --- - -def _ordered(u, v): - """Returns the nodes in an undirected edge in lower-triangular order""" - return (u, v) if u < v else (v, u) - - -def _unpack_available_edges(avail, weight=None, G=None): - """Helper to separate avail into edges and corresponding weights""" - if weight is None: - weight = 'weight' - if isinstance(avail, dict): - avail_uv = list(avail.keys()) - avail_w = list(avail.values()) - else: - def _try_getitem(d): - try: - return d[weight] - except TypeError: - return d - avail_uv = [tup[0:2] for tup in avail] - avail_w = [1 if len(tup) == 2 else _try_getitem(tup[-1]) - for tup in avail] - - if G is not None: - # Edges already in the graph are filtered - flags = [not G.has_edge(u, v) for u, v in avail_uv] - avail_uv = list(it.compress(avail_uv, flags)) - avail_w = list(it.compress(avail_w, flags)) - return avail_uv, avail_w - - -MetaEdge = namedtuple('MetaEdge', ('meta_uv', 'uv', 'w')) - - -def _lightest_meta_edges(mapping, avail_uv, avail_w): - """Maps available edges in the original graph to edges in the metagraph. - - Parameters - ---------- - mapping : dict - mapping produced by :func:`collapse`, that maps each node in the - original graph to a node in the meta graph - - avail_uv : list - list of edges - - avail_w : list - list of edge weights - - Notes - ----- - Each node in the metagraph is a k-edge-connected component in the original - graph. We don't care about any edge within the same k-edge-connected - component, so we ignore self edges. We also are only intereseted in the - minimum weight edge bridging each k-edge-connected component so, we group - the edges by meta-edge and take the lightest in each group. - - Example - ------- - >>> # Each group represents a meta-node - >>> groups = ([1, 2, 3], [4, 5], [6]) - >>> mapping = {n: meta_n for meta_n, ns in enumerate(groups) for n in ns} - >>> avail_uv = [(1, 2), (3, 6), (1, 4), (5, 2), (6, 1), (2, 6), (3, 1)] - >>> avail_w = [ 20, 99, 20, 15, 50, 99, 20] - >>> sorted(_lightest_meta_edges(mapping, avail_uv, avail_w)) - [MetaEdge(meta_uv=(0, 1), uv=(5, 2), w=15), MetaEdge(meta_uv=(0, 2), uv=(6, 1), w=50)] - """ - grouped_wuv = defaultdict(list) - for w, (u, v) in zip(avail_w, avail_uv): - # Order the meta-edge so it can be used as a dict key - meta_uv = _ordered(mapping[u], mapping[v]) - # Group each available edge using the meta-edge as a key - grouped_wuv[meta_uv].append((w, u, v)) - - # Now that all available edges are grouped, choose one per group - for (mu, mv), choices_wuv in grouped_wuv.items(): - # Ignore available edges within the same meta-node - if mu != mv: - # Choose the lightest available edge belonging to each meta-edge - w, u, v = min(choices_wuv) - yield MetaEdge((mu, mv), (u, v), w) - - -def unconstrained_one_edge_augmentation(G): - """Finds the smallest set of edges to connect G. - - This is a variant of the unweighted MST problem. - If G is not empty, a feasible solution always exists. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - Yields - ------ - edge : tuple - Edges in the one-edge-augmentation of G - - See Also - -------- - :func:`one_edge_augmentation` - :func:`k_edge_augmentation` - - Example - ------- - >>> G = nx.Graph([(1, 2), (2, 3), (4, 5)]) - >>> G.add_nodes_from([6, 7, 8]) - >>> sorted(unconstrained_one_edge_augmentation(G)) - [(1, 4), (4, 6), (6, 7), (7, 8)] - """ - ccs1 = list(nx.connected_components(G)) - C = collapse(G, ccs1) - # When we are not constrained, we can just make a meta graph tree. - meta_nodes = list(C.nodes()) - # build a path in the metagraph - meta_aug = list(zip(meta_nodes, meta_nodes[1:])) - # map that path to the original graph - inverse = defaultdict(list) - for k, v in C.graph['mapping'].items(): - inverse[v].append(k) - for mu, mv in meta_aug: - yield (inverse[mu][0], inverse[mv][0]) - - -def weighted_one_edge_augmentation(G, avail, weight=None, partial=False): - """Finds the minimum weight set of edges to connect G if one exists. - - This is a variant of the weighted MST problem. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - avail : dict or a set of 2 or 3 tuples - For more details, see :func:`k_edge_augmentation`. - - weight : string - key to use to find weights if ``avail`` is a set of 3-tuples. - For more details, see :func:`k_edge_augmentation`. - - partial : boolean - If partial is True and no feasible k-edge-augmentation exists, then the - augmenting edges minimize the number of connected components. - - Yields - ------ - edge : tuple - Edges in the subset of avail chosen to connect G. - - See Also - -------- - :func:`one_edge_augmentation` - :func:`k_edge_augmentation` - - Example - ------- - >>> G = nx.Graph([(1, 2), (2, 3), (4, 5)]) - >>> G.add_nodes_from([6, 7, 8]) - >>> # any edge not in avail has an implicit weight of infinity - >>> avail = [(1, 3), (1, 5), (4, 7), (4, 8), (6, 1), (8, 1), (8, 2)] - >>> sorted(weighted_one_edge_augmentation(G, avail)) - [(1, 5), (4, 7), (6, 1), (8, 1)] - >>> # find another solution by giving large weights to edges in the - >>> # previous solution (note some of the old edges must be used) - >>> avail = [(1, 3), (1, 5, 99), (4, 7, 9), (6, 1, 99), (8, 1, 99), (8, 2)] - >>> sorted(weighted_one_edge_augmentation(G, avail)) - [(1, 5), (4, 7), (6, 1), (8, 2)] - """ - avail_uv, avail_w = _unpack_available_edges(avail, weight=weight, G=G) - # Collapse CCs in the original graph into nodes in a metagraph - # Then find an MST of the metagraph instead of the original graph - C = collapse(G, nx.connected_components(G)) - mapping = C.graph['mapping'] - # Assign each available edge to an edge in the metagraph - candidate_mapping = _lightest_meta_edges(mapping, avail_uv, avail_w) - # nx.set_edge_attributes(C, name='weight', values=0) - C.add_edges_from( - (mu, mv, {'weight': w, 'generator': uv}) - for (mu, mv), uv, w in candidate_mapping - ) - # Find MST of the meta graph - meta_mst = nx.minimum_spanning_tree(C) - if not partial and not nx.is_connected(meta_mst): - raise nx.NetworkXUnfeasible( - 'Not possible to connect G with available edges') - # Yield the edge that generated the meta-edge - for mu, mv, d in meta_mst.edges(data=True): - if 'generator' in d: - edge = d['generator'] - yield edge - - -def unconstrained_bridge_augmentation(G): - """Finds an optimal 2-edge-augmentation of G using the fewest edges. - - This is an implementation of the algorithm detailed in [1]_. - The basic idea is to construct a meta-graph of bridge-ccs, connect leaf - nodes of the trees to connect the entire graph, and finally connect the - leafs of the tree in dfs-preorder to bridge connect the entire graph. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - Yields - ------ - edge : tuple - Edges in the bridge augmentation of G - - Notes - ----- - Input: a graph G. - First find the bridge components of G and collapse each bridge-cc into a - node of a metagraph graph C, which is guaranteed to be a forest of trees. - - C contains p "leafs" --- nodes with exactly one incident edge. - C contains q "isolated nodes" --- nodes with no incident edges. - - Theorem: If p + q > 1, then at least :math:`ceil(p / 2) + q` edges are - needed to bridge connect C. This algorithm achieves this min number. - - The method first adds enough edges to make G into a tree and then pairs - leafs in a simple fashion. - - Let n be the number of trees in C. Let v(i) be an isolated vertex in the - i-th tree if one exists, otherwise it is a pair of distinct leafs nodes - in the i-th tree. Alternating edges from these sets (i.e. adding edges - A1 = [(v(i)[0], v(i + 1)[1]), v(i + 1)[0], v(i + 2)[1])...]) connects C - into a tree T. This tree has p' = p + 2q - 2(n -1) leafs and no isolated - vertices. A1 has n - 1 edges. The next step finds ceil(p' / 2) edges to - biconnect any tree with p' leafs. - - Convert T into an arborescence T' by picking an arbitrary root node with - degree >= 2 and directing all edges away from the root. Note the - implementation implicitly constructs T'. - - The leafs of T are the nodes with no existing edges in T'. - Order the leafs of T' by DFS prorder. Then break this list in half - and add the zipped pairs to A2. - - The set A = A1 + A2 is the minimum augmentation in the metagraph. - - To convert this to edges in the original graph - - References - ---------- - .. [1] Eswaran, Kapali P., and R. Endre Tarjan. (1975) Augmentation problems. - http://epubs.siam.org/doi/abs/10.1137/0205044 - - See Also - -------- - :func:`bridge_augmentation` - :func:`k_edge_augmentation` - - Example - ------- - >>> G = nx.path_graph((1, 2, 3, 4, 5, 6, 7)) - >>> sorted(unconstrained_bridge_augmentation(G)) - [(1, 7)] - >>> G = nx.path_graph((1, 2, 3, 2, 4, 5, 6, 7)) - >>> sorted(unconstrained_bridge_augmentation(G)) - [(1, 3), (3, 7)] - >>> G = nx.Graph([(0, 1), (0, 2), (1, 2)]) - >>> G.add_node(4) - >>> sorted(unconstrained_bridge_augmentation(G)) - [(1, 4), (4, 0)] - """ - # ----- - # Mapping of terms from (Eswaran and Tarjan): - # G = G_0 - the input graph - # C = G_0' - the bridge condensation of G. (This is a forest of trees) - # A1 = A_1 - the edges to connect the forest into a tree - # leaf = pendant - a node with degree of 1 - - # alpha(v) = maps the node v in G to its meta-node in C - # beta(x) = maps the meta-node x in C to any node in the bridge - # component of G corresponding to x. - - # find the 2-edge-connected components of G - bridge_ccs = list(nx.connectivity.bridge_components(G)) - # condense G into an forest C - C = collapse(G, bridge_ccs) - - # Choose pairs of distinct leaf nodes in each tree. If this is not - # possible then make a pair using the single isolated node in the tree. - vset1 = [ - tuple(cc) * 2 # case1: an isolated node - if len(cc) == 1 else - sorted(cc, key=C.degree)[0:2] # case2: pair of leaf nodes - for cc in nx.connected_components(C) - ] - if len(vset1) > 1: - # Use this set to construct edges that connect C into a tree. - nodes1 = [vs[0] for vs in vset1] - nodes2 = [vs[1] for vs in vset1] - A1 = list(zip(nodes1[1:], nodes2)) - else: - A1 = [] - # Connect each tree in the forest to construct an arborescence - T = C.copy() - T.add_edges_from(A1) - - # If there are only two leaf nodes, we simply connect them. - leafs = [n for n, d in T.degree() if d == 1] - if len(leafs) == 1: - A2 = [] - if len(leafs) == 2: - A2 = [tuple(leafs)] - else: - # Choose an arbitrary non-leaf root - try: - root = next(n for n, d in T.degree() if d > 1) - except StopIteration: # no nodes found with degree > 1 - return - # order the leaves of C by (induced directed) preorder - v2 = [n for n in nx.dfs_preorder_nodes(T, root) if T.degree(n) == 1] - # connecting first half of the leafs in pre-order to the second - # half will bridge connect the tree with the fewest edges. - half = int(math.ceil(len(v2) / 2.0)) - A2 = list(zip(v2[:half], v2[-half:])) - - # collect the edges used to augment the original forest - aug_tree_edges = A1 + A2 - - # Construct the mapping (beta) from meta-nodes to regular nodes - inverse = defaultdict(list) - for k, v in C.graph['mapping'].items(): - inverse[v].append(k) - # sort so we choose minimum degree nodes first - inverse = {mu: sorted(mapped, key=lambda u: (G.degree(u), u)) - for mu, mapped in inverse.items()} - - # For each meta-edge, map back to an arbitrary pair in the original graph - G2 = G.copy() - for mu, mv in aug_tree_edges: - # Find the first available edge that doesn't exist and return it - for u, v in it.product(inverse[mu], inverse[mv]): - if not G2.has_edge(u, v): - G2.add_edge(u, v) - yield u, v - break - - -def weighted_bridge_augmentation(G, avail, weight=None): - """Finds an approximate min-weight 2-edge-augmentation of G. - - This is an implementation of the approximation algorithm detailed in [1]_. - It chooses a set of edges from avail to add to G that renders it - 2-edge-connected if such a subset exists. This is done by finding a - minimum spanning arborescence of a specially constructed metagraph. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - avail : set of 2 or 3 tuples. - candidate edges (with optional weights) to choose from - - weight : string - key to use to find weights if avail is a set of 3-tuples where the - third item in each tuple is a dictionary. - - Yields - ------ - edge : tuple - Edges in the subset of avail chosen to bridge augment G. - - Notes - ----- - Finding a weighted 2-edge-augmentation is NP-hard. - Any edge not in ``avail`` is considered to have a weight of infinity. - The approximation factor is 2 if ``G`` is connected and 3 if it is not. - Runs in :math:`O(m + n log(n))` time - - References - ---------- - .. [1] Khuller, Samir, and Ramakrishna Thurimella. (1993) Approximation - algorithms for graph augmentation. - http://www.sciencedirect.com/science/article/pii/S0196677483710102 - - See Also - -------- - :func:`bridge_augmentation` - :func:`k_edge_augmentation` - - Example - ------- - >>> G = nx.path_graph((1, 2, 3, 4)) - >>> # When the weights are equal, (1, 4) is the best - >>> avail = [(1, 4, 1), (1, 3, 1), (2, 4, 1)] - >>> sorted(weighted_bridge_augmentation(G, avail)) - [(1, 4)] - >>> # Giving (1, 4) a high weight makes the two edge solution the best. - >>> avail = [(1, 4, 1000), (1, 3, 1), (2, 4, 1)] - >>> sorted(weighted_bridge_augmentation(G, avail)) - [(1, 3), (2, 4)] - >>> #------ - >>> G = nx.path_graph((1, 2, 3, 4)) - >>> G.add_node(5) - >>> avail = [(1, 5, 11), (2, 5, 10), (4, 3, 1), (4, 5, 1)] - >>> sorted(weighted_bridge_augmentation(G, avail=avail)) - [(1, 5), (4, 5)] - >>> avail = [(1, 5, 11), (2, 5, 10), (4, 3, 1), (4, 5, 51)] - >>> sorted(weighted_bridge_augmentation(G, avail=avail)) - [(1, 5), (2, 5), (4, 5)] - """ - - if weight is None: - weight = 'weight' - - # If input G is not connected the approximation factor increases to 3 - if not nx.is_connected(G): - H = G.copy() - connectors = list(one_edge_augmentation(H, avail=avail, weight=weight)) - H.add_edges_from(connectors) - - for edge in connectors: - yield edge - else: - connectors = [] - H = G - - if len(avail) == 0: - if nx.has_bridges(H): - raise nx.NetworkXUnfeasible('no augmentation possible') - - avail_uv, avail_w = _unpack_available_edges(avail, weight=weight, G=H) - - # Collapse input into a metagraph. Meta nodes are bridge-ccs - bridge_ccs = nx.connectivity.bridge_components(H) - C = collapse(H, bridge_ccs) - - # Use the meta graph to shrink avail to a small feasible subset - mapping = C.graph['mapping'] - # Choose the minimum weight feasible edge in each group - meta_to_wuv = { - (mu, mv): (w, uv) - for (mu, mv), uv, w in _lightest_meta_edges(mapping, avail_uv, avail_w) - } - - # Mapping of terms from (Khuller and Thurimella): - # C : G_0 = (V, E^0) - # This is the metagraph where each node is a 2-edge-cc in G. - # The edges in C represent bridges in the original graph. - # (mu, mv) : E - E^0 # they group both avail and given edges in E - # T : \Gamma - # D : G^D = (V, E_D) - - # The paper uses ancestor because children point to parents, which is - # contrary to networkx standards. So, we actually need to run - # nx.least_common_ancestor on the reversed Tree. - - # Pick an arbitrary leaf from C as the root - try: - root = next(n for n, d in C.degree() if d == 1) - except StopIteration: # no nodes found with degree == 1 - return - # Root C into a tree TR by directing all edges away from the root - # Note in their paper T directs edges towards the root - TR = nx.dfs_tree(C, root) - - # Add to D the directed edges of T and set their weight to zero - # This indicates that it costs nothing to use edges that were given. - D = nx.reverse(TR).copy() - - nx.set_edge_attributes(D, name='weight', values=0) - - # The LCA of mu and mv in T is the shared ancestor of mu and mv that is - # located farthest from the root. - lca_gen = nx.tree_all_pairs_lowest_common_ancestor( - TR, root=root, pairs=meta_to_wuv.keys()) - - for (mu, mv), lca in lca_gen: - w, uv = meta_to_wuv[(mu, mv)] - if lca == mu: - # If u is an ancestor of v in TR, then add edge u->v to D - D.add_edge(lca, mv, weight=w, generator=uv) - elif lca == mv: - # If v is an ancestor of u in TR, then add edge v->u to D - D.add_edge(lca, mu, weight=w, generator=uv) - else: - # If neither u nor v is a ancestor of the other in TR - # let t = lca(TR, u, v) and add edges t->u and t->v - # Track the original edge that GENERATED these edges. - D.add_edge(lca, mu, weight=w, generator=uv) - D.add_edge(lca, mv, weight=w, generator=uv) - - # Then compute a minimum rooted branching - try: - # Note the original edges must be directed towards to root for the - # branching to give us a bridge-augmentation. - A = _minimum_rooted_branching(D, root) - except nx.NetworkXException: - # If there is no branching then augmentation is not possible - raise nx.NetworkXUnfeasible('no 2-edge-augmentation possible') - - # For each edge e, in the branching that did not belong to the directed - # tree T, add the corresponding edge that **GENERATED** it (this is not - # necesarilly e itself!) - - # ensure the third case does not generate edges twice - bridge_connectors = set() - for mu, mv in A.edges(): - data = D.get_edge_data(mu, mv) - if 'generator' in data: - # Add the avail edge that generated the branching edge. - edge = data['generator'] - bridge_connectors.add(edge) - - for edge in bridge_connectors: - yield edge - - -def _minimum_rooted_branching(D, root): - """Helper function to compute a minimum rooted branching (aka rooted - arborescence) - - Before the branching can be computed, the directed graph must be rooted by - removing the predecessors of root. - - A branching / arborescence of rooted graph G is a subgraph that contains a - directed path from the root to every other vertex. It is the directed - analog of the minimum spanning tree problem. - - References - ---------- - [1] Khuller, Samir (2002) Advanced Algorithms Lecture 24 Notes. - https://www.cs.umd.edu/class/spring2011/cmsc651/lec07.pdf - """ - rooted = D.copy() - # root the graph by removing all predecessors to `root`. - rooted.remove_edges_from([(u, root) for u in D.predecessors(root)]) - # Then compute the branching / arborescence. - A = nx.minimum_spanning_arborescence(rooted) - return A - - -def collapse(G, grouped_nodes): - """Collapses each group of nodes into a single node. - - This is similar to condensation, but works on undirected graphs. - - Parameters - ---------- - G : NetworkX Graph - - grouped_nodes: list or generator - Grouping of nodes to collapse. The grouping must be disjoint. - If grouped_nodes are strongly_connected_components then this is - equivalent to :func:`condensation`. - - Returns - ------- - C : NetworkX Graph - The collapsed graph C of G with respect to the node grouping. The node - labels are integers corresponding to the index of the component in the - list of grouped_nodes. C has a graph attribute named 'mapping' with a - dictionary mapping the original nodes to the nodes in C to which they - belong. Each node in C also has a node attribute 'members' with the set - of original nodes in G that form the group that the node in C - represents. - - Examples - -------- - >>> # Collapses a graph using disjoint groups, but not necesarilly connected - >>> G = nx.Graph([(1, 0), (2, 3), (3, 1), (3, 4), (4, 5), (5, 6), (5, 7)]) - >>> G.add_node('A') - >>> grouped_nodes = [{0, 1, 2, 3}, {5, 6, 7}] - >>> C = collapse(G, grouped_nodes) - >>> members = nx.get_node_attributes(C, 'members') - >>> sorted(members.keys()) - [0, 1, 2, 3] - >>> member_values = set(map(frozenset, members.values())) - >>> assert {0, 1, 2, 3} in member_values - >>> assert {4} in member_values - >>> assert {5, 6, 7} in member_values - >>> assert {'A'} in member_values - """ - mapping = {} - members = {} - C = G.__class__() - i = 0 # required if G is empty - remaining = set(G.nodes()) - for i, group in enumerate(grouped_nodes): - group = set(group) - assert remaining.issuperset(group), ( - 'grouped nodes must exist in G and be disjoint') - remaining.difference_update(group) - members[i] = group - mapping.update((n, i) for n in group) - # remaining nodes are in their own group - for i, node in enumerate(remaining, start=i + 1): - group = set([node]) - members[i] = group - mapping.update((n, i) for n in group) - number_of_groups = i + 1 - C.add_nodes_from(range(number_of_groups)) - C.add_edges_from((mapping[u], mapping[v]) for u, v in G.edges() - if mapping[u] != mapping[v]) - # Add a list of members (ie original nodes) to each node (ie scc) in C. - nx.set_node_attributes(C, name='members', values=members) - # Add mapping dict as graph attribute - C.graph['mapping'] = mapping - return C - - -def complement_edges(G): - """Returns only the edges in the complement of G - - Parameters - ---------- - G : NetworkX Graph - - Yields - ------ - edge : tuple - Edges in the complement of G - - Example - ------- - >>> G = nx.path_graph((1, 2, 3, 4)) - >>> sorted(complement_edges(G)) - [(1, 3), (1, 4), (2, 4)] - >>> G = nx.path_graph((1, 2, 3, 4), nx.DiGraph()) - >>> sorted(complement_edges(G)) - [(1, 3), (1, 4), (2, 1), (2, 4), (3, 1), (3, 2), (4, 1), (4, 2), (4, 3)] - >>> G = nx.complete_graph(1000) - >>> sorted(complement_edges(G)) - [] - """ - if G.is_directed(): - for u, v in it.combinations(G.nodes(), 2): - if v not in G.adj[u]: - yield (u, v) - if u not in G.adj[v]: - yield (v, u) - else: - for u, v in it.combinations(G.nodes(), 2): - if v not in G.adj[u]: - yield (u, v) - - -if sys.version_info[0] == 2: - def _compat_shuffle(rng, input): - """ - python2 workaround so shuffle works the same as python3 - - References - ---------- - https://stackoverflow.com/questions/38943038/diff-shuffle-py2-py3 - """ - def _randbelow(n): - "Return a random int in the range [0,n). Raises ValueError if n==0." - getrandbits = rng.getrandbits - k = n.bit_length() # don't use (n-1) here because n can be 1 - r = getrandbits(k) # 0 <= r < 2**k - while r >= n: - r = getrandbits(k) - return r - - for i in range(len(input) - 1, 0, -1): - # pick an element in input[:i+1] with which to exchange input[i] - j = _randbelow(i + 1) - input[i], input[j] = input[j], input[i] -else: - def _compat_shuffle(rng, input): - """wrapper around rng.shuffle for python 2 compatibility reasons""" - rng.shuffle(input) - - -@py_random_state(4) -@not_implemented_for('multigraph') -@not_implemented_for('directed') -def greedy_k_edge_augmentation(G, k, avail=None, weight=None, seed=None): - """Greedy algorithm for finding a k-edge-augmentation - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - k : integer - Desired edge connectivity - - avail : dict or a set of 2 or 3 tuples - For more details, see :func:`k_edge_augmentation`. - - weight : string - key to use to find weights if ``avail`` is a set of 3-tuples. - For more details, see :func:`k_edge_augmentation`. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Yields - ------ - edge : tuple - Edges in the greedy augmentation of G - - Notes - ----- - The algorithm is simple. Edges are incrementally added between parts of the - graph that are not yet locally k-edge-connected. Then edges are from the - augmenting set are pruned as long as local-edge-connectivity is not broken. - - This algorithm is greedy and does not provide optimality guarantees. It - exists only to provide :func:`k_edge_augmentation` with the ability to - generate a feasible solution for arbitrary k. - - See Also - -------- - :func:`k_edge_augmentation` - - Example - ------- - >>> G = nx.path_graph((1, 2, 3, 4, 5, 6, 7)) - >>> sorted(greedy_k_edge_augmentation(G, k=2)) - [(1, 7)] - >>> sorted(greedy_k_edge_augmentation(G, k=1, avail=[])) - [] - >>> G = nx.path_graph((1, 2, 3, 4, 5, 6, 7)) - >>> avail = {(u, v): 1 for (u, v) in complement_edges(G)} - >>> # randomized pruning process can produce different solutions - >>> sorted(greedy_k_edge_augmentation(G, k=4, avail=avail, seed=2)) - [(1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (2, 4), (2, 6), (3, 7), (5, 7)] - >>> sorted(greedy_k_edge_augmentation(G, k=4, avail=avail, seed=3)) - [(1, 3), (1, 5), (1, 6), (2, 4), (2, 6), (3, 7), (4, 7), (5, 7)] - """ - # Result set - aug_edges = [] - - done = is_k_edge_connected(G, k) - if done: - return - if avail is None: - # all edges are available - avail_uv = list(complement_edges(G)) - avail_w = [1] * len(avail_uv) - else: - # Get the unique set of unweighted edges - avail_uv, avail_w = _unpack_available_edges(avail, weight=weight, G=G) - - # Greedy: order lightest edges. Use degree sum to tie-break - tiebreaker = [sum(map(G.degree, uv)) for uv in avail_uv] - avail_wduv = sorted(zip(avail_w, tiebreaker, avail_uv)) - avail_uv = [uv for w, d, uv in avail_wduv] - - # Incrementally add edges in until we are k-connected - H = G.copy() - for (u, v) in avail_uv: - done = False - if not is_locally_k_edge_connected(H, u, v, k=k): - # Only add edges in parts that are not yet locally k-edge-connected - aug_edges.append((u, v)) - H.add_edge(u, v) - # Did adding this edge help? - if H.degree(u) >= k and H.degree(v) >= k: - done = is_k_edge_connected(H, k) - if done: - break - - # Check for feasibility - if not done: - raise nx.NetworkXUnfeasible( - 'not able to k-edge-connect with available edges') - - # Randomized attempt to reduce the size of the solution - _compat_shuffle(seed, aug_edges) - for (u, v) in list(aug_edges): - # Don't remove if we know it would break connectivity - if H.degree(u) <= k or H.degree(v) <= k: - continue - H.remove_edge(u, v) - aug_edges.remove((u, v)) - if not is_k_edge_connected(H, k=k): - # If removing this edge breaks feasibility, undo - H.add_edge(u, v) - aug_edges.append((u, v)) - - # Generate results - for edge in aug_edges: - yield edge diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/edge_kcomponents.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/edge_kcomponents.py deleted file mode 100644 index c9902819..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/edge_kcomponents.py +++ /dev/null @@ -1,596 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Jon Crall (erotemic@gmail.com) -""" -Algorithms for finding k-edge-connected components and subgraphs. - -A k-edge-connected component (k-edge-cc) is a maximal set of nodes in G, such -that all pairs of node have an edge-connectivity of at least k. - -A k-edge-connected subgraph (k-edge-subgraph) is a maximal set of nodes in G, -such that the subgraph of G defined by the nodes has an edge-connectivity at -least k. -""" -import networkx as nx -from networkx.utils import arbitrary_element -from networkx.utils import not_implemented_for -from networkx.algorithms import bridges -from functools import partial -import itertools as it - -__all__ = [ - 'k_edge_components', - 'k_edge_subgraphs', - 'bridge_components', - 'EdgeComponentAuxGraph', -] - - -@not_implemented_for('multigraph') -def k_edge_components(G, k): - """Generates nodes in each maximal k-edge-connected component in G. - - Parameters - ---------- - G : NetworkX graph - - k : Integer - Desired edge connectivity - - Returns - ------- - k_edge_components : a generator of k-edge-ccs. Each set of returned nodes - will have k-edge-connectivity in the graph G. - - See Also - ------- - :func:`local_edge_connectivity` - :func:`k_edge_subgraphs` : similar to this function, but the subgraph - defined by the nodes must also have k-edge-connectivity. - :func:`k_components` : similar to this function, but uses node-connectivity - instead of edge-connectivity - - Raises - ------ - NetworkXNotImplemented: - If the input graph is a multigraph. - - ValueError: - If k is less than 1 - - Notes - ----- - Attempts to use the most efficient implementation available based on k. - If k=1, this is simply simply connected components for directed graphs and - connected components for undirected graphs. - If k=2 on an efficient bridge connected component algorithm from _[1] is - run based on the chain decomposition. - Otherwise, the algorithm from _[2] is used. - - Example - ------- - >>> import itertools as it - >>> from networkx.utils import pairwise - >>> paths = [ - ... (1, 2, 4, 3, 1, 4), - ... (5, 6, 7, 8, 5, 7, 8, 6), - ... ] - >>> G = nx.Graph() - >>> G.add_nodes_from(it.chain(*paths)) - >>> G.add_edges_from(it.chain(*[pairwise(path) for path in paths])) - >>> # note this returns {1, 4} unlike k_edge_subgraphs - >>> sorted(map(sorted, nx.k_edge_components(G, k=3))) - [[1, 4], [2], [3], [5, 6, 7, 8]] - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Bridge_%28graph_theory%29 - .. [2] Wang, Tianhao, et al. (2015) A simple algorithm for finding all - k-edge-connected components. - http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0136264 - """ - # Compute k-edge-ccs using the most efficient algorithms available. - if k < 1: - raise ValueError('k cannot be less than 1') - if G.is_directed(): - if k == 1: - return nx.strongly_connected_components(G) - else: - # TODO: investigate https://arxiv.org/abs/1412.6466 for k=2 - aux_graph = EdgeComponentAuxGraph.construct(G) - return aux_graph.k_edge_components(k) - else: - if k == 1: - return nx.connected_components(G) - elif k == 2: - return bridge_components(G) - else: - aux_graph = EdgeComponentAuxGraph.construct(G) - return aux_graph.k_edge_components(k) - - -@not_implemented_for('multigraph') -def k_edge_subgraphs(G, k): - """Generates nodes in each maximal k-edge-connected subgraph in G. - - Parameters - ---------- - G : NetworkX graph - - k : Integer - Desired edge connectivity - - Returns - ------- - k_edge_subgraphs : a generator of k-edge-subgraphs - Each k-edge-subgraph is a maximal set of nodes that defines a subgraph - of G that is k-edge-connected. - - See Also - ------- - :func:`edge_connectivity` - :func:`k_edge_components` : similar to this function, but nodes only - need to have k-edge-connctivity within the graph G and the subgraphs - might not be k-edge-connected. - - Raises - ------ - NetworkXNotImplemented: - If the input graph is a multigraph. - - ValueError: - If k is less than 1 - - Notes - ----- - Attempts to use the most efficient implementation available based on k. - If k=1, or k=2 and the graph is undirected, then this simply calls - `k_edge_components`. Otherwise the algorithm from _[1] is used. - - Example - ------- - >>> import itertools as it - >>> from networkx.utils import pairwise - >>> paths = [ - ... (1, 2, 4, 3, 1, 4), - ... (5, 6, 7, 8, 5, 7, 8, 6), - ... ] - >>> G = nx.Graph() - >>> G.add_nodes_from(it.chain(*paths)) - >>> G.add_edges_from(it.chain(*[pairwise(path) for path in paths])) - >>> # note this does not return {1, 4} unlike k_edge_components - >>> sorted(map(sorted, nx.k_edge_subgraphs(G, k=3))) - [[1], [2], [3], [4], [5, 6, 7, 8]] - - References - ---------- - .. [1] Zhou, Liu, et al. (2012) Finding maximal k-edge-connected subgraphs - from a large graph. ACM International Conference on Extending Database - Technology 2012 480-–491. - https://openproceedings.org/2012/conf/edbt/ZhouLYLCL12.pdf - """ - if k < 1: - raise ValueError('k cannot be less than 1') - if G.is_directed(): - if k <= 1: - # For directed graphs , - # When k == 1, k-edge-ccs and k-edge-subgraphs are the same - return k_edge_components(G, k) - else: - return _k_edge_subgraphs_nodes(G, k) - else: - if k <= 2: - # For undirected graphs, - # when k <= 2, k-edge-ccs and k-edge-subgraphs are the same - return k_edge_components(G, k) - else: - return _k_edge_subgraphs_nodes(G, k) - - -def _k_edge_subgraphs_nodes(G, k): - """Helper to get the nodes from the subgraphs. - - This allows k_edge_subgraphs to return a generator. - """ - for C in general_k_edge_subgraphs(G, k): - yield set(C.nodes()) - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def bridge_components(G): - """Finds all bridge-connected components G. - - Parameters - ---------- - G : NetworkX undirected graph - - Returns - ------- - bridge_components : a generator of 2-edge-connected components - - - See Also - -------- - :func:`k_edge_subgraphs` : this function is a special case for an - undirected graph where k=2. - :func:`biconnected_components` : similar to this function, but is defined - using 2-node-connectivity instead of 2-edge-connectivity. - - Raises - ------ - NetworkXNotImplemented: - If the input graph is directed or a multigraph. - - Notes - ----- - Bridge-connected components are also known as 2-edge-connected components. - - Example - ------- - >>> # The barbell graph with parameter zero has a single bridge - >>> G = nx.barbell_graph(5, 0) - >>> from networkx.algorithms.connectivity.edge_kcomponents import bridge_components - >>> sorted(map(sorted, bridge_components(G))) - [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]] - """ - H = G.copy() - H.remove_edges_from(bridges(G)) - for cc in nx.connected_components(H): - yield cc - - -class EdgeComponentAuxGraph(object): - r"""A simple algorithm to find all k-edge-connected components in a graph. - - Constructing the AuxillaryGraph (which may take some time) allows for the - k-edge-ccs to be found in linear time for arbitrary k. - - Notes - ----- - This implementation is based on [1]_. The idea is to construct an auxiliary - graph from which the k-edge-ccs can be extracted in linear time. The - auxiliary graph is constructed in $O(|V|\cdot F)$ operations, where F is the - complexity of max flow. Querying the components takes an additional $O(|V|)$ - operations. This algorithm can be slow for large graphs, but it handles an - arbitrary k and works for both directed and undirected inputs. - - The undirected case for k=1 is exactly connected components. - The undirected case for k=2 is exactly bridge connected components. - The directed case for k=1 is exactly strongly connected components. - - References - ---------- - .. [1] Wang, Tianhao, et al. (2015) A simple algorithm for finding all - k-edge-connected components. - http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0136264 - - Example - ------- - >>> import itertools as it - >>> from networkx.utils import pairwise - >>> from networkx.algorithms.connectivity import EdgeComponentAuxGraph - >>> # Build an interesting graph with multiple levels of k-edge-ccs - >>> paths = [ - ... (1, 2, 3, 4, 1, 3, 4, 2), # a 3-edge-cc (a 4 clique) - ... (5, 6, 7, 5), # a 2-edge-cc (a 3 clique) - ... (1, 5), # combine first two ccs into a 1-edge-cc - ... (0,), # add an additional disconnected 1-edge-cc - ... ] - >>> G = nx.Graph() - >>> G.add_nodes_from(it.chain(*paths)) - >>> G.add_edges_from(it.chain(*[pairwise(path) for path in paths])) - >>> # Constructing the AuxGraph takes about O(n ** 4) - >>> aux_graph = EdgeComponentAuxGraph.construct(G) - >>> # Once constructed, querying takes O(n) - >>> sorted(map(sorted, aux_graph.k_edge_components(k=1))) - [[0], [1, 2, 3, 4, 5, 6, 7]] - >>> sorted(map(sorted, aux_graph.k_edge_components(k=2))) - [[0], [1, 2, 3, 4], [5, 6, 7]] - >>> sorted(map(sorted, aux_graph.k_edge_components(k=3))) - [[0], [1, 2, 3, 4], [5], [6], [7]] - >>> sorted(map(sorted, aux_graph.k_edge_components(k=4))) - [[0], [1], [2], [3], [4], [5], [6], [7]] - - Example - ------- - >>> # The auxiliary graph is primarilly used for k-edge-ccs but it - >>> # can also speed up the queries of k-edge-subgraphs by refining the - >>> # search space. - >>> import itertools as it - >>> from networkx.utils import pairwise - >>> from networkx.algorithms.connectivity import EdgeComponentAuxGraph - >>> paths = [ - ... (1, 2, 4, 3, 1, 4), - ... ] - >>> G = nx.Graph() - >>> G.add_nodes_from(it.chain(*paths)) - >>> G.add_edges_from(it.chain(*[pairwise(path) for path in paths])) - >>> aux_graph = EdgeComponentAuxGraph.construct(G) - >>> sorted(map(sorted, aux_graph.k_edge_subgraphs(k=3))) - [[1], [2], [3], [4]] - >>> sorted(map(sorted, aux_graph.k_edge_components(k=3))) - [[1, 4], [2], [3]] - """ - - # @not_implemented_for('multigraph') # TODO: fix decor for classmethods - @classmethod - def construct(EdgeComponentAuxGraph, G): - """Builds an auxiliary graph encoding edge-connectivity between nodes. - - Notes - ----- - Given G=(V, E), initialize an empty auxiliary graph A. - Choose an arbitrary source node s. Initialize a set N of available - nodes (that can be used as the sink). The algorithm picks an - arbitrary node t from N - {s}, and then computes the minimum st-cut - (S, T) with value w. If G is directed the the minimum of the st-cut or - the ts-cut is used instead. Then, the edge (s, t) is added to the - auxiliary graph with weight w. The algorithm is called recursively - first using S as the available nodes and s as the source, and then - using T and t. Recursion stops when the source is the only available - node. - - Parameters - ---------- - G : NetworkX graph - """ - # workaround for classmethod decorator - not_implemented_for('multigraph')(lambda G: G)(G) - - def _recursive_build(H, A, source, avail): - # Terminate once the flow has been compute to every node. - if {source} == avail: - return - # pick an arbitrary node as the sink - sink = arbitrary_element(avail - {source}) - # find the minimum cut and its weight - value, (S, T) = nx.minimum_cut(H, source, sink) - if H.is_directed(): - # check if the reverse direction has a smaller cut - value_, (T_, S_) = nx.minimum_cut(H, sink, source) - if value_ < value: - value, S, T = value_, S_, T_ - # add edge with weight of cut to the aux graph - A.add_edge(source, sink, weight=value) - # recursively call until all but one node is used - _recursive_build(H, A, source, avail.intersection(S)) - _recursive_build(H, A, sink, avail.intersection(T)) - - # Copy input to ensure all edges have unit capacity - H = G.__class__() - H.add_nodes_from(G.nodes()) - H.add_edges_from(G.edges(), capacity=1) - - # A is the auxiliary graph to be constructed - # It is a weighted undirected tree - A = nx.Graph() - - # Pick an arbitrary node as the source - if H.number_of_nodes() > 0: - source = arbitrary_element(H.nodes()) - # Initialize a set of elements that can be chosen as the sink - avail = set(H.nodes()) - - # This constructs A - _recursive_build(H, A, source, avail) - - # This class is a container the holds the auxiliary graph A and - # provides access the the k_edge_components function. - self = EdgeComponentAuxGraph() - self.A = A - self.H = H - return self - - def k_edge_components(self, k): - """Queries the auxiliary graph for k-edge-connected components. - - Parameters - ---------- - k : Integer - Desired edge connectivity - - Returns - ------- - k_edge_components : a generator of k-edge-ccs - - Notes - ----- - Given the auxiliary graph, the k-edge-connected components can be - determined in linear time by removing all edges with weights less than - k from the auxiliary graph. The resulting connected components are the - k-edge-ccs in the original graph. - """ - if k < 1: - raise ValueError('k cannot be less than 1') - A = self.A - # "traverse the auxiliary graph A and delete all edges with weights less - # than k" - aux_weights = nx.get_edge_attributes(A, 'weight') - # Create a relevant graph with the auxiliary edges with weights >= k - R = nx.Graph() - R.add_nodes_from(A.nodes()) - R.add_edges_from(e for e, w in aux_weights.items() if w >= k) - - # Return the nodes that are k-edge-connected in the original graph - for cc in nx.connected_components(R): - yield cc - - def k_edge_subgraphs(self, k): - """Queries the auxiliary graph for k-edge-connected subgraphs. - - Parameters - ---------- - k : Integer - Desired edge connectivity - - Returns - ------- - k_edge_subgraphs : a generator of k-edge-subgraphs - - Notes - ----- - Refines the k-edge-ccs into k-edge-subgraphs. The running time is more - than $O(|V|)$. - - For single values of k it is faster to use `nx.k_edge_subgraphs`. - But for multiple values of k, it can be faster to build AuxGraph and - then use this method. - """ - if k < 1: - raise ValueError('k cannot be less than 1') - H = self.H - A = self.A - # "traverse the auxiliary graph A and delete all edges with weights less - # than k" - aux_weights = nx.get_edge_attributes(A, 'weight') - # Create a relevant graph with the auxiliary edges with weights >= k - R = nx.Graph() - R.add_nodes_from(A.nodes()) - R.add_edges_from(e for e, w in aux_weights.items() if w >= k) - - # Return the components whose subgraphs are k-edge-connected - for cc in nx.connected_components(R): - if len(cc) < k: - # Early return optimization - for node in cc: - yield {node} - else: - # Call subgraph solution to refine the results - C = H.subgraph(cc) - for sub_cc in k_edge_subgraphs(C, k): - yield sub_cc - - -def _low_degree_nodes(G, k, nbunch=None): - """Helper for finding nodes with degree less than k.""" - # Nodes with degree less than k cannot be k-edge-connected. - if G.is_directed(): - # Consider both in and out degree in the directed case - seen = set() - for node, degree in G.out_degree(nbunch): - if degree < k: - seen.add(node) - yield node - for node, degree in G.in_degree(nbunch): - if node not in seen and degree < k: - seen.add(node) - yield node - else: - # Only the degree matters in the undirected case - for node, degree in G.degree(nbunch): - if degree < k: - yield node - - -def _high_degree_components(G, k): - """Helper for filtering components that can't be k-edge-connected. - - Removes and generates each node with degree less than k. Then generates - remaining components where all nodes have degree at least k. - """ - # Iteravely remove parts of the graph that are not k-edge-connected - H = G.copy() - singletons = set(_low_degree_nodes(H, k)) - while singletons: - # Only search neighbors of removed nodes - nbunch = set(it.chain.from_iterable(map(H.neighbors, singletons))) - nbunch.difference_update(singletons) - H.remove_nodes_from(singletons) - for node in singletons: - yield {node} - singletons = set(_low_degree_nodes(H, k, nbunch)) - - # Note: remaining connected components may not be k-edge-connected - if G.is_directed(): - for cc in nx.strongly_connected_components(H): - yield cc - else: - for cc in nx.connected_components(H): - yield cc - - -def general_k_edge_subgraphs(G, k): - """General algorithm to find all maximal k-edge-connected subgraphs in G. - - Returns - ------- - k_edge_subgraphs : a generator of nx.Graphs that are k-edge-subgraphs - Each k-edge-subgraph is a maximal set of nodes that defines a subgraph - of G that is k-edge-connected. - - Notes - ----- - Implementation of the basic algorithm from _[1]. The basic idea is to find - a global minimum cut of the graph. If the cut value is at least k, then the - graph is a k-edge-connected subgraph and can be added to the results. - Otherwise, the cut is used to split the graph in two and the procedure is - applied recursively. If the graph is just a single node, then it is also - added to the results. At the end, each result is either guaranteed to be - a single node or a subgraph of G that is k-edge-connected. - - This implementation contains optimizations for reducing the number of calls - to max-flow, but there are other optimizations in _[1] that could be - implemented. - - References - ---------- - .. [1] Zhou, Liu, et al. (2012) Finding maximal k-edge-connected subgraphs - from a large graph. ACM International Conference on Extending Database - Technology 2012 480-–491. - https://openproceedings.org/2012/conf/edbt/ZhouLYLCL12.pdf - - Example - ------- - >>> from networkx.utils import pairwise - >>> paths = [ - ... (11, 12, 13, 14, 11, 13, 14, 12), # a 4-clique - ... (21, 22, 23, 24, 21, 23, 24, 22), # another 4-clique - ... # connect the cliques with high degree but low connectivity - ... (50, 13), - ... (12, 50, 22), - ... (13, 102, 23), - ... (14, 101, 24), - ... ] - >>> G = nx.Graph(it.chain(*[pairwise(path) for path in paths])) - >>> sorted(map(len, k_edge_subgraphs(G, k=3))) - [1, 1, 1, 4, 4] - """ - if k < 1: - raise ValueError('k cannot be less than 1') - - # Node pruning optimization (incorporates early return) - # find_ccs is either connected_components/strongly_connected_components - find_ccs = partial(_high_degree_components, k=k) - - # Quick return optimization - if G.number_of_nodes() < k: - for node in G.nodes(): - yield G.subgraph([node]).copy() - return - - # Intermediate results - R0 = {G.subgraph(cc).copy() for cc in find_ccs(G)} - # Subdivide CCs in the intermediate results until they are k-conn - while R0: - G1 = R0.pop() - if G1.number_of_nodes() == 1: - yield G1 - else: - # Find a global minimum cut - cut_edges = nx.minimum_edge_cut(G1) - cut_value = len(cut_edges) - if cut_value < k: - # G1 is not k-edge-connected, so subdivide it - G1.remove_edges_from(cut_edges) - for cc in find_ccs(G1): - R0.add(G1.subgraph(cc).copy()) - else: - # Otherwise we found a k-edge-connected subgraph - yield G1 diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/kcomponents.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/kcomponents.py deleted file mode 100644 index 4f5013ec..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/kcomponents.py +++ /dev/null @@ -1,225 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Moody and White algorithm for k-components -""" -from collections import defaultdict -from itertools import combinations -from operator import itemgetter - -import networkx as nx -from networkx.utils import not_implemented_for -# Define the default maximum flow function. -from networkx.algorithms.flow import edmonds_karp -default_flow_func = edmonds_karp - -__author__ = '\n'.join(['Jordi Torrents ']) - -__all__ = ['k_components'] - - -@not_implemented_for('directed') -def k_components(G, flow_func=None): - r"""Returns the k-component structure of a graph G. - - A `k`-component is a maximal subgraph of a graph G that has, at least, - node connectivity `k`: we need to remove at least `k` nodes to break it - into more components. `k`-components have an inherent hierarchical - structure because they are nested in terms of connectivity: a connected - graph can contain several 2-components, each of which can contain - one or more 3-components, and so forth. - - Parameters - ---------- - G : NetworkX graph - - flow_func : function - Function to perform the underlying flow computations. Default value - :meth:`edmonds_karp`. This function performs better in sparse graphs with - right tailed degree distributions. :meth:`shortest_augmenting_path` will - perform better in denser graphs. - - Returns - ------- - k_components : dict - Dictionary with all connectivity levels `k` in the input Graph as keys - and a list of sets of nodes that form a k-component of level `k` as - values. - - Raises - ------ - NetworkXNotImplemented: - If the input graph is directed. - - Examples - -------- - >>> # Petersen graph has 10 nodes and it is triconnected, thus all - >>> # nodes are in a single component on all three connectivity levels - >>> G = nx.petersen_graph() - >>> k_components = nx.k_components(G) - - Notes - ----- - Moody and White [1]_ (appendix A) provide an algorithm for identifying - k-components in a graph, which is based on Kanevsky's algorithm [2]_ - for finding all minimum-size node cut-sets of a graph (implemented in - :meth:`all_node_cuts` function): - - 1. Compute node connectivity, k, of the input graph G. - - 2. Identify all k-cutsets at the current level of connectivity using - Kanevsky's algorithm. - - 3. Generate new graph components based on the removal of - these cutsets. Nodes in a cutset belong to both sides - of the induced cut. - - 4. If the graph is neither complete nor trivial, return to 1; - else end. - - This implementation also uses some heuristics (see [3]_ for details) - to speed up the computation. - - See also - -------- - node_connectivity - all_node_cuts - biconnected_components : special case of this function when k=2 - k_edge_components : similar to this function, but uses edge-connectivity - instead of node-connectivity - - References - ---------- - .. [1] Moody, J. and D. White (2003). Social cohesion and embeddedness: - A hierarchical conception of social groups. - American Sociological Review 68(1), 103--28. - http://www2.asanet.org/journals/ASRFeb03MoodyWhite.pdf - - .. [2] Kanevsky, A. (1993). Finding all minimum-size separating vertex - sets in a graph. Networks 23(6), 533--541. - http://onlinelibrary.wiley.com/doi/10.1002/net.3230230604/abstract - - .. [3] Torrents, J. and F. Ferraro (2015). Structural Cohesion: - Visualization and Heuristics for Fast Computation. - https://arxiv.org/pdf/1503.04476v1 - - """ - # Dictionary with connectivity level (k) as keys and a list of - # sets of nodes that form a k-component as values. Note that - # k-compoents can overlap (but only k - 1 nodes). - k_components = defaultdict(list) - # Define default flow function - if flow_func is None: - flow_func = default_flow_func - # Bicomponents as a base to check for higher order k-components - for component in nx.connected_components(G): - # isolated nodes have connectivity 0 - comp = set(component) - if len(comp) > 1: - k_components[1].append(comp) - bicomponents = [G.subgraph(c) for c in nx.biconnected_components(G)] - for bicomponent in bicomponents: - bicomp = set(bicomponent) - # avoid considering dyads as bicomponents - if len(bicomp) > 2: - k_components[2].append(bicomp) - for B in bicomponents: - if len(B) <= 2: - continue - k = nx.node_connectivity(B, flow_func=flow_func) - if k > 2: - k_components[k].append(set(B)) - # Perform cuts in a DFS like order. - cuts = list(nx.all_node_cuts(B, k=k, flow_func=flow_func)) - stack = [(k, _generate_partition(B, cuts, k))] - while stack: - (parent_k, partition) = stack[-1] - try: - nodes = next(partition) - C = B.subgraph(nodes) - this_k = nx.node_connectivity(C, flow_func=flow_func) - if this_k > parent_k and this_k > 2: - k_components[this_k].append(set(C)) - cuts = list(nx.all_node_cuts(C, k=this_k, flow_func=flow_func)) - if cuts: - stack.append((this_k, _generate_partition(C, cuts, this_k))) - except StopIteration: - stack.pop() - - # This is necessary because k-components may only be reported at their - # maximum k level. But we want to return a dictionary in which keys are - # connectivity levels and values list of sets of components, without - # skipping any connectivity level. Also, it's possible that subsets of - # an already detected k-component appear at a level k. Checking for this - # in the while loop above penalizes the common case. Thus we also have to - # _consolidate all connectivity levels in _reconstruct_k_components. - return _reconstruct_k_components(k_components) - - -def _consolidate(sets, k): - """Merge sets that share k or more elements. - - See: http://rosettacode.org/wiki/Set_consolidation - - The iterative python implementation posted there is - faster than this because of the overhead of building a - Graph and calling nx.connected_components, but it's not - clear for us if we can use it in NetworkX because there - is no licence for the code. - - """ - G = nx.Graph() - nodes = {i: s for i, s in enumerate(sets)} - G.add_nodes_from(nodes) - G.add_edges_from((u, v) for u, v in combinations(nodes, 2) - if len(nodes[u] & nodes[v]) >= k) - for component in nx.connected_components(G): - yield set.union(*[nodes[n] for n in component]) - - -def _generate_partition(G, cuts, k): - def has_nbrs_in_partition(G, node, partition): - for n in G[node]: - if n in partition: - return True - return False - components = [] - nodes = ({n for n, d in G.degree() if d > k} - - {n for cut in cuts for n in cut}) - H = G.subgraph(nodes) - for cc in nx.connected_components(H): - component = set(cc) - for cut in cuts: - for node in cut: - if has_nbrs_in_partition(G, node, cc): - component.add(node) - if len(component) < G.order(): - components.append(component) - for component in _consolidate(components, k + 1): - yield component - - -def _reconstruct_k_components(k_comps): - result = dict() - max_k = max(k_comps) - for k in reversed(range(1, max_k + 1)): - if k == max_k: - result[k] = list(_consolidate(k_comps[k], k)) - elif k not in k_comps: - result[k] = list(_consolidate(result[k + 1], k)) - else: - nodes_at_k = set.union(*k_comps[k]) - to_add = [c for c in result[k + 1] if any(n not in nodes_at_k for n in c)] - if to_add: - result[k] = list(_consolidate(k_comps[k] + to_add, k)) - else: - result[k] = list(_consolidate(k_comps[k], k)) - return result - - -def build_k_number_dict(kcomps): - result = {} - for k, comps in sorted(kcomps.items(), key=itemgetter(0)): - for comp in comps: - for node in comp: - result[node] = k - return result diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/kcutsets.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/kcutsets.py deleted file mode 100644 index d45f80cc..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/kcutsets.py +++ /dev/null @@ -1,239 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Kanevsky all minimum node k cutsets algorithm. -""" -import copy -from collections import defaultdict -from itertools import combinations -from operator import itemgetter - -import networkx as nx -from .utils import build_auxiliary_node_connectivity -from networkx.algorithms.flow import ( - build_residual_network, - edmonds_karp, - shortest_augmenting_path, -) -default_flow_func = edmonds_karp - - -__author__ = '\n'.join(['Jordi Torrents ']) - -__all__ = ['all_node_cuts'] - - -def all_node_cuts(G, k=None, flow_func=None): - r"""Returns all minimum k cutsets of an undirected graph G. - - This implementation is based on Kanevsky's algorithm [1]_ for finding all - minimum-size node cut-sets of an undirected graph G; ie the set (or sets) - of nodes of cardinality equal to the node connectivity of G. Thus if - removed, would break G into two or more connected components. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - k : Integer - Node connectivity of the input graph. If k is None, then it is - computed. Default value: None. - - flow_func : function - Function to perform the underlying flow computations. Default value - edmonds_karp. This function performs better in sparse graphs with - right tailed degree distributions. shortest_augmenting_path will - perform better in denser graphs. - - - Returns - ------- - cuts : a generator of node cutsets - Each node cutset has cardinality equal to the node connectivity of - the input graph. - - Examples - -------- - >>> # A two-dimensional grid graph has 4 cutsets of cardinality 2 - >>> G = nx.grid_2d_graph(5, 5) - >>> cutsets = list(nx.all_node_cuts(G)) - >>> len(cutsets) - 4 - >>> all(2 == len(cutset) for cutset in cutsets) - True - >>> nx.node_connectivity(G) - 2 - - Notes - ----- - This implementation is based on the sequential algorithm for finding all - minimum-size separating vertex sets in a graph [1]_. The main idea is to - compute minimum cuts using local maximum flow computations among a set - of nodes of highest degree and all other non-adjacent nodes in the Graph. - Once we find a minimum cut, we add an edge between the high degree - node and the target node of the local maximum flow computation to make - sure that we will not find that minimum cut again. - - See also - -------- - node_connectivity - edmonds_karp - shortest_augmenting_path - - References - ---------- - .. [1] Kanevsky, A. (1993). Finding all minimum-size separating vertex - sets in a graph. Networks 23(6), 533--541. - http://onlinelibrary.wiley.com/doi/10.1002/net.3230230604/abstract - - """ - if not nx.is_connected(G): - raise nx.NetworkXError('Input graph is disconnected.') - - # Address some corner cases first. - # For complete Graphs - if nx.density(G) == 1: - for cut_set in combinations(G, len(G) - 1): - yield set(cut_set) - return - # Initialize data structures. - # Keep track of the cuts already computed so we do not repeat them. - seen = [] - # Even-Tarjan reduction is what we call auxiliary digraph - # for node connectivity. - H = build_auxiliary_node_connectivity(G) - H_nodes = H.nodes # for speed - mapping = H.graph['mapping'] - # Keep a copy of original predecessors, H will be modified later. - # Shallow copy is enough. - original_H_pred = copy.copy(H._pred) - R = build_residual_network(H, 'capacity') - kwargs = dict(capacity='capacity', residual=R) - # Define default flow function - if flow_func is None: - flow_func = default_flow_func - if flow_func is shortest_augmenting_path: - kwargs['two_phase'] = True - # Begin the actual algorithm - # step 1: Find node connectivity k of G - if k is None: - k = nx.node_connectivity(G, flow_func=flow_func) - # step 2: - # Find k nodes with top degree, call it X: - X = {n for n, d in sorted(G.degree(), key=itemgetter(1), reverse=True)[:k]} - # Check if X is a k-node-cutset - if _is_separating_set(G, X): - seen.append(X) - yield X - - for x in X: - # step 3: Compute local connectivity flow of x with all other - # non adjacent nodes in G - non_adjacent = set(G) - X - set(G[x]) - for v in non_adjacent: - # step 4: compute maximum flow in an Even-Tarjan reduction H of G - # and step 5: build the associated residual network R - R = flow_func(H, '%sB' % mapping[x], '%sA' % mapping[v], **kwargs) - flow_value = R.graph['flow_value'] - - if flow_value == k: - # Find the nodes incident to the flow. - E1 = flowed_edges = [(u, w) for (u, w, d) in - R.edges(data=True) - if d['flow'] != 0] - VE1 = incident_nodes = set([n for edge in E1 for n in edge]) - # Remove saturated edges form the residual network. - # Note that reversed edges are introduced with capacity 0 - # in the residual graph and they need to be removed too. - saturated_edges = [(u, w, d) for (u, w, d) in - R.edges(data=True) - if d['capacity'] == d['flow'] - or d['capacity'] == 0] - R.remove_edges_from(saturated_edges) - R_closure = nx.transitive_closure(R) - # step 6: shrink the strongly connected components of - # residual flow network R and call it L. - L = nx.condensation(R) - cmap = L.graph['mapping'] - inv_cmap = defaultdict(list) - for n, scc in cmap.items(): - inv_cmap[scc].append(n) - # Find the incident nodes in the condensed graph. - VE1 = set([cmap[n] for n in VE1]) - # step 7: Compute all antichains of L; - # they map to closed sets in H. - # Any edge in H that links a closed set is part of a cutset. - for antichain in nx.antichains(L): - # Only antichains that are subsets of incident nodes counts. - # Lemma 8 in reference. - if not set(antichain).issubset(VE1): - continue - # Nodes in an antichain of the condensation graph of - # the residual network map to a closed set of nodes that - # define a node partition of the auxiliary digraph H - # through taking all of antichain's predecessors in the - # transitive closure. - S = set() - for scc in antichain: - S.update(inv_cmap[scc]) - S_ancestors = set() - for n in S: - S_ancestors.update(R_closure._pred[n]) - S.update(S_ancestors) - if '%sB' % mapping[x] not in S or '%sA' % mapping[v] in S: - continue - # Find the cutset that links the node partition (S,~S) in H - cutset = set() - for u in S: - cutset.update((u, w) - for w in original_H_pred[u] if w not in S) - # The edges in H that form the cutset are internal edges - # (ie edges that represent a node of the original graph G) - if any([H_nodes[u]['id'] != H_nodes[w]['id'] - for u, w in cutset]): - continue - node_cut = {H_nodes[u]['id'] for u, _ in cutset} - - if len(node_cut) == k: - # The cut is invalid if it includes internal edges of - # end nodes. The other half of Lemma 8 in ref. - if x in node_cut or v in node_cut: - continue - if node_cut not in seen: - yield node_cut - seen.append(node_cut) - - # Add an edge (x, v) to make sure that we do not - # find this cutset again. This is equivalent - # of adding the edge in the input graph - # G.add_edge(x, v) and then regenerate H and R: - # Add edges to the auxiliary digraph. - # See build_residual_network for convention we used - # in residual graphs. - H.add_edge('%sB' % mapping[x], '%sA' % mapping[v], - capacity=1) - H.add_edge('%sB' % mapping[v], '%sA' % mapping[x], - capacity=1) - # Add edges to the residual network. - R.add_edge('%sB' % mapping[x], '%sA' % mapping[v], - capacity=1) - R.add_edge('%sA' % mapping[v], '%sB' % mapping[x], - capacity=0) - R.add_edge('%sB' % mapping[v], '%sA' % mapping[x], - capacity=1) - R.add_edge('%sA' % mapping[x], '%sB' % mapping[v], - capacity=0) - - # Add again the saturated edges to reuse the residual network - R.add_edges_from(saturated_edges) - - -def _is_separating_set(G, cut): - """Assumes that the input graph is connected""" - if len(cut) == len(G) - 1: - return True - - H = nx.restricted_view(G, cut, []) - if nx.is_connected(H): - return False - return True diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/stoerwagner.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/stoerwagner.py deleted file mode 100644 index 2e70fb95..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/stoerwagner.py +++ /dev/null @@ -1,157 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2014 -# ysitu -# All rights reserved. -# BSD license. -""" -Stoer-Wagner minimum cut algorithm. -""" -from itertools import islice - -import networkx as nx -from ...utils import BinaryHeap -from ...utils import not_implemented_for -from ...utils import arbitrary_element - -__author__ = 'ysitu ' - -__all__ = ['stoer_wagner'] - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def stoer_wagner(G, weight='weight', heap=BinaryHeap): - r"""Returns the weighted minimum edge cut using the Stoer-Wagner algorithm. - - Determine the minimum edge cut of a connected graph using the - Stoer-Wagner algorithm. In weighted cases, all weights must be - nonnegative. - - The running time of the algorithm depends on the type of heaps used: - - ============== ============================================= - Type of heap Running time - ============== ============================================= - Binary heap $O(n (m + n) \log n)$ - Fibonacci heap $O(nm + n^2 \log n)$ - Pairing heap $O(2^{2 \sqrt{\log \log n}} nm + n^2 \log n)$ - ============== ============================================= - - Parameters - ---------- - G : NetworkX graph - Edges of the graph are expected to have an attribute named by the - weight parameter below. If this attribute is not present, the edge is - considered to have unit weight. - - weight : string - Name of the weight attribute of the edges. If the attribute is not - present, unit weight is assumed. Default value: 'weight'. - - heap : class - Type of heap to be used in the algorithm. It should be a subclass of - :class:`MinHeap` or implement a compatible interface. - - If a stock heap implementation is to be used, :class:`BinaryHeap` is - recommended over :class:`PairingHeap` for Python implementations without - optimized attribute accesses (e.g., CPython) despite a slower - asymptotic running time. For Python implementations with optimized - attribute accesses (e.g., PyPy), :class:`PairingHeap` provides better - performance. Default value: :class:`BinaryHeap`. - - Returns - ------- - cut_value : integer or float - The sum of weights of edges in a minimum cut. - - partition : pair of node lists - A partitioning of the nodes that defines a minimum cut. - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or a multigraph. - - NetworkXError - If the graph has less than two nodes, is not connected or has a - negative-weighted edge. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_edge('x', 'a', weight=3) - >>> G.add_edge('x', 'b', weight=1) - >>> G.add_edge('a', 'c', weight=3) - >>> G.add_edge('b', 'c', weight=5) - >>> G.add_edge('b', 'd', weight=4) - >>> G.add_edge('d', 'e', weight=2) - >>> G.add_edge('c', 'y', weight=2) - >>> G.add_edge('e', 'y', weight=3) - >>> cut_value, partition = nx.stoer_wagner(G) - >>> cut_value - 4 - """ - n = len(G) - if n < 2: - raise nx.NetworkXError('graph has less than two nodes.') - if not nx.is_connected(G): - raise nx.NetworkXError('graph is not connected.') - - # Make a copy of the graph for internal use. - G = nx.Graph((u, v, {'weight': e.get(weight, 1)}) - for u, v, e in G.edges(data=True) if u != v) - - for u, v, e, in G.edges(data=True): - if e['weight'] < 0: - raise nx.NetworkXError('graph has a negative-weighted edge.') - - cut_value = float('inf') - nodes = set(G) - contractions = [] # contracted node pairs - - # Repeatedly pick a pair of nodes to contract until only one node is left. - for i in range(n - 1): - # Pick an arbitrary node u and create a set A = {u}. - u = arbitrary_element(G) - A = set([u]) - # Repeatedly pick the node "most tightly connected" to A and add it to - # A. The tightness of connectivity of a node not in A is defined by the - # of edges connecting it to nodes in A. - h = heap() # min-heap emulating a max-heap - for v, e in G[u].items(): - h.insert(v, -e['weight']) - # Repeat until all but one node has been added to A. - for j in range(n - i - 2): - u = h.pop()[0] - A.add(u) - for v, e, in G[u].items(): - if v not in A: - h.insert(v, h.get(v, 0) - e['weight']) - # A and the remaining node v define a "cut of the phase". There is a - # minimum cut of the original graph that is also a cut of the phase. - # Due to contractions in earlier phases, v may in fact represent - # multiple nodes in the original graph. - v, w = h.min() - w = -w - if w < cut_value: - cut_value = w - best_phase = i - # Contract v and the last node added to A. - contractions.append((u, v)) - for w, e in G[v].items(): - if w != u: - if w not in G[u]: - G.add_edge(u, w, weight=e['weight']) - else: - G[u][w]['weight'] += e['weight'] - G.remove_node(v) - - # Recover the optimal partitioning from the contractions. - G = nx.Graph(islice(contractions, best_phase)) - v = contractions[best_phase][1] - G.add_node(v) - reachable = set(nx.single_source_shortest_path_length(G, v)) - partition = (list(reachable), list(nodes - reachable)) - - return cut_value, partition diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_connectivity.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_connectivity.py deleted file mode 100644 index ed2a3ab9..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_connectivity.py +++ /dev/null @@ -1,368 +0,0 @@ -import itertools -import pytest - -import networkx as nx -from networkx.algorithms import flow -from networkx.algorithms.connectivity import local_edge_connectivity -from networkx.algorithms.connectivity import local_node_connectivity - -flow_funcs = [ - flow.boykov_kolmogorov, - flow.dinitz, - flow.edmonds_karp, - flow.preflow_push, - flow.shortest_augmenting_path, -] - - -msg = "Assertion failed in function: {0}" - -# helper functions for tests - - -def _generate_no_biconnected(max_attempts=50): - attempts = 0 - while True: - G = nx.fast_gnp_random_graph(100, 0.0575, seed=42) - if nx.is_connected(G) and not nx.is_biconnected(G): - attempts = 0 - yield G - else: - if attempts >= max_attempts: - msg = "Tried %d times: no suitable Graph." - raise Exception(msg % max_attempts) - else: - attempts += 1 - - -def test_average_connectivity(): - # figure 1 from: - # Beineke, L., O. Oellermann, and R. Pippert (2002). The average - # connectivity of a graph. Discrete mathematics 252(1-3), 31-45 - # http://www.sciencedirect.com/science/article/pii/S0012365X01001807 - G1 = nx.path_graph(3) - G1.add_edges_from([(1, 3), (1, 4)]) - G2 = nx.path_graph(3) - G2.add_edges_from([(1, 3), (1, 4), (0, 3), (0, 4), (3, 4)]) - G3 = nx.Graph() - for flow_func in flow_funcs: - kwargs = dict(flow_func=flow_func) - assert nx.average_node_connectivity(G1, **kwargs) == 1, msg.format(flow_func.__name__) - assert nx.average_node_connectivity(G2, **kwargs) == 2.2, msg.format(flow_func.__name__) - assert nx.average_node_connectivity(G3, **kwargs) == 0, msg.format(flow_func.__name__) - - -def test_average_connectivity_directed(): - G = nx.DiGraph([(1, 3), (1, 4), (1, 5)]) - for flow_func in flow_funcs: - assert nx.average_node_connectivity(G) == 0.25, msg.format(flow_func.__name__) - - -def test_articulation_points(): - Ggen = _generate_no_biconnected() - for flow_func in flow_funcs: - for i in range(3): - G = next(Ggen) - assert nx.node_connectivity(G, flow_func=flow_func) == 1, msg.format(flow_func.__name__) - - -def test_brandes_erlebach(): - # Figure 1 chapter 7: Connectivity - # http://www.informatik.uni-augsburg.de/thi/personen/kammer/Graph_Connectivity.pdf - G = nx.Graph() - G.add_edges_from([(1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 6), (3, 4), - (3, 6), (4, 6), (4, 7), (5, 7), (6, 8), (6, 9), (7, 8), - (7, 10), (8, 11), (9, 10), (9, 11), (10, 11)]) - for flow_func in flow_funcs: - kwargs = dict(flow_func=flow_func) - assert 3 == local_edge_connectivity(G, 1, 11, **kwargs), msg.format(flow_func.__name__) - assert 3 == nx.edge_connectivity(G, 1, 11, **kwargs), msg.format(flow_func.__name__) - assert 2 == local_node_connectivity(G, 1, 11, **kwargs), msg.format(flow_func.__name__) - assert 2 == nx.node_connectivity(G, 1, 11, **kwargs), msg.format(flow_func.__name__) - assert 2 == nx.edge_connectivity(G, **kwargs), msg.format(flow_func.__name__) - assert 2 == nx.node_connectivity(G, **kwargs), msg.format(flow_func.__name__) - - -def test_white_harary_1(): - # Figure 1b white and harary (2001) - # # http://eclectic.ss.uci.edu/~drwhite/sm-w23.PDF - # A graph with high adhesion (edge connectivity) and low cohesion - # (vertex connectivity) - G = nx.disjoint_union(nx.complete_graph(4), nx.complete_graph(4)) - G.remove_node(7) - for i in range(4, 7): - G.add_edge(0, i) - G = nx.disjoint_union(G, nx.complete_graph(4)) - G.remove_node(G.order() - 1) - for i in range(7, 10): - G.add_edge(0, i) - for flow_func in flow_funcs: - assert 1 == nx.node_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - assert 3 == nx.edge_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - - -def test_white_harary_2(): - # Figure 8 white and harary (2001) - # # http://eclectic.ss.uci.edu/~drwhite/sm-w23.PDF - G = nx.disjoint_union(nx.complete_graph(4), nx.complete_graph(4)) - G.add_edge(0, 4) - # kappa <= lambda <= delta - assert 3 == min(nx.core_number(G).values()) - for flow_func in flow_funcs: - assert 1 == nx.node_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - assert 1 == nx.edge_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - - -def test_complete_graphs(): - for n in range(5, 20, 5): - for flow_func in flow_funcs: - G = nx.complete_graph(n) - assert n - 1 == nx.node_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - assert n - 1 == nx.node_connectivity(G.to_directed(), - flow_func=flow_func), msg.format(flow_func.__name__) - assert n - 1 == nx.edge_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - assert n - 1 == nx.edge_connectivity(G.to_directed(), - flow_func=flow_func), msg.format(flow_func.__name__) - - -def test_empty_graphs(): - for k in range(5, 25, 5): - G = nx.empty_graph(k) - for flow_func in flow_funcs: - assert 0 == nx.node_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - assert 0 == nx.edge_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - - -def test_petersen(): - G = nx.petersen_graph() - for flow_func in flow_funcs: - assert 3 == nx.node_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - assert 3 == nx.edge_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - - -def test_tutte(): - G = nx.tutte_graph() - for flow_func in flow_funcs: - assert 3 == nx.node_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - assert 3 == nx.edge_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - - -def test_dodecahedral(): - G = nx.dodecahedral_graph() - for flow_func in flow_funcs: - assert 3 == nx.node_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - assert 3 == nx.edge_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - - -def test_octahedral(): - G = nx.octahedral_graph() - for flow_func in flow_funcs: - assert 4 == nx.node_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - assert 4 == nx.edge_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - - -def test_icosahedral(): - G = nx.icosahedral_graph() - for flow_func in flow_funcs: - assert 5 == nx.node_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - assert 5 == nx.edge_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - - -def test_missing_source(): - G = nx.path_graph(4) - for flow_func in flow_funcs: - pytest.raises(nx.NetworkXError, nx.node_connectivity, G, 10, 1, - flow_func=flow_func) - - -def test_missing_target(): - G = nx.path_graph(4) - for flow_func in flow_funcs: - pytest.raises(nx.NetworkXError, nx.node_connectivity, G, 1, 10, - flow_func=flow_func) - - -def test_edge_missing_source(): - G = nx.path_graph(4) - for flow_func in flow_funcs: - pytest.raises(nx.NetworkXError, nx.edge_connectivity, G, 10, 1, - flow_func=flow_func) - - -def test_edge_missing_target(): - G = nx.path_graph(4) - for flow_func in flow_funcs: - pytest.raises(nx.NetworkXError, nx.edge_connectivity, G, 1, 10, - flow_func=flow_func) - - -def test_not_weakly_connected(): - G = nx.DiGraph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5]) - for flow_func in flow_funcs: - assert nx.node_connectivity(G) == 0, msg.format(flow_func.__name__) - assert nx.edge_connectivity(G) == 0, msg.format(flow_func.__name__) - - -def test_not_connected(): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5]) - for flow_func in flow_funcs: - assert nx.node_connectivity(G) == 0, msg.format(flow_func.__name__) - assert nx.edge_connectivity(G) == 0, msg.format(flow_func.__name__) - - -def test_directed_edge_connectivity(): - G = nx.cycle_graph(10, create_using=nx.DiGraph()) # only one direction - D = nx.cycle_graph(10).to_directed() # 2 reciprocal edges - for flow_func in flow_funcs: - assert 1 == nx.edge_connectivity(G, flow_func=flow_func), msg.format(flow_func.__name__) - assert 1 == local_edge_connectivity(G, 1, 4, flow_func=flow_func), msg.format(flow_func.__name__) - assert 1 == nx.edge_connectivity(G, 1, 4, flow_func=flow_func), msg.format(flow_func.__name__) - assert 2 == nx.edge_connectivity(D, flow_func=flow_func), msg.format(flow_func.__name__) - assert 2 == local_edge_connectivity(D, 1, 4, flow_func=flow_func), msg.format(flow_func.__name__) - assert 2 == nx.edge_connectivity(D, 1, 4, flow_func=flow_func), msg.format(flow_func.__name__) - - -def test_cutoff(): - G = nx.complete_graph(5) - for local_func in [local_edge_connectivity, local_node_connectivity]: - for flow_func in flow_funcs: - if flow_func is flow.preflow_push: - # cutoff is not supported by preflow_push - continue - for cutoff in [3, 2, 1]: - result = local_func(G, 0, 4, flow_func=flow_func, cutoff=cutoff) - assert cutoff == result, "cutoff error in {0}".format(flow_func.__name__) - - -def test_invalid_auxiliary(): - G = nx.complete_graph(5) - pytest.raises(nx.NetworkXError, local_node_connectivity, G, 0, 3, - auxiliary=G) - - -def test_interface_only_source(): - G = nx.complete_graph(5) - for interface_func in [nx.node_connectivity, nx.edge_connectivity]: - pytest.raises(nx.NetworkXError, interface_func, G, s=0) - - -def test_interface_only_target(): - G = nx.complete_graph(5) - for interface_func in [nx.node_connectivity, nx.edge_connectivity]: - pytest.raises(nx.NetworkXError, interface_func, G, t=3) - - -def test_edge_connectivity_flow_vs_stoer_wagner(): - graph_funcs = [ - nx.icosahedral_graph, - nx.octahedral_graph, - nx.dodecahedral_graph, - ] - for graph_func in graph_funcs: - G = graph_func() - assert nx.stoer_wagner(G)[0] == nx.edge_connectivity(G) - - -class TestAllPairsNodeConnectivity: - - @classmethod - def setup_class(cls): - cls.path = nx.path_graph(7) - cls.directed_path = nx.path_graph(7, create_using=nx.DiGraph()) - cls.cycle = nx.cycle_graph(7) - cls.directed_cycle = nx.cycle_graph(7, create_using=nx.DiGraph()) - cls.gnp = nx.gnp_random_graph(30, 0.1, seed=42) - cls.directed_gnp = nx.gnp_random_graph(30, 0.1, directed=True, seed=42) - cls.K20 = nx.complete_graph(20) - cls.K10 = nx.complete_graph(10) - cls.K5 = nx.complete_graph(5) - cls.G_list = [cls.path, cls.directed_path, cls.cycle, - cls.directed_cycle, cls.gnp, cls.directed_gnp, - cls.K10, cls.K5, cls.K20] - - def test_cycles(self): - K_undir = nx.all_pairs_node_connectivity(self.cycle) - for source in K_undir: - for target, k in K_undir[source].items(): - assert k == 2 - K_dir = nx.all_pairs_node_connectivity(self.directed_cycle) - for source in K_dir: - for target, k in K_dir[source].items(): - assert k == 1 - - def test_complete(self): - for G in [self.K10, self.K5, self.K20]: - K = nx.all_pairs_node_connectivity(G) - for source in K: - for target, k in K[source].items(): - assert k == len(G) - 1 - - def test_paths(self): - K_undir = nx.all_pairs_node_connectivity(self.path) - for source in K_undir: - for target, k in K_undir[source].items(): - assert k == 1 - K_dir = nx.all_pairs_node_connectivity(self.directed_path) - for source in K_dir: - for target, k in K_dir[source].items(): - if source < target: - assert k == 1 - else: - assert k == 0 - - def test_all_pairs_connectivity_nbunch(self): - G = nx.complete_graph(5) - nbunch = [0, 2, 3] - C = nx.all_pairs_node_connectivity(G, nbunch=nbunch) - assert len(C) == len(nbunch) - - def test_all_pairs_connectivity_icosahedral(self): - G = nx.icosahedral_graph() - C = nx.all_pairs_node_connectivity(G) - assert all(5 == C[u][v] for u, v in itertools.combinations(G, 2)) - - def test_all_pairs_connectivity(self): - G = nx.Graph() - nodes = [0, 1, 2, 3] - nx.add_path(G, nodes) - A = {n: {} for n in G} - for u, v in itertools.combinations(nodes, 2): - A[u][v] = A[v][u] = nx.node_connectivity(G, u, v) - C = nx.all_pairs_node_connectivity(G) - assert (sorted((k, sorted(v)) for k, v in A.items()) == - sorted((k, sorted(v)) for k, v in C.items())) - - def test_all_pairs_connectivity_directed(self): - G = nx.DiGraph() - nodes = [0, 1, 2, 3] - nx.add_path(G, nodes) - A = {n: {} for n in G} - for u, v in itertools.permutations(nodes, 2): - A[u][v] = nx.node_connectivity(G, u, v) - C = nx.all_pairs_node_connectivity(G) - assert (sorted((k, sorted(v)) for k, v in A.items()) == - sorted((k, sorted(v)) for k, v in C.items())) - - def test_all_pairs_connectivity_nbunch_combinations(self): - G = nx.complete_graph(5) - nbunch = [0, 2, 3] - A = {n: {} for n in nbunch} - for u, v in itertools.combinations(nbunch, 2): - A[u][v] = A[v][u] = nx.node_connectivity(G, u, v) - C = nx.all_pairs_node_connectivity(G, nbunch=nbunch) - assert (sorted((k, sorted(v)) for k, v in A.items()) == - sorted((k, sorted(v)) for k, v in C.items())) - - def test_all_pairs_connectivity_nbunch_iter(self): - G = nx.complete_graph(5) - nbunch = [0, 2, 3] - A = {n: {} for n in nbunch} - for u, v in itertools.combinations(nbunch, 2): - A[u][v] = A[v][u] = nx.node_connectivity(G, u, v) - C = nx.all_pairs_node_connectivity(G, nbunch=iter(nbunch)) - assert (sorted((k, sorted(v)) for k, v in A.items()) == - sorted((k, sorted(v)) for k, v in C.items())) diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_cuts.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_cuts.py deleted file mode 100644 index ea5dbbb5..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_cuts.py +++ /dev/null @@ -1,283 +0,0 @@ -import pytest - -import networkx as nx -from networkx.algorithms import flow -from networkx.algorithms.connectivity import minimum_st_edge_cut -from networkx.algorithms.connectivity import minimum_st_node_cut -from networkx.utils import arbitrary_element - -flow_funcs = [ - flow.boykov_kolmogorov, - flow.dinitz, - flow.edmonds_karp, - flow.preflow_push, - flow.shortest_augmenting_path, -] - -msg = "Assertion failed in function: {0}" - -# Tests for node and edge cutsets - - -def _generate_no_biconnected(max_attempts=50): - attempts = 0 - while True: - G = nx.fast_gnp_random_graph(100, 0.0575, seed=42) - if nx.is_connected(G) and not nx.is_biconnected(G): - attempts = 0 - yield G - else: - if attempts >= max_attempts: - msg = "Tried %d times: no suitable Graph." % attempts - raise Exception(msg % max_attempts) - else: - attempts += 1 - - -def test_articulation_points(): - Ggen = _generate_no_biconnected() - for flow_func in flow_funcs: - for i in range(1): # change 1 to 3 or more for more realizations. - G = next(Ggen) - cut = nx.minimum_node_cut(G, flow_func=flow_func) - assert len(cut) == 1, msg.format(flow_func.__name__) - assert cut.pop() in set(nx.articulation_points(G)), msg.format(flow_func.__name__) - - -def test_brandes_erlebach_book(): - # Figure 1 chapter 7: Connectivity - # http://www.informatik.uni-augsburg.de/thi/personen/kammer/Graph_Connectivity.pdf - G = nx.Graph() - G.add_edges_from([(1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 6), (3, 4), - (3, 6), (4, 6), (4, 7), (5, 7), (6, 8), (6, 9), (7, 8), - (7, 10), (8, 11), (9, 10), (9, 11), (10, 11)]) - for flow_func in flow_funcs: - kwargs = dict(flow_func=flow_func) - # edge cutsets - assert 3 == len(nx.minimum_edge_cut(G, 1, 11, **kwargs)), msg.format(flow_func.__name__) - edge_cut = nx.minimum_edge_cut(G, **kwargs) - # Node 5 has only two edges - assert 2 == len(edge_cut), msg.format(flow_func.__name__) - H = G.copy() - H.remove_edges_from(edge_cut) - assert not nx.is_connected(H), msg.format(flow_func.__name__) - # node cuts - assert set([6, 7]) == minimum_st_node_cut(G, 1, 11, **kwargs), msg.format(flow_func.__name__) - assert set([6, 7]) == nx.minimum_node_cut(G, 1, 11, **kwargs), msg.format(flow_func.__name__) - node_cut = nx.minimum_node_cut(G, **kwargs) - assert 2 == len(node_cut), msg.format(flow_func.__name__) - H = G.copy() - H.remove_nodes_from(node_cut) - assert not nx.is_connected(H), msg.format(flow_func.__name__) - - -def test_white_harary_paper(): - # Figure 1b white and harary (2001) - # http://eclectic.ss.uci.edu/~drwhite/sm-w23.PDF - # A graph with high adhesion (edge connectivity) and low cohesion - # (node connectivity) - G = nx.disjoint_union(nx.complete_graph(4), nx.complete_graph(4)) - G.remove_node(7) - for i in range(4, 7): - G.add_edge(0, i) - G = nx.disjoint_union(G, nx.complete_graph(4)) - G.remove_node(G.order() - 1) - for i in range(7, 10): - G.add_edge(0, i) - for flow_func in flow_funcs: - kwargs = dict(flow_func=flow_func) - # edge cuts - edge_cut = nx.minimum_edge_cut(G, **kwargs) - assert 3 == len(edge_cut), msg.format(flow_func.__name__) - H = G.copy() - H.remove_edges_from(edge_cut) - assert not nx.is_connected(H), msg.format(flow_func.__name__) - # node cuts - node_cut = nx.minimum_node_cut(G, **kwargs) - assert set([0]) == node_cut, msg.format(flow_func.__name__) - H = G.copy() - H.remove_nodes_from(node_cut) - assert not nx.is_connected(H), msg.format(flow_func.__name__) - - -def test_petersen_cutset(): - G = nx.petersen_graph() - for flow_func in flow_funcs: - kwargs = dict(flow_func=flow_func) - # edge cuts - edge_cut = nx.minimum_edge_cut(G, **kwargs) - assert 3 == len(edge_cut), msg.format(flow_func.__name__) - H = G.copy() - H.remove_edges_from(edge_cut) - assert not nx.is_connected(H), msg.format(flow_func.__name__) - # node cuts - node_cut = nx.minimum_node_cut(G, **kwargs) - assert 3 == len(node_cut), msg.format(flow_func.__name__) - H = G.copy() - H.remove_nodes_from(node_cut) - assert not nx.is_connected(H), msg.format(flow_func.__name__) - - -def test_octahedral_cutset(): - G = nx.octahedral_graph() - for flow_func in flow_funcs: - kwargs = dict(flow_func=flow_func) - # edge cuts - edge_cut = nx.minimum_edge_cut(G, **kwargs) - assert 4 == len(edge_cut), msg.format(flow_func.__name__) - H = G.copy() - H.remove_edges_from(edge_cut) - assert not nx.is_connected(H), msg.format(flow_func.__name__) - # node cuts - node_cut = nx.minimum_node_cut(G, **kwargs) - assert 4 == len(node_cut), msg.format(flow_func.__name__) - H = G.copy() - H.remove_nodes_from(node_cut) - assert not nx.is_connected(H), msg.format(flow_func.__name__) - - -def test_icosahedral_cutset(): - G = nx.icosahedral_graph() - for flow_func in flow_funcs: - kwargs = dict(flow_func=flow_func) - # edge cuts - edge_cut = nx.minimum_edge_cut(G, **kwargs) - assert 5 == len(edge_cut), msg.format(flow_func.__name__) - H = G.copy() - H.remove_edges_from(edge_cut) - assert not nx.is_connected(H), msg.format(flow_func.__name__) - # node cuts - node_cut = nx.minimum_node_cut(G, **kwargs) - assert 5 == len(node_cut), msg.format(flow_func.__name__) - H = G.copy() - H.remove_nodes_from(node_cut) - assert not nx.is_connected(H), msg.format(flow_func.__name__) - - -def test_node_cutset_exception(): - G = nx.Graph() - G.add_edges_from([(1, 2), (3, 4)]) - for flow_func in flow_funcs: - pytest.raises(nx.NetworkXError, nx.minimum_node_cut, G, flow_func=flow_func) - - -def test_node_cutset_random_graphs(): - for flow_func in flow_funcs: - for i in range(3): - G = nx.fast_gnp_random_graph(50, 0.25, seed=42) - if not nx.is_connected(G): - ccs = iter(nx.connected_components(G)) - start = arbitrary_element(next(ccs)) - G.add_edges_from((start, arbitrary_element(c)) for c in ccs) - cutset = nx.minimum_node_cut(G, flow_func=flow_func) - assert nx.node_connectivity(G) == len(cutset), msg.format(flow_func.__name__) - G.remove_nodes_from(cutset) - assert not nx.is_connected(G), msg.format(flow_func.__name__) - - -def test_edge_cutset_random_graphs(): - for flow_func in flow_funcs: - for i in range(3): - G = nx.fast_gnp_random_graph(50, 0.25, seed=42) - if not nx.is_connected(G): - ccs = iter(nx.connected_components(G)) - start = arbitrary_element(next(ccs)) - G.add_edges_from((start, arbitrary_element(c)) for c in ccs) - cutset = nx.minimum_edge_cut(G, flow_func=flow_func) - assert nx.edge_connectivity(G) == len(cutset), msg.format(flow_func.__name__) - G.remove_edges_from(cutset) - assert not nx.is_connected(G), msg.format(flow_func.__name__) - - -def test_empty_graphs(): - G = nx.Graph() - D = nx.DiGraph() - for interface_func in [nx.minimum_node_cut, nx.minimum_edge_cut]: - for flow_func in flow_funcs: - pytest.raises(nx.NetworkXPointlessConcept, interface_func, G, - flow_func=flow_func) - pytest.raises(nx.NetworkXPointlessConcept, interface_func, D, - flow_func=flow_func) - - -def test_unbounded(): - G = nx.complete_graph(5) - for flow_func in flow_funcs: - assert 4 == len(minimum_st_edge_cut(G, 1, 4, flow_func=flow_func)) - - -def test_missing_source(): - G = nx.path_graph(4) - for interface_func in [nx.minimum_edge_cut, nx.minimum_node_cut]: - for flow_func in flow_funcs: - pytest.raises(nx.NetworkXError, interface_func, G, 10, 1, - flow_func=flow_func) - - -def test_missing_target(): - G = nx.path_graph(4) - for interface_func in [nx.minimum_edge_cut, nx.minimum_node_cut]: - for flow_func in flow_funcs: - pytest.raises(nx.NetworkXError, interface_func, G, 1, 10, - flow_func=flow_func) - - -def test_not_weakly_connected(): - G = nx.DiGraph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5]) - for interface_func in [nx.minimum_edge_cut, nx.minimum_node_cut]: - for flow_func in flow_funcs: - pytest.raises(nx.NetworkXError, interface_func, G, - flow_func=flow_func) - - -def test_not_connected(): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5]) - for interface_func in [nx.minimum_edge_cut, nx.minimum_node_cut]: - for flow_func in flow_funcs: - pytest.raises(nx.NetworkXError, interface_func, G, - flow_func=flow_func) - - -def tests_min_cut_complete(): - G = nx.complete_graph(5) - for interface_func in [nx.minimum_edge_cut, nx.minimum_node_cut]: - for flow_func in flow_funcs: - assert 4 == len(interface_func(G, flow_func=flow_func)) - - -def tests_min_cut_complete_directed(): - G = nx.complete_graph(5) - G = G.to_directed() - for interface_func in [nx.minimum_edge_cut, nx.minimum_node_cut]: - for flow_func in flow_funcs: - assert 4 == len(interface_func(G, flow_func=flow_func)) - - -def tests_minimum_st_node_cut(): - G = nx.Graph() - G.add_nodes_from([0, 1, 2, 3, 7, 8, 11, 12]) - G.add_edges_from([(7, 11), (1, 11), (1, 12), (12, 8), (0, 1)]) - nodelist = minimum_st_node_cut(G, 7, 11) - assert(nodelist == []) - - -def test_invalid_auxiliary(): - G = nx.complete_graph(5) - pytest.raises(nx.NetworkXError, minimum_st_node_cut, G, 0, 3, - auxiliary=G) - - -def test_interface_only_source(): - G = nx.complete_graph(5) - for interface_func in [nx.minimum_node_cut, nx.minimum_edge_cut]: - pytest.raises(nx.NetworkXError, interface_func, G, s=0) - - -def test_interface_only_target(): - G = nx.complete_graph(5) - for interface_func in [nx.minimum_node_cut, nx.minimum_edge_cut]: - pytest.raises(nx.NetworkXError, interface_func, G, t=3) diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_disjoint_paths.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_disjoint_paths.py deleted file mode 100644 index deebfe6f..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_disjoint_paths.py +++ /dev/null @@ -1,237 +0,0 @@ -# test_disjoint_paths.py - Tests for flow based node and edge disjoint paths. -# -# Copyright 2016 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -import pytest - -import networkx as nx -from networkx.algorithms import flow -from networkx.utils import pairwise - -flow_funcs = [ - flow.boykov_kolmogorov, - flow.edmonds_karp, - flow.dinitz, - flow.preflow_push, - flow.shortest_augmenting_path, -] - -msg = "Assertion failed in function: {0}" - - -def is_path(G, path): - return all(v in G[u] for u, v in pairwise(path)) - - -def are_edge_disjoint_paths(G, paths): - if not paths: - return False - for path in paths: - assert is_path(G, path) - paths_edges = [list(pairwise(p)) for p in paths] - num_of_edges = sum(len(e) for e in paths_edges) - num_unique_edges = len(set.union(*[set(es) for es in paths_edges])) - if num_of_edges == num_unique_edges: - return True - return False - - -def are_node_disjoint_paths(G, paths): - if not paths: - return False - for path in paths: - assert is_path(G, path) - # first and last nodes are source and target - st = {paths[0][0], paths[0][-1]} - num_of_nodes = len([n for path in paths for n in path if n not in st]) - num_unique_nodes = len({n for path in paths for n in path if n not in st}) - if num_of_nodes == num_unique_nodes: - return True - return False - - -def test_graph_from_pr_2053(): - G = nx.Graph() - G.add_edges_from([ - ('A', 'B'), ('A', 'D'), ('A', 'F'), ('A', 'G'), - ('B', 'C'), ('B', 'D'), ('B', 'G'), ('C', 'D'), - ('C', 'E'), ('C', 'Z'), ('D', 'E'), ('D', 'F'), - ('E', 'F'), ('E', 'Z'), ('F', 'Z'), ('G', 'Z')]) - for flow_func in flow_funcs: - kwargs = dict(flow_func=flow_func) - # edge disjoint paths - edge_paths = list(nx.edge_disjoint_paths(G, 'A', 'Z', **kwargs)) - assert are_edge_disjoint_paths(G, edge_paths), msg.format(flow_func.__name__) - assert nx.edge_connectivity(G, 'A', 'Z') == len(edge_paths), msg.format(flow_func.__name__) - # node disjoint paths - node_paths = list(nx.node_disjoint_paths(G, 'A', 'Z', **kwargs)) - assert are_node_disjoint_paths(G, node_paths), msg.format(flow_func.__name__) - assert nx.node_connectivity(G, 'A', 'Z') == len(node_paths), msg.format(flow_func.__name__) - - -def test_florentine_families(): - G = nx.florentine_families_graph() - for flow_func in flow_funcs: - kwargs = dict(flow_func=flow_func) - # edge disjoint paths - edge_dpaths = list(nx.edge_disjoint_paths(G, 'Medici', 'Strozzi', **kwargs)) - assert are_edge_disjoint_paths(G, edge_dpaths), msg.format(flow_func.__name__) - assert nx.edge_connectivity(G, 'Medici', 'Strozzi') == len(edge_dpaths), msg.format(flow_func.__name__) - # node disjoint paths - node_dpaths = list(nx.node_disjoint_paths(G, 'Medici', 'Strozzi', **kwargs)) - assert are_node_disjoint_paths(G, node_dpaths), msg.format(flow_func.__name__) - assert nx.node_connectivity(G, 'Medici', 'Strozzi') == len(node_dpaths), msg.format(flow_func.__name__) - - -def test_karate(): - G = nx.karate_club_graph() - for flow_func in flow_funcs: - kwargs = dict(flow_func=flow_func) - # edge disjoint paths - edge_dpaths = list(nx.edge_disjoint_paths(G, 0, 33, **kwargs)) - assert are_edge_disjoint_paths(G, edge_dpaths), msg.format(flow_func.__name__) - assert nx.edge_connectivity(G, 0, 33) == len(edge_dpaths), msg.format(flow_func.__name__) - # node disjoint paths - node_dpaths = list(nx.node_disjoint_paths(G, 0, 33, **kwargs)) - assert are_node_disjoint_paths(G, node_dpaths), msg.format(flow_func.__name__) - assert nx.node_connectivity(G, 0, 33) == len(node_dpaths), msg.format(flow_func.__name__) - - -def test_petersen_disjoint_paths(): - G = nx.petersen_graph() - for flow_func in flow_funcs: - kwargs = dict(flow_func=flow_func) - # edge disjoint paths - edge_dpaths = list(nx.edge_disjoint_paths(G, 0, 6, **kwargs)) - assert are_edge_disjoint_paths(G, edge_dpaths), msg.format(flow_func.__name__) - assert 3 == len(edge_dpaths), msg.format(flow_func.__name__) - # node disjoint paths - node_dpaths = list(nx.node_disjoint_paths(G, 0, 6, **kwargs)) - assert are_node_disjoint_paths(G, node_dpaths), msg.format(flow_func.__name__) - assert 3 == len(node_dpaths), msg.format(flow_func.__name__) - - -def test_octahedral_disjoint_paths(): - G = nx.octahedral_graph() - for flow_func in flow_funcs: - kwargs = dict(flow_func=flow_func) - # edge disjoint paths - edge_dpaths = list(nx.edge_disjoint_paths(G, 0, 5, **kwargs)) - assert are_edge_disjoint_paths(G, edge_dpaths), msg.format(flow_func.__name__) - assert 4 == len(edge_dpaths), msg.format(flow_func.__name__) - # node disjoint paths - node_dpaths = list(nx.node_disjoint_paths(G, 0, 5, **kwargs)) - assert are_node_disjoint_paths(G, node_dpaths), msg.format(flow_func.__name__) - assert 4 == len(node_dpaths), msg.format(flow_func.__name__) - - -def test_icosahedral_disjoint_paths(): - G = nx.icosahedral_graph() - for flow_func in flow_funcs: - kwargs = dict(flow_func=flow_func) - # edge disjoint paths - edge_dpaths = list(nx.edge_disjoint_paths(G, 0, 6, **kwargs)) - assert are_edge_disjoint_paths(G, edge_dpaths), msg.format(flow_func.__name__) - assert 5 == len(edge_dpaths), msg.format(flow_func.__name__) - # node disjoint paths - node_dpaths = list(nx.node_disjoint_paths(G, 0, 6, **kwargs)) - assert are_node_disjoint_paths(G, node_dpaths), msg.format(flow_func.__name__) - assert 5 == len(node_dpaths), msg.format(flow_func.__name__) - - -def test_cutoff_disjoint_paths(): - G = nx.icosahedral_graph() - for flow_func in flow_funcs: - kwargs = dict(flow_func=flow_func) - for cutoff in [2, 4]: - kwargs['cutoff'] = cutoff - # edge disjoint paths - edge_dpaths = list(nx.edge_disjoint_paths(G, 0, 6, **kwargs)) - assert are_edge_disjoint_paths(G, edge_dpaths), msg.format(flow_func.__name__) - assert cutoff == len(edge_dpaths), msg.format(flow_func.__name__) - # node disjoint paths - node_dpaths = list(nx.node_disjoint_paths(G, 0, 6, **kwargs)) - assert are_node_disjoint_paths(G, node_dpaths), msg.format(flow_func.__name__) - assert cutoff == len(node_dpaths), msg.format(flow_func.__name__) - - -def test_missing_source_edge_paths(): - with pytest.raises(nx.NetworkXError): - G = nx.path_graph(4) - list(nx.edge_disjoint_paths(G, 10, 1)) - - -def test_missing_source_node_paths(): - with pytest.raises(nx.NetworkXError): - G = nx.path_graph(4) - list(nx.node_disjoint_paths(G, 10, 1)) - - -def test_missing_target_edge_paths(): - with pytest.raises(nx.NetworkXError): - G = nx.path_graph(4) - list(nx.edge_disjoint_paths(G, 1, 10)) - - -def test_missing_target_node_paths(): - with pytest.raises(nx.NetworkXError): - G = nx.path_graph(4) - list(nx.node_disjoint_paths(G, 1, 10)) - - -def test_not_weakly_connected_edges(): - with pytest.raises(nx.NetworkXNoPath): - G = nx.DiGraph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5]) - list(nx.edge_disjoint_paths(G, 1, 5)) - - -def test_not_weakly_connected_nodes(): - with pytest.raises(nx.NetworkXNoPath): - G = nx.DiGraph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5]) - list(nx.node_disjoint_paths(G, 1, 5)) - - -def test_not_connected_edges(): - with pytest.raises(nx.NetworkXNoPath): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5]) - list(nx.edge_disjoint_paths(G, 1, 5)) - - -def test_not_connected_nodes(): - with pytest.raises(nx.NetworkXNoPath): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5]) - list(nx.node_disjoint_paths(G, 1, 5)) - - -def test_isolated_edges(): - with pytest.raises(nx.NetworkXNoPath): - G = nx.Graph() - G.add_node(1) - nx.add_path(G, [4, 5]) - list(nx.edge_disjoint_paths(G, 1, 5)) - - -def test_isolated_nodes(): - with pytest.raises(nx.NetworkXNoPath): - G = nx.Graph() - G.add_node(1) - nx.add_path(G, [4, 5]) - list(nx.node_disjoint_paths(G, 1, 5)) - - -def test_invalid_auxiliary(): - with pytest.raises(nx.NetworkXError): - G = nx.complete_graph(5) - list(nx.node_disjoint_paths(G, 0, 3, auxiliary=G)) diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_edge_augmentation.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_edge_augmentation.py deleted file mode 100644 index f87d837c..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_edge_augmentation.py +++ /dev/null @@ -1,473 +0,0 @@ -# -*- coding: utf-8 -*- -import random -import networkx as nx -import itertools as it -from networkx.utils import pairwise -import pytest -from networkx.algorithms.connectivity import ( - k_edge_augmentation, -) -from networkx.algorithms.connectivity.edge_augmentation import ( - collapse, - complement_edges, - is_locally_k_edge_connected, - is_k_edge_connected, - _unpack_available_edges, -) - -# This should be set to the largest k for which an efficient algorithm is -# explicitly defined. -MAX_EFFICIENT_K = 2 - - -def tarjan_bridge_graph(): - # graph from tarjan paper - # RE Tarjan - "A note on finding the bridges of a graph" - # Information Processing Letters, 1974 - Elsevier - # doi:10.1016/0020-0190(74)90003-9. - # define 2-connected components and bridges - ccs = [(1, 2, 4, 3, 1, 4), (5, 6, 7, 5), (8, 9, 10, 8), - (17, 18, 16, 15, 17), (11, 12, 14, 13, 11, 14)] - bridges = [(4, 8), (3, 5), (3, 17)] - G = nx.Graph(it.chain(*(pairwise(path) for path in ccs + bridges))) - return G - - -def test_weight_key(): - G = nx.Graph() - G.add_nodes_from([ - 1, 2, 3, 4, 5, 6, 7, 8, 9]) - G.add_edges_from([(3, 8), (1, 2), (2, 3)]) - impossible = {(3, 6), (3, 9)} - rng = random.Random(0) - avail_uv = list(set(complement_edges(G)) - impossible) - avail = [(u, v, {'cost': rng.random()}) for u, v in avail_uv] - - _augment_and_check(G, k=1) - _augment_and_check(G, k=1, avail=avail_uv) - _augment_and_check(G, k=1, avail=avail, weight='cost') - - _check_augmentations(G, avail, weight='cost') - - -def test_is_locally_k_edge_connected_exceptions(): - pytest.raises(nx.NetworkXNotImplemented, - is_k_edge_connected, - nx.DiGraph(), k=0) - pytest.raises(nx.NetworkXNotImplemented, - is_k_edge_connected, - nx.MultiGraph(), k=0) - pytest.raises(ValueError, is_k_edge_connected, - nx.Graph(), k=0) - - -def test_is_k_edge_connected(): - G = nx.barbell_graph(10, 0) - assert is_k_edge_connected(G, k=1) - assert not is_k_edge_connected(G, k=2) - - G = nx.Graph() - G.add_nodes_from([5, 15]) - assert not is_k_edge_connected(G, k=1) - assert not is_k_edge_connected(G, k=2) - - G = nx.complete_graph(5) - assert is_k_edge_connected(G, k=1) - assert is_k_edge_connected(G, k=2) - assert is_k_edge_connected(G, k=3) - assert is_k_edge_connected(G, k=4) - - -def test_is_k_edge_connected_exceptions(): - pytest.raises(nx.NetworkXNotImplemented, - is_locally_k_edge_connected, - nx.DiGraph(), 1, 2, k=0) - pytest.raises(nx.NetworkXNotImplemented, - is_locally_k_edge_connected, - nx.MultiGraph(), 1, 2, k=0) - pytest.raises(ValueError, - is_locally_k_edge_connected, - nx.Graph(), 1, 2, k=0) - - -def test_is_locally_k_edge_connected(): - G = nx.barbell_graph(10, 0) - assert is_locally_k_edge_connected(G, 5, 15, k=1) - assert not is_locally_k_edge_connected(G, 5, 15, k=2) - - G = nx.Graph() - G.add_nodes_from([5, 15]) - assert not is_locally_k_edge_connected(G, 5, 15, k=2) - - -def test_null_graph(): - G = nx.Graph() - _check_augmentations(G, max_k=MAX_EFFICIENT_K + 2) - - -def test_cliques(): - for n in range(1, 10): - G = nx.complete_graph(n) - _check_augmentations(G, max_k=MAX_EFFICIENT_K + 2) - - -def test_clique_and_node(): - for n in range(1, 10): - G = nx.complete_graph(n) - G.add_node(n + 1) - _check_augmentations(G, max_k=MAX_EFFICIENT_K + 2) - - -def test_point_graph(): - G = nx.Graph() - G.add_node(1) - _check_augmentations(G, max_k=MAX_EFFICIENT_K + 2) - - -def test_edgeless_graph(): - G = nx.Graph() - G.add_nodes_from([1, 2, 3, 4]) - _check_augmentations(G) - - -def test_invalid_k(): - G = nx.Graph() - pytest.raises(ValueError, list, k_edge_augmentation(G, k=-1)) - pytest.raises(ValueError, list, k_edge_augmentation(G, k=0)) - - -def test_unfeasible(): - G = tarjan_bridge_graph() - pytest.raises(nx.NetworkXUnfeasible, list, - k_edge_augmentation(G, k=1, avail=[])) - - pytest.raises(nx.NetworkXUnfeasible, list, - k_edge_augmentation(G, k=2, avail=[])) - - pytest.raises(nx.NetworkXUnfeasible, list, - k_edge_augmentation(G, k=2, avail=[(7, 9)])) - - # partial solutions should not error if real solutions are infeasible - aug_edges = list(k_edge_augmentation(G, k=2, avail=[(7, 9)], partial=True)) - assert aug_edges == [(7, 9)] - - _check_augmentations(G, avail=[], max_k=MAX_EFFICIENT_K + 2) - - _check_augmentations(G, avail=[(7, 9)], max_k=MAX_EFFICIENT_K + 2) - - -def test_tarjan(): - G = tarjan_bridge_graph() - - aug_edges = set(_augment_and_check(G, k=2)[0]) - print('aug_edges = {!r}'.format(aug_edges)) - # can't assert edge exactly equality due to non-determinant edge order - # but we do know the size of the solution must be 3 - assert len(aug_edges) == 3 - - avail = [(9, 7), (8, 5), (2, 10), (6, 13), (11, 18), (1, 17), (2, 3), - (16, 17), (18, 14), (15, 14)] - aug_edges = set(_augment_and_check(G, avail=avail, k=2)[0]) - - # Can't assert exact length since approximation depends on the order of a - # dict traversal. - assert len(aug_edges) <= 3 * 2 - - _check_augmentations(G, avail) - - -def test_configuration(): - # seeds = [2718183590, 2470619828, 1694705158, 3001036531, 2401251497] - seeds = [1001, 1002, 1003, 1004] - for seed in seeds: - deg_seq = nx.random_powerlaw_tree_sequence(20, seed=seed, tries=5000) - G = nx.Graph(nx.configuration_model(deg_seq, seed=seed)) - G.remove_edges_from(nx.selfloop_edges(G)) - _check_augmentations(G) - - -def test_shell(): - # seeds = [2057382236, 3331169846, 1840105863, 476020778, 2247498425] - seeds = [18] - for seed in seeds: - constructor = [(12, 70, 0.8), (15, 40, 0.6)] - G = nx.random_shell_graph(constructor, seed=seed) - _check_augmentations(G) - - -def test_karate(): - G = nx.karate_club_graph() - _check_augmentations(G) - - -def test_star(): - G = nx.star_graph(3) - _check_augmentations(G) - - G = nx.star_graph(5) - _check_augmentations(G) - - G = nx.star_graph(10) - _check_augmentations(G) - - -def test_barbell(): - G = nx.barbell_graph(5, 0) - _check_augmentations(G) - - G = nx.barbell_graph(5, 2) - _check_augmentations(G) - - G = nx.barbell_graph(5, 3) - _check_augmentations(G) - - G = nx.barbell_graph(5, 4) - _check_augmentations(G) - - -def test_bridge(): - G = nx.Graph([(2393, 2257), (2393, 2685), (2685, 2257), (1758, 2257)]) - _check_augmentations(G) - - -def test_gnp_augmentation(): - rng = random.Random(0) - G = nx.gnp_random_graph(30, 0.005, seed=0) - # Randomly make edges available - avail = {(u, v): 1 + rng.random() - for u, v in complement_edges(G) - if rng.random() < .25} - _check_augmentations(G, avail) - - -def _assert_solution_properties(G, aug_edges, avail_dict=None): - """ Checks that aug_edges are consistently formatted """ - if avail_dict is not None: - assert all(e in avail_dict for e in aug_edges), 'when avail is specified aug-edges should be in avail' - - unique_aug = set(map(tuple, map(sorted, aug_edges))) - unique_aug = list(map(tuple, map(sorted, aug_edges))) - assert len(aug_edges) == len(unique_aug), 'edges should be unique' - - assert not any(u == v for u, v in unique_aug), 'should be no self-edges' - - assert not any(G.has_edge(u, v) for u, v in unique_aug), 'aug edges and G.edges should be disjoint' - - -def _augment_and_check(G, k, avail=None, weight=None, verbose=False, - orig_k=None, max_aug_k=None): - """ - Does one specific augmentation and checks for properties of the result - """ - if orig_k is None: - try: - orig_k = nx.edge_connectivity(G) - except nx.NetworkXPointlessConcept: - orig_k = 0 - info = {} - try: - if avail is not None: - # ensure avail is in dict form - avail_dict = dict(zip(*_unpack_available_edges(avail, - weight=weight))) - else: - avail_dict = None - try: - # Find the augmentation if possible - generator = nx.k_edge_augmentation(G, k=k, weight=weight, - avail=avail) - assert not isinstance(generator, list), 'should always return an iter' - aug_edges = [] - for edge in generator: - aug_edges.append(edge) - except nx.NetworkXUnfeasible: - infeasible = True - info['infeasible'] = True - assert len(aug_edges) == 0, 'should not generate anything if unfeasible' - - if avail is None: - n_nodes = G.number_of_nodes() - assert n_nodes <= k, ( - 'unconstrained cases are only unfeasible if |V| <= k. ' - 'Got |V|={} and k={}'.format(n_nodes, k) - ) - else: - if max_aug_k is None: - G_aug_all = G.copy() - G_aug_all.add_edges_from(avail_dict.keys()) - try: - max_aug_k = nx.edge_connectivity(G_aug_all) - except nx.NetworkXPointlessConcept: - max_aug_k = 0 - - assert max_aug_k < k, ( - 'avail should only be unfeasible if using all edges ' - 'does not achieve k-edge-connectivity') - - # Test for a partial solution - partial_edges = list(nx.k_edge_augmentation( - G, k=k, weight=weight, partial=True, avail=avail)) - - info['n_partial_edges'] = len(partial_edges) - - if avail_dict is None: - assert set(partial_edges) == set(complement_edges(G)), ( - 'unweighted partial solutions should be the complement') - elif len(avail_dict) > 0: - H = G.copy() - - # Find the partial / full augmented connectivity - H.add_edges_from(partial_edges) - partial_conn = nx.edge_connectivity(H) - - H.add_edges_from(set(avail_dict.keys())) - full_conn = nx.edge_connectivity(H) - - # Full connectivity should be no better than our partial - # solution. - assert partial_conn == full_conn, 'adding more edges should not increase k-conn' - - # Find the new edge-connectivity after adding the augmenting edges - aug_edges = partial_edges - else: - infeasible = False - - # Find the weight of the augmentation - num_edges = len(aug_edges) - if avail is not None: - total_weight = sum([avail_dict[e] for e in aug_edges]) - else: - total_weight = num_edges - - info['total_weight'] = total_weight - info['num_edges'] = num_edges - - # Find the new edge-connectivity after adding the augmenting edges - G_aug = G.copy() - G_aug.add_edges_from(aug_edges) - try: - aug_k = nx.edge_connectivity(G_aug) - except nx.NetworkXPointlessConcept: - aug_k = 0 - info['aug_k'] = aug_k - - # Do checks - if not infeasible and orig_k < k: - assert info['aug_k'] >= k, ( - 'connectivity should increase to k={} or more'.format(k)) - - assert info['aug_k'] >= orig_k, ( - 'augmenting should never reduce connectivity') - - _assert_solution_properties(G, aug_edges, avail_dict) - - except Exception: - info['failed'] = True - print('edges = {}'.format(list(G.edges()))) - print('nodes = {}'.format(list(G.nodes()))) - print('aug_edges = {}'.format(list(aug_edges))) - print('info = {}'.format(info)) - raise - else: - if verbose: - print('info = {}'.format(info)) - - if infeasible: - aug_edges = None - return aug_edges, info - - -def _check_augmentations(G, avail=None, max_k=None, weight=None, - verbose=False): - """ Helper to check weighted/unweighted cases with multiple values of k """ - # Using all available edges, find the maximum edge-connectivity - try: - orig_k = nx.edge_connectivity(G) - except nx.NetworkXPointlessConcept: - orig_k = 0 - - if avail is not None: - all_aug_edges = _unpack_available_edges(avail, weight=weight)[0] - G_aug_all = G.copy() - G_aug_all.add_edges_from(all_aug_edges) - try: - max_aug_k = nx.edge_connectivity(G_aug_all) - except nx.NetworkXPointlessConcept: - max_aug_k = 0 - else: - max_aug_k = G.number_of_nodes() - 1 - - if max_k is None: - max_k = min(4, max_aug_k) - - avail_uniform = {e: 1 for e in complement_edges(G)} - - if verbose: - print('\n=== CHECK_AUGMENTATION ===') - print('G.number_of_nodes = {!r}'.format(G.number_of_nodes())) - print('G.number_of_edges = {!r}'.format(G.number_of_edges())) - print('max_k = {!r}'.format(max_k)) - print('max_aug_k = {!r}'.format(max_aug_k)) - print('orig_k = {!r}'.format(orig_k)) - - # check augmentation for multiple values of k - for k in range(1, max_k + 1): - if verbose: - print('---------------') - print('Checking k = {}'.format(k)) - - # Check the unweighted version - if verbose: - print('unweighted case') - aug_edges1, info1 = _augment_and_check( - G, k=k, verbose=verbose, orig_k=orig_k) - - # Check that the weighted version with all available edges and uniform - # weights gives a similar solution to the unweighted case. - if verbose: - print('weighted uniform case') - aug_edges2, info2 = _augment_and_check( - G, k=k, avail=avail_uniform, verbose=verbose, - orig_k=orig_k, - max_aug_k=G.number_of_nodes() - 1) - - # Check the weighted version - if avail is not None: - if verbose: - print('weighted case') - aug_edges3, info3 = _augment_and_check( - G, k=k, avail=avail, weight=weight, verbose=verbose, - max_aug_k=max_aug_k, orig_k=orig_k) - - if aug_edges1 is not None: - # Check approximation ratios - if k == 1: - # when k=1, both solutions should be optimal - assert info2['total_weight'] == info1['total_weight'] - if k == 2: - # when k=2, the weighted version is an approximation - if orig_k == 0: - # the approximation ratio is 3 if G is not connected - assert (info2['total_weight'] <= - info1['total_weight'] * 3) - else: - # the approximation ratio is 2 if G is was connected - assert (info2['total_weight'] <= - info1['total_weight'] * 2) - _check_unconstrained_bridge_property(G, info1) - - -def _check_unconstrained_bridge_property(G, info1): - # Check Theorem 5 from Eswaran and Tarjan. (1975) Augmentation problems - import math - bridge_ccs = list(nx.connectivity.bridge_components(G)) - # condense G into an forest C - C = collapse(G, bridge_ccs) - - p = len([n for n, d in C.degree() if d == 1]) # leafs - q = len([n for n, d in C.degree() if d == 0]) # isolated - if p + q > 1: - size_target = int(math.ceil(p / 2.0)) + q - size_aug = info1['num_edges'] - assert size_aug == size_target, ( - 'augmentation size is different from what theory predicts') diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_edge_kcomponents.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_edge_kcomponents.py deleted file mode 100644 index 7758a6f0..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_edge_kcomponents.py +++ /dev/null @@ -1,500 +0,0 @@ -# -*- coding: utf-8 -*- -import networkx as nx -import itertools as it -import pytest -from networkx.utils import pairwise -from networkx.algorithms.connectivity import ( - bridge_components, - EdgeComponentAuxGraph, -) -from networkx.algorithms.connectivity.edge_kcomponents import ( - general_k_edge_subgraphs, -) - - -# ---------------- -# Helper functions -# ---------------- - -def fset(list_of_sets): - """ allows == to be used for list of sets """ - return set(map(frozenset, list_of_sets)) - - -def _assert_subgraph_edge_connectivity(G, ccs_subgraph, k): - """ - tests properties of k-edge-connected subgraphs - - the actual edge connectivity should be no less than k unless the cc is a - single node. - """ - for cc in ccs_subgraph: - C = G.subgraph(cc) - if len(cc) > 1: - connectivity = nx.edge_connectivity(C) - assert connectivity >= k - - -def _memo_connectivity(G, u, v, memo): - edge = (u, v) - if edge in memo: - return memo[edge] - if not G.is_directed(): - redge = (v, u) - if redge in memo: - return memo[redge] - memo[edge] = nx.edge_connectivity(G, *edge) - return memo[edge] - - -def _all_pairs_connectivity(G, cc, k, memo): - # Brute force check - for u, v in it.combinations(cc, 2): - # Use a memoization dict to save on computation - connectivity = _memo_connectivity(G, u, v, memo) - if G.is_directed(): - connectivity = min(connectivity, _memo_connectivity(G, v, u, memo)) - assert connectivity >= k - - -def _assert_local_cc_edge_connectivity(G, ccs_local, k, memo): - """ - tests properties of k-edge-connected components - - the local edge connectivity between each pair of nodes in the the original - graph should be no less than k unless the cc is a single node. - """ - for cc in ccs_local: - if len(cc) > 1: - # Strategy for testing a bit faster: If the subgraph has high edge - # connectivity then it must have local connectivity - C = G.subgraph(cc) - connectivity = nx.edge_connectivity(C) - if connectivity < k: - # Otherwise do the brute force (with memoization) check - _all_pairs_connectivity(G, cc, k, memo) - - -# Helper function -def _check_edge_connectivity(G): - """ - Helper - generates all k-edge-components using the aux graph. Checks the - both local and subgraph edge connectivity of each cc. Also checks that - alternate methods of computing the k-edge-ccs generate the same result. - """ - # Construct the auxiliary graph that can be used to make each k-cc or k-sub - aux_graph = EdgeComponentAuxGraph.construct(G) - - # memoize the local connectivity in this graph - memo = {} - - for k in it.count(1): - # Test "local" k-edge-components and k-edge-subgraphs - ccs_local = fset(aux_graph.k_edge_components(k)) - ccs_subgraph = fset(aux_graph.k_edge_subgraphs(k)) - - # Check connectivity properties that should be garuenteed by the - # algorithms. - _assert_local_cc_edge_connectivity(G, ccs_local, k, memo) - _assert_subgraph_edge_connectivity(G, ccs_subgraph, k) - - if k == 1 or k == 2 and not G.is_directed(): - assert ccs_local == ccs_subgraph, 'Subgraphs and components should be the same when k == 1 or (k == 2 and not G.directed())' - - if G.is_directed(): - # Test special case methods are the same as the aux graph - if k == 1: - alt_sccs = fset(nx.strongly_connected_components(G)) - assert alt_sccs == ccs_local, 'k=1 failed alt' - assert alt_sccs == ccs_subgraph, 'k=1 failed alt' - else: - # Test special case methods are the same as the aux graph - if k == 1: - alt_ccs = fset(nx.connected_components(G)) - assert alt_ccs == ccs_local, 'k=1 failed alt' - assert alt_ccs == ccs_subgraph, 'k=1 failed alt' - elif k == 2: - alt_bridge_ccs = fset(bridge_components(G)) - assert alt_bridge_ccs == ccs_local, 'k=2 failed alt' - assert alt_bridge_ccs == ccs_subgraph, 'k=2 failed alt' - # if new methods for k == 3 or k == 4 are implemented add them here - - # Check the general subgraph method works by itself - alt_subgraph_ccs = fset([set(C.nodes()) for C in - general_k_edge_subgraphs(G, k=k)]) - assert alt_subgraph_ccs == ccs_subgraph, 'alt subgraph method failed' - - # Stop once k is larger than all special case methods - # and we cannot break down ccs any further. - if k > 2 and all(len(cc) == 1 for cc in ccs_local): - break - - -# ---------------- -# Misc tests -# ---------------- - -def test_zero_k_exception(): - G = nx.Graph() - # functions that return generators error immediately - pytest.raises(ValueError, nx.k_edge_components, G, k=0) - pytest.raises(ValueError, nx.k_edge_subgraphs, G, k=0) - - # actual generators only error when you get the first item - aux_graph = EdgeComponentAuxGraph.construct(G) - pytest.raises(ValueError, list, aux_graph.k_edge_components(k=0)) - pytest.raises(ValueError, list, aux_graph.k_edge_subgraphs(k=0)) - - pytest.raises(ValueError, list, general_k_edge_subgraphs(G, k=0)) - - -def test_empty_input(): - G = nx.Graph() - assert [] == list(nx.k_edge_components(G, k=5)) - assert [] == list(nx.k_edge_subgraphs(G, k=5)) - - G = nx.DiGraph() - assert [] == list(nx.k_edge_components(G, k=5)) - assert [] == list(nx.k_edge_subgraphs(G, k=5)) - - -def test_not_implemented(): - G = nx.MultiGraph() - pytest.raises(nx.NetworkXNotImplemented, EdgeComponentAuxGraph.construct, G) - pytest.raises(nx.NetworkXNotImplemented, nx.k_edge_components, G, k=2) - pytest.raises(nx.NetworkXNotImplemented, nx.k_edge_subgraphs, G, k=2) - pytest.raises(nx.NetworkXNotImplemented, bridge_components, G) - pytest.raises(nx.NetworkXNotImplemented, bridge_components, nx.DiGraph()) - - -def test_general_k_edge_subgraph_quick_return(): - # tests quick return optimization - G = nx.Graph() - G.add_node(0) - subgraphs = list(general_k_edge_subgraphs(G, k=1)) - assert len(subgraphs) == 1 - for subgraph in subgraphs: - assert subgraph.number_of_nodes() == 1 - - G.add_node(1) - subgraphs = list(general_k_edge_subgraphs(G, k=1)) - assert len(subgraphs) == 2 - for subgraph in subgraphs: - assert subgraph.number_of_nodes() == 1 - - -# ---------------- -# Undirected tests -# ---------------- - -def test_random_gnp(): - # seeds = [1550709854, 1309423156, 4208992358, 2785630813, 1915069929] - seeds = [12, 13] - - for seed in seeds: - G = nx.gnp_random_graph(20, 0.2, seed=seed) - _check_edge_connectivity(G) - - -def test_configuration(): - # seeds = [2718183590, 2470619828, 1694705158, 3001036531, 2401251497] - seeds = [14, 15] - for seed in seeds: - deg_seq = nx.random_powerlaw_tree_sequence(20, seed=seed, tries=5000) - G = nx.Graph(nx.configuration_model(deg_seq, seed=seed)) - G.remove_edges_from(nx.selfloop_edges(G)) - _check_edge_connectivity(G) - - -def test_shell(): - # seeds = [2057382236, 3331169846, 1840105863, 476020778, 2247498425] - seeds = [20] - for seed in seeds: - constructor = [(12, 70, 0.8), (15, 40, 0.6)] - G = nx.random_shell_graph(constructor, seed=seed) - _check_edge_connectivity(G) - - -def test_karate(): - G = nx.karate_club_graph() - _check_edge_connectivity(G) - - -def test_tarjan_bridge(): - # graph from tarjan paper - # RE Tarjan - "A note on finding the bridges of a graph" - # Information Processing Letters, 1974 - Elsevier - # doi:10.1016/0020-0190(74)90003-9. - # define 2-connected components and bridges - ccs = [(1, 2, 4, 3, 1, 4), (5, 6, 7, 5), (8, 9, 10, 8), - (17, 18, 16, 15, 17), (11, 12, 14, 13, 11, 14)] - bridges = [(4, 8), (3, 5), (3, 17)] - G = nx.Graph(it.chain(*(pairwise(path) for path in ccs + bridges))) - _check_edge_connectivity(G) - - -def test_bridge_cc(): - # define 2-connected components and bridges - cc2 = [(1, 2, 4, 3, 1, 4), (8, 9, 10, 8), (11, 12, 13, 11)] - bridges = [(4, 8), (3, 5), (20, 21), (22, 23, 24)] - G = nx.Graph(it.chain(*(pairwise(path) for path in cc2 + bridges))) - bridge_ccs = fset(bridge_components(G)) - target_ccs = fset([ - {1, 2, 3, 4}, {5}, {8, 9, 10}, {11, 12, 13}, {20}, - {21}, {22}, {23}, {24} - ]) - assert bridge_ccs == target_ccs - _check_edge_connectivity(G) - - -def test_undirected_aux_graph(): - # Graph similar to the one in - # http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0136264 - a, b, c, d, e, f, g, h, i = 'abcdefghi' - paths = [ - (a, d, b, f, c), - (a, e, b), - (a, e, b, c, g, b, a), - (c, b), - (f, g, f), - (h, i) - ] - G = nx.Graph(it.chain(*[pairwise(path) for path in paths])) - aux_graph = EdgeComponentAuxGraph.construct(G) - - components_1 = fset(aux_graph.k_edge_subgraphs(k=1)) - target_1 = fset([{a, b, c, d, e, f, g}, {h, i}]) - assert target_1 == components_1 - - # Check that the undirected case for k=1 agrees with CCs - alt_1 = fset(nx.k_edge_subgraphs(G, k=1)) - assert alt_1 == components_1 - - components_2 = fset(aux_graph.k_edge_subgraphs(k=2)) - target_2 = fset([{a, b, c, d, e, f, g}, {h}, {i}]) - assert target_2 == components_2 - - # Check that the undirected case for k=2 agrees with bridge components - alt_2 = fset(nx.k_edge_subgraphs(G, k=2)) - assert alt_2 == components_2 - - components_3 = fset(aux_graph.k_edge_subgraphs(k=3)) - target_3 = fset([{a}, {b, c, f, g}, {d}, {e}, {h}, {i}]) - assert target_3 == components_3 - - components_4 = fset(aux_graph.k_edge_subgraphs(k=4)) - target_4 = fset([{a}, {b}, {c}, {d}, {e}, {f}, {g}, {h}, {i}]) - assert target_4 == components_4 - - _check_edge_connectivity(G) - - -def test_local_subgraph_difference(): - paths = [ - (11, 12, 13, 14, 11, 13, 14, 12), # first 4-clique - (21, 22, 23, 24, 21, 23, 24, 22), # second 4-clique - # paths connecting each node of the 4 cliques - (11, 101, 21), - (12, 102, 22), - (13, 103, 23), - (14, 104, 24), - ] - G = nx.Graph(it.chain(*[pairwise(path) for path in paths])) - aux_graph = EdgeComponentAuxGraph.construct(G) - - # Each clique is returned separately in k-edge-subgraphs - subgraph_ccs = fset(aux_graph.k_edge_subgraphs(3)) - subgraph_target = fset([{101}, {102}, {103}, {104}, - {21, 22, 23, 24}, {11, 12, 13, 14}]) - assert subgraph_ccs == subgraph_target - - # But in k-edge-ccs they are returned together - # because they are locally 3-edge-connected - local_ccs = fset(aux_graph.k_edge_components(3)) - local_target = fset([{101}, {102}, {103}, {104}, - {11, 12, 13, 14, 21, 22, 23, 24}]) - assert local_ccs == local_target - - -def test_local_subgraph_difference_directed(): - dipaths = [ - (1, 2, 3, 4, 1), - (1, 3, 1), - ] - G = nx.DiGraph(it.chain(*[pairwise(path) for path in dipaths])) - - assert ( - fset(nx.k_edge_components(G, k=1)) == - fset(nx.k_edge_subgraphs(G, k=1))) - - # Unlike undirected graphs, when k=2, for directed graphs there is a case - # where the k-edge-ccs are not the same as the k-edge-subgraphs. - # (in directed graphs ccs and subgraphs are the same when k=2) - assert ( - fset(nx.k_edge_components(G, k=2)) != - fset(nx.k_edge_subgraphs(G, k=2))) - - assert ( - fset(nx.k_edge_components(G, k=3)) == - fset(nx.k_edge_subgraphs(G, k=3))) - - _check_edge_connectivity(G) - - -def test_triangles(): - paths = [ - (11, 12, 13, 11), # first 3-clique - (21, 22, 23, 21), # second 3-clique - (11, 21), # connected by an edge - ] - G = nx.Graph(it.chain(*[pairwise(path) for path in paths])) - - # subgraph and ccs are the same in all cases here - assert ( - fset(nx.k_edge_components(G, k=1)) == - fset(nx.k_edge_subgraphs(G, k=1))) - - assert ( - fset(nx.k_edge_components(G, k=2)) == - fset(nx.k_edge_subgraphs(G, k=2))) - - assert ( - fset(nx.k_edge_components(G, k=3)) == - fset(nx.k_edge_subgraphs(G, k=3))) - - _check_edge_connectivity(G) - - -def test_four_clique(): - paths = [ - (11, 12, 13, 14, 11, 13, 14, 12), # first 4-clique - (21, 22, 23, 24, 21, 23, 24, 22), # second 4-clique - # paths connecting the 4 cliques such that they are - # 3-connected in G, but not in the subgraph. - # Case where the nodes bridging them do not have degree less than 3. - (100, 13), - (12, 100, 22), - (13, 200, 23), - (14, 300, 24), - ] - G = nx.Graph(it.chain(*[pairwise(path) for path in paths])) - - # The subgraphs and ccs are different for k=3 - local_ccs = fset(nx.k_edge_components(G, k=3)) - subgraphs = fset(nx.k_edge_subgraphs(G, k=3)) - assert local_ccs != subgraphs - - # The cliques ares in the same cc - clique1 = frozenset(paths[0]) - clique2 = frozenset(paths[1]) - assert clique1.union(clique2).union({100}) in local_ccs - - # but different subgraphs - assert clique1 in subgraphs - assert clique2 in subgraphs - - assert G.degree(100) == 3 - - _check_edge_connectivity(G) - - -def test_five_clique(): - # Make a graph that can be disconnected less than 4 edges, but no node has - # degree less than 4. - G = nx.disjoint_union(nx.complete_graph(5), nx.complete_graph(5)) - paths = [ - # add aux-connections - (1, 100, 6), (2, 100, 7), (3, 200, 8), (4, 200, 100), - ] - G.add_edges_from(it.chain(*[pairwise(path) for path in paths])) - assert min(dict(nx.degree(G)).values()) == 4 - - # For k=3 they are the same - assert ( - fset(nx.k_edge_components(G, k=3)) == - fset(nx.k_edge_subgraphs(G, k=3))) - - # For k=4 they are the different - # the aux nodes are in the same CC as clique 1 but no the same subgraph - assert ( - fset(nx.k_edge_components(G, k=4)) != - fset(nx.k_edge_subgraphs(G, k=4))) - - # For k=5 they are not the same - assert ( - fset(nx.k_edge_components(G, k=5)) != - fset(nx.k_edge_subgraphs(G, k=5))) - - # For k=6 they are the same - assert ( - fset(nx.k_edge_components(G, k=6)) == - fset(nx.k_edge_subgraphs(G, k=6))) - _check_edge_connectivity(G) - - -# ---------------- -# Undirected tests -# ---------------- - -def test_directed_aux_graph(): - # Graph similar to the one in - # http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0136264 - a, b, c, d, e, f, g, h, i = 'abcdefghi' - dipaths = [ - (a, d, b, f, c), - (a, e, b), - (a, e, b, c, g, b, a), - (c, b), - (f, g, f), - (h, i) - ] - G = nx.DiGraph(it.chain(*[pairwise(path) for path in dipaths])) - aux_graph = EdgeComponentAuxGraph.construct(G) - - components_1 = fset(aux_graph.k_edge_subgraphs(k=1)) - target_1 = fset([{a, b, c, d, e, f, g}, {h}, {i}]) - assert target_1 == components_1 - - # Check that the directed case for k=1 agrees with SCCs - alt_1 = fset(nx.strongly_connected_components(G)) - assert alt_1 == components_1 - - components_2 = fset(aux_graph.k_edge_subgraphs(k=2)) - target_2 = fset([{i}, {e}, {d}, {b, c, f, g}, {h}, {a}]) - assert target_2 == components_2 - - components_3 = fset(aux_graph.k_edge_subgraphs(k=3)) - target_3 = fset([{a}, {b}, {c}, {d}, {e}, {f}, {g}, {h}, {i}]) - assert target_3 == components_3 - - -def test_random_gnp_directed(): - # seeds = [3894723670, 500186844, 267231174, 2181982262, 1116750056] - seeds = [21] - for seed in seeds: - G = nx.gnp_random_graph(20, 0.2, directed=True, seed=seed) - _check_edge_connectivity(G) - - -def test_configuration_directed(): - # seeds = [671221681, 2403749451, 124433910, 672335939, 1193127215] - seeds = [67] - for seed in seeds: - deg_seq = nx.random_powerlaw_tree_sequence(20, seed=seed, tries=5000) - G = nx.DiGraph(nx.configuration_model(deg_seq, seed=seed)) - G.remove_edges_from(nx.selfloop_edges(G)) - _check_edge_connectivity(G) - - -def test_shell_directed(): - # seeds = [3134027055, 4079264063, 1350769518, 1405643020, 530038094] - seeds = [31] - for seed in seeds: - constructor = [(12, 70, 0.8), (15, 40, 0.6)] - G = nx.random_shell_graph(constructor, seed=seed).to_directed() - _check_edge_connectivity(G) - - -def test_karate_directed(): - G = nx.karate_club_graph().to_directed() - _check_edge_connectivity(G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_kcomponents.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_kcomponents.py deleted file mode 100644 index f1160261..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_kcomponents.py +++ /dev/null @@ -1,250 +0,0 @@ -# Test for Moody and White k-components algorithm -import pytest -import networkx as nx -from networkx.algorithms.connectivity.kcomponents import ( - build_k_number_dict, - _consolidate, -) - -## -# A nice synthetic graph -## - - -def torrents_and_ferraro_graph(): - # Graph from https://arxiv.org/pdf/1503.04476v1 p.26 - G = nx.convert_node_labels_to_integers( - nx.grid_graph([5, 5]), - label_attribute='labels', - ) - rlabels = nx.get_node_attributes(G, 'labels') - labels = {v: k for k, v in rlabels.items()} - - for nodes in [(labels[(0, 4)], labels[(1, 4)]), - (labels[(3, 4)], labels[(4, 4)])]: - new_node = G.order() + 1 - # Petersen graph is triconnected - P = nx.petersen_graph() - G = nx.disjoint_union(G, P) - # Add two edges between the grid and P - G.add_edge(new_node + 1, nodes[0]) - G.add_edge(new_node, nodes[1]) - # K5 is 4-connected - K = nx.complete_graph(5) - G = nx.disjoint_union(G, K) - # Add three edges between P and K5 - G.add_edge(new_node + 2, new_node + 11) - G.add_edge(new_node + 3, new_node + 12) - G.add_edge(new_node + 4, new_node + 13) - # Add another K5 sharing a node - G = nx.disjoint_union(G, K) - nbrs = G[new_node + 10] - G.remove_node(new_node + 10) - for nbr in nbrs: - G.add_edge(new_node + 17, nbr) - # This edge makes the graph biconnected; it's - # needed because K5s share only one node. - G.add_edge(new_node + 16, new_node + 8) - - for nodes in [(labels[(0, 0)], labels[(1, 0)]), - (labels[(3, 0)], labels[(4, 0)])]: - new_node = G.order() + 1 - # Petersen graph is triconnected - P = nx.petersen_graph() - G = nx.disjoint_union(G, P) - # Add two edges between the grid and P - G.add_edge(new_node + 1, nodes[0]) - G.add_edge(new_node, nodes[1]) - # K5 is 4-connected - K = nx.complete_graph(5) - G = nx.disjoint_union(G, K) - # Add three edges between P and K5 - G.add_edge(new_node + 2, new_node + 11) - G.add_edge(new_node + 3, new_node + 12) - G.add_edge(new_node + 4, new_node + 13) - # Add another K5 sharing two nodes - G = nx.disjoint_union(G, K) - nbrs = G[new_node + 10] - G.remove_node(new_node + 10) - for nbr in nbrs: - G.add_edge(new_node + 17, nbr) - nbrs2 = G[new_node + 9] - G.remove_node(new_node + 9) - for nbr in nbrs2: - G.add_edge(new_node + 18, nbr) - return G - - -def test_directed(): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.gnp_random_graph(10, 0.2, directed=True, seed=42) - nx.k_components(G) - - -# Helper function -def _check_connectivity(G, k_components): - for k, components in k_components.items(): - if k < 3: - continue - # check that k-components have node connectivity >= k. - for component in components: - C = G.subgraph(component) - K = nx.node_connectivity(C) - assert K >= k - - -def test_torrents_and_ferraro_graph(): - G = torrents_and_ferraro_graph() - result = nx.k_components(G) - _check_connectivity(G, result) - - # In this example graph there are 8 3-components, 4 with 15 nodes - # and 4 with 5 nodes. - assert len(result[3]) == 8 - assert len([c for c in result[3] if len(c) == 15]) == 4 - assert len([c for c in result[3] if len(c) == 5]) == 4 - # There are also 8 4-components all with 5 nodes. - assert len(result[4]) == 8 - assert all(len(c) == 5 for c in result[4]) - - -def test_random_gnp(): - G = nx.gnp_random_graph(50, 0.2, seed=42) - result = nx.k_components(G) - _check_connectivity(G, result) - - -def test_shell(): - constructor = [(20, 80, 0.8), (80, 180, 0.6)] - G = nx.random_shell_graph(constructor, seed=42) - result = nx.k_components(G) - _check_connectivity(G, result) - - -def test_configuration(): - deg_seq = nx.random_powerlaw_tree_sequence(100, tries=5, seed=72) - G = nx.Graph(nx.configuration_model(deg_seq)) - G.remove_edges_from(nx.selfloop_edges(G)) - result = nx.k_components(G) - _check_connectivity(G, result) - - -def test_karate(): - G = nx.karate_club_graph() - result = nx.k_components(G) - _check_connectivity(G, result) - - -def test_karate_component_number(): - karate_k_num = { - 0: 4, 1: 4, 2: 4, 3: 4, 4: 3, 5: 3, 6: 3, 7: 4, 8: 4, 9: 2, - 10: 3, 11: 1, 12: 2, 13: 4, 14: 2, 15: 2, 16: 2, 17: 2, - 18: 2, 19: 3, 20: 2, 21: 2, 22: 2, 23: 3, 24: 3, 25: 3, - 26: 2, 27: 3, 28: 3, 29: 3, 30: 4, 31: 3, 32: 4, 33: 4 - } - G = nx.karate_club_graph() - k_components = nx.k_components(G) - k_num = build_k_number_dict(k_components) - assert karate_k_num == k_num - - -def test_davis_southern_women(): - G = nx.davis_southern_women_graph() - result = nx.k_components(G) - _check_connectivity(G, result) - - -def test_davis_southern_women_detail_3_and_4(): - solution = { - 3: [{ - 'Nora Fayette', - 'E10', - 'Myra Liddel', - 'E12', - 'E14', - 'Frances Anderson', - 'Evelyn Jefferson', - 'Ruth DeSand', - 'Helen Lloyd', - 'Eleanor Nye', - 'E9', - 'E8', - 'E5', - 'E4', - 'E7', - 'E6', - 'E1', - 'Verne Sanderson', - 'E3', - 'E2', - 'Theresa Anderson', - 'Pearl Oglethorpe', - 'Katherina Rogers', - 'Brenda Rogers', - 'E13', - 'Charlotte McDowd', - 'Sylvia Avondale', - 'Laura Mandeville', - }, - ], - 4: [{ - 'Nora Fayette', - 'E10', - 'Verne Sanderson', - 'E12', - 'Frances Anderson', - 'Evelyn Jefferson', - 'Ruth DeSand', - 'Helen Lloyd', - 'Eleanor Nye', - 'E9', - 'E8', - 'E5', - 'E4', - 'E7', - 'E6', - 'Myra Liddel', - 'E3', - 'Theresa Anderson', - 'Katherina Rogers', - 'Brenda Rogers', - 'Charlotte McDowd', - 'Sylvia Avondale', - 'Laura Mandeville', - }, - ], - } - G = nx.davis_southern_women_graph() - result = nx.k_components(G) - for k, components in result.items(): - if k < 3: - continue - assert len(components) == len(solution[k]) - for component in components: - assert component in solution[k] - - -def test_set_consolidation_rosettacode(): - # Tests from http://rosettacode.org/wiki/Set_consolidation - def list_of_sets_equal(result, solution): - assert ( - {frozenset(s) for s in result} == - {frozenset(s) for s in solution}) - question = [{'A', 'B'}, {'C', 'D'}] - solution = [{'A', 'B'}, {'C', 'D'}] - list_of_sets_equal(_consolidate(question, 1), solution) - question = [{'A', 'B'}, {'B', 'C'}] - solution = [{'A', 'B', 'C'}] - list_of_sets_equal(_consolidate(question, 1), solution) - question = [{'A', 'B'}, {'C', 'D'}, {'D', 'B'}] - solution = [{'A', 'C', 'B', 'D'}] - list_of_sets_equal(_consolidate(question, 1), solution) - question = [{'H', 'I', 'K'}, {'A', 'B'}, {'C', 'D'}, {'D', 'B'}, {'F', 'G', 'H'}] - solution = [{'A', 'C', 'B', 'D'}, {'G', 'F', 'I', 'H', 'K'}] - list_of_sets_equal(_consolidate(question, 1), solution) - question = [{'A', 'H'}, {'H', 'I', 'K'}, {'A', 'B'}, {'C', 'D'}, {'D', 'B'}, {'F', 'G', 'H'}] - solution = [{'A', 'C', 'B', 'D', 'G', 'F', 'I', 'H', 'K'}] - list_of_sets_equal(_consolidate(question, 1), solution) - question = [{'H', 'I', 'K'}, {'A', 'B'}, {'C', 'D'}, {'D', 'B'}, {'F', 'G', 'H'}, {'A', 'H'}] - solution = [{'A', 'C', 'B', 'D', 'G', 'F', 'I', 'H', 'K'}] - list_of_sets_equal(_consolidate(question, 1), solution) diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_kcutsets.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_kcutsets.py deleted file mode 100644 index 492b309d..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_kcutsets.py +++ /dev/null @@ -1,274 +0,0 @@ -# Jordi Torrents -# Test for k-cutsets -import itertools -import pytest - -import networkx as nx -from networkx.algorithms import flow -from networkx.algorithms.connectivity.kcutsets import _is_separating_set - -MAX_CUTSETS_TO_TEST = 4 # originally 100. cut to decrease testing time - -flow_funcs = [ - flow.boykov_kolmogorov, - flow.dinitz, - flow.edmonds_karp, - flow.preflow_push, - flow.shortest_augmenting_path, -] - - -## -# Some nice synthetic graphs -## -def graph_example_1(): - G = nx.convert_node_labels_to_integers(nx.grid_graph([5, 5]), - label_attribute='labels') - rlabels = nx.get_node_attributes(G, 'labels') - labels = {v: k for k, v in rlabels.items()} - - for nodes in [(labels[(0, 0)], labels[(1, 0)]), - (labels[(0, 4)], labels[(1, 4)]), - (labels[(3, 0)], labels[(4, 0)]), - (labels[(3, 4)], labels[(4, 4)])]: - new_node = G.order() + 1 - # Petersen graph is triconnected - P = nx.petersen_graph() - G = nx.disjoint_union(G, P) - # Add two edges between the grid and P - G.add_edge(new_node + 1, nodes[0]) - G.add_edge(new_node, nodes[1]) - # K5 is 4-connected - K = nx.complete_graph(5) - G = nx.disjoint_union(G, K) - # Add three edges between P and K5 - G.add_edge(new_node + 2, new_node + 11) - G.add_edge(new_node + 3, new_node + 12) - G.add_edge(new_node + 4, new_node + 13) - # Add another K5 sharing a node - G = nx.disjoint_union(G, K) - nbrs = G[new_node + 10] - G.remove_node(new_node + 10) - for nbr in nbrs: - G.add_edge(new_node + 17, nbr) - G.add_edge(new_node + 16, new_node + 5) - return G - - -def torrents_and_ferraro_graph(): - G = nx.convert_node_labels_to_integers(nx.grid_graph([5, 5]), - label_attribute='labels') - rlabels = nx.get_node_attributes(G, 'labels') - labels = {v: k for k, v in rlabels.items()} - - for nodes in [(labels[(0, 4)], labels[(1, 4)]), - (labels[(3, 4)], labels[(4, 4)])]: - new_node = G.order() + 1 - # Petersen graph is triconnected - P = nx.petersen_graph() - G = nx.disjoint_union(G, P) - # Add two edges between the grid and P - G.add_edge(new_node + 1, nodes[0]) - G.add_edge(new_node, nodes[1]) - # K5 is 4-connected - K = nx.complete_graph(5) - G = nx.disjoint_union(G, K) - # Add three edges between P and K5 - G.add_edge(new_node + 2, new_node + 11) - G.add_edge(new_node + 3, new_node + 12) - G.add_edge(new_node + 4, new_node + 13) - # Add another K5 sharing a node - G = nx.disjoint_union(G, K) - nbrs = G[new_node + 10] - G.remove_node(new_node + 10) - for nbr in nbrs: - G.add_edge(new_node + 17, nbr) - # Commenting this makes the graph not biconnected !! - # This stupid mistake make one reviewer very angry :P - G.add_edge(new_node + 16, new_node + 8) - - for nodes in [(labels[(0, 0)], labels[(1, 0)]), - (labels[(3, 0)], labels[(4, 0)])]: - new_node = G.order() + 1 - # Petersen graph is triconnected - P = nx.petersen_graph() - G = nx.disjoint_union(G, P) - # Add two edges between the grid and P - G.add_edge(new_node + 1, nodes[0]) - G.add_edge(new_node, nodes[1]) - # K5 is 4-connected - K = nx.complete_graph(5) - G = nx.disjoint_union(G, K) - # Add three edges between P and K5 - G.add_edge(new_node + 2, new_node + 11) - G.add_edge(new_node + 3, new_node + 12) - G.add_edge(new_node + 4, new_node + 13) - # Add another K5 sharing two nodes - G = nx.disjoint_union(G, K) - nbrs = G[new_node + 10] - G.remove_node(new_node + 10) - for nbr in nbrs: - G.add_edge(new_node + 17, nbr) - nbrs2 = G[new_node + 9] - G.remove_node(new_node + 9) - for nbr in nbrs2: - G.add_edge(new_node + 18, nbr) - return G - - -# Helper function -def _check_separating_sets(G): - for cc in nx.connected_components(G): - if len(cc) < 3: - continue - Gc = G.subgraph(cc) - node_conn = nx.node_connectivity(Gc) - all_cuts = nx.all_node_cuts(Gc) - # Only test a limited number of cut sets to reduce test time. - for cut in itertools.islice(all_cuts, MAX_CUTSETS_TO_TEST): - assert node_conn == len(cut) - assert not nx.is_connected(nx.restricted_view(G, cut, [])) - - -def test_torrents_and_ferraro_graph(): - G = torrents_and_ferraro_graph() - _check_separating_sets(G) - - -def test_example_1(): - G = graph_example_1() - _check_separating_sets(G) - - -def test_random_gnp(): - G = nx.gnp_random_graph(100, 0.1, seed=42) - _check_separating_sets(G) - - -def test_shell(): - constructor = [(20, 80, 0.8), (80, 180, 0.6)] - G = nx.random_shell_graph(constructor, seed=42) - _check_separating_sets(G) - - -def test_configuration(): - deg_seq = nx.random_powerlaw_tree_sequence(100, tries=5, seed=72) - G = nx.Graph(nx.configuration_model(deg_seq)) - G.remove_edges_from(nx.selfloop_edges(G)) - _check_separating_sets(G) - - -def test_karate(): - G = nx.karate_club_graph() - _check_separating_sets(G) - - -def _generate_no_biconnected(max_attempts=50): - attempts = 0 - while True: - G = nx.fast_gnp_random_graph(100, 0.0575, seed=42) - if nx.is_connected(G) and not nx.is_biconnected(G): - attempts = 0 - yield G - else: - if attempts >= max_attempts: - msg = "Tried %d times: no suitable Graph." % attempts - raise Exception(msg % max_attempts) - else: - attempts += 1 - - -def test_articulation_points(): - Ggen = _generate_no_biconnected() - for i in range(1): # change 1 to 3 or more for more realizations. - G = next(Ggen) - articulation_points = list({a} for a in nx.articulation_points(G)) - for cut in nx.all_node_cuts(G): - assert cut in articulation_points - - -def test_grid_2d_graph(): - # All minimum node cuts of a 2d grid - # are the four pairs of nodes that are - # neighbors of the four corner nodes. - G = nx.grid_2d_graph(5, 5) - solution = [ - set([(0, 1), (1, 0)]), - set([(3, 0), (4, 1)]), - set([(3, 4), (4, 3)]), - set([(0, 3), (1, 4)]), - ] - for cut in nx.all_node_cuts(G): - assert cut in solution - - -def test_disconnected_graph(): - G = nx.fast_gnp_random_graph(100, 0.01, seed=42) - cuts = nx.all_node_cuts(G) - pytest.raises(nx.NetworkXError, next, cuts) - - -def test_alternative_flow_functions(): - graphs = [nx.grid_2d_graph(4, 4), - nx.cycle_graph(5)] - for G in graphs: - node_conn = nx.node_connectivity(G) - for flow_func in flow_funcs: - all_cuts = nx.all_node_cuts(G, flow_func=flow_func) - # Only test a limited number of cut sets to reduce test time. - for cut in itertools.islice(all_cuts, MAX_CUTSETS_TO_TEST): - assert node_conn == len(cut) - assert not nx.is_connected(nx.restricted_view(G, cut, [])) - - -def test_is_separating_set_complete_graph(): - G = nx.complete_graph(5) - assert _is_separating_set(G, {0, 1, 2, 3}) - - -def test_is_separating_set(): - for i in [5, 10, 15]: - G = nx.star_graph(i) - max_degree_node = max(G, key=G.degree) - assert _is_separating_set(G, {max_degree_node}) - - -def test_non_repeated_cuts(): - # The algorithm was repeating the cut {0, 1} for the giant biconnected - # component of the Karate club graph. - K = nx.karate_club_graph() - bcc = max(list(nx.biconnected_components(K)), key=len) - G = K.subgraph(bcc) - solution = [{32, 33}, {2, 33}, {0, 3}, {0, 1}, {29, 33}] - cuts = list(nx.all_node_cuts(G)) - if len(solution) != len(cuts): - print(nx.info(G)) - print("Solution: {}".format(solution)) - print("Result: {}".format(cuts)) - assert len(solution) == len(cuts) - for cut in cuts: - assert cut in solution - - -def test_cycle_graph(): - G = nx.cycle_graph(5) - solution = [{0, 2}, {0, 3}, {1, 3}, {1, 4}, {2, 4}] - cuts = list(nx.all_node_cuts(G)) - assert len(solution) == len(cuts) - for cut in cuts: - assert cut in solution - - -def test_complete_graph(): - G = nx.complete_graph(5) - solution = [ - {0, 1, 2, 3}, - {0, 1, 2, 4}, - {0, 1, 3, 4}, - {0, 2, 3, 4}, - {1, 2, 3, 4}, - ] - cuts = list(nx.all_node_cuts(G)) - assert len(solution) == len(cuts) - for cut in cuts: - assert cut in solution diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_stoer_wagner.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_stoer_wagner.py deleted file mode 100644 index 10fa53c8..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/tests/test_stoer_wagner.py +++ /dev/null @@ -1,101 +0,0 @@ -from itertools import chain -import networkx as nx -import pytest - -def _check_partition(G, cut_value, partition, weight): - assert isinstance(partition, tuple) - assert len(partition) == 2 - assert isinstance(partition[0], list) - assert isinstance(partition[1], list) - assert len(partition[0]) > 0 - assert len(partition[1]) > 0 - assert sum(map(len, partition)) == len(G) - assert set(chain.from_iterable(partition)) == set(G) - partition = tuple(map(set, partition)) - w = 0 - for u, v, e in G.edges(data=True): - if (u in partition[0]) == (v in partition[1]): - w += e.get(weight, 1) - assert w == cut_value - - -def _test_stoer_wagner(G, answer, weight='weight'): - cut_value, partition = nx.stoer_wagner(G, weight, - heap=nx.utils.PairingHeap) - assert cut_value == answer - _check_partition(G, cut_value, partition, weight) - cut_value, partition = nx.stoer_wagner(G, weight, - heap=nx.utils.BinaryHeap) - assert cut_value == answer - _check_partition(G, cut_value, partition, weight) - - -def test_graph1(): - G = nx.Graph() - G.add_edge('x', 'a', weight=3) - G.add_edge('x', 'b', weight=1) - G.add_edge('a', 'c', weight=3) - G.add_edge('b', 'c', weight=5) - G.add_edge('b', 'd', weight=4) - G.add_edge('d', 'e', weight=2) - G.add_edge('c', 'y', weight=2) - G.add_edge('e', 'y', weight=3) - _test_stoer_wagner(G, 4) - - -def test_graph2(): - G = nx.Graph() - G.add_edge('x', 'a') - G.add_edge('x', 'b') - G.add_edge('a', 'c') - G.add_edge('b', 'c') - G.add_edge('b', 'd') - G.add_edge('d', 'e') - G.add_edge('c', 'y') - G.add_edge('e', 'y') - _test_stoer_wagner(G, 2) - - -def test_graph3(): - # Source: - # Stoer, M. and Wagner, F. (1997). "A simple min-cut algorithm". Journal of - # the ACM 44 (4), 585-591. - G = nx.Graph() - G.add_edge(1, 2, weight=2) - G.add_edge(1, 5, weight=3) - G.add_edge(2, 3, weight=3) - G.add_edge(2, 5, weight=2) - G.add_edge(2, 6, weight=2) - G.add_edge(3, 4, weight=4) - G.add_edge(3, 7, weight=2) - G.add_edge(4, 7, weight=2) - G.add_edge(4, 8, weight=2) - G.add_edge(5, 6, weight=3) - G.add_edge(6, 7, weight=1) - G.add_edge(7, 8, weight=3) - _test_stoer_wagner(G, 4) - - -def test_weight_name(): - G = nx.Graph() - G.add_edge(1, 2, weight=1, cost=8) - G.add_edge(1, 3, cost=2) - G.add_edge(2, 3, cost=4) - _test_stoer_wagner(G, 6, weight='cost') - - -def test_exceptions(): - G = nx.Graph() - pytest.raises(nx.NetworkXError, nx.stoer_wagner, G) - G.add_node(1) - pytest.raises(nx.NetworkXError, nx.stoer_wagner, G) - G.add_node(2) - pytest.raises(nx.NetworkXError, nx.stoer_wagner, G) - G.add_edge(1, 2, weight=-2) - pytest.raises(nx.NetworkXError, nx.stoer_wagner, G) - G = nx.DiGraph() - pytest.raises(nx.NetworkXNotImplemented, nx.stoer_wagner, G) - G = nx.MultiGraph() - pytest.raises(nx.NetworkXNotImplemented, nx.stoer_wagner, G) - G = nx.MultiDiGraph() - pytest.raises(nx.NetworkXNotImplemented, nx.stoer_wagner, G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/connectivity/utils.py b/extensions/fablabchemnitz/networkx/algorithms/connectivity/utils.py deleted file mode 100644 index d6582ed8..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/connectivity/utils.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Utilities for connectivity package -""" -import networkx as nx - -__author__ = '\n'.join(['Jordi Torrents ']) - -__all__ = ['build_auxiliary_node_connectivity', - 'build_auxiliary_edge_connectivity'] - - -def build_auxiliary_node_connectivity(G): - r"""Creates a directed graph D from an undirected graph G to compute flow - based node connectivity. - - For an undirected graph G having `n` nodes and `m` edges we derive a - directed graph D with `2n` nodes and `2m+n` arcs by replacing each - original node `v` with two nodes `vA`, `vB` linked by an (internal) - arc in D. Then for each edge (`u`, `v`) in G we add two arcs (`uB`, `vA`) - and (`vB`, `uA`) in D. Finally we set the attribute capacity = 1 for each - arc in D [1]_. - - For a directed graph having `n` nodes and `m` arcs we derive a - directed graph D with `2n` nodes and `m+n` arcs by replacing each - original node `v` with two nodes `vA`, `vB` linked by an (internal) - arc (`vA`, `vB`) in D. Then for each arc (`u`, `v`) in G we add one - arc (`uB`, `vA`) in D. Finally we set the attribute capacity = 1 for - each arc in D. - - A dictionary with a mapping between nodes in the original graph and the - auxiliary digraph is stored as a graph attribute: H.graph['mapping']. - - References - ---------- - .. [1] Kammer, Frank and Hanjo Taubig. Graph Connectivity. in Brandes and - Erlebach, 'Network Analysis: Methodological Foundations', Lecture - Notes in Computer Science, Volume 3418, Springer-Verlag, 2005. - http://www.informatik.uni-augsburg.de/thi/personen/kammer/Graph_Connectivity.pdf - - """ - directed = G.is_directed() - - mapping = {} - H = nx.DiGraph() - - for i, node in enumerate(G): - mapping[node] = i - H.add_node('%dA' % i, id=node) - H.add_node('%dB' % i, id=node) - H.add_edge('%dA' % i, '%dB' % i, capacity=1) - - edges = [] - for (source, target) in G.edges(): - edges.append(('%sB' % mapping[source], '%sA' % mapping[target])) - if not directed: - edges.append(('%sB' % mapping[target], '%sA' % mapping[source])) - H.add_edges_from(edges, capacity=1) - - # Store mapping as graph attribute - H.graph['mapping'] = mapping - return H - - -def build_auxiliary_edge_connectivity(G): - """Auxiliary digraph for computing flow based edge connectivity - - If the input graph is undirected, we replace each edge (`u`,`v`) with - two reciprocal arcs (`u`, `v`) and (`v`, `u`) and then we set the attribute - 'capacity' for each arc to 1. If the input graph is directed we simply - add the 'capacity' attribute. Part of algorithm 1 in [1]_ . - - References - ---------- - .. [1] Abdol-Hossein Esfahanian. Connectivity Algorithms. (this is a - chapter, look for the reference of the book). - http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf - """ - if G.is_directed(): - H = nx.DiGraph() - H.add_nodes_from(G.nodes()) - H.add_edges_from(G.edges(), capacity=1) - return H - else: - H = nx.DiGraph() - H.add_nodes_from(G.nodes()) - for (source, target) in G.edges(): - H.add_edges_from([(source, target), (target, source)], capacity=1) - return H diff --git a/extensions/fablabchemnitz/networkx/algorithms/core.py b/extensions/fablabchemnitz/networkx/algorithms/core.py deleted file mode 100644 index 22c8cbe9..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/core.py +++ /dev/null @@ -1,522 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# Antoine Allard -# All rights reserved. -# BSD license. -# -# Authors: Dan Schult (dschult@colgate.edu) -# Jason Grout (jason-sage@creativetrax.com) -# Aric Hagberg (hagberg@lanl.gov) -# Antoine Allard (antoine.allard@phy.ulaval.ca) -""" -Find the k-cores of a graph. - -The k-core is found by recursively pruning nodes with degrees less than k. - -See the following references for details: - -An O(m) Algorithm for Cores Decomposition of Networks -Vladimir Batagelj and Matjaz Zaversnik, 2003. -https://arxiv.org/abs/cs.DS/0310049 - -Generalized Cores -Vladimir Batagelj and Matjaz Zaversnik, 2002. -https://arxiv.org/pdf/cs/0202039 - -For directed graphs a more general notion is that of D-cores which -looks at (k, l) restrictions on (in, out) degree. The (k, k) D-core -is the k-core. - -D-cores: Measuring Collaboration of Directed Graphs Based on Degeneracy -Christos Giatsidis, Dimitrios M. Thilikos, Michalis Vazirgiannis, ICDM 2011. -http://www.graphdegeneracy.org/dcores_ICDM_2011.pdf - -Multi-scale structure and topological anomaly detection via a new network \ -statistic: The onion decomposition -L. Hébert-Dufresne, J. A. Grochow, and A. Allard -Scientific Reports 6, 31708 (2016) -http://doi.org/10.1038/srep31708 - -""" -import networkx as nx -from networkx.exception import NetworkXError -from networkx.utils import not_implemented_for - -__all__ = ['core_number', 'find_cores', 'k_core', 'k_shell', - 'k_crust', 'k_corona', 'k_truss', 'onion_layers'] - - -@not_implemented_for('multigraph') -def core_number(G): - """Returns the core number for each vertex. - - A k-core is a maximal subgraph that contains nodes of degree k or more. - - The core number of a node is the largest value k of a k-core containing - that node. - - Parameters - ---------- - G : NetworkX graph - A graph or directed graph - - Returns - ------- - core_number : dictionary - A dictionary keyed by node to the core number. - - Raises - ------ - NetworkXError - The k-core is not implemented for graphs with self loops - or parallel edges. - - Notes - ----- - Not implemented for graphs with parallel edges or self loops. - - For directed graphs the node degree is defined to be the - in-degree + out-degree. - - References - ---------- - .. [1] An O(m) Algorithm for Cores Decomposition of Networks - Vladimir Batagelj and Matjaz Zaversnik, 2003. - https://arxiv.org/abs/cs.DS/0310049 - """ - if nx.number_of_selfloops(G) > 0: - msg = ('Input graph has self loops which is not permitted; ' - 'Consider using G.remove_edges_from(nx.selfloop_edges(G)).') - raise NetworkXError(msg) - degrees = dict(G.degree()) - # Sort nodes by degree. - nodes = sorted(degrees, key=degrees.get) - bin_boundaries = [0] - curr_degree = 0 - for i, v in enumerate(nodes): - if degrees[v] > curr_degree: - bin_boundaries.extend([i] * (degrees[v] - curr_degree)) - curr_degree = degrees[v] - node_pos = {v: pos for pos, v in enumerate(nodes)} - # The initial guess for the core number of a node is its degree. - core = degrees - nbrs = {v: list(nx.all_neighbors(G, v)) for v in G} - for v in nodes: - for u in nbrs[v]: - if core[u] > core[v]: - nbrs[u].remove(v) - pos = node_pos[u] - bin_start = bin_boundaries[core[u]] - node_pos[u] = bin_start - node_pos[nodes[bin_start]] = pos - nodes[bin_start], nodes[pos] = nodes[pos], nodes[bin_start] - bin_boundaries[core[u]] += 1 - core[u] -= 1 - return core - - -find_cores = core_number - - -def _core_subgraph(G, k_filter, k=None, core=None): - """Returns the subgraph induced by nodes passing filter `k_filter`. - - Parameters - ---------- - G : NetworkX graph - The graph or directed graph to process - k_filter : filter function - This function filters the nodes chosen. It takes three inputs: - A node of G, the filter's cutoff, and the core dict of the graph. - The function should return a Boolean value. - k : int, optional - The order of the core. If not specified use the max core number. - This value is used as the cutoff for the filter. - core : dict, optional - Precomputed core numbers keyed by node for the graph `G`. - If not specified, the core numbers will be computed from `G`. - - """ - if core is None: - core = core_number(G) - if k is None: - k = max(core.values()) - nodes = (v for v in core if k_filter(v, k, core)) - return G.subgraph(nodes).copy() - - -def k_core(G, k=None, core_number=None): - """Returns the k-core of G. - - A k-core is a maximal subgraph that contains nodes of degree k or more. - - Parameters - ---------- - G : NetworkX graph - A graph or directed graph - k : int, optional - The order of the core. If not specified return the main core. - core_number : dictionary, optional - Precomputed core numbers for the graph G. - - Returns - ------- - G : NetworkX graph - The k-core subgraph - - Raises - ------ - NetworkXError - The k-core is not defined for graphs with self loops or parallel edges. - - Notes - ----- - The main core is the core with the largest degree. - - Not implemented for graphs with parallel edges or self loops. - - For directed graphs the node degree is defined to be the - in-degree + out-degree. - - Graph, node, and edge attributes are copied to the subgraph. - - See Also - -------- - core_number - - References - ---------- - .. [1] An O(m) Algorithm for Cores Decomposition of Networks - Vladimir Batagelj and Matjaz Zaversnik, 2003. - https://arxiv.org/abs/cs.DS/0310049 - """ - def k_filter(v, k, c): - return c[v] >= k - return _core_subgraph(G, k_filter, k, core_number) - - -def k_shell(G, k=None, core_number=None): - """Returns the k-shell of G. - - The k-shell is the subgraph induced by nodes with core number k. - That is, nodes in the k-core that are not in the (k+1)-core. - - Parameters - ---------- - G : NetworkX graph - A graph or directed graph. - k : int, optional - The order of the shell. If not specified return the outer shell. - core_number : dictionary, optional - Precomputed core numbers for the graph G. - - - Returns - ------- - G : NetworkX graph - The k-shell subgraph - - Raises - ------ - NetworkXError - The k-shell is not implemented for graphs with self loops - or parallel edges. - - Notes - ----- - This is similar to k_corona but in that case only neighbors in the - k-core are considered. - - Not implemented for graphs with parallel edges or self loops. - - For directed graphs the node degree is defined to be the - in-degree + out-degree. - - Graph, node, and edge attributes are copied to the subgraph. - - See Also - -------- - core_number - k_corona - - - References - ---------- - .. [1] A model of Internet topology using k-shell decomposition - Shai Carmi, Shlomo Havlin, Scott Kirkpatrick, Yuval Shavitt, - and Eran Shir, PNAS July 3, 2007 vol. 104 no. 27 11150-11154 - http://www.pnas.org/content/104/27/11150.full - """ - def k_filter(v, k, c): - return c[v] == k - return _core_subgraph(G, k_filter, k, core_number) - - -def k_crust(G, k=None, core_number=None): - """Returns the k-crust of G. - - The k-crust is the graph G with the k-core removed. - - Parameters - ---------- - G : NetworkX graph - A graph or directed graph. - k : int, optional - The order of the shell. If not specified return the main crust. - core_number : dictionary, optional - Precomputed core numbers for the graph G. - - Returns - ------- - G : NetworkX graph - The k-crust subgraph - - Raises - ------ - NetworkXError - The k-crust is not implemented for graphs with self loops - or parallel edges. - - Notes - ----- - This definition of k-crust is different than the definition in [1]_. - The k-crust in [1]_ is equivalent to the k+1 crust of this algorithm. - - Not implemented for graphs with parallel edges or self loops. - - For directed graphs the node degree is defined to be the - in-degree + out-degree. - - Graph, node, and edge attributes are copied to the subgraph. - - See Also - -------- - core_number - - References - ---------- - .. [1] A model of Internet topology using k-shell decomposition - Shai Carmi, Shlomo Havlin, Scott Kirkpatrick, Yuval Shavitt, - and Eran Shir, PNAS July 3, 2007 vol. 104 no. 27 11150-11154 - http://www.pnas.org/content/104/27/11150.full - """ - # Default for k is one less than in _core_subgraph, so just inline. - # Filter is c[v] <= k - if core_number is None: - core_number = find_cores(G) - if k is None: - k = max(core_number.values()) - 1 - nodes = (v for v in core_number if core_number[v] <= k) - return G.subgraph(nodes).copy() - - -def k_corona(G, k, core_number=None): - """Returns the k-corona of G. - - The k-corona is the subgraph of nodes in the k-core which have - exactly k neighbours in the k-core. - - Parameters - ---------- - G : NetworkX graph - A graph or directed graph - k : int - The order of the corona. - core_number : dictionary, optional - Precomputed core numbers for the graph G. - - Returns - ------- - G : NetworkX graph - The k-corona subgraph - - Raises - ------ - NetworkXError - The k-cornoa is not defined for graphs with self loops or - parallel edges. - - Notes - ----- - Not implemented for graphs with parallel edges or self loops. - - For directed graphs the node degree is defined to be the - in-degree + out-degree. - - Graph, node, and edge attributes are copied to the subgraph. - - See Also - -------- - core_number - - References - ---------- - .. [1] k -core (bootstrap) percolation on complex networks: - Critical phenomena and nonlocal effects, - A. V. Goltsev, S. N. Dorogovtsev, and J. F. F. Mendes, - Phys. Rev. E 73, 056101 (2006) - http://link.aps.org/doi/10.1103/PhysRevE.73.056101 - """ - def func(v, k, c): - return c[v] == k and k == sum(1 for w in G[v] if c[w] >= k) - return _core_subgraph(G, func, k, core_number) - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def k_truss(G, k): - """Returns the k-truss of `G`. - - The k-truss is the maximal subgraph of `G` which contains at least three - vertices where every edge is incident to at least `k` triangles. - - Parameters - ---------- - G : NetworkX graph - An undirected graph - k : int - The order of the truss - - Returns - ------- - H : NetworkX graph - The k-truss subgraph - - Raises - ------ - NetworkXError - - The k-truss is not defined for graphs with self loops or parallel edges - or directed graphs. - - Notes - ----- - A k-clique is a (k-2)-truss and a k-truss is a (k+1)-core. - - Not implemented for digraphs or graphs with parallel edges or self loops. - - Graph, node, and edge attributes are copied to the subgraph. - - References - ---------- - .. [1] Bounds and Algorithms for k-truss. Paul Burkhardt, Vance Faber, - David G. Harris, 2018. https://arxiv.org/abs/1806.05523v2 - .. [2] Trusses: Cohesive Subgraphs for Social Network Analysis. Jonathan - Cohen, 2005. - """ - H = G.copy() - - n_dropped = 1 - while n_dropped > 0: - n_dropped = 0 - to_drop = [] - seen = set() - for u in H: - nbrs_u = set(H[u]) - seen.add(u) - new_nbrs = [v for v in nbrs_u if v not in seen] - for v in new_nbrs: - if len(nbrs_u & set(H[v])) < k: - to_drop.append((u, v)) - H.remove_edges_from(to_drop) - n_dropped = len(to_drop) - H.remove_nodes_from(list(nx.isolates(H))) - - return H - - -@not_implemented_for('multigraph') -@not_implemented_for('directed') -def onion_layers(G): - """Returns the layer of each vertex in the onion decomposition of the graph. - - The onion decomposition refines the k-core decomposition by providing - information on the internal organization of each k-shell. It is usually - used alongside the `core numbers`. - - Parameters - ---------- - G : NetworkX graph - A simple graph without self loops or parallel edges - - Returns - ------- - od_layers : dictionary - A dictionary keyed by vertex to the onion layer. The layers are - contiguous integers starting at 1. - - Raises - ------ - NetworkXError - The onion decomposition is not implemented for graphs with self loops - or parallel edges or for directed graphs. - - Notes - ----- - Not implemented for graphs with parallel edges or self loops. - - Not implemented for directed graphs. - - See Also - -------- - core_number - - References - ---------- - .. [1] Multi-scale structure and topological anomaly detection via a new - network statistic: The onion decomposition - L. Hébert-Dufresne, J. A. Grochow, and A. Allard - Scientific Reports 6, 31708 (2016) - http://doi.org/10.1038/srep31708 - .. [2] Percolation and the effective structure of complex networks - A. Allard and L. Hébert-Dufresne - Physical Review X 9, 011023 (2019) - http://doi.org/10.1103/PhysRevX.9.011023 - """ - if nx.number_of_selfloops(G) > 0: - msg = ('Input graph contains self loops which is not permitted; ' - 'Consider using G.remove_edges_from(nx.selfloop_edges(G)).') - raise NetworkXError(msg) - # Dictionaries to register the k-core/onion decompositions. - od_layers = {} - # Adjacency list - neighbors = {v: list(nx.all_neighbors(G, v)) for v in G} - # Effective degree of nodes. - degrees = dict(G.degree()) - # Performs the onion decomposition. - current_core = 1 - current_layer = 1 - # Sets vertices of degree 0 to layer 1, if any. - isolated_nodes = [v for v in nx.isolates(G)] - if len(isolated_nodes) > 0: - for v in isolated_nodes: - od_layers[v] = current_layer - degrees.pop(v) - current_layer = 2 - # Finds the layer for the remaining nodes. - while len(degrees) > 0: - # Sets the order for looking at nodes. - nodes = sorted(degrees, key=degrees.get) - # Sets properly the current core. - min_degree = degrees[nodes[0]] - if min_degree > current_core: - current_core = min_degree - # Identifies vertices in the current layer. - this_layer = [] - for n in nodes: - if degrees[n] > current_core: - break - this_layer.append(n) - # Identifies the core/layer of the vertices in the current layer. - for v in this_layer: - od_layers[v] = current_layer - for n in neighbors[v]: - neighbors[n].remove(v) - degrees[n] = degrees[n] - 1 - degrees.pop(v) - # Updates the layer count. - current_layer = current_layer + 1 - # Returns the dictionaries containing the onion layer of each vertices. - return od_layers diff --git a/extensions/fablabchemnitz/networkx/algorithms/covering.py b/extensions/fablabchemnitz/networkx/algorithms/covering.py deleted file mode 100644 index 5c308d38..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/covering.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2016-2019 NetworkX developers. -# Copyright (C) 2016 by -# Nishant Nikhil -# All rights reserved. -# BSD license. - -""" Functions related to graph covers.""" - -import networkx as nx -from networkx.utils import not_implemented_for, arbitrary_element -from functools import partial -from itertools import chain - - -__all__ = ['min_edge_cover', 'is_edge_cover'] - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def min_edge_cover(G, matching_algorithm=None): - """Returns a set of edges which constitutes - the minimum edge cover of the graph. - - A smallest edge cover can be found in polynomial time by finding - a maximum matching and extending it greedily so that all nodes - are covered. - - Parameters - ---------- - G : NetworkX graph - An undirected bipartite graph. - - matching_algorithm : function - A function that returns a maximum cardinality matching in a - given bipartite graph. The function must take one input, the - graph ``G``, and return a dictionary mapping each node to its - mate. If not specified, - :func:`~networkx.algorithms.bipartite.matching.hopcroft_karp_matching` - will be used. Other possibilities include - :func:`~networkx.algorithms.bipartite.matching.eppstein_matching`, - or matching algorithms in the - :mod:`networkx.algorithms.matching` module. - - Returns - ------- - min_cover : set - - It contains all the edges of minimum edge cover - in form of tuples. It contains both the edges `(u, v)` and `(v, u)` - for given nodes `u` and `v` among the edges of minimum edge cover. - - Notes - ----- - An edge cover of a graph is a set of edges such that every node of - the graph is incident to at least one edge of the set. - The minimum edge cover is an edge covering of smallest cardinality. - - Due to its implementation, the worst-case running time of this algorithm - is bounded by the worst-case running time of the function - ``matching_algorithm``. - - Minimum edge cover for bipartite graph can also be found using the - function present in :mod:`networkx.algorithms.bipartite.covering` - """ - if nx.number_of_isolates(G) > 0: - # ``min_cover`` does not exist as there is an isolated node - raise nx.NetworkXException( - "Graph has a node with no edge incident on it, " - "so no edge cover exists.") - if matching_algorithm is None: - matching_algorithm = partial(nx.max_weight_matching, - maxcardinality=True) - maximum_matching = matching_algorithm(G) - # ``min_cover`` is superset of ``maximum_matching`` - try: - min_cover = set(maximum_matching.items()) # bipartite matching case returns dict - except AttributeError: - min_cover = maximum_matching - # iterate for uncovered nodes - uncovered_nodes = set(G) - {v for u, v in min_cover} - {u for u, v in min_cover} - for v in uncovered_nodes: - # Since `v` is uncovered, each edge incident to `v` will join it - # with a covered node (otherwise, if there were an edge joining - # uncovered nodes `u` and `v`, the maximum matching algorithm - # would have found it), so we can choose an arbitrary edge - # incident to `v`. (This applies only in a simple graph, not a - # multigraph.) - u = arbitrary_element(G[v]) - min_cover.add((u, v)) - min_cover.add((v, u)) - return min_cover - - -@not_implemented_for('directed') -def is_edge_cover(G, cover): - """Decides whether a set of edges is a valid edge cover of the graph. - - Given a set of edges, whether it is an edge covering can - be decided if we just check whether all nodes of the graph - has an edge from the set, incident on it. - - Parameters - ---------- - G : NetworkX graph - An undirected bipartite graph. - - cover : set - Set of edges to be checked. - - Returns - ------- - bool - Whether the set of edges is a valid edge cover of the graph. - - Notes - ----- - An edge cover of a graph is a set of edges such that every node of - the graph is incident to at least one edge of the set. - """ - return set(G) <= set(chain.from_iterable(cover)) diff --git a/extensions/fablabchemnitz/networkx/algorithms/cuts.py b/extensions/fablabchemnitz/networkx/algorithms/cuts.py deleted file mode 100644 index 86553b4d..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/cuts.py +++ /dev/null @@ -1,395 +0,0 @@ -# -*- coding: utf-8 -*- -# cuts.py - functions for computing and evaluating cuts -# -# Copyright 2011 Ben Edwards . -# Copyright 2011 Aric Hagberg . -# Copyright 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Functions for finding and evaluating cuts in a graph. - -""" - -from itertools import chain - -import networkx as nx - -__all__ = ['boundary_expansion', 'conductance', 'cut_size', 'edge_expansion', - 'mixing_expansion', 'node_expansion', 'normalized_cut_size', - 'volume'] - - -# TODO STILL NEED TO UPDATE ALL THE DOCUMENTATION! - -def cut_size(G, S, T=None, weight=None): - """Returns the size of the cut between two sets of nodes. - - A *cut* is a partition of the nodes of a graph into two sets. The - *cut size* is the sum of the weights of the edges "between" the two - sets of nodes. - - Parameters - ---------- - G : NetworkX graph - - S : sequence - A sequence of nodes in `G`. - - T : sequence - A sequence of nodes in `G`. If not specified, this is taken to - be the set complement of `S`. - - weight : object - Edge attribute key to use as weight. If not specified, edges - have weight one. - - Returns - ------- - number - Total weight of all edges from nodes in set `S` to nodes in - set `T` (and, in the case of directed graphs, all edges from - nodes in `T` to nodes in `S`). - - Examples - -------- - In the graph with two cliques joined by a single edges, the natural - bipartition of the graph into two blocks, one for each clique, - yields a cut of weight one:: - - >>> G = nx.barbell_graph(3, 0) - >>> S = {0, 1, 2} - >>> T = {3, 4, 5} - >>> nx.cut_size(G, S, T) - 1 - - Each parallel edge in a multigraph is counted when determining the - cut size:: - - >>> G = nx.MultiGraph(['ab', 'ab']) - >>> S = {'a'} - >>> T = {'b'} - >>> nx.cut_size(G, S, T) - 2 - - Notes - ----- - In a multigraph, the cut size is the total weight of edges including - multiplicity. - - """ - edges = nx.edge_boundary(G, S, T, data=weight, default=1) - if G.is_directed(): - edges = chain(edges, nx.edge_boundary(G, T, S, data=weight, default=1)) - return sum(weight for u, v, weight in edges) - - -def volume(G, S, weight=None): - """Returns the volume of a set of nodes. - - The *volume* of a set *S* is the sum of the (out-)degrees of nodes - in *S* (taking into account parallel edges in multigraphs). [1] - - Parameters - ---------- - G : NetworkX graph - - S : sequence - A sequence of nodes in `G`. - - weight : object - Edge attribute key to use as weight. If not specified, edges - have weight one. - - Returns - ------- - number - The volume of the set of nodes represented by `S` in the graph - `G`. - - See also - -------- - conductance - cut_size - edge_expansion - edge_boundary - normalized_cut_size - - References - ---------- - .. [1] David Gleich. - *Hierarchical Directed Spectral Graph Partitioning*. - - - """ - degree = G.out_degree if G.is_directed() else G.degree - return sum(d for v, d in degree(S, weight=weight)) - - -def normalized_cut_size(G, S, T=None, weight=None): - """Returns the normalized size of the cut between two sets of nodes. - - The *normalized cut size* is the cut size times the sum of the - reciprocal sizes of the volumes of the two sets. [1] - - Parameters - ---------- - G : NetworkX graph - - S : sequence - A sequence of nodes in `G`. - - T : sequence - A sequence of nodes in `G`. - - weight : object - Edge attribute key to use as weight. If not specified, edges - have weight one. - - Returns - ------- - number - The normalized cut size between the two sets `S` and `T`. - - Notes - ----- - In a multigraph, the cut size is the total weight of edges including - multiplicity. - - See also - -------- - conductance - cut_size - edge_expansion - volume - - References - ---------- - .. [1] David Gleich. - *Hierarchical Directed Spectral Graph Partitioning*. - - - """ - if T is None: - T = set(G) - set(S) - num_cut_edges = cut_size(G, S, T=T, weight=weight) - volume_S = volume(G, S, weight=weight) - volume_T = volume(G, T, weight=weight) - return num_cut_edges * ((1 / volume_S) + (1 / volume_T)) - - -def conductance(G, S, T=None, weight=None): - """Returns the conductance of two sets of nodes. - - The *conductance* is the quotient of the cut size and the smaller of - the volumes of the two sets. [1] - - Parameters - ---------- - G : NetworkX graph - - S : sequence - A sequence of nodes in `G`. - - T : sequence - A sequence of nodes in `G`. - - weight : object - Edge attribute key to use as weight. If not specified, edges - have weight one. - - Returns - ------- - number - The conductance between the two sets `S` and `T`. - - See also - -------- - cut_size - edge_expansion - normalized_cut_size - volume - - References - ---------- - .. [1] David Gleich. - *Hierarchical Directed Spectral Graph Partitioning*. - - - """ - if T is None: - T = set(G) - set(S) - num_cut_edges = cut_size(G, S, T, weight=weight) - volume_S = volume(G, S, weight=weight) - volume_T = volume(G, T, weight=weight) - return num_cut_edges / min(volume_S, volume_T) - - -def edge_expansion(G, S, T=None, weight=None): - """Returns the edge expansion between two node sets. - - The *edge expansion* is the quotient of the cut size and the smaller - of the cardinalities of the two sets. [1] - - Parameters - ---------- - G : NetworkX graph - - S : sequence - A sequence of nodes in `G`. - - T : sequence - A sequence of nodes in `G`. - - weight : object - Edge attribute key to use as weight. If not specified, edges - have weight one. - - Returns - ------- - number - The edge expansion between the two sets `S` and `T`. - - See also - -------- - boundary_expansion - mixing_expansion - node_expansion - - References - ---------- - .. [1] Fan Chung. - *Spectral Graph Theory*. - (CBMS Regional Conference Series in Mathematics, No. 92), - American Mathematical Society, 1997, ISBN 0-8218-0315-8 - - - """ - if T is None: - T = set(G) - set(S) - num_cut_edges = cut_size(G, S, T=T, weight=weight) - return num_cut_edges / min(len(S), len(T)) - - -def mixing_expansion(G, S, T=None, weight=None): - """Returns the mixing expansion between two node sets. - - The *mixing expansion* is the quotient of the cut size and twice the - number of edges in the graph. [1] - - Parameters - ---------- - G : NetworkX graph - - S : sequence - A sequence of nodes in `G`. - - T : sequence - A sequence of nodes in `G`. - - weight : object - Edge attribute key to use as weight. If not specified, edges - have weight one. - - Returns - ------- - number - The mixing expansion between the two sets `S` and `T`. - - See also - -------- - boundary_expansion - edge_expansion - node_expansion - - References - ---------- - .. [1] Vadhan, Salil P. - "Pseudorandomness." - *Foundations and Trends - in Theoretical Computer Science* 7.1–3 (2011): 1–336. - - - """ - num_cut_edges = cut_size(G, S, T=T, weight=weight) - num_total_edges = G.number_of_edges() - return num_cut_edges / (2 * num_total_edges) - - -# TODO What is the generalization to two arguments, S and T? Does the -# denominator become `min(len(S), len(T))`? -def node_expansion(G, S): - """Returns the node expansion of the set `S`. - - The *node expansion* is the quotient of the size of the node - boundary of *S* and the cardinality of *S*. [1] - - Parameters - ---------- - G : NetworkX graph - - S : sequence - A sequence of nodes in `G`. - - Returns - ------- - number - The node expansion of the set `S`. - - See also - -------- - boundary_expansion - edge_expansion - mixing_expansion - - References - ---------- - .. [1] Vadhan, Salil P. - "Pseudorandomness." - *Foundations and Trends - in Theoretical Computer Science* 7.1–3 (2011): 1–336. - - - """ - neighborhood = set(chain.from_iterable(G.neighbors(v) for v in S)) - return len(neighborhood) / len(S) - - -# TODO What is the generalization to two arguments, S and T? Does the -# denominator become `min(len(S), len(T))`? -def boundary_expansion(G, S): - """Returns the boundary expansion of the set `S`. - - The *boundary expansion* is the quotient of the size of the edge - boundary and the cardinality of *S*. [1] - - Parameters - ---------- - G : NetworkX graph - - S : sequence - A sequence of nodes in `G`. - - Returns - ------- - number - The boundary expansion of the set `S`. - - See also - -------- - edge_expansion - mixing_expansion - node_expansion - - References - ---------- - .. [1] Vadhan, Salil P. - "Pseudorandomness." - *Foundations and Trends in Theoretical Computer Science* - 7.1–3 (2011): 1–336. - - - """ - return len(nx.node_boundary(G, S)) / len(S) diff --git a/extensions/fablabchemnitz/networkx/algorithms/cycles.py b/extensions/fablabchemnitz/networkx/algorithms/cycles.py deleted file mode 100644 index 77d78baa..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/cycles.py +++ /dev/null @@ -1,624 +0,0 @@ -# Copyright (C) 2010-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Jon Olav Vik -# Dan Schult -# Aric Hagberg -# Debsankha Manik -""" -======================== -Cycle finding algorithms -======================== -""" - -from collections import defaultdict -from itertools import tee - -import networkx as nx -from networkx.utils import not_implemented_for, pairwise - -__all__ = [ - 'cycle_basis', 'simple_cycles', - 'recursive_simple_cycles', 'find_cycle', - 'minimum_cycle_basis', -] - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def cycle_basis(G, root=None): - """ Returns a list of cycles which form a basis for cycles of G. - - A basis for cycles of a network is a minimal collection of - cycles such that any cycle in the network can be written - as a sum of cycles in the basis. Here summation of cycles - is defined as "exclusive or" of the edges. Cycle bases are - useful, e.g. when deriving equations for electric circuits - using Kirchhoff's Laws. - - Parameters - ---------- - G : NetworkX Graph - root : node, optional - Specify starting node for basis. - - Returns - ------- - A list of cycle lists. Each cycle list is a list of nodes - which forms a cycle (loop) in G. - - Examples - -------- - >>> G = nx.Graph() - >>> nx.add_cycle(G, [0, 1, 2, 3]) - >>> nx.add_cycle(G, [0, 3, 4, 5]) - >>> print(nx.cycle_basis(G, 0)) - [[3, 4, 5, 0], [1, 2, 3, 0]] - - Notes - ----- - This is adapted from algorithm CACM 491 [1]_. - - References - ---------- - .. [1] Paton, K. An algorithm for finding a fundamental set of - cycles of a graph. Comm. ACM 12, 9 (Sept 1969), 514-518. - - See Also - -------- - simple_cycles - """ - gnodes = set(G.nodes()) - cycles = [] - while gnodes: # loop over connected components - if root is None: - root = gnodes.pop() - stack = [root] - pred = {root: root} - used = {root: set()} - while stack: # walk the spanning tree finding cycles - z = stack.pop() # use last-in so cycles easier to find - zused = used[z] - for nbr in G[z]: - if nbr not in used: # new node - pred[nbr] = z - stack.append(nbr) - used[nbr] = set([z]) - elif nbr == z: # self loops - cycles.append([z]) - elif nbr not in zused: # found a cycle - pn = used[nbr] - cycle = [nbr, z] - p = pred[z] - while p not in pn: - cycle.append(p) - p = pred[p] - cycle.append(p) - cycles.append(cycle) - used[nbr].add(z) - gnodes -= set(pred) - root = None - return cycles - - -@not_implemented_for('undirected') -def simple_cycles(G): - """Find simple cycles (elementary circuits) of a directed graph. - - A `simple cycle`, or `elementary circuit`, is a closed path where - no node appears twice. Two elementary circuits are distinct if they - are not cyclic permutations of each other. - - This is a nonrecursive, iterator/generator version of Johnson's - algorithm [1]_. There may be better algorithms for some cases [2]_ [3]_. - - Parameters - ---------- - G : NetworkX DiGraph - A directed graph - - Returns - ------- - cycle_generator: generator - A generator that produces elementary cycles of the graph. - Each cycle is represented by a list of nodes along the cycle. - - Examples - -------- - >>> edges = [(0, 0), (0, 1), (0, 2), (1, 2), (2, 0), (2, 1), (2, 2)] - >>> G = nx.DiGraph(edges) - >>> len(list(nx.simple_cycles(G))) - 5 - - To filter the cycles so that they don't include certain nodes or edges, - copy your graph and eliminate those nodes or edges before calling - - >>> copyG = G.copy() - >>> copyG.remove_nodes_from([1]) - >>> copyG.remove_edges_from([(0, 1)]) - >>> len(list(nx.simple_cycles(copyG))) - 3 - - - Notes - ----- - The implementation follows pp. 79-80 in [1]_. - - The time complexity is $O((n+e)(c+1))$ for $n$ nodes, $e$ edges and $c$ - elementary circuits. - - References - ---------- - .. [1] Finding all the elementary circuits of a directed graph. - D. B. Johnson, SIAM Journal on Computing 4, no. 1, 77-84, 1975. - https://doi.org/10.1137/0204007 - .. [2] Enumerating the cycles of a digraph: a new preprocessing strategy. - G. Loizou and P. Thanish, Information Sciences, v. 27, 163-182, 1982. - .. [3] A search strategy for the elementary cycles of a directed graph. - J.L. Szwarcfiter and P.E. Lauer, BIT NUMERICAL MATHEMATICS, - v. 16, no. 2, 192-204, 1976. - - See Also - -------- - cycle_basis - """ - def _unblock(thisnode, blocked, B): - stack = set([thisnode]) - while stack: - node = stack.pop() - if node in blocked: - blocked.remove(node) - stack.update(B[node]) - B[node].clear() - - # Johnson's algorithm requires some ordering of the nodes. - # We assign the arbitrary ordering given by the strongly connected comps - # There is no need to track the ordering as each node removed as processed. - # Also we save the actual graph so we can mutate it. We only take the - # edges because we do not want to copy edge and node attributes here. - subG = type(G)(G.edges()) - sccs = [scc for scc in nx.strongly_connected_components(subG) - if len(scc) > 1] - - # Johnson's algorithm exclude self cycle edges like (v, v) - # To be backward compatible, we record those cycles in advance - # and then remove from subG - for v in subG: - if subG.has_edge(v, v): - yield [v] - subG.remove_edge(v, v) - - while sccs: - scc = sccs.pop() - sccG = subG.subgraph(scc) - # order of scc determines ordering of nodes - startnode = scc.pop() - # Processing node runs "circuit" routine from recursive version - path = [startnode] - blocked = set() # vertex: blocked from search? - closed = set() # nodes involved in a cycle - blocked.add(startnode) - B = defaultdict(set) # graph portions that yield no elementary circuit - stack = [(startnode, list(sccG[startnode]))] # sccG gives comp nbrs - while stack: - thisnode, nbrs = stack[-1] - if nbrs: - nextnode = nbrs.pop() - if nextnode == startnode: - yield path[:] - closed.update(path) -# print "Found a cycle", path, closed - elif nextnode not in blocked: - path.append(nextnode) - stack.append((nextnode, list(sccG[nextnode]))) - closed.discard(nextnode) - blocked.add(nextnode) - continue - # done with nextnode... look for more neighbors - if not nbrs: # no more nbrs - if thisnode in closed: - _unblock(thisnode, blocked, B) - else: - for nbr in sccG[thisnode]: - if thisnode not in B[nbr]: - B[nbr].add(thisnode) - stack.pop() -# assert path[-1] == thisnode - path.pop() - # done processing this node - H = subG.subgraph(scc) # make smaller to avoid work in SCC routine - sccs.extend(scc for scc in nx.strongly_connected_components(H) - if len(scc) > 1) - - -@not_implemented_for('undirected') -def recursive_simple_cycles(G): - """Find simple cycles (elementary circuits) of a directed graph. - - A `simple cycle`, or `elementary circuit`, is a closed path where - no node appears twice. Two elementary circuits are distinct if they - are not cyclic permutations of each other. - - This version uses a recursive algorithm to build a list of cycles. - You should probably use the iterator version called simple_cycles(). - Warning: This recursive version uses lots of RAM! - - Parameters - ---------- - G : NetworkX DiGraph - A directed graph - - Returns - ------- - A list of cycles, where each cycle is represented by a list of nodes - along the cycle. - - Example: - - >>> edges = [(0, 0), (0, 1), (0, 2), (1, 2), (2, 0), (2, 1), (2, 2)] - >>> G = nx.DiGraph(edges) - >>> nx.recursive_simple_cycles(G) - [[0], [2], [0, 1, 2], [0, 2], [1, 2]] - - See Also - -------- - cycle_basis (for undirected graphs) - - Notes - ----- - The implementation follows pp. 79-80 in [1]_. - - The time complexity is $O((n+e)(c+1))$ for $n$ nodes, $e$ edges and $c$ - elementary circuits. - - References - ---------- - .. [1] Finding all the elementary circuits of a directed graph. - D. B. Johnson, SIAM Journal on Computing 4, no. 1, 77-84, 1975. - https://doi.org/10.1137/0204007 - - See Also - -------- - simple_cycles, cycle_basis - """ - # Jon Olav Vik, 2010-08-09 - def _unblock(thisnode): - """Recursively unblock and remove nodes from B[thisnode].""" - if blocked[thisnode]: - blocked[thisnode] = False - while B[thisnode]: - _unblock(B[thisnode].pop()) - - def circuit(thisnode, startnode, component): - closed = False # set to True if elementary path is closed - path.append(thisnode) - blocked[thisnode] = True - for nextnode in component[thisnode]: # direct successors of thisnode - if nextnode == startnode: - result.append(path[:]) - closed = True - elif not blocked[nextnode]: - if circuit(nextnode, startnode, component): - closed = True - if closed: - _unblock(thisnode) - else: - for nextnode in component[thisnode]: - if thisnode not in B[nextnode]: # TODO: use set for speedup? - B[nextnode].append(thisnode) - path.pop() # remove thisnode from path - return closed - - path = [] # stack of nodes in current path - blocked = defaultdict(bool) # vertex: blocked from search? - B = defaultdict(list) # graph portions that yield no elementary circuit - result = [] # list to accumulate the circuits found - - # Johnson's algorithm exclude self cycle edges like (v, v) - # To be backward compatible, we record those cycles in advance - # and then remove from subG - for v in G: - if G.has_edge(v, v): - result.append([v]) - G.remove_edge(v, v) - - # Johnson's algorithm requires some ordering of the nodes. - # They might not be sortable so we assign an arbitrary ordering. - ordering = dict(zip(G, range(len(G)))) - for s in ordering: - # Build the subgraph induced by s and following nodes in the ordering - subgraph = G.subgraph(node for node in G - if ordering[node] >= ordering[s]) - # Find the strongly connected component in the subgraph - # that contains the least node according to the ordering - strongcomp = nx.strongly_connected_components(subgraph) - mincomp = min(strongcomp, key=lambda ns: min(ordering[n] for n in ns)) - component = G.subgraph(mincomp) - if len(component) > 1: - # smallest node in the component according to the ordering - startnode = min(component, key=ordering.__getitem__) - for node in component: - blocked[node] = False - B[node][:] = [] - dummy = circuit(startnode, startnode, component) - return result - - -def find_cycle(G, source=None, orientation=None): - """Returns a cycle found via depth-first traversal. - - The cycle is a list of edges indicating the cyclic path. - Orientation of directed edges is controlled by `orientation`. - - Parameters - ---------- - G : graph - A directed/undirected graph/multigraph. - - source : node, list of nodes - The node from which the traversal begins. If None, then a source - is chosen arbitrarily and repeatedly until all edges from each node in - the graph are searched. - - orientation : None | 'original' | 'reverse' | 'ignore' (default: None) - For directed graphs and directed multigraphs, edge traversals need not - respect the original orientation of the edges. - When set to 'reverse' every edge is traversed in the reverse direction. - When set to 'ignore', every edge is treated as undirected. - When set to 'original', every edge is treated as directed. - In all three cases, the yielded edge tuples add a last entry to - indicate the direction in which that edge was traversed. - If orientation is None, the yielded edge has no direction indicated. - The direction is respected, but not reported. - - Returns - ------- - edges : directed edges - A list of directed edges indicating the path taken for the loop. - If no cycle is found, then an exception is raised. - For graphs, an edge is of the form `(u, v)` where `u` and `v` - are the tail and head of the edge as determined by the traversal. - For multigraphs, an edge is of the form `(u, v, key)`, where `key` is - the key of the edge. When the graph is directed, then `u` and `v` - are always in the order of the actual directed edge. - If orientation is not None then the edge tuple is extended to include - the direction of traversal ('forward' or 'reverse') on that edge. - - Raises - ------ - NetworkXNoCycle - If no cycle was found. - - Examples - -------- - In this example, we construct a DAG and find, in the first call, that there - are no directed cycles, and so an exception is raised. In the second call, - we ignore edge orientations and find that there is an undirected cycle. - Note that the second call finds a directed cycle while effectively - traversing an undirected graph, and so, we found an "undirected cycle". - This means that this DAG structure does not form a directed tree (which - is also known as a polytree). - - >>> import networkx as nx - >>> G = nx.DiGraph([(0, 1), (0, 2), (1, 2)]) - >>> try: - ... nx.find_cycle(G, orientation='original') - ... except: - ... pass - ... - >>> list(nx.find_cycle(G, orientation='ignore')) - [(0, 1, 'forward'), (1, 2, 'forward'), (0, 2, 'reverse')] - - """ - if not G.is_directed() or orientation in (None, 'original'): - def tailhead(edge): - return edge[:2] - elif orientation == 'reverse': - def tailhead(edge): - return edge[1], edge[0] - elif orientation == 'ignore': - def tailhead(edge): - if edge[-1] == 'reverse': - return edge[1], edge[0] - return edge[:2] - - explored = set() - cycle = [] - final_node = None - for start_node in G.nbunch_iter(source): - if start_node in explored: - # No loop is possible. - continue - - edges = [] - # All nodes seen in this iteration of edge_dfs - seen = {start_node} - # Nodes in active path. - active_nodes = {start_node} - previous_head = None - - for edge in nx.edge_dfs(G, start_node, orientation): - # Determine if this edge is a continuation of the active path. - tail, head = tailhead(edge) - if head in explored: - # Then we've already explored it. No loop is possible. - continue - if previous_head is not None and tail != previous_head: - # This edge results from backtracking. - # Pop until we get a node whose head equals the current tail. - # So for example, we might have: - # (0, 1), (1, 2), (2, 3), (1, 4) - # which must become: - # (0, 1), (1, 4) - while True: - try: - popped_edge = edges.pop() - except IndexError: - edges = [] - active_nodes = {tail} - break - else: - popped_head = tailhead(popped_edge)[1] - active_nodes.remove(popped_head) - - if edges: - last_head = tailhead(edges[-1])[1] - if tail == last_head: - break - edges.append(edge) - - if head in active_nodes: - # We have a loop! - cycle.extend(edges) - final_node = head - break - else: - seen.add(head) - active_nodes.add(head) - previous_head = head - - if cycle: - break - else: - explored.update(seen) - - else: - assert(len(cycle) == 0) - raise nx.exception.NetworkXNoCycle('No cycle found.') - - # We now have a list of edges which ends on a cycle. - # So we need to remove from the beginning edges that are not relevant. - - for i, edge in enumerate(cycle): - tail, head = tailhead(edge) - if tail == final_node: - break - - return cycle[i:] - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def minimum_cycle_basis(G, weight=None): - """ Returns a minimum weight cycle basis for G - - Minimum weight means a cycle basis for which the total weight - (length for unweighted graphs) of all the cycles is minimum. - - Parameters - ---------- - G : NetworkX Graph - weight: string - name of the edge attribute to use for edge weights - - Returns - ------- - A list of cycle lists. Each cycle list is a list of nodes - which forms a cycle (loop) in G. Note that the nodes are not - necessarily returned in a order by which they appear in the cycle - - Examples - -------- - >>> G=nx.Graph() - >>> nx.add_cycle(G, [0,1,2,3]) - >>> nx.add_cycle(G, [0,3,4,5]) - >>> print([sorted(c) for c in nx.minimum_cycle_basis(G)]) - [[0, 1, 2, 3], [0, 3, 4, 5]] - - References: - [1] Kavitha, Telikepalli, et al. "An O(m^2n) Algorithm for - Minimum Cycle Basis of Graphs." - http://link.springer.com/article/10.1007/s00453-007-9064-z - [2] de Pina, J. 1995. Applications of shortest path methods. - Ph.D. thesis, University of Amsterdam, Netherlands - - See Also - -------- - simple_cycles, cycle_basis - """ - # We first split the graph in commected subgraphs - return sum((_min_cycle_basis(G.subgraph(c), weight) for c in - nx.connected_components(G)), []) - - -def _min_cycle_basis(comp, weight): - cb = [] - # We extract the edges not in a spanning tree. We do not really need a - # *minimum* spanning tree. That is why we call the next function with - # weight=None. Depending on implementation, it may be faster as well - spanning_tree_edges = list(nx.minimum_spanning_edges(comp, weight=None, - data=False)) - edges_excl = [frozenset(e) for e in comp.edges() - if e not in spanning_tree_edges] - N = len(edges_excl) - - # We maintain a set of vectors orthogonal to sofar found cycles - set_orth = [set([edge]) for edge in edges_excl] - for k in range(N): - # kth cycle is "parallel" to kth vector in set_orth - new_cycle = _min_cycle(comp, set_orth[k], weight=weight) - cb.append(list(set().union(*new_cycle))) - # now update set_orth so that k+1,k+2... th elements are - # orthogonal to the newly found cycle, as per [p. 336, 1] - base = set_orth[k] - set_orth[k + 1:] = [orth ^ base if len(orth & new_cycle) % 2 else orth - for orth in set_orth[k + 1:]] - return cb - - -def _min_cycle(G, orth, weight=None): - """ - Computes the minimum weight cycle in G, - orthogonal to the vector orth as per [p. 338, 1] - """ - T = nx.Graph() - - nodes_idx = {node: idx for idx, node in enumerate(G.nodes())} - idx_nodes = {idx: node for node, idx in nodes_idx.items()} - - nnodes = len(nodes_idx) - - # Add 2 copies of each edge in G to T. If edge is in orth, add cross edge; - # otherwise in-plane edge - for u, v, data in G.edges(data=True): - uidx, vidx = nodes_idx[u], nodes_idx[v] - edge_w = data.get(weight, 1) - if frozenset((u, v)) in orth: - T.add_edges_from( - [(uidx, nnodes + vidx), (nnodes + uidx, vidx)], weight=edge_w) - else: - T.add_edges_from( - [(uidx, vidx), (nnodes + uidx, nnodes + vidx)], weight=edge_w) - - all_shortest_pathlens = dict(nx.shortest_path_length(T, weight=weight)) - cross_paths_w_lens = {n: all_shortest_pathlens[n][nnodes + n] - for n in range(nnodes)} - - # Now compute shortest paths in T, which translates to cyles in G - start = min(cross_paths_w_lens, key=cross_paths_w_lens.get) - end = nnodes + start - min_path = nx.shortest_path(T, source=start, target=end, weight='weight') - - # Now we obtain the actual path, re-map nodes in T to those in G - min_path_nodes = [node if node < nnodes else node - nnodes - for node in min_path] - # Now remove the edges that occur two times - mcycle_pruned = _path_to_cycle(min_path_nodes) - - return {frozenset((idx_nodes[u], idx_nodes[v])) for u, v in mcycle_pruned} - - -def _path_to_cycle(path): - """ - Removes the edges from path that occur even number of times. - Returns a set of edges - """ - edges = set() - for edge in pairwise(path): - # Toggle whether to keep the current edge. - edges ^= {edge} - return edges diff --git a/extensions/fablabchemnitz/networkx/algorithms/dag.py b/extensions/fablabchemnitz/networkx/algorithms/dag.py deleted file mode 100644 index 22ea10f9..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/dag.py +++ /dev/null @@ -1,919 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2006-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: -# Aric Hagberg -# Dan Schult -# Ben Edwards -# Neil Girdhar -# -"""Algorithms for directed acyclic graphs (DAGs). - -Note that most of these functions are only guaranteed to work for DAGs. -In general, these functions do not check for acyclic-ness, so it is up -to the user to check for that. -""" - -from collections import defaultdict, deque -from math import gcd -from functools import partial -from itertools import chain -from itertools import product -from itertools import starmap -import heapq - -import networkx as nx -from networkx.algorithms.traversal.breadth_first_search import \ - descendants_at_distance -from networkx.generators.trees import NIL -from networkx.utils import arbitrary_element -from networkx.utils import consume -from networkx.utils import pairwise -from networkx.utils import not_implemented_for - -__all__ = ['descendants', - 'ancestors', - 'topological_sort', - 'lexicographical_topological_sort', - 'all_topological_sorts', - 'is_directed_acyclic_graph', - 'is_aperiodic', - 'transitive_closure', - 'transitive_closure_dag', - 'transitive_reduction', - 'antichains', - 'dag_longest_path', - 'dag_longest_path_length', - 'dag_to_branching'] - -chaini = chain.from_iterable - - -def descendants(G, source): - """Returns all nodes reachable from `source` in `G`. - - Parameters - ---------- - G : NetworkX DiGraph - A directed acyclic graph (DAG) - source : node in `G` - - Returns - ------- - set() - The descendants of `source` in `G` - """ - if not G.has_node(source): - raise nx.NetworkXError("The node %s is not in the graph." % source) - des = set(n for n, d in nx.shortest_path_length(G, source=source).items()) - return des - {source} - - -def ancestors(G, source): - """Returns all nodes having a path to `source` in `G`. - - Parameters - ---------- - G : NetworkX DiGraph - A directed acyclic graph (DAG) - source : node in `G` - - Returns - ------- - set() - The ancestors of source in G - """ - if not G.has_node(source): - raise nx.NetworkXError("The node %s is not in the graph." % source) - anc = set(n for n, d in nx.shortest_path_length(G, target=source).items()) - return anc - {source} - - -def has_cycle(G): - """Decides whether the directed graph has a cycle.""" - try: - consume(topological_sort(G)) - except nx.NetworkXUnfeasible: - return True - else: - return False - - -def is_directed_acyclic_graph(G): - """Returns True if the graph `G` is a directed acyclic graph (DAG) or - False if not. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - bool - True if `G` is a DAG, False otherwise - """ - return G.is_directed() and not has_cycle(G) - - -def topological_sort(G): - """Returns a generator of nodes in topologically sorted order. - - A topological sort is a nonunique permutation of the nodes such that an - edge from u to v implies that u appears before v in the topological sort - order. - - Parameters - ---------- - G : NetworkX digraph - A directed acyclic graph (DAG) - - Returns - ------- - iterable - An iterable of node names in topological sorted order. - - Raises - ------ - NetworkXError - Topological sort is defined for directed graphs only. If the graph `G` - is undirected, a :exc:`NetworkXError` is raised. - - NetworkXUnfeasible - If `G` is not a directed acyclic graph (DAG) no topological sort exists - and a :exc:`NetworkXUnfeasible` exception is raised. This can also be - raised if `G` is changed while the returned iterator is being processed - - RuntimeError - If `G` is changed while the returned iterator is being processed. - - Examples - -------- - To get the reverse order of the topological sort: - - >>> DG = nx.DiGraph([(1, 2), (2, 3)]) - >>> list(reversed(list(nx.topological_sort(DG)))) - [3, 2, 1] - - If your DiGraph naturally has the edges representing tasks/inputs - and nodes representing people/processes that initiate tasks, then - topological_sort is not quite what you need. You will have to change - the tasks to nodes with dependence reflected by edges. The result is - a kind of topological sort of the edges. This can be done - with :func:`networkx.line_graph` as follows: - - >>> list(nx.topological_sort(nx.line_graph(DG))) - [(1, 2), (2, 3)] - - Notes - ----- - This algorithm is based on a description and proof in - "Introduction to Algorithms: A Creative Approach" [1]_ . - - See also - -------- - is_directed_acyclic_graph, lexicographical_topological_sort - - References - ---------- - .. [1] Manber, U. (1989). - *Introduction to Algorithms - A Creative Approach.* Addison-Wesley. - """ - if not G.is_directed(): - raise nx.NetworkXError( - "Topological sort not defined on undirected graphs.") - - indegree_map = {v: d for v, d in G.in_degree() if d > 0} - # These nodes have zero indegree and ready to be returned. - zero_indegree = [v for v, d in G.in_degree() if d == 0] - - while zero_indegree: - node = zero_indegree.pop() - if node not in G: - raise RuntimeError("Graph changed during iteration") - for _, child in G.edges(node): - try: - indegree_map[child] -= 1 - except KeyError: - raise RuntimeError("Graph changed during iteration") - if indegree_map[child] == 0: - zero_indegree.append(child) - del indegree_map[child] - - yield node - - if indegree_map: - raise nx.NetworkXUnfeasible("Graph contains a cycle or graph changed " - "during iteration") - - -def lexicographical_topological_sort(G, key=None): - """Returns a generator of nodes in lexicographically topologically sorted - order. - - A topological sort is a nonunique permutation of the nodes such that an - edge from u to v implies that u appears before v in the topological sort - order. - - Parameters - ---------- - G : NetworkX digraph - A directed acyclic graph (DAG) - - key : function, optional - This function maps nodes to keys with which to resolve ambiguities in - the sort order. Defaults to the identity function. - - Returns - ------- - iterable - An iterable of node names in lexicographical topological sort order. - - Raises - ------ - NetworkXError - Topological sort is defined for directed graphs only. If the graph `G` - is undirected, a :exc:`NetworkXError` is raised. - - NetworkXUnfeasible - If `G` is not a directed acyclic graph (DAG) no topological sort exists - and a :exc:`NetworkXUnfeasible` exception is raised. This can also be - raised if `G` is changed while the returned iterator is being processed - - RuntimeError - If `G` is changed while the returned iterator is being processed. - - Notes - ----- - This algorithm is based on a description and proof in - "Introduction to Algorithms: A Creative Approach" [1]_ . - - See also - -------- - topological_sort - - References - ---------- - .. [1] Manber, U. (1989). - *Introduction to Algorithms - A Creative Approach.* Addison-Wesley. - """ - if not G.is_directed(): - msg = "Topological sort not defined on undirected graphs." - raise nx.NetworkXError(msg) - - if key is None: - def key(node): - return node - - nodeid_map = {n: i for i, n in enumerate(G)} - - def create_tuple(node): - return key(node), nodeid_map[node], node - - indegree_map = {v: d for v, d in G.in_degree() if d > 0} - # These nodes have zero indegree and ready to be returned. - zero_indegree = [create_tuple(v) for v, d in G.in_degree() if d == 0] - heapq.heapify(zero_indegree) - - while zero_indegree: - _, _, node = heapq.heappop(zero_indegree) - - if node not in G: - raise RuntimeError("Graph changed during iteration") - for _, child in G.edges(node): - try: - indegree_map[child] -= 1 - except KeyError: - raise RuntimeError("Graph changed during iteration") - if indegree_map[child] == 0: - heapq.heappush(zero_indegree, create_tuple(child)) - del indegree_map[child] - - yield node - - if indegree_map: - msg = "Graph contains a cycle or graph changed during iteration" - raise nx.NetworkXUnfeasible(msg) - - -@not_implemented_for('undirected') -def all_topological_sorts(G): - """Returns a generator of _all_ topological sorts of the directed graph G. - - A topological sort is a nonunique permutation of the nodes such that an - edge from u to v implies that u appears before v in the topological sort - order. - - Parameters - ---------- - G : NetworkX DiGraph - A directed graph - - Returns - ------- - generator - All topological sorts of the digraph G - - Raises - ------ - NetworkXNotImplemented - If `G` is not directed - NetworkXUnfeasible - If `G` is not acyclic - - Examples - -------- - To enumerate all topological sorts of directed graph: - - >>> DG = nx.DiGraph([(1, 2), (2, 3), (2, 4)]) - >>> list(nx.all_topological_sorts(DG)) - [[1, 2, 4, 3], [1, 2, 3, 4]] - - Notes - ----- - Implements an iterative version of the algorithm given in [1]. - - References - ---------- - .. [1] Knuth, Donald E., Szwarcfiter, Jayme L. (1974). - "A Structured Program to Generate All Topological Sorting Arrangements" - Information Processing Letters, Volume 2, Issue 6, 1974, Pages 153-157, - ISSN 0020-0190, - https://doi.org/10.1016/0020-0190(74)90001-5. - Elsevier (North-Holland), Amsterdam - """ - if not G.is_directed(): - raise nx.NetworkXError( - "Topological sort not defined on undirected graphs.") - - # the names of count and D are chosen to match the global variables in [1] - # number of edges originating in a vertex v - count = dict(G.in_degree()) - # vertices with indegree 0 - D = deque([v for v, d in G.in_degree() if d == 0]) - # stack of first value chosen at a position k in the topological sort - bases = [] - current_sort = [] - - # do-while construct - while True: - assert all([count[v] == 0 for v in D]) - - if len(current_sort) == len(G): - yield list(current_sort) - - # clean-up stack - while len(current_sort) > 0: - assert len(bases) == len(current_sort) - q = current_sort.pop() - - # "restores" all edges (q, x) - # NOTE: it is important to iterate over edges instead - # of successors, so count is updated correctly in multigraphs - for _, j in G.out_edges(q): - count[j] += 1 - assert count[j] >= 0 - # remove entries from D - while len(D) > 0 and count[D[-1]] > 0: - D.pop() - - # corresponds to a circular shift of the values in D - # if the first value chosen (the base) is in the first - # position of D again, we are done and need to consider the - # previous condition - D.appendleft(q) - if D[-1] == bases[-1]: - # all possible values have been chosen at current position - # remove corresponding marker - bases.pop() - else: - # there are still elements that have not been fixed - # at the current position in the topological sort - # stop removing elements, escape inner loop - break - - else: - if len(D) == 0: - raise nx.NetworkXUnfeasible("Graph contains a cycle.") - - # choose next node - q = D.pop() - # "erase" all edges (q, x) - # NOTE: it is important to iterate over edges instead - # of successors, so count is updated correctly in multigraphs - for _, j in G.out_edges(q): - count[j] -= 1 - assert count[j] >= 0 - if count[j] == 0: - D.append(j) - current_sort.append(q) - - # base for current position might _not_ be fixed yet - if len(bases) < len(current_sort): - bases.append(q) - - if len(bases) == 0: - break - - -def is_aperiodic(G): - """Returns True if `G` is aperiodic. - - A directed graph is aperiodic if there is no integer k > 1 that - divides the length of every cycle in the graph. - - Parameters - ---------- - G : NetworkX DiGraph - A directed graph - - Returns - ------- - bool - True if the graph is aperiodic False otherwise - - Raises - ------ - NetworkXError - If `G` is not directed - - Notes - ----- - This uses the method outlined in [1]_, which runs in $O(m)$ time - given $m$ edges in `G`. Note that a graph is not aperiodic if it is - acyclic as every integer trivial divides length 0 cycles. - - References - ---------- - .. [1] Jarvis, J. P.; Shier, D. R. (1996), - "Graph-theoretic analysis of finite Markov chains," - in Shier, D. R.; Wallenius, K. T., Applied Mathematical Modeling: - A Multidisciplinary Approach, CRC Press. - """ - if not G.is_directed(): - raise nx.NetworkXError( - "is_aperiodic not defined for undirected graphs") - - s = arbitrary_element(G) - levels = {s: 0} - this_level = [s] - g = 0 - lev = 1 - while this_level: - next_level = [] - for u in this_level: - for v in G[u]: - if v in levels: # Non-Tree Edge - g = gcd(g, levels[u] - levels[v] + 1) - else: # Tree Edge - next_level.append(v) - levels[v] = lev - this_level = next_level - lev += 1 - if len(levels) == len(G): # All nodes in tree - return g == 1 - else: - return g == 1 and nx.is_aperiodic(G.subgraph(set(G) - set(levels))) - - -@not_implemented_for('undirected') -def transitive_closure(G, reflexive=False): - """ Returns transitive closure of a directed graph - - The transitive closure of G = (V,E) is a graph G+ = (V,E+) such that - for all v, w in V there is an edge (v, w) in E+ if and only if there - is a path from v to w in G. - - Handling of paths from v to v has some flexibility within this definition. - A reflexive transitive closure creates a self-loop for the path - from v to v of length 0. The usual transitive closure creates a - self-loop only if a cycle exists (a path from v to v with length > 0). - We also allow an option for no self-loops. - - Parameters - ---------- - G : NetworkX DiGraph - A directed graph - reflexive : Bool or None, optional (default: False) - Determines when cycles create self-loops in the Transitive Closure. - If True, trivial cycles (length 0) create self-loops. The result - is a reflexive tranistive closure of G. - If False (the default) non-trivial cycles create self-loops. - If None, self-loops are not created. - - Returns - ------- - NetworkX DiGraph - The transitive closure of `G` - - Raises - ------ - NetworkXNotImplemented - If `G` is not directed - - References - ---------- - .. [1] http://www.ics.uci.edu/~eppstein/PADS/PartialOrder.py - - TODO this function applies to all directed graphs and is probably misplaced - here in dag.py - """ - if reflexive is None: - TC = G.copy() - for v in G: - edges = ((v, u) for u in nx.dfs_preorder_nodes(G, v) if v != u) - TC.add_edges_from(edges) - return TC - if reflexive is True: - TC = G.copy() - for v in G: - edges = ((v, u) for u in nx.dfs_preorder_nodes(G, v)) - TC.add_edges_from(edges) - return TC - # reflexive is False - TC = G.copy() - for v in G: - edges = ((v, w) for u, w in nx.edge_dfs(G, v)) - TC.add_edges_from(edges) - return TC - - -@not_implemented_for('undirected') -def transitive_closure_dag(G, topo_order=None): - """ Returns the transitive closure of a directed acyclic graph. - - This function is faster than the function `transitive_closure`, but fails - if the graph has a cycle. - - The transitive closure of G = (V,E) is a graph G+ = (V,E+) such that - for all v, w in V there is an edge (v, w) in E+ if and only if there - is a non-null path from v to w in G. - - Parameters - ---------- - G : NetworkX DiGraph - A directed acyclic graph (DAG) - - topo_order: list or tuple, optional - A topological order for G (if None, the function will compute one) - - Returns - ------- - NetworkX DiGraph - The transitive closure of `G` - - Raises - ------ - NetworkXNotImplemented - If `G` is not directed - NetworkXUnfeasible - If `G` has a cycle - - Notes - ----- - This algorithm is probably simple enough to be well-known but I didn't find - a mention in the literature. - """ - if topo_order is None: - topo_order = list(topological_sort(G)) - - TC = G.copy() - - # idea: traverse vertices following a reverse topological order, connecting - # each vertex to its descendants at distance 2 as we go - for v in reversed(topo_order): - TC.add_edges_from((v, u) for u in descendants_at_distance(TC, v, 2)) - - return TC - - -@not_implemented_for('undirected') -def transitive_reduction(G): - """ Returns transitive reduction of a directed graph - - The transitive reduction of G = (V,E) is a graph G- = (V,E-) such that - for all v,w in V there is an edge (v,w) in E- if and only if (v,w) is - in E and there is no path from v to w in G with length greater than 1. - - Parameters - ---------- - G : NetworkX DiGraph - A directed acyclic graph (DAG) - - Returns - ------- - NetworkX DiGraph - The transitive reduction of `G` - - Raises - ------ - NetworkXError - If `G` is not a directed acyclic graph (DAG) transitive reduction is - not uniquely defined and a :exc:`NetworkXError` exception is raised. - - References - ---------- - https://en.wikipedia.org/wiki/Transitive_reduction - - """ - if not is_directed_acyclic_graph(G): - msg = "Directed Acyclic Graph required for transitive_reduction" - raise nx.NetworkXError(msg) - TR = nx.DiGraph() - TR.add_nodes_from(G.nodes()) - descendants = {} - # count before removing set stored in descendants - check_count = dict(G.in_degree) - for u in G: - u_nbrs = set(G[u]) - for v in G[u]: - if v in u_nbrs: - if v not in descendants: - descendants[v] = {y for x, y in nx.dfs_edges(G, v)} - u_nbrs -= descendants[v] - check_count[v] -= 1 - if check_count[v] == 0: - del descendants[v] - TR.add_edges_from((u, v) for v in u_nbrs) - return TR - - -@not_implemented_for('undirected') -def antichains(G, topo_order=None): - """Generates antichains from a directed acyclic graph (DAG). - - An antichain is a subset of a partially ordered set such that any - two elements in the subset are incomparable. - - Parameters - ---------- - G : NetworkX DiGraph - A directed acyclic graph (DAG) - - topo_order: list or tuple, optional - A topological order for G (if None, the function will compute one) - - Returns - ------- - generator object - - Raises - ------ - NetworkXNotImplemented - If `G` is not directed - - NetworkXUnfeasible - If `G` contains a cycle - - Notes - ----- - This function was originally developed by Peter Jipsen and Franco Saliola - for the SAGE project. It's included in NetworkX with permission from the - authors. Original SAGE code at: - - https://github.com/sagemath/sage/blob/master/src/sage/combinat/posets/hasse_diagram.py - - References - ---------- - .. [1] Free Lattices, by R. Freese, J. Jezek and J. B. Nation, - AMS, Vol 42, 1995, p. 226. - """ - if topo_order is None: - topo_order = list(nx.topological_sort(G)) - - TC = nx.transitive_closure_dag(G, topo_order) - antichains_stacks = [([], list(reversed(topo_order)))] - - while antichains_stacks: - (antichain, stack) = antichains_stacks.pop() - # Invariant: - # - the elements of antichain are independent - # - the elements of stack are independent from those of antichain - yield antichain - while stack: - x = stack.pop() - new_antichain = antichain + [x] - new_stack = [ - t for t in stack if not ((t in TC[x]) or (x in TC[t]))] - antichains_stacks.append((new_antichain, new_stack)) - - -@not_implemented_for('undirected') -def dag_longest_path(G, weight='weight', default_weight=1, topo_order=None): - """Returns the longest path in a directed acyclic graph (DAG). - - If `G` has edges with `weight` attribute the edge data are used as - weight values. - - Parameters - ---------- - G : NetworkX DiGraph - A directed acyclic graph (DAG) - - weight : str, optional - Edge data key to use for weight - - default_weight : int, optional - The weight of edges that do not have a weight attribute - - topo_order: list or tuple, optional - A topological order for G (if None, the function will compute one) - - Returns - ------- - list - Longest path - - Raises - ------ - NetworkXNotImplemented - If `G` is not directed - - See also - -------- - dag_longest_path_length - - """ - if not G: - return [] - - if topo_order is None: - topo_order = nx.topological_sort(G) - - dist = {} # stores {v : (length, u)} - for v in topo_order: - us = [(dist[u][0] + data.get(weight, default_weight), u) - for u, data in G.pred[v].items()] - - # Use the best predecessor if there is one and its distance is - # non-negative, otherwise terminate. - maxu = max(us, key=lambda x: x[0]) if us else (0, v) - dist[v] = maxu if maxu[0] >= 0 else (0, v) - - u = None - v = max(dist, key=lambda x: dist[x][0]) - path = [] - while u != v: - path.append(v) - u = v - v = dist[v][1] - - path.reverse() - return path - - -@not_implemented_for('undirected') -def dag_longest_path_length(G, weight='weight', default_weight=1): - """Returns the longest path length in a DAG - - Parameters - ---------- - G : NetworkX DiGraph - A directed acyclic graph (DAG) - - weight : string, optional - Edge data key to use for weight - - default_weight : int, optional - The weight of edges that do not have a weight attribute - - Returns - ------- - int - Longest path length - - Raises - ------ - NetworkXNotImplemented - If `G` is not directed - - See also - -------- - dag_longest_path - """ - path = nx.dag_longest_path(G, weight, default_weight) - path_length = 0 - for (u, v) in pairwise(path): - path_length += G[u][v].get(weight, default_weight) - - return path_length - - -def root_to_leaf_paths(G): - """Yields root-to-leaf paths in a directed acyclic graph. - - `G` must be a directed acyclic graph. If not, the behavior of this - function is undefined. A "root" in this graph is a node of in-degree - zero and a "leaf" a node of out-degree zero. - - When invoked, this function iterates over each path from any root to - any leaf. A path is a list of nodes. - - """ - roots = (v for v, d in G.in_degree() if d == 0) - leaves = (v for v, d in G.out_degree() if d == 0) - all_paths = partial(nx.all_simple_paths, G) - # TODO In Python 3, this would be better as `yield from ...`. - return chaini(starmap(all_paths, product(roots, leaves))) - - -@not_implemented_for('multigraph') -@not_implemented_for('undirected') -def dag_to_branching(G): - """Returns a branching representing all (overlapping) paths from - root nodes to leaf nodes in the given directed acyclic graph. - - As described in :mod:`networkx.algorithms.tree.recognition`, a - *branching* is a directed forest in which each node has at most one - parent. In other words, a branching is a disjoint union of - *arborescences*. For this function, each node of in-degree zero in - `G` becomes a root of one of the arborescences, and there will be - one leaf node for each distinct path from that root to a leaf node - in `G`. - - Each node `v` in `G` with *k* parents becomes *k* distinct nodes in - the returned branching, one for each parent, and the sub-DAG rooted - at `v` is duplicated for each copy. The algorithm then recurses on - the children of each copy of `v`. - - Parameters - ---------- - G : NetworkX graph - A directed acyclic graph. - - Returns - ------- - DiGraph - The branching in which there is a bijection between root-to-leaf - paths in `G` (in which multiple paths may share the same leaf) - and root-to-leaf paths in the branching (in which there is a - unique path from a root to a leaf). - - Each node has an attribute 'source' whose value is the original - node to which this node corresponds. No other graph, node, or - edge attributes are copied into this new graph. - - Raises - ------ - NetworkXNotImplemented - If `G` is not directed, or if `G` is a multigraph. - - HasACycle - If `G` is not acyclic. - - Examples - -------- - To examine which nodes in the returned branching were produced by - which original node in the directed acyclic graph, we can collect - the mapping from source node to new nodes into a dictionary. For - example, consider the directed diamond graph:: - - >>> from collections import defaultdict - >>> from operator import itemgetter - >>> - >>> G = nx.DiGraph(nx.utils.pairwise('abd')) - >>> G.add_edges_from(nx.utils.pairwise('acd')) - >>> B = nx.dag_to_branching(G) - >>> - >>> sources = defaultdict(set) - >>> for v, source in B.nodes(data='source'): - ... sources[source].add(v) - >>> len(sources['a']) - 1 - >>> len(sources['d']) - 2 - - To copy node attributes from the original graph to the new graph, - you can use a dictionary like the one constructed in the above - example:: - - >>> for source, nodes in sources.items(): - ... for v in nodes: - ... B.nodes[v].update(G.nodes[source]) - - Notes - ----- - This function is not idempotent in the sense that the node labels in - the returned branching may be uniquely generated each time the - function is invoked. In fact, the node labels may not be integers; - in order to relabel the nodes to be more readable, you can use the - :func:`networkx.convert_node_labels_to_integers` function. - - The current implementation of this function uses - :func:`networkx.prefix_tree`, so it is subject to the limitations of - that function. - - """ - if has_cycle(G): - msg = 'dag_to_branching is only defined for acyclic graphs' - raise nx.HasACycle(msg) - paths = root_to_leaf_paths(G) - B, root = nx.prefix_tree(paths) - # Remove the synthetic `root` and `NIL` nodes in the prefix tree. - B.remove_node(root) - B.remove_node(NIL) - return B diff --git a/extensions/fablabchemnitz/networkx/algorithms/distance_measures.py b/extensions/fablabchemnitz/networkx/algorithms/distance_measures.py deleted file mode 100644 index e2b7a960..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/distance_measures.py +++ /dev/null @@ -1,590 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# William Schwartz -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg (hagberg@lanl.gov) -# Dan Schult (dschult@colgate.edu) -# Brian Kiefer (bkiefer@asu.edu) -"""Graph diameter, radius, eccentricity and other properties.""" - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ['extrema_bounding', 'eccentricity', 'diameter', - 'radius', 'periphery', 'center', 'barycenter', - 'resistance_distance'] - - -def extrema_bounding(G, compute="diameter"): - """Compute requested extreme distance metric of undirected graph G - - Computation is based on smart lower and upper bounds, and in practice - linear in the number of nodes, rather than quadratic (except for some - border cases such as complete graphs or circle shaped graphs). - - Parameters - ---------- - G : NetworkX graph - An undirected graph - - compute : string denoting the requesting metric - "diameter" for the maximal eccentricity value, - "radius" for the minimal eccentricity value, - "periphery" for the set of nodes with eccentricity equal to the diameter - "center" for the set of nodes with eccentricity equal to the radius - - Returns - ------- - value : value of the requested metric - int for "diameter" and "radius" or - list of nodes for "center" and "periphery" - - Raises - ------ - NetworkXError - If the graph consists of multiple components - - Notes - ----- - This algorithm was proposed in the following papers: - - F.W. Takes and W.A. Kosters, Determining the Diameter of Small World - Networks, in Proceedings of the 20th ACM International Conference on - Information and Knowledge Management (CIKM 2011), pp. 1191-1196, 2011. - doi: https://doi.org/10.1145/2063576.2063748 - - F.W. Takes and W.A. Kosters, Computing the Eccentricity Distribution of - Large Graphs, Algorithms 6(1): 100-118, 2013. - doi: https://doi.org/10.3390/a6010100 - - M. Borassi, P. Crescenzi, M. Habib, W.A. Kosters, A. Marino and F.W. Takes, - Fast Graph Diameter and Radius BFS-Based Computation in (Weakly Connected) - Real-World Graphs, Theoretical Computer Science 586: 59-80, 2015. - doi: https://doi.org/10.1016/j.tcs.2015.02.033 - """ - - # init variables - degrees = dict(G.degree()) # start with the highest degree node - minlowernode = max(degrees, key=degrees.get) - N = len(degrees) # number of nodes - # alternate between smallest lower and largest upper bound - high = False - # status variables - ecc_lower = dict.fromkeys(G, 0) - ecc_upper = dict.fromkeys(G, N) - candidates = set(G) - - # (re)set bound extremes - minlower = N - maxlower = 0 - minupper = N - maxupper = 0 - - # repeat the following until there are no more candidates - while candidates: - if high: - current = maxuppernode # select node with largest upper bound - else: - current = minlowernode # select node with smallest lower bound - high = not high - - # get distances from/to current node and derive eccentricity - dist = dict(nx.single_source_shortest_path_length(G, current)) - if len(dist) != N: - msg = ('Cannot compute metric because graph is not connected.') - raise nx.NetworkXError(msg) - current_ecc = max(dist.values()) - - # print status update -# print ("ecc of " + str(current) + " (" + str(ecc_lower[current]) + "/" -# + str(ecc_upper[current]) + ", deg: " + str(dist[current]) + ") is " -# + str(current_ecc)) -# print(ecc_upper) - - # (re)set bound extremes - maxuppernode = None - minlowernode = None - - # update node bounds - for i in candidates: - # update eccentricity bounds - d = dist[i] - ecc_lower[i] = low = max(ecc_lower[i], max(d, (current_ecc - d))) - ecc_upper[i] = upp = min(ecc_upper[i], current_ecc + d) - - # update min/max values of lower and upper bounds - minlower = min(ecc_lower[i], minlower) - maxlower = max(ecc_lower[i], maxlower) - minupper = min(ecc_upper[i], minupper) - maxupper = max(ecc_upper[i], maxupper) - - # update candidate set - if compute == 'diameter': - ruled_out = {i for i in candidates if ecc_upper[i] <= maxlower and - 2 * ecc_lower[i] >= maxupper} - - elif compute == 'radius': - ruled_out = {i for i in candidates if ecc_lower[i] >= minupper and - ecc_upper[i] + 1 <= 2 * minlower} - - elif compute == 'periphery': - ruled_out = {i for i in candidates if ecc_upper[i] < maxlower and - (maxlower == maxupper or ecc_lower[i] > maxupper)} - - elif compute == 'center': - ruled_out = {i for i in candidates if ecc_lower[i] > minupper and - (minlower == minupper or ecc_upper[i] + 1 < 2 * minlower)} - - elif compute == 'eccentricities': - ruled_out = {} - - ruled_out.update(i for i in candidates if ecc_lower[i] == ecc_upper[i]) - candidates -= ruled_out - -# for i in ruled_out: -# print("removing %g: ecc_u: %g maxl: %g ecc_l: %g maxu: %g"% -# (i,ecc_upper[i],maxlower,ecc_lower[i],maxupper)) -# print("node %g: ecc_u: %g maxl: %g ecc_l: %g maxu: %g"% -# (4,ecc_upper[4],maxlower,ecc_lower[4],maxupper)) -# print("NODE 4: %g"%(ecc_upper[4] <= maxlower)) -# print("NODE 4: %g"%(2 * ecc_lower[4] >= maxupper)) -# print("NODE 4: %g"%(ecc_upper[4] <= maxlower -# and 2 * ecc_lower[4] >= maxupper)) - - # updating maxuppernode and minlowernode for selection in next round - for i in candidates: - if minlowernode is None \ - or (ecc_lower[i] == ecc_lower[minlowernode] - and degrees[i] > degrees[minlowernode]) \ - or (ecc_lower[i] < ecc_lower[minlowernode]): - minlowernode = i - - if maxuppernode is None \ - or (ecc_upper[i] == ecc_upper[maxuppernode] - and degrees[i] > degrees[maxuppernode]) \ - or (ecc_upper[i] > ecc_upper[maxuppernode]): - maxuppernode = i - - # print status update -# print (" min=" + str(minlower) + "/" + str(minupper) + -# " max=" + str(maxlower) + "/" + str(maxupper) + -# " candidates: " + str(len(candidates))) -# print("cand:",candidates) -# print("ecc_l",ecc_lower) -# print("ecc_u",ecc_upper) -# wait = input("press Enter to continue") - - # return the correct value of the requested metric - if compute == 'diameter': - return maxlower - elif compute == 'radius': - return minupper - elif compute == 'periphery': - p = [v for v in G if ecc_lower[v] == maxlower] - return p - elif compute == 'center': - c = [v for v in G if ecc_upper[v] == minupper] - return c - elif compute == 'eccentricities': - return ecc_lower - return None - - -def eccentricity(G, v=None, sp=None): - """Returns the eccentricity of nodes in G. - - The eccentricity of a node v is the maximum distance from v to - all other nodes in G. - - Parameters - ---------- - G : NetworkX graph - A graph - - v : node, optional - Return value of specified node - - sp : dict of dicts, optional - All pairs shortest path lengths as a dictionary of dictionaries - - Returns - ------- - ecc : dictionary - A dictionary of eccentricity values keyed by node. - """ -# if v is None: # none, use entire graph -# nodes=G.nodes() -# elif v in G: # is v a single node -# nodes=[v] -# else: # assume v is a container of nodes -# nodes=v - order = G.order() - - e = {} - for n in G.nbunch_iter(v): - if sp is None: - length = nx.single_source_shortest_path_length(G, n) - L = len(length) - else: - try: - length = sp[n] - L = len(length) - except TypeError: - raise nx.NetworkXError('Format of "sp" is invalid.') - if L != order: - if G.is_directed(): - msg = ('Found infinite path length because the digraph is not' - ' strongly connected') - else: - msg = ('Found infinite path length because the graph is not' - ' connected') - raise nx.NetworkXError(msg) - - e[n] = max(length.values()) - - if v in G: - return e[v] # return single value - else: - return e - - -def diameter(G, e=None, usebounds=False): - """Returns the diameter of the graph G. - - The diameter is the maximum eccentricity. - - Parameters - ---------- - G : NetworkX graph - A graph - - e : eccentricity dictionary, optional - A precomputed dictionary of eccentricities. - - Returns - ------- - d : integer - Diameter of graph - - See Also - -------- - eccentricity - """ - if usebounds is True and e is None and not G.is_directed(): - return extrema_bounding(G, compute="diameter") - if e is None: - e = eccentricity(G) - return max(e.values()) - - -def periphery(G, e=None, usebounds=False): - """Returns the periphery of the graph G. - - The periphery is the set of nodes with eccentricity equal to the diameter. - - Parameters - ---------- - G : NetworkX graph - A graph - - e : eccentricity dictionary, optional - A precomputed dictionary of eccentricities. - - Returns - ------- - p : list - List of nodes in periphery - - See Also - -------- - barycenter - center - """ - if usebounds is True and e is None and not G.is_directed(): - return extrema_bounding(G, compute="periphery") - if e is None: - e = eccentricity(G) - diameter = max(e.values()) - p = [v for v in e if e[v] == diameter] - return p - - -def radius(G, e=None, usebounds=False): - """Returns the radius of the graph G. - - The radius is the minimum eccentricity. - - Parameters - ---------- - G : NetworkX graph - A graph - - e : eccentricity dictionary, optional - A precomputed dictionary of eccentricities. - - Returns - ------- - r : integer - Radius of graph - """ - if usebounds is True and e is None and not G.is_directed(): - return extrema_bounding(G, compute="radius") - if e is None: - e = eccentricity(G) - return min(e.values()) - - -def center(G, e=None, usebounds=False): - """Returns the center of the graph G. - - The center is the set of nodes with eccentricity equal to radius. - - Parameters - ---------- - G : NetworkX graph - A graph - - e : eccentricity dictionary, optional - A precomputed dictionary of eccentricities. - - Returns - ------- - c : list - List of nodes in center - - See Also - -------- - barycenter - periphery - """ - if usebounds is True and e is None and not G.is_directed(): - return extrema_bounding(G, compute="center") - if e is None: - e = eccentricity(G) - radius = min(e.values()) - p = [v for v in e if e[v] == radius] - return p - - -def barycenter(G, weight=None, attr=None, sp=None): - r"""Calculate barycenter of a connected graph, optionally with edge weights. - - The :dfn:`barycenter` a - :func:`connected ` graph - :math:`G` is the subgraph induced by the set of its nodes :math:`v` - minimizing the objective function - - .. math:: - - \sum_{u \in V(G)} d_G(u, v), - - where :math:`d_G` is the (possibly weighted) :func:`path length - `. - The barycenter is also called the :dfn:`median`. See [West01]_, p. 78. - - Parameters - ---------- - G : :class:`networkx.Graph` - The connected graph :math:`G`. - weight : :class:`str`, optional - Passed through to - :func:`~networkx.algorithms.shortest_paths.generic.shortest_path_length`. - attr : :class:`str`, optional - If given, write the value of the objective function to each node's - `attr` attribute. Otherwise do not store the value. - sp : dict of dicts, optional - All pairs shortest path lengths as a dictionary of dictionaries - - Returns - ------- - :class:`list` - Nodes of `G` that induce the barycenter of `G`. - - Raises - ------ - :exc:`networkx.NetworkXNoPath` - If `G` is disconnected. `G` may appear disconnected to - :func:`barycenter` if `sp` is given but is missing shortest path - lengths for any pairs. - :exc:`ValueError` - If `sp` and `weight` are both given. - - See Also - -------- - center - periphery - """ - if sp is None: - sp = nx.shortest_path_length(G, weight=weight) - else: - sp = sp.items() - if weight is not None: - raise ValueError('Cannot use both sp, weight arguments together') - smallest, barycenter_vertices, n = float('inf'), [], len(G) - for v, dists in sp: - if len(dists) < n: - raise nx.NetworkXNoPath( - ("Input graph %r is disconnected, so every induced subgraph " - "has infinite barycentricity.") % G) - barycentricity = sum(dists.values()) - if attr is not None: - G.nodes[v][attr] = barycentricity - if barycentricity < smallest: - smallest = barycentricity - barycenter_vertices = [v] - elif barycentricity == smallest: - barycenter_vertices.append(v) - return barycenter_vertices - - -def _laplacian_submatrix(node, mat, node_list): - """Removes row/col from a sparse matrix and returns the submatrix - """ - j = node_list.index(node) - n = list(range(len(node_list))) - n.pop(j) - - if mat.shape[0] != mat.shape[1]: - raise nx.NetworkXError('Matrix must be square') - elif len(node_list) != mat.shape[0]: - msg = "Node list length does not match matrix dimentions" - raise nx.NetworkXError(msg) - - mat = mat.tocsr() - mat = mat[n, :] - - mat = mat.tocsc() - mat = mat[:, n] - - node_list.pop(j) - - return mat, node_list - - -def _count_lu_permutations(perm_array): - """Counts the number of permutations in SuperLU perm_c or perm_r - """ - perm_cnt = 0 - arr = perm_array.tolist() - for i in range(len(arr)): - if i != arr[i]: - perm_cnt += 1 - n = arr.index(i) - arr[n] = arr[i] - arr[i] = i - - return perm_cnt - - -@not_implemented_for('directed') -def resistance_distance(G, nodeA, nodeB, weight=None, invert_weight=True): - """Returns the resistance distance between node A and node B on graph G. - - The resistance distance between two nodes of a graph is akin to treating - the graph as a grid of resistorses with a resistance equal to the provided - weight. - - If weight is not provided, then a weight of 1 is used for all edges. - - Parameters - ---------- - G : NetworkX graph - A graph - - nodeA : node - A node within graph G. - - nodeB : node - A node within graph G, exclusive of Node A. - - weight : string or None, optional (default=None) - The edge data key used to compute the resistance distance. - If None, then each edge has weight 1. - - invert_weight : boolean (default=True) - Proper calculation of resistance distance requires building the - Laplacian matrix with the reciprocal of the weight. Not required - if the weight is already inverted. Weight cannot be zero. - - Returns - ------- - rd : float - Value of effective resistance distance - - Notes - ----- - Overview discussion: - * https://en.wikipedia.org/wiki/Resistance_distance - * http://mathworld.wolfram.com/ResistanceDistance.html - - Additional details: - Vaya Sapobi Samui Vos, “Methods for determining the effective resistance,” M.S., - Mathematisch Instituut, Universiteit Leiden, Leiden, Netherlands, 2016 - Available: `Link to thesis `_ - """ - import numpy as np - import scipy.sparse - - if not nx.is_connected(G): - msg = ('Graph G must be strongly connected.') - raise nx.NetworkXError(msg) - elif nodeA not in G: - msg = ('Node A is not in graph G.') - raise nx.NetworkXError(msg) - elif nodeB not in G: - msg = ('Node B is not in graph G.') - raise nx.NetworkXError(msg) - elif nodeA == nodeB: - msg = ('Node A and Node B cannot be the same.') - raise nx.NetworkXError(msg) - - G = G.copy() - node_list = list(G) - - if invert_weight and weight is not None: - if G.is_multigraph(): - for (u, v, k, d) in G.edges(keys=True, data=True): - d[weight] = 1/d[weight] - else: - for (u, v, d) in G.edges(data=True): - d[weight] = 1/d[weight] - # Replace with collapsing topology or approximated zero? - - # Using determinants to compute the effective resistance is more memory - # efficent than directly calculating the psuedo-inverse - L = nx.laplacian_matrix(G, node_list, weight=weight) - - Lsub_a, node_list_a = _laplacian_submatrix(nodeA, L.copy(), - node_list[:]) - Lsub_ab, node_list_ab = _laplacian_submatrix(nodeB, Lsub_a.copy(), - node_list_a[:]) - - # Factorize Laplacian submatrixes and extract diagonals - # Order the diagonals to minimize the likelihood over overflows - # during computing the determinant - lu_a = scipy.sparse.linalg.splu(Lsub_a, options=dict(SymmetricMode=True)) - LdiagA = lu_a.U.diagonal() - LdiagA_s = np.product(np.sign(LdiagA)) * np.product(lu_a.L.diagonal()) - LdiagA_s *= (-1)**_count_lu_permutations(lu_a.perm_r) - LdiagA_s *= (-1)**_count_lu_permutations(lu_a.perm_c) - LdiagA = np.absolute(LdiagA) - LdiagA = np.sort(LdiagA) - - lu_ab = scipy.sparse.linalg.splu(Lsub_ab, options=dict(SymmetricMode=True)) - LdiagAB = lu_ab.U.diagonal() - LdiagAB_s = np.product(np.sign(LdiagAB)) * np.product(lu_ab.L.diagonal()) - LdiagAB_s *= (-1)**_count_lu_permutations(lu_ab.perm_r) - LdiagAB_s *= (-1)**_count_lu_permutations(lu_ab.perm_c) - LdiagAB = np.absolute(LdiagAB) - LdiagAB = np.sort(LdiagAB) - - # Calculate the ratio of determinant, rd = det(Lsub_ab)/det(Lsub_a) - Ldet = np.product(np.divide(np.append(LdiagAB, [1]), LdiagA)) - rd = Ldet * LdiagAB_s / LdiagA_s - - return rd diff --git a/extensions/fablabchemnitz/networkx/algorithms/distance_regular.py b/extensions/fablabchemnitz/networkx/algorithms/distance_regular.py deleted file mode 100644 index fbdce44d..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/distance_regular.py +++ /dev/null @@ -1,233 +0,0 @@ -# Copyright (C) 2011 by -# Dheeraj M R -# Aric Hagberg -# All rights reserved. -# BSD license. -""" -======================= -Distance-regular graphs -======================= -""" - -import networkx as nx -from networkx.utils import not_implemented_for -from .distance_measures import diameter - -__author__ = """\n""".join(['Dheeraj M R ', - 'Aric Hagberg ']) - -__all__ = ['is_distance_regular', 'is_strongly_regular', - 'intersection_array', 'global_parameters'] - - -def is_distance_regular(G): - """Returns True if the graph is distance regular, False otherwise. - - A connected graph G is distance-regular if for any nodes x,y - and any integers i,j=0,1,...,d (where d is the graph - diameter), the number of vertices at distance i from x and - distance j from y depends only on i,j and the graph distance - between x and y, independently of the choice of x and y. - - Parameters - ---------- - G: Networkx graph (undirected) - - Returns - ------- - bool - True if the graph is Distance Regular, False otherwise - - Examples - -------- - >>> G=nx.hypercube_graph(6) - >>> nx.is_distance_regular(G) - True - - See Also - -------- - intersection_array, global_parameters - - Notes - ----- - For undirected and simple graphs only - - References - ---------- - .. [1] Brouwer, A. E.; Cohen, A. M.; and Neumaier, A. - Distance-Regular Graphs. New York: Springer-Verlag, 1989. - .. [2] Weisstein, Eric W. "Distance-Regular Graph." - http://mathworld.wolfram.com/Distance-RegularGraph.html - - """ - try: - intersection_array(G) - return True - except nx.NetworkXError: - return False - - -def global_parameters(b, c): - """Returns global parameters for a given intersection array. - - Given a distance-regular graph G with integers b_i, c_i,i = 0,....,d - such that for any 2 vertices x,y in G at a distance i=d(x,y), there - are exactly c_i neighbors of y at a distance of i-1 from x and b_i - neighbors of y at a distance of i+1 from x. - - Thus, a distance regular graph has the global parameters, - [[c_0,a_0,b_0],[c_1,a_1,b_1],......,[c_d,a_d,b_d]] for the - intersection array [b_0,b_1,.....b_{d-1};c_1,c_2,.....c_d] - where a_i+b_i+c_i=k , k= degree of every vertex. - - Parameters - ---------- - b : list - - c : list - - Returns - ------- - iterable - An iterable over three tuples. - - Examples - -------- - >>> G = nx.dodecahedral_graph() - >>> b, c = nx.intersection_array(G) - >>> list(nx.global_parameters(b, c)) - [(0, 0, 3), (1, 0, 2), (1, 1, 1), (1, 1, 1), (2, 0, 1), (3, 0, 0)] - - References - ---------- - .. [1] Weisstein, Eric W. "Global Parameters." - From MathWorld--A Wolfram Web Resource. - http://mathworld.wolfram.com/GlobalParameters.html - - See Also - -------- - intersection_array - """ - return ((y, b[0] - x - y, x) for x, y in zip(b + [0], [0] + c)) - - -@not_implemented_for('directed', 'multigraph') -def intersection_array(G): - """Returns the intersection array of a distance-regular graph. - - Given a distance-regular graph G with integers b_i, c_i,i = 0,....,d - such that for any 2 vertices x,y in G at a distance i=d(x,y), there - are exactly c_i neighbors of y at a distance of i-1 from x and b_i - neighbors of y at a distance of i+1 from x. - - A distance regular graph's intersection array is given by, - [b_0,b_1,.....b_{d-1};c_1,c_2,.....c_d] - - Parameters - ---------- - G: Networkx graph (undirected) - - Returns - ------- - b,c: tuple of lists - - Examples - -------- - >>> G=nx.icosahedral_graph() - >>> nx.intersection_array(G) - ([5, 2, 1], [1, 2, 5]) - - References - ---------- - .. [1] Weisstein, Eric W. "Intersection Array." - From MathWorld--A Wolfram Web Resource. - http://mathworld.wolfram.com/IntersectionArray.html - - See Also - -------- - global_parameters - """ - # test for regular graph (all degrees must be equal) - degree = iter(G.degree()) - (_, k) = next(degree) - for _, knext in degree: - if knext != k: - raise nx.NetworkXError('Graph is not distance regular.') - k = knext - path_length = dict(nx.all_pairs_shortest_path_length(G)) - diameter = max([max(path_length[n].values()) for n in path_length]) - bint = {} # 'b' intersection array - cint = {} # 'c' intersection array - for u in G: - for v in G: - try: - i = path_length[u][v] - except KeyError: # graph must be connected - raise nx.NetworkXError('Graph is not distance regular.') - # number of neighbors of v at a distance of i-1 from u - c = len([n for n in G[v] if path_length[n][u] == i - 1]) - # number of neighbors of v at a distance of i+1 from u - b = len([n for n in G[v] if path_length[n][u] == i + 1]) - # b,c are independent of u and v - if cint.get(i, c) != c or bint.get(i, b) != b: - raise nx.NetworkXError('Graph is not distance regular') - bint[i] = b - cint[i] = c - return ([bint.get(j, 0) for j in range(diameter)], - [cint.get(j + 1, 0) for j in range(diameter)]) - - -# TODO There is a definition for directed strongly regular graphs. -@not_implemented_for('directed', 'multigraph') -def is_strongly_regular(G): - """Returns True if and only if the given graph is strongly - regular. - - An undirected graph is *strongly regular* if - - * it is regular, - * each pair of adjacent vertices has the same number of neighbors in - common, - * each pair of nonadjacent vertices has the same number of neighbors - in common. - - Each strongly regular graph is a distance-regular graph. - Conversely, if a distance-regular graph has diameter two, then it is - a strongly regular graph. For more information on distance-regular - graphs, see :func:`is_distance_regular`. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - Returns - ------- - bool - Whether `G` is strongly regular. - - Examples - -------- - - The cycle graph on five vertices is strongly regular. It is - two-regular, each pair of adjacent vertices has no shared neighbors, - and each pair of nonadjacent vertices has one shared neighbor:: - - >>> import networkx as nx - >>> G = nx.cycle_graph(5) - >>> nx.is_strongly_regular(G) - True - - """ - # Here is an alternate implementation based directly on the - # definition of strongly regular graphs: - # - # return (all_equal(G.degree().values()) - # and all_equal(len(common_neighbors(G, u, v)) - # for u, v in G.edges()) - # and all_equal(len(common_neighbors(G, u, v)) - # for u, v in non_edges(G))) - # - # We instead use the fact that a distance-regular graph of diameter - # two is strongly regular. - return is_distance_regular(G) and diameter(G) == 2 diff --git a/extensions/fablabchemnitz/networkx/algorithms/dominance.py b/extensions/fablabchemnitz/networkx/algorithms/dominance.py deleted file mode 100644 index b016eceb..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/dominance.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright (C) 2014-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: ysitu (ysitu@users.noreply.github.com) -""" -Dominance algorithms. -""" - -from functools import reduce -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ['immediate_dominators', 'dominance_frontiers'] - - -@not_implemented_for('undirected') -def immediate_dominators(G, start): - """Returns the immediate dominators of all nodes of a directed graph. - - Parameters - ---------- - G : a DiGraph or MultiDiGraph - The graph where dominance is to be computed. - - start : node - The start node of dominance computation. - - Returns - ------- - idom : dict keyed by nodes - A dict containing the immediate dominators of each node reachable from - `start`. - - Raises - ------ - NetworkXNotImplemented - If `G` is undirected. - - NetworkXError - If `start` is not in `G`. - - Notes - ----- - Except for `start`, the immediate dominators are the parents of their - corresponding nodes in the dominator tree. - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (1, 3), (2, 5), (3, 4), (4, 5)]) - >>> sorted(nx.immediate_dominators(G, 1).items()) - [(1, 1), (2, 1), (3, 1), (4, 3), (5, 1)] - - References - ---------- - .. [1] K. D. Cooper, T. J. Harvey, and K. Kennedy. - A simple, fast dominance algorithm. - Software Practice & Experience, 4:110, 2001. - """ - if start not in G: - raise nx.NetworkXError('start is not in G') - - idom = {start: start} - - order = list(nx.dfs_postorder_nodes(G, start)) - dfn = {u: i for i, u in enumerate(order)} - order.pop() - order.reverse() - - def intersect(u, v): - while u != v: - while dfn[u] < dfn[v]: - u = idom[u] - while dfn[u] > dfn[v]: - v = idom[v] - return u - - changed = True - while changed: - changed = False - for u in order: - new_idom = reduce(intersect, (v for v in G.pred[u] if v in idom)) - if u not in idom or idom[u] != new_idom: - idom[u] = new_idom - changed = True - - return idom - - -def dominance_frontiers(G, start): - """Returns the dominance frontiers of all nodes of a directed graph. - - Parameters - ---------- - G : a DiGraph or MultiDiGraph - The graph where dominance is to be computed. - - start : node - The start node of dominance computation. - - Returns - ------- - df : dict keyed by nodes - A dict containing the dominance frontiers of each node reachable from - `start` as lists. - - Raises - ------ - NetworkXNotImplemented - If `G` is undirected. - - NetworkXError - If `start` is not in `G`. - - Examples - -------- - >>> G = nx.DiGraph([(1, 2), (1, 3), (2, 5), (3, 4), (4, 5)]) - >>> sorted((u, sorted(df)) for u, df in nx.dominance_frontiers(G, 1).items()) - [(1, []), (2, [5]), (3, [5]), (4, [5]), (5, [])] - - References - ---------- - .. [1] K. D. Cooper, T. J. Harvey, and K. Kennedy. - A simple, fast dominance algorithm. - Software Practice & Experience, 4:110, 2001. - """ - idom = nx.immediate_dominators(G, start) - - df = {u: set() for u in idom} - for u in idom: - if len(G.pred[u]) >= 2: - for v in G.pred[u]: - if v in idom: - while v != idom[u]: - df[v].add(u) - v = idom[v] - return df diff --git a/extensions/fablabchemnitz/networkx/algorithms/dominating.py b/extensions/fablabchemnitz/networkx/algorithms/dominating.py deleted file mode 100644 index 4289f894..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/dominating.py +++ /dev/null @@ -1,94 +0,0 @@ -# -*- coding: utf-8 -*- -"""Functions for computing dominating sets in a graph.""" -from itertools import chain - -import networkx as nx -from networkx.utils import arbitrary_element - -__author__ = '\n'.join(['Jordi Torrents ']) -__all__ = ['dominating_set', 'is_dominating_set'] - - -def dominating_set(G, start_with=None): - r"""Finds a dominating set for the graph G. - - A *dominating set* for a graph with node set *V* is a subset *D* of - *V* such that every node not in *D* is adjacent to at least one - member of *D* [1]_. - - Parameters - ---------- - G : NetworkX graph - - start_with : node (default=None) - Node to use as a starting point for the algorithm. - - Returns - ------- - D : set - A dominating set for G. - - Notes - ----- - This function is an implementation of algorithm 7 in [2]_ which - finds some dominating set, not necessarily the smallest one. - - See also - -------- - is_dominating_set - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Dominating_set - - .. [2] Abdol-Hossein Esfahanian. Connectivity Algorithms. - http://www.cse.msu.edu/~cse835/Papers/Graph_connectivity_revised.pdf - - """ - all_nodes = set(G) - if start_with is None: - start_with = arbitrary_element(all_nodes) - if start_with not in G: - raise nx.NetworkXError('node {} is not in G'.format(start_with)) - dominating_set = {start_with} - dominated_nodes = set(G[start_with]) - remaining_nodes = all_nodes - dominated_nodes - dominating_set - while remaining_nodes: - # Choose an arbitrary node and determine its undominated neighbors. - v = remaining_nodes.pop() - undominated_neighbors = set(G[v]) - dominating_set - # Add the node to the dominating set and the neighbors to the - # dominated set. Finally, remove all of those nodes from the set - # of remaining nodes. - dominating_set.add(v) - dominated_nodes |= undominated_neighbors - remaining_nodes -= undominated_neighbors - return dominating_set - - -def is_dominating_set(G, nbunch): - """Checks if `nbunch` is a dominating set for `G`. - - A *dominating set* for a graph with node set *V* is a subset *D* of - *V* such that every node not in *D* is adjacent to at least one - member of *D* [1]_. - - Parameters - ---------- - G : NetworkX graph - - nbunch : iterable - An iterable of nodes in the graph `G`. - - See also - -------- - dominating_set - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Dominating_set - - """ - testset = set(n for n in nbunch if n in G) - nbrs = set(chain.from_iterable(G[n] for n in testset)) - return len(set(G) - testset - nbrs) == 0 diff --git a/extensions/fablabchemnitz/networkx/algorithms/efficiency_measures.py b/extensions/fablabchemnitz/networkx/algorithms/efficiency_measures.py deleted file mode 100644 index fe5a5f2f..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/efficiency_measures.py +++ /dev/null @@ -1,155 +0,0 @@ -# efficiency.py - functions for computing node, edge, and graph efficiency -# -# Copyright 2011, 2012, 2013, 2014, 2015 NetworkX developers -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Provides functions for computing the efficiency of nodes and graphs.""" - -from itertools import permutations - -import networkx as nx -from networkx.exception import NetworkXNoPath -from ..utils import not_implemented_for - -__all__ = ['efficiency', 'local_efficiency', 'global_efficiency'] - - -@not_implemented_for('directed') -def efficiency(G, u, v): - """Returns the efficiency of a pair of nodes in a graph. - - The *efficiency* of a pair of nodes is the multiplicative inverse of the - shortest path distance between the nodes [1]_. Returns 0 if no path - between nodes. - - Parameters - ---------- - G : :class:`networkx.Graph` - An undirected graph for which to compute the average local efficiency. - u, v : node - Nodes in the graph ``G``. - - Returns - ------- - float - Multiplicative inverse of the shortest path distance between the nodes. - - Notes - ----- - Edge weights are ignored when computing the shortest path distances. - - See also - -------- - local_efficiency - global_efficiency - - References - ---------- - .. [1] Latora, Vito, and Massimo Marchiori. - "Efficient behavior of small-world networks." - *Physical Review Letters* 87.19 (2001): 198701. - - - """ - try: - eff = 1 / nx.shortest_path_length(G, u, v) - except NetworkXNoPath: - eff = 0 - return eff - - -@not_implemented_for('directed') -def global_efficiency(G): - """Returns the average global efficiency of the graph. - - The *efficiency* of a pair of nodes in a graph is the multiplicative - inverse of the shortest path distance between the nodes. The *average - global efficiency* of a graph is the average efficiency of all pairs of - nodes [1]_. - - Parameters - ---------- - G : :class:`networkx.Graph` - An undirected graph for which to compute the average global efficiency. - - Returns - ------- - float - The average global efficiency of the graph. - - Notes - ----- - Edge weights are ignored when computing the shortest path distances. - - See also - -------- - local_efficiency - - References - ---------- - .. [1] Latora, Vito, and Massimo Marchiori. - "Efficient behavior of small-world networks." - *Physical Review Letters* 87.19 (2001): 198701. - - - """ - n = len(G) - denom = n * (n - 1) - if denom != 0: - lengths = nx.all_pairs_shortest_path_length(G) - g_eff = 0 - for source, targets in lengths: - for target, distance in targets.items(): - if distance > 0: - g_eff += 1 / distance - g_eff /= denom - # g_eff = sum(1 / d for s, tgts in lengths - # for t, d in tgts.items() if d > 0) / denom - else: - g_eff = 0 - # TODO This can be made more efficient by computing all pairs shortest - # path lengths in parallel. - return g_eff - -@not_implemented_for('directed') -def local_efficiency(G): - """Returns the average local efficiency of the graph. - - The *efficiency* of a pair of nodes in a graph is the multiplicative - inverse of the shortest path distance between the nodes. The *local - efficiency* of a node in the graph is the average global efficiency of the - subgraph induced by the neighbors of the node. The *average local - efficiency* is the average of the local efficiencies of each node [1]_. - - Parameters - ---------- - G : :class:`networkx.Graph` - An undirected graph for which to compute the average local efficiency. - - Returns - ------- - float - The average local efficiency of the graph. - - Notes - ----- - Edge weights are ignored when computing the shortest path distances. - - See also - -------- - global_efficiency - - References - ---------- - .. [1] Latora, Vito, and Massimo Marchiori. - "Efficient behavior of small-world networks." - *Physical Review Letters* 87.19 (2001): 198701. - - - """ - # TODO This summation can be trivially parallelized. - efficiency_list = (global_efficiency(G.subgraph(G[v])) for v in G) - return sum(efficiency_list) / len(G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/euler.py b/extensions/fablabchemnitz/networkx/algorithms/euler.py deleted file mode 100644 index 7d96c05c..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/euler.py +++ /dev/null @@ -1,379 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2010 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: -# Nima Mohammadi -# Aric Hagberg -# Mike Trenfield -""" -Eulerian circuits and graphs. -""" -from itertools import combinations - -import networkx as nx -from ..utils import arbitrary_element, not_implemented_for - -__all__ = ['is_eulerian', 'eulerian_circuit', 'eulerize', - 'is_semieulerian', 'has_eulerian_path', 'eulerian_path', - ] - - -def is_eulerian(G): - """Returns True if and only if `G` is Eulerian. - - A graph is *Eulerian* if it has an Eulerian circuit. An *Eulerian - circuit* is a closed walk that includes each edge of a graph exactly - once. - - Parameters - ---------- - G : NetworkX graph - A graph, either directed or undirected. - - Examples - -------- - >>> nx.is_eulerian(nx.DiGraph({0: [3], 1: [2], 2: [3], 3: [0, 1]})) - True - >>> nx.is_eulerian(nx.complete_graph(5)) - True - >>> nx.is_eulerian(nx.petersen_graph()) - False - - Notes - ----- - If the graph is not connected (or not strongly connected, for - directed graphs), this function returns False. - - """ - if G.is_directed(): - # Every node must have equal in degree and out degree and the - # graph must be strongly connected - return (all(G.in_degree(n) == G.out_degree(n) for n in G) and - nx.is_strongly_connected(G)) - # An undirected Eulerian graph has no vertices of odd degree and - # must be connected. - return all(d % 2 == 0 for v, d in G.degree()) and nx.is_connected(G) - - -def is_semieulerian(G): - """Return True iff `G` is semi-Eulerian. - - G is semi-Eulerian if it has an Eulerian path but no Eulerian circuit. - """ - return has_eulerian_path(G) and not is_eulerian(G) - - -def _find_path_start(G): - """Return a suitable starting vertex for an Eulerian path. - - If no path exists, return None. - """ - if not has_eulerian_path(G): - return None - - if is_eulerian(G): - return arbitrary_element(G) - - if G.is_directed(): - v1, v2 = [v for v in G if G.in_degree(v) != G.out_degree(v)] - # Determines which is the 'start' node (as opposed to the 'end') - if G.out_degree(v1) > G.in_degree(v1): - return v1 - else: - return v2 - - else: - # In an undirected graph randomly choose one of the possibilities - start = [v for v in G if G.degree(v) % 2 != 0][0] - return start - - -def _simplegraph_eulerian_circuit(G, source): - if G.is_directed(): - degree = G.out_degree - edges = G.out_edges - else: - degree = G.degree - edges = G.edges - vertex_stack = [source] - last_vertex = None - while vertex_stack: - current_vertex = vertex_stack[-1] - if degree(current_vertex) == 0: - if last_vertex is not None: - yield (last_vertex, current_vertex) - last_vertex = current_vertex - vertex_stack.pop() - else: - _, next_vertex = arbitrary_element(edges(current_vertex)) - vertex_stack.append(next_vertex) - G.remove_edge(current_vertex, next_vertex) - - -def _multigraph_eulerian_circuit(G, source): - if G.is_directed(): - degree = G.out_degree - edges = G.out_edges - else: - degree = G.degree - edges = G.edges - vertex_stack = [(source, None)] - last_vertex = None - last_key = None - while vertex_stack: - current_vertex, current_key = vertex_stack[-1] - if degree(current_vertex) == 0: - if last_vertex is not None: - yield (last_vertex, current_vertex, last_key) - last_vertex, last_key = current_vertex, current_key - vertex_stack.pop() - else: - triple = arbitrary_element(edges(current_vertex, keys=True)) - _, next_vertex, next_key = triple - vertex_stack.append((next_vertex, next_key)) - G.remove_edge(current_vertex, next_vertex, next_key) - - -def eulerian_circuit(G, source=None, keys=False): - """Returns an iterator over the edges of an Eulerian circuit in `G`. - - An *Eulerian circuit* is a closed walk that includes each edge of a - graph exactly once. - - Parameters - ---------- - G : NetworkX graph - A graph, either directed or undirected. - - source : node, optional - Starting node for circuit. - - keys : bool - If False, edges generated by this function will be of the form - ``(u, v)``. Otherwise, edges will be of the form ``(u, v, k)``. - This option is ignored unless `G` is a multigraph. - - Returns - ------- - edges : iterator - An iterator over edges in the Eulerian circuit. - - Raises - ------ - NetworkXError - If the graph is not Eulerian. - - See Also - -------- - is_eulerian - - Notes - ----- - This is a linear time implementation of an algorithm adapted from [1]_. - - For general information about Euler tours, see [2]_. - - References - ---------- - .. [1] J. Edmonds, E. L. Johnson. - Matching, Euler tours and the Chinese postman. - Mathematical programming, Volume 5, Issue 1 (1973), 111-114. - .. [2] https://en.wikipedia.org/wiki/Eulerian_path - - Examples - -------- - To get an Eulerian circuit in an undirected graph:: - - >>> G = nx.complete_graph(3) - >>> list(nx.eulerian_circuit(G)) - [(0, 2), (2, 1), (1, 0)] - >>> list(nx.eulerian_circuit(G, source=1)) - [(1, 2), (2, 0), (0, 1)] - - To get the sequence of vertices in an Eulerian circuit:: - - >>> [u for u, v in nx.eulerian_circuit(G)] - [0, 2, 1] - - """ - if not is_eulerian(G): - raise nx.NetworkXError("G is not Eulerian.") - if G.is_directed(): - G = G.reverse() - else: - G = G.copy() - if source is None: - source = arbitrary_element(G) - if G.is_multigraph(): - for u, v, k in _multigraph_eulerian_circuit(G, source): - if keys: - yield u, v, k - else: - yield u, v - else: - for u, v in _simplegraph_eulerian_circuit(G, source): - yield u, v - - -def has_eulerian_path(G): - """Return True iff `G` has an Eulerian path. - - An Eulerian path is a path in a graph which uses each edge of a graph - exactly once. - - A directed graph has an Eulerian path iff: - - at most one vertex has out_degree - in_degree = 1, - - at most one vertex has in_degree - out_degree = 1, - - every other vertex has equal in_degree and out_degree, - - and all of its vertices with nonzero degree belong to a - - single connected component of the underlying undirected graph. - - An undirected graph has an Eulerian path iff: - - exactly zero or two vertices have odd degree, - - and all of its vertices with nonzero degree belong to a - - single connected component. - - Parameters - ---------- - G : NetworkX Graph - The graph to find an euler path in. - - Returns - ------- - Bool : True if G has an eulerian path. - - See Also - -------- - is_eulerian - eulerian_path - """ - if G.is_directed(): - ins = G.in_degree - outs = G.out_degree - semibalanced_ins = sum(ins(v) - outs(v) == 1 for v in G) - semibalanced_outs = sum(outs(v) - ins(v) == 1 for v in G) - return (semibalanced_ins <= 1 and - semibalanced_outs <= 1 and - sum(G.in_degree(v) != G.out_degree(v) for v in G) <= 2 and - nx.is_weakly_connected(G)) - else: - return (sum(d % 2 == 1 for v, d in G.degree()) in (0, 2) - and nx.is_connected(G)) - - -def eulerian_path(G, source=None, keys=False): - """Return an iterator over the edges of an Eulerian path in `G`. - - Parameters - ---------- - G : NetworkX Graph - The graph in which to look for an eulerian path. - source : node or None (default: None) - The node at which to start the search. None means search over all - starting nodes. - keys : Bool (default: False) - Indicates whether to yield edge 3-tuples (u, v, edge_key). - The default yields edge 2-tuples - - Yields - ------ - Edge tuples along the eulerian path. - - Warning: If `source` provided is not the start node of an Euler path - will raise error even if an Euler Path exists. - """ - if not has_eulerian_path(G): - raise nx.NetworkXError("Graph has no Eulerian paths.") - if G.is_directed(): - G = G.reverse() - else: - G = G.copy() - if source is None: - source = _find_path_start(G) - if G.is_multigraph(): - for u, v, k in _multigraph_eulerian_circuit(G, source): - if keys: - yield u, v, k - else: - yield u, v - else: - for u, v in _simplegraph_eulerian_circuit(G, source): - yield u, v - - -@not_implemented_for('directed') -def eulerize(G): - """Transforms a graph into an Eulerian graph - - Parameters - ---------- - G : NetworkX graph - An undirected graph - - Returns - ------- - G : NetworkX multigraph - - Raises - ------ - NetworkXError - If the graph is not connected. - - See Also - -------- - is_eulerian - eulerian_circuit - - References - ---------- - .. [1] J. Edmonds, E. L. Johnson. - Matching, Euler tours and the Chinese postman. - Mathematical programming, Volume 5, Issue 1 (1973), 111-114. - [2] https://en.wikipedia.org/wiki/Eulerian_path - .. [3] http://web.math.princeton.edu/math_alive/5/Notes1.pdf - - Examples - -------- - >>> G = nx.complete_graph(10) - >>> H = nx.eulerize(G) - >>> nx.is_eulerian(H) - True - - """ - if G.order() == 0: - raise nx.NetworkXPointlessConcept("Cannot Eulerize null graph") - if not nx.is_connected(G): - raise nx.NetworkXError("G is not connected") - odd_degree_nodes = [n for n, d in G.degree() if d % 2 == 1] - G = nx.MultiGraph(G) - if len(odd_degree_nodes) == 0: - return G - - # get all shortest paths between vertices of odd degree - odd_deg_pairs_paths = [(m, - {n: nx.shortest_path(G, source=m, target=n)} - ) - for m, n in combinations(odd_degree_nodes, 2)] - - # use inverse path lengths as edge-weights in a new graph - # store the paths in the graph for easy indexing later - Gp = nx.Graph() - for n, Ps in odd_deg_pairs_paths: - for m, P in Ps.items(): - if n != m: - Gp.add_edge(m, n, weight=1/len(P), path=P) - - # find the minimum weight matching of edges in the weighted graph - best_matching = nx.Graph(list(nx.max_weight_matching(Gp))) - - # duplicate each edge along each path in the set of paths in Gp - for m, n in best_matching.edges(): - path = Gp[m][n]["path"] - G.add_edges_from(nx.utils.pairwise(path)) - return G diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/flow/__init__.py deleted file mode 100644 index c5d19abe..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/flow/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -from .maxflow import * -from .mincost import * -from .boykovkolmogorov import * -from .dinitz_alg import * -from .edmondskarp import * -from .gomory_hu import * -from .preflowpush import * -from .shortestaugmentingpath import * -from .capacityscaling import * -from .networksimplex import * -from .utils import build_flow_dict, build_residual_network diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/boykovkolmogorov.py b/extensions/fablabchemnitz/networkx/algorithms/flow/boykovkolmogorov.py deleted file mode 100644 index 55cee438..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/flow/boykovkolmogorov.py +++ /dev/null @@ -1,377 +0,0 @@ -# boykovkolmogorov.py - Boykov Kolmogorov algorithm for maximum flow problems. -# -# Copyright 2016-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -# -# Author: Jordi Torrents -""" -Boykov-Kolmogorov algorithm for maximum flow problems. -""" -from collections import deque -from operator import itemgetter - -import networkx as nx -from networkx.algorithms.flow.utils import build_residual_network - -__all__ = ['boykov_kolmogorov'] - - -def boykov_kolmogorov(G, s, t, capacity='capacity', residual=None, - value_only=False, cutoff=None): - r"""Find a maximum single-commodity flow using Boykov-Kolmogorov algorithm. - - This function returns the residual network resulting after computing - the maximum flow. See below for details about the conventions - NetworkX uses for defining residual networks. - - This algorithm has worse case complexity $O(n^2 m |C|)$ for $n$ nodes, $m$ - edges, and $|C|$ the cost of the minimum cut [1]_. This implementation - uses the marking heuristic defined in [2]_ which improves its running - time in many practical problems. - - Parameters - ---------- - G : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - s : node - Source node for the flow. - - t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - residual : NetworkX graph - Residual network on which the algorithm is to be executed. If None, a - new residual network is created. Default value: None. - - value_only : bool - If True compute only the value of the maximum flow. This parameter - will be ignored by this algorithm because it is not applicable. - - cutoff : integer, float - If specified, the algorithm will terminate when the flow value reaches - or exceeds the cutoff. In this case, it may be unable to immediately - determine a minimum cut. Default value: None. - - Returns - ------- - R : NetworkX DiGraph - Residual network after computing the maximum flow. - - Raises - ------ - NetworkXError - The algorithm does not support MultiGraph and MultiDiGraph. If - the input graph is an instance of one of these two classes, a - NetworkXError is raised. - - NetworkXUnbounded - If the graph has a path of infinite capacity, the value of a - feasible flow on the graph is unbounded above and the function - raises a NetworkXUnbounded. - - See also - -------- - :meth:`maximum_flow` - :meth:`minimum_cut` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Notes - ----- - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. If :samp:`cutoff` is not - specified, reachability to :samp:`t` using only edges :samp:`(u, v)` such - that :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Examples - -------- - >>> import networkx as nx - >>> from networkx.algorithms.flow import boykov_kolmogorov - - The functions that implement flow algorithms and output a residual - network, such as this one, are not imported to the base NetworkX - namespace, so you have to explicitly import them from the flow package. - - >>> G = nx.DiGraph() - >>> G.add_edge('x','a', capacity=3.0) - >>> G.add_edge('x','b', capacity=1.0) - >>> G.add_edge('a','c', capacity=3.0) - >>> G.add_edge('b','c', capacity=5.0) - >>> G.add_edge('b','d', capacity=4.0) - >>> G.add_edge('d','e', capacity=2.0) - >>> G.add_edge('c','y', capacity=2.0) - >>> G.add_edge('e','y', capacity=3.0) - >>> R = boykov_kolmogorov(G, 'x', 'y') - >>> flow_value = nx.maximum_flow_value(G, 'x', 'y') - >>> flow_value - 3.0 - >>> flow_value == R.graph['flow_value'] - True - - A nice feature of the Boykov-Kolmogorov algorithm is that a partition - of the nodes that defines a minimum cut can be easily computed based - on the search trees used during the algorithm. These trees are stored - in the graph attribute `trees` of the residual network. - - >>> source_tree, target_tree = R.graph['trees'] - >>> partition = (set(source_tree), set(G) - set(source_tree)) - - Or equivalently: - - >>> partition = (set(G) - set(target_tree), set(target_tree)) - - References - ---------- - .. [1] Boykov, Y., & Kolmogorov, V. (2004). An experimental comparison - of min-cut/max-flow algorithms for energy minimization in vision. - Pattern Analysis and Machine Intelligence, IEEE Transactions on, - 26(9), 1124-1137. - http://www.csd.uwo.ca/~yuri/Papers/pami04.pdf - - .. [2] Vladimir Kolmogorov. Graph-based Algorithms for Multi-camera - Reconstruction Problem. PhD thesis, Cornell University, CS Department, - 2003. pp. 109-114. - https://pub.ist.ac.at/~vnk/papers/thesis.pdf - - """ - R = boykov_kolmogorov_impl(G, s, t, capacity, residual, cutoff) - R.graph['algorithm'] = 'boykov_kolmogorov' - return R - - -def boykov_kolmogorov_impl(G, s, t, capacity, residual, cutoff): - if s not in G: - raise nx.NetworkXError('node %s not in graph' % str(s)) - if t not in G: - raise nx.NetworkXError('node %s not in graph' % str(t)) - if s == t: - raise nx.NetworkXError('source and sink are the same node') - - if residual is None: - R = build_residual_network(G, capacity) - else: - R = residual - - # Initialize/reset the residual network. - # This is way too slow - #nx.set_edge_attributes(R, 0, 'flow') - for u in R: - for e in R[u].values(): - e['flow'] = 0 - - # Use an arbitrary high value as infinite. It is computed - # when building the residual network. - INF = R.graph['inf'] - - if cutoff is None: - cutoff = INF - - R_succ = R.succ - R_pred = R.pred - - def grow(): - """Bidirectional breadth-first search for the growth stage. - - Returns a connecting edge, that is and edge that connects - a node from the source search tree with a node from the - target search tree. - The first node in the connecting edge is always from the - source tree and the last node from the target tree. - """ - while active: - u = active[0] - if u in source_tree: - this_tree = source_tree - other_tree = target_tree - neighbors = R_succ - else: - this_tree = target_tree - other_tree = source_tree - neighbors = R_pred - for v, attr in neighbors[u].items(): - if attr['capacity'] - attr['flow'] > 0: - if v not in this_tree: - if v in other_tree: - return (u, v) if this_tree is source_tree else (v, u) - this_tree[v] = u - dist[v] = dist[u] + 1 - timestamp[v] = timestamp[u] - active.append(v) - elif v in this_tree and _is_closer(u, v): - this_tree[v] = u - dist[v] = dist[u] + 1 - timestamp[v] = timestamp[u] - _ = active.popleft() - return None, None - - def augment(u, v): - """Augmentation stage. - - Reconstruct path and determine its residual capacity. - We start from a connecting edge, which links a node - from the source tree to a node from the target tree. - The connecting edge is the output of the grow function - and the input of this function. - """ - attr = R_succ[u][v] - flow = min(INF, attr['capacity'] - attr['flow']) - path = [u] - # Trace a path from u to s in source_tree. - w = u - while w != s: - n = w - w = source_tree[n] - attr = R_pred[n][w] - flow = min(flow, attr['capacity'] - attr['flow']) - path.append(w) - path.reverse() - # Trace a path from v to t in target_tree. - path.append(v) - w = v - while w != t: - n = w - w = target_tree[n] - attr = R_succ[n][w] - flow = min(flow, attr['capacity'] - attr['flow']) - path.append(w) - # Augment flow along the path and check for saturated edges. - it = iter(path) - u = next(it) - these_orphans = [] - for v in it: - R_succ[u][v]['flow'] += flow - R_succ[v][u]['flow'] -= flow - if R_succ[u][v]['flow'] == R_succ[u][v]['capacity']: - if v in source_tree: - source_tree[v] = None - these_orphans.append(v) - if u in target_tree: - target_tree[u] = None - these_orphans.append(u) - u = v - orphans.extend(sorted(these_orphans, key=dist.get)) - return flow - - def adopt(): - """Adoption stage. - - Reconstruct search trees by adopting or discarding orphans. - During augmentation stage some edges got saturated and thus - the source and target search trees broke down to forests, with - orphans as roots of some of its trees. We have to reconstruct - the search trees rooted to source and target before we can grow - them again. - """ - while orphans: - u = orphans.popleft() - if u in source_tree: - tree = source_tree - neighbors = R_pred - else: - tree = target_tree - neighbors = R_succ - nbrs = ((n, attr, dist[n]) for n, attr in neighbors[u].items() - if n in tree) - for v, attr, d in sorted(nbrs, key=itemgetter(2)): - if attr['capacity'] - attr['flow'] > 0: - if _has_valid_root(v, tree): - tree[u] = v - dist[u] = dist[v] + 1 - timestamp[u] = time - break - else: - nbrs = ((n, attr, dist[n]) for n, attr in neighbors[u].items() - if n in tree) - for v, attr, d in sorted(nbrs, key=itemgetter(2)): - if attr['capacity'] - attr['flow'] > 0: - if v not in active: - active.append(v) - if tree[v] == u: - tree[v] = None - orphans.appendleft(v) - if u in active: - active.remove(u) - del tree[u] - - def _has_valid_root(n, tree): - path = [] - v = n - while v is not None: - path.append(v) - if v == s or v == t: - base_dist = 0 - break - elif timestamp[v] == time: - base_dist = dist[v] - break - v = tree[v] - else: - return False - length = len(path) - for i, u in enumerate(path, 1): - dist[u] = base_dist + length - i - timestamp[u] = time - return True - - def _is_closer(u, v): - return timestamp[v] <= timestamp[u] and dist[v] > dist[u] + 1 - - source_tree = {s: None} - target_tree = {t: None} - active = deque([s, t]) - orphans = deque() - flow_value = 0 - # data structures for the marking heuristic - time = 1 - timestamp = {s: time, t: time} - dist = {s: 0, t: 0} - while flow_value < cutoff: - # Growth stage - u, v = grow() - if u is None: - break - time += 1 - # Augmentation stage - flow_value += augment(u, v) - # Adoption stage - adopt() - - if flow_value * 2 > INF: - raise nx.NetworkXUnbounded('Infinite capacity path, flow unbounded above.') - - # Add source and target tree in a graph attribute. - # A partition that defines a minimum cut can be directly - # computed from the search trees as explained in the docstrings. - R.graph['trees'] = (source_tree, target_tree) - # Add the standard flow_value graph attribute. - R.graph['flow_value'] = flow_value - return R diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/capacityscaling.py b/extensions/fablabchemnitz/networkx/algorithms/flow/capacityscaling.py deleted file mode 100644 index dd390fd5..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/flow/capacityscaling.py +++ /dev/null @@ -1,383 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Capacity scaling minimum cost flow algorithm. -""" - -__author__ = """ysitu """ -# Copyright (C) 2014 ysitu -# All rights reserved. -# BSD license. - -__all__ = ['capacity_scaling'] - -from itertools import chain -from math import log -import networkx as nx -from ...utils import BinaryHeap -from ...utils import generate_unique_node -from ...utils import not_implemented_for -from ...utils import arbitrary_element - - -def _detect_unboundedness(R): - """Detect infinite-capacity negative cycles. - """ - s = generate_unique_node() - G = nx.DiGraph() - G.add_nodes_from(R) - - # Value simulating infinity. - inf = R.graph['inf'] - # True infinity. - f_inf = float('inf') - for u in R: - for v, e in R[u].items(): - # Compute the minimum weight of infinite-capacity (u, v) edges. - w = f_inf - for k, e in e.items(): - if e['capacity'] == inf: - w = min(w, e['weight']) - if w != f_inf: - G.add_edge(u, v, weight=w) - - if nx.negative_edge_cycle(G): - raise nx.NetworkXUnbounded( - 'Negative cost cycle of infinite capacity found. ' - 'Min cost flow may be unbounded below.') - - -@not_implemented_for('undirected') -def _build_residual_network(G, demand, capacity, weight): - """Build a residual network and initialize a zero flow. - """ - if sum(G.nodes[u].get(demand, 0) for u in G) != 0: - raise nx.NetworkXUnfeasible("Sum of the demands should be 0.") - - R = nx.MultiDiGraph() - R.add_nodes_from((u, {'excess': -G.nodes[u].get(demand, 0), - 'potential': 0}) for u in G) - - inf = float('inf') - # Detect selfloops with infinite capacities and negative weights. - for u, v, e in nx.selfloop_edges(G, data=True): - if e.get(weight, 0) < 0 and e.get(capacity, inf) == inf: - raise nx.NetworkXUnbounded( - 'Negative cost cycle of infinite capacity found. ' - 'Min cost flow may be unbounded below.') - - # Extract edges with positive capacities. Self loops excluded. - if G.is_multigraph(): - edge_list = [(u, v, k, e) - for u, v, k, e in G.edges(data=True, keys=True) - if u != v and e.get(capacity, inf) > 0] - else: - edge_list = [(u, v, 0, e) for u, v, e in G.edges(data=True) - if u != v and e.get(capacity, inf) > 0] - # Simulate infinity with the larger of the sum of absolute node imbalances - # the sum of finite edge capacities or any positive value if both sums are - # zero. This allows the infinite-capacity edges to be distinguished for - # unboundedness detection and directly participate in residual capacity - # calculation. - inf = max(sum(abs(R.nodes[u]['excess']) for u in R), - 2 * sum(e[capacity] for u, v, k, e in edge_list - if capacity in e and e[capacity] != inf)) or 1 - for u, v, k, e in edge_list: - r = min(e.get(capacity, inf), inf) - w = e.get(weight, 0) - # Add both (u, v) and (v, u) into the residual network marked with the - # original key. (key[1] == True) indicates the (u, v) is in the - # original network. - R.add_edge(u, v, key=(k, True), capacity=r, weight=w, flow=0) - R.add_edge(v, u, key=(k, False), capacity=0, weight=-w, flow=0) - - # Record the value simulating infinity. - R.graph['inf'] = inf - - _detect_unboundedness(R) - - return R - - -def _build_flow_dict(G, R, capacity, weight): - """Build a flow dictionary from a residual network. - """ - inf = float('inf') - flow_dict = {} - if G.is_multigraph(): - for u in G: - flow_dict[u] = {} - for v, es in G[u].items(): - flow_dict[u][v] = dict( - # Always saturate negative selfloops. - (k, (0 if (u != v or e.get(capacity, inf) <= 0 or - e.get(weight, 0) >= 0) else e[capacity])) - for k, e in es.items()) - for v, es in R[u].items(): - if v in flow_dict[u]: - flow_dict[u][v].update((k[0], e['flow']) - for k, e in es.items() - if e['flow'] > 0) - else: - for u in G: - flow_dict[u] = dict( - # Always saturate negative selfloops. - (v, (0 if (u != v or e.get(capacity, inf) <= 0 or - e.get(weight, 0) >= 0) else e[capacity])) - for v, e in G[u].items()) - flow_dict[u].update((v, e['flow']) for v, es in R[u].items() - for e in es.values() if e['flow'] > 0) - return flow_dict - - -def capacity_scaling(G, demand='demand', capacity='capacity', weight='weight', - heap=BinaryHeap): - r"""Find a minimum cost flow satisfying all demands in digraph G. - - This is a capacity scaling successive shortest augmenting path algorithm. - - G is a digraph with edge costs and capacities and in which nodes - have demand, i.e., they want to send or receive some amount of - flow. A negative demand means that the node wants to send flow, a - positive demand means that the node want to receive flow. A flow on - the digraph G satisfies all demand if the net flow into each node - is equal to the demand of that node. - - Parameters - ---------- - G : NetworkX graph - DiGraph or MultiDiGraph on which a minimum cost flow satisfying all - demands is to be found. - - demand : string - Nodes of the graph G are expected to have an attribute demand - that indicates how much flow a node wants to send (negative - demand) or receive (positive demand). Note that the sum of the - demands should be 0 otherwise the problem in not feasible. If - this attribute is not present, a node is considered to have 0 - demand. Default value: 'demand'. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - weight : string - Edges of the graph G are expected to have an attribute weight - that indicates the cost incurred by sending one unit of flow on - that edge. If not present, the weight is considered to be 0. - Default value: 'weight'. - - heap : class - Type of heap to be used in the algorithm. It should be a subclass of - :class:`MinHeap` or implement a compatible interface. - - If a stock heap implementation is to be used, :class:`BinaryHeap` is - recommended over :class:`PairingHeap` for Python implementations without - optimized attribute accesses (e.g., CPython) despite a slower - asymptotic running time. For Python implementations with optimized - attribute accesses (e.g., PyPy), :class:`PairingHeap` provides better - performance. Default value: :class:`BinaryHeap`. - - Returns - ------- - flowCost : integer - Cost of a minimum cost flow satisfying all demands. - - flowDict : dictionary - If G is a digraph, a dict-of-dicts keyed by nodes such that - flowDict[u][v] is the flow on edge (u, v). - If G is a MultiDiGraph, a dict-of-dicts-of-dicts keyed by nodes - so that flowDict[u][v][key] is the flow on edge (u, v, key). - - Raises - ------ - NetworkXError - This exception is raised if the input graph is not directed, - not connected. - - NetworkXUnfeasible - This exception is raised in the following situations: - - * The sum of the demands is not zero. Then, there is no - flow satisfying all demands. - * There is no flow satisfying all demand. - - NetworkXUnbounded - This exception is raised if the digraph G has a cycle of - negative cost and infinite capacity. Then, the cost of a flow - satisfying all demands is unbounded below. - - Notes - ----- - This algorithm does not work if edge weights are floating-point numbers. - - See also - -------- - :meth:`network_simplex` - - Examples - -------- - A simple example of a min cost flow problem. - - >>> import networkx as nx - >>> G = nx.DiGraph() - >>> G.add_node('a', demand = -5) - >>> G.add_node('d', demand = 5) - >>> G.add_edge('a', 'b', weight = 3, capacity = 4) - >>> G.add_edge('a', 'c', weight = 6, capacity = 10) - >>> G.add_edge('b', 'd', weight = 1, capacity = 9) - >>> G.add_edge('c', 'd', weight = 2, capacity = 5) - >>> flowCost, flowDict = nx.capacity_scaling(G) - >>> flowCost - 24 - >>> flowDict # doctest: +SKIP - {'a': {'c': 1, 'b': 4}, 'c': {'d': 1}, 'b': {'d': 4}, 'd': {}} - - It is possible to change the name of the attributes used for the - algorithm. - - >>> G = nx.DiGraph() - >>> G.add_node('p', spam = -4) - >>> G.add_node('q', spam = 2) - >>> G.add_node('a', spam = -2) - >>> G.add_node('d', spam = -1) - >>> G.add_node('t', spam = 2) - >>> G.add_node('w', spam = 3) - >>> G.add_edge('p', 'q', cost = 7, vacancies = 5) - >>> G.add_edge('p', 'a', cost = 1, vacancies = 4) - >>> G.add_edge('q', 'd', cost = 2, vacancies = 3) - >>> G.add_edge('t', 'q', cost = 1, vacancies = 2) - >>> G.add_edge('a', 't', cost = 2, vacancies = 4) - >>> G.add_edge('d', 'w', cost = 3, vacancies = 4) - >>> G.add_edge('t', 'w', cost = 4, vacancies = 1) - >>> flowCost, flowDict = nx.capacity_scaling(G, demand = 'spam', - ... capacity = 'vacancies', - ... weight = 'cost') - >>> flowCost - 37 - >>> flowDict # doctest: +SKIP - {'a': {'t': 4}, 'd': {'w': 2}, 'q': {'d': 1}, 'p': {'q': 2, 'a': 2}, 't': {'q': 1, 'w': 1}, 'w': {}} - """ - R = _build_residual_network(G, demand, capacity, weight) - - inf = float('inf') - # Account cost of negative selfloops. - flow_cost = sum( - 0 if e.get(capacity, inf) <= 0 or e.get(weight, 0) >= 0 - else e[capacity] * e[weight] - for u, v, e in nx.selfloop_edges(G, data=True)) - - # Determine the maxmimum edge capacity. - wmax = max(chain([-inf], - (e['capacity'] for u, v, e in R.edges(data=True)))) - if wmax == -inf: - # Residual network has no edges. - return flow_cost, _build_flow_dict(G, R, capacity, weight) - - R_nodes = R.nodes - R_succ = R.succ - - delta = 2 ** int(log(wmax, 2)) - while delta >= 1: - # Saturate Δ-residual edges with negative reduced costs to achieve - # Δ-optimality. - for u in R: - p_u = R_nodes[u]['potential'] - for v, es in R_succ[u].items(): - for k, e in es.items(): - flow = e['capacity'] - e['flow'] - if e['weight'] - p_u + R_nodes[v]['potential'] < 0: - flow = e['capacity'] - e['flow'] - if flow >= delta: - e['flow'] += flow - R_succ[v][u][(k[0], not k[1])]['flow'] -= flow - R_nodes[u]['excess'] -= flow - R_nodes[v]['excess'] += flow - # Determine the Δ-active nodes. - S = set() - T = set() - S_add = S.add - S_remove = S.remove - T_add = T.add - T_remove = T.remove - for u in R: - excess = R_nodes[u]['excess'] - if excess >= delta: - S_add(u) - elif excess <= -delta: - T_add(u) - # Repeatedly augment flow from S to T along shortest paths until - # Δ-feasibility is achieved. - while S and T: - s = arbitrary_element(S) - t = None - # Search for a shortest path in terms of reduce costs from s to - # any t in T in the Δ-residual network. - d = {} - pred = {s: None} - h = heap() - h_insert = h.insert - h_get = h.get - h_insert(s, 0) - while h: - u, d_u = h.pop() - d[u] = d_u - if u in T: - # Path found. - t = u - break - p_u = R_nodes[u]['potential'] - for v, es in R_succ[u].items(): - if v in d: - continue - wmin = inf - # Find the minimum-weighted (u, v) Δ-residual edge. - for k, e in es.items(): - if e['capacity'] - e['flow'] >= delta: - w = e['weight'] - if w < wmin: - wmin = w - kmin = k - emin = e - if wmin == inf: - continue - # Update the distance label of v. - d_v = d_u + wmin - p_u + R_nodes[v]['potential'] - if h_insert(v, d_v): - pred[v] = (u, kmin, emin) - if t is not None: - # Augment Δ units of flow from s to t. - while u != s: - v = u - u, k, e = pred[v] - e['flow'] += delta - R_succ[v][u][(k[0], not k[1])]['flow'] -= delta - # Account node excess and deficit. - R_nodes[s]['excess'] -= delta - R_nodes[t]['excess'] += delta - if R_nodes[s]['excess'] < delta: - S_remove(s) - if R_nodes[t]['excess'] > -delta: - T_remove(t) - # Update node potentials. - d_t = d[t] - for u, d_u in d.items(): - R_nodes[u]['potential'] -= d_u - d_t - else: - # Path not found. - S_remove(s) - delta //= 2 - - if any(R.nodes[u]['excess'] != 0 for u in R): - raise nx.NetworkXUnfeasible('No flow satisfying all demands.') - - # Calculate the flow cost. - for u in R: - for v, es in R_succ[u].items(): - for e in es.values(): - flow = e['flow'] - if flow > 0: - flow_cost += flow * e['weight'] - - return flow_cost, _build_flow_dict(G, R, capacity, weight) diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/dinitz_alg.py b/extensions/fablabchemnitz/networkx/algorithms/flow/dinitz_alg.py deleted file mode 100644 index 8dcba1a0..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/flow/dinitz_alg.py +++ /dev/null @@ -1,223 +0,0 @@ -# dinitz.py - Dinitz' algorithm for maximum flow problems. -# -# Copyright 2016-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -# -# Author: Jordi Torrents -""" -Dinitz' algorithm for maximum flow problems. -""" -from collections import deque - -import networkx as nx -from networkx.algorithms.flow.utils import build_residual_network -from networkx.utils import pairwise - -__all__ = ['dinitz'] - - -def dinitz(G, s, t, capacity='capacity', residual=None, value_only=False, cutoff=None): - """Find a maximum single-commodity flow using Dinitz' algorithm. - - This function returns the residual network resulting after computing - the maximum flow. See below for details about the conventions - NetworkX uses for defining residual networks. - - This algorithm has a running time of $O(n^2 m)$ for $n$ nodes and $m$ - edges [1]_. - - - Parameters - ---------- - G : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - s : node - Source node for the flow. - - t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - residual : NetworkX graph - Residual network on which the algorithm is to be executed. If None, a - new residual network is created. Default value: None. - - value_only : bool - If True compute only the value of the maximum flow. This parameter - will be ignored by this algorithm because it is not applicable. - - cutoff : integer, float - If specified, the algorithm will terminate when the flow value reaches - or exceeds the cutoff. In this case, it may be unable to immediately - determine a minimum cut. Default value: None. - - Returns - ------- - R : NetworkX DiGraph - Residual network after computing the maximum flow. - - Raises - ------ - NetworkXError - The algorithm does not support MultiGraph and MultiDiGraph. If - the input graph is an instance of one of these two classes, a - NetworkXError is raised. - - NetworkXUnbounded - If the graph has a path of infinite capacity, the value of a - feasible flow on the graph is unbounded above and the function - raises a NetworkXUnbounded. - - See also - -------- - :meth:`maximum_flow` - :meth:`minimum_cut` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Notes - ----- - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. If :samp:`cutoff` is not - specified, reachability to :samp:`t` using only edges :samp:`(u, v)` such - that :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Examples - -------- - >>> import networkx as nx - >>> from networkx.algorithms.flow import dinitz - - The functions that implement flow algorithms and output a residual - network, such as this one, are not imported to the base NetworkX - namespace, so you have to explicitly import them from the flow package. - - >>> G = nx.DiGraph() - >>> G.add_edge('x','a', capacity=3.0) - >>> G.add_edge('x','b', capacity=1.0) - >>> G.add_edge('a','c', capacity=3.0) - >>> G.add_edge('b','c', capacity=5.0) - >>> G.add_edge('b','d', capacity=4.0) - >>> G.add_edge('d','e', capacity=2.0) - >>> G.add_edge('c','y', capacity=2.0) - >>> G.add_edge('e','y', capacity=3.0) - >>> R = dinitz(G, 'x', 'y') - >>> flow_value = nx.maximum_flow_value(G, 'x', 'y') - >>> flow_value - 3.0 - >>> flow_value == R.graph['flow_value'] - True - - References - ---------- - .. [1] Dinitz' Algorithm: The Original Version and Even's Version. - 2006. Yefim Dinitz. In Theoretical Computer Science. Lecture - Notes in Computer Science. Volume 3895. pp 218-240. - http://www.cs.bgu.ac.il/~dinitz/Papers/Dinitz_alg.pdf - - """ - R = dinitz_impl(G, s, t, capacity, residual, cutoff) - R.graph['algorithm'] = 'dinitz' - return R - - -def dinitz_impl(G, s, t, capacity, residual, cutoff): - if s not in G: - raise nx.NetworkXError('node %s not in graph' % str(s)) - if t not in G: - raise nx.NetworkXError('node %s not in graph' % str(t)) - if s == t: - raise nx.NetworkXError('source and sink are the same node') - - if residual is None: - R = build_residual_network(G, capacity) - else: - R = residual - - # Initialize/reset the residual network. - for u in R: - for e in R[u].values(): - e['flow'] = 0 - - # Use an arbitrary high value as infinite. It is computed - # when building the residual network. - INF = R.graph['inf'] - - if cutoff is None: - cutoff = INF - - R_succ = R.succ - R_pred = R.pred - - def breath_first_search(): - parents = {} - queue = deque([s]) - while queue: - if t in parents: - break - u = queue.popleft() - for v in R_succ[u]: - attr = R_succ[u][v] - if v not in parents and attr['capacity'] - attr['flow'] > 0: - parents[v] = u - queue.append(v) - return parents - - def depth_first_search(parents): - """Build a path using DFS starting from the sink""" - path = [] - u = t - flow = INF - while u != s: - path.append(u) - v = parents[u] - flow = min(flow, R_pred[u][v]['capacity'] - R_pred[u][v]['flow']) - u = v - path.append(s) - # Augment the flow along the path found - if flow > 0: - for u, v in pairwise(path): - R_pred[u][v]['flow'] += flow - R_pred[v][u]['flow'] -= flow - return flow - - flow_value = 0 - while flow_value < cutoff: - parents = breath_first_search() - if t not in parents: - break - this_flow = depth_first_search(parents) - if this_flow * 2 > INF: - raise nx.NetworkXUnbounded( - 'Infinite capacity path, flow unbounded above.') - flow_value += this_flow - - R.graph['flow_value'] = flow_value - return R diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/edmondskarp.py b/extensions/fablabchemnitz/networkx/algorithms/flow/edmondskarp.py deleted file mode 100644 index aa94f980..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/flow/edmondskarp.py +++ /dev/null @@ -1,250 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Edmonds-Karp algorithm for maximum flow problems. -""" - -__author__ = """ysitu """ -# Copyright (C) 2014 ysitu -# All rights reserved. -# BSD license. - -import networkx as nx -from networkx.algorithms.flow.utils import * - -__all__ = ['edmonds_karp'] - - -def edmonds_karp_core(R, s, t, cutoff): - """Implementation of the Edmonds-Karp algorithm. - """ - R_nodes = R.nodes - R_pred = R.pred - R_succ = R.succ - - inf = R.graph['inf'] - - def augment(path): - """Augment flow along a path from s to t. - """ - # Determine the path residual capacity. - flow = inf - it = iter(path) - u = next(it) - for v in it: - attr = R_succ[u][v] - flow = min(flow, attr['capacity'] - attr['flow']) - u = v - if flow * 2 > inf: - raise nx.NetworkXUnbounded( - 'Infinite capacity path, flow unbounded above.') - # Augment flow along the path. - it = iter(path) - u = next(it) - for v in it: - R_succ[u][v]['flow'] += flow - R_succ[v][u]['flow'] -= flow - u = v - return flow - - def bidirectional_bfs(): - """Bidirectional breadth-first search for an augmenting path. - """ - pred = {s: None} - q_s = [s] - succ = {t: None} - q_t = [t] - while True: - q = [] - if len(q_s) <= len(q_t): - for u in q_s: - for v, attr in R_succ[u].items(): - if v not in pred and attr['flow'] < attr['capacity']: - pred[v] = u - if v in succ: - return v, pred, succ - q.append(v) - if not q: - return None, None, None - q_s = q - else: - for u in q_t: - for v, attr in R_pred[u].items(): - if v not in succ and attr['flow'] < attr['capacity']: - succ[v] = u - if v in pred: - return v, pred, succ - q.append(v) - if not q: - return None, None, None - q_t = q - - # Look for shortest augmenting paths using breadth-first search. - flow_value = 0 - while flow_value < cutoff: - v, pred, succ = bidirectional_bfs() - if pred is None: - break - path = [v] - # Trace a path from s to v. - u = v - while u != s: - u = pred[u] - path.append(u) - path.reverse() - # Trace a path from v to t. - u = v - while u != t: - u = succ[u] - path.append(u) - flow_value += augment(path) - - return flow_value - - -def edmonds_karp_impl(G, s, t, capacity, residual, cutoff): - """Implementation of the Edmonds-Karp algorithm. - """ - if s not in G: - raise nx.NetworkXError('node %s not in graph' % str(s)) - if t not in G: - raise nx.NetworkXError('node %s not in graph' % str(t)) - if s == t: - raise nx.NetworkXError('source and sink are the same node') - - if residual is None: - R = build_residual_network(G, capacity) - else: - R = residual - - # Initialize/reset the residual network. - for u in R: - for e in R[u].values(): - e['flow'] = 0 - - if cutoff is None: - cutoff = float('inf') - R.graph['flow_value'] = edmonds_karp_core(R, s, t, cutoff) - - return R - - -def edmonds_karp(G, s, t, capacity='capacity', residual=None, value_only=False, - cutoff=None): - """Find a maximum single-commodity flow using the Edmonds-Karp algorithm. - - This function returns the residual network resulting after computing - the maximum flow. See below for details about the conventions - NetworkX uses for defining residual networks. - - This algorithm has a running time of $O(n m^2)$ for $n$ nodes and $m$ - edges. - - - Parameters - ---------- - G : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - s : node - Source node for the flow. - - t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - residual : NetworkX graph - Residual network on which the algorithm is to be executed. If None, a - new residual network is created. Default value: None. - - value_only : bool - If True compute only the value of the maximum flow. This parameter - will be ignored by this algorithm because it is not applicable. - - cutoff : integer, float - If specified, the algorithm will terminate when the flow value reaches - or exceeds the cutoff. In this case, it may be unable to immediately - determine a minimum cut. Default value: None. - - Returns - ------- - R : NetworkX DiGraph - Residual network after computing the maximum flow. - - Raises - ------ - NetworkXError - The algorithm does not support MultiGraph and MultiDiGraph. If - the input graph is an instance of one of these two classes, a - NetworkXError is raised. - - NetworkXUnbounded - If the graph has a path of infinite capacity, the value of a - feasible flow on the graph is unbounded above and the function - raises a NetworkXUnbounded. - - See also - -------- - :meth:`maximum_flow` - :meth:`minimum_cut` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Notes - ----- - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. If :samp:`cutoff` is not - specified, reachability to :samp:`t` using only edges :samp:`(u, v)` such - that :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Examples - -------- - >>> import networkx as nx - >>> from networkx.algorithms.flow import edmonds_karp - - The functions that implement flow algorithms and output a residual - network, such as this one, are not imported to the base NetworkX - namespace, so you have to explicitly import them from the flow package. - - >>> G = nx.DiGraph() - >>> G.add_edge('x','a', capacity=3.0) - >>> G.add_edge('x','b', capacity=1.0) - >>> G.add_edge('a','c', capacity=3.0) - >>> G.add_edge('b','c', capacity=5.0) - >>> G.add_edge('b','d', capacity=4.0) - >>> G.add_edge('d','e', capacity=2.0) - >>> G.add_edge('c','y', capacity=2.0) - >>> G.add_edge('e','y', capacity=3.0) - >>> R = edmonds_karp(G, 'x', 'y') - >>> flow_value = nx.maximum_flow_value(G, 'x', 'y') - >>> flow_value - 3.0 - >>> flow_value == R.graph['flow_value'] - True - - """ - R = edmonds_karp_impl(G, s, t, capacity, residual, cutoff) - R.graph['algorithm'] = 'edmonds_karp' - return R diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/gomory_hu.py b/extensions/fablabchemnitz/networkx/algorithms/flow/gomory_hu.py deleted file mode 100644 index 9827efd1..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/flow/gomory_hu.py +++ /dev/null @@ -1,188 +0,0 @@ -# -*- coding: utf-8 -*- -# gomory_hu.py - function for computing Gomory Hu trees -# -# Copyright 2017-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -# -# Author: Jordi Torrents -""" -Gomory-Hu tree of undirected Graphs. -""" -import networkx as nx -from networkx.utils import not_implemented_for - -from .edmondskarp import edmonds_karp -from .utils import build_residual_network - -default_flow_func = edmonds_karp - -__all__ = ['gomory_hu_tree'] - - -@not_implemented_for('directed') -def gomory_hu_tree(G, capacity='capacity', flow_func=None): - r"""Returns the Gomory-Hu tree of an undirected graph G. - - A Gomory-Hu tree of an undirected graph with capacities is a - weighted tree that represents the minimum s-t cuts for all s-t - pairs in the graph. - - It only requires `n-1` minimum cut computations instead of the - obvious `n(n-1)/2`. The tree represents all s-t cuts as the - minimum cut value among any pair of nodes is the minimum edge - weight in the shortest path between the two nodes in the - Gomory-Hu tree. - - The Gomory-Hu tree also has the property that removing the - edge with the minimum weight in the shortest path between - any two nodes leaves two connected components that form - a partition of the nodes in G that defines the minimum s-t - cut. - - See Examples section below for details. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - flow_func : function - Function to perform the underlying flow computations. Default value - :func:`edmonds_karp`. This function performs better in sparse graphs - with right tailed degree distributions. - :func:`shortest_augmenting_path` will perform better in denser - graphs. - - Returns - ------- - Tree : NetworkX graph - A NetworkX graph representing the Gomory-Hu tree of the input graph. - - Raises - ------ - NetworkXNotImplemented : Exception - Raised if the input graph is directed. - - NetworkXError: Exception - Raised if the input graph is an empty Graph. - - Examples - -------- - >>> G = nx.karate_club_graph() - >>> nx.set_edge_attributes(G, 1, 'capacity') - >>> T = nx.gomory_hu_tree(G) - >>> # The value of the minimum cut between any pair - ... # of nodes in G is the minimum edge weight in the - ... # shortest path between the two nodes in the - ... # Gomory-Hu tree. - ... def minimum_edge_weight_in_shortest_path(T, u, v): - ... path = nx.shortest_path(T, u, v, weight='weight') - ... return min((T[u][v]['weight'], (u,v)) for (u, v) in zip(path, path[1:])) - >>> u, v = 0, 33 - >>> cut_value, edge = minimum_edge_weight_in_shortest_path(T, u, v) - >>> cut_value - 10 - >>> nx.minimum_cut_value(G, u, v) - 10 - >>> # The Comory-Hu tree also has the property that removing the - ... # edge with the minimum weight in the shortest path between - ... # any two nodes leaves two connected components that form - ... # a partition of the nodes in G that defines the minimum s-t - ... # cut. - ... cut_value, edge = minimum_edge_weight_in_shortest_path(T, u, v) - >>> T.remove_edge(*edge) - >>> U, V = list(nx.connected_components(T)) - >>> # Thus U and V form a partition that defines a minimum cut - ... # between u and v in G. You can compute the edge cut set, - ... # that is, the set of edges that if removed from G will - ... # disconnect u from v in G, with this information: - ... cutset = set() - >>> for x, nbrs in ((n, G[n]) for n in U): - ... cutset.update((x, y) for y in nbrs if y in V) - >>> # Because we have set the capacities of all edges to 1 - ... # the cutset contains ten edges - ... len(cutset) - 10 - >>> # You can use any maximum flow algorithm for the underlying - ... # flow computations using the argument flow_func - ... from networkx.algorithms import flow - >>> T = nx.gomory_hu_tree(G, flow_func=flow.boykov_kolmogorov) - >>> cut_value, edge = minimum_edge_weight_in_shortest_path(T, u, v) - >>> cut_value - 10 - >>> nx.minimum_cut_value(G, u, v, flow_func=flow.boykov_kolmogorov) - 10 - - Notes - ----- - This implementation is based on Gusfield approach [1]_ to compute - Comory-Hu trees, which does not require node contractions and has - the same computational complexity than the original method. - - See also - -------- - :func:`minimum_cut` - :func:`maximum_flow` - - References - ---------- - .. [1] Gusfield D: Very simple methods for all pairs network flow analysis. - SIAM J Comput 19(1):143-155, 1990. - - """ - if flow_func is None: - flow_func = default_flow_func - - if len(G) == 0: # empty graph - msg = 'Empty Graph does not have a Gomory-Hu tree representation' - raise nx.NetworkXError(msg) - - # Start the tree as a star graph with an arbitrary node at the center - tree = {} - labels = {} - iter_nodes = iter(G) - root = next(iter_nodes) - for n in iter_nodes: - tree[n] = root - - # Reuse residual network - R = build_residual_network(G, capacity) - - # For all the leaves in the star graph tree (that is n-1 nodes). - for source in tree: - # Find neighbor in the tree - target = tree[source] - # compute minimum cut - cut_value, partition = nx.minimum_cut(G, source, target, - capacity=capacity, - flow_func=flow_func, - residual=R) - labels[(source, target)] = cut_value - # Update the tree - # Source will always be in partition[0] and target in partition[1] - for node in partition[0]: - if node != source and node in tree and tree[node] == target: - tree[node] = source - labels[node, source] = labels.get((node, target), cut_value) - # - if target != root and tree[target] in partition[0]: - labels[source, tree[target]] = labels[target, tree[target]] - labels[target, source] = cut_value - tree[source] = tree[target] - tree[target] = source - - # Build the tree - T = nx.Graph() - T.add_nodes_from(G) - T.add_weighted_edges_from(((u, v, labels[u, v]) for u, v in tree.items())) - return T diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/maxflow.py b/extensions/fablabchemnitz/networkx/algorithms/flow/maxflow.py deleted file mode 100644 index b3073596..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/flow/maxflow.py +++ /dev/null @@ -1,613 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Maximum flow (and minimum cut) algorithms on capacitated graphs. -""" -import networkx as nx - -from .boykovkolmogorov import boykov_kolmogorov -from .dinitz_alg import dinitz -from .edmondskarp import edmonds_karp -from .preflowpush import preflow_push -from .shortestaugmentingpath import shortest_augmenting_path -from .utils import build_flow_dict -# Define the default flow function for computing maximum flow. -default_flow_func = preflow_push -# Functions that don't support cutoff for minimum cut computations. -flow_funcs = [ - boykov_kolmogorov, - dinitz, - edmonds_karp, - preflow_push, - shortest_augmenting_path, -] - -__all__ = ['maximum_flow', - 'maximum_flow_value', - 'minimum_cut', - 'minimum_cut_value'] - - -def maximum_flow(flowG, _s, _t, - capacity='capacity', flow_func=None, **kwargs): - """Find a maximum single-commodity flow. - - Parameters - ---------- - flowG : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - _s : node - Source node for the flow. - - _t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - flow_func : function - A function for computing the maximum flow among a pair of nodes - in a capacitated graph. The function has to accept at least three - parameters: a Graph or Digraph, a source node, and a target node. - And return a residual network that follows NetworkX conventions - (see Notes). If flow_func is None, the default maximum - flow function (:meth:`preflow_push`) is used. See below for - alternative algorithms. The choice of the default function may change - from version to version and should not be relied on. Default value: - None. - - kwargs : Any other keyword parameter is passed to the function that - computes the maximum flow. - - Returns - ------- - flow_value : integer, float - Value of the maximum flow, i.e., net outflow from the source. - - flow_dict : dict - A dictionary containing the value of the flow that went through - each edge. - - Raises - ------ - NetworkXError - The algorithm does not support MultiGraph and MultiDiGraph. If - the input graph is an instance of one of these two classes, a - NetworkXError is raised. - - NetworkXUnbounded - If the graph has a path of infinite capacity, the value of a - feasible flow on the graph is unbounded above and the function - raises a NetworkXUnbounded. - - See also - -------- - :meth:`maximum_flow_value` - :meth:`minimum_cut` - :meth:`minimum_cut_value` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Notes - ----- - The function used in the flow_func parameter has to return a residual - network that follows NetworkX conventions: - - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. Reachability to :samp:`t` using - only edges :samp:`(u, v)` such that - :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Specific algorithms may store extra data in :samp:`R`. - - The function should supports an optional boolean parameter value_only. When - True, it can optionally terminate the algorithm as soon as the maximum flow - value and the minimum cut can be determined. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.DiGraph() - >>> G.add_edge('x','a', capacity=3.0) - >>> G.add_edge('x','b', capacity=1.0) - >>> G.add_edge('a','c', capacity=3.0) - >>> G.add_edge('b','c', capacity=5.0) - >>> G.add_edge('b','d', capacity=4.0) - >>> G.add_edge('d','e', capacity=2.0) - >>> G.add_edge('c','y', capacity=2.0) - >>> G.add_edge('e','y', capacity=3.0) - - maximum_flow returns both the value of the maximum flow and a - dictionary with all flows. - - >>> flow_value, flow_dict = nx.maximum_flow(G, 'x', 'y') - >>> flow_value - 3.0 - >>> print(flow_dict['x']['b']) - 1.0 - - You can also use alternative algorithms for computing the - maximum flow by using the flow_func parameter. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> flow_value == nx.maximum_flow(G, 'x', 'y', - ... flow_func=shortest_augmenting_path)[0] - True - - """ - if flow_func is None: - if kwargs: - raise nx.NetworkXError("You have to explicitly set a flow_func if" - " you need to pass parameters via kwargs.") - flow_func = default_flow_func - - if not callable(flow_func): - raise nx.NetworkXError("flow_func has to be callable.") - - R = flow_func(flowG, _s, _t, capacity=capacity, value_only=False, **kwargs) - flow_dict = build_flow_dict(flowG, R) - - return (R.graph['flow_value'], flow_dict) - - -def maximum_flow_value(flowG, _s, _t, - capacity='capacity', flow_func=None, **kwargs): - """Find the value of maximum single-commodity flow. - - Parameters - ---------- - flowG : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - _s : node - Source node for the flow. - - _t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - flow_func : function - A function for computing the maximum flow among a pair of nodes - in a capacitated graph. The function has to accept at least three - parameters: a Graph or Digraph, a source node, and a target node. - And return a residual network that follows NetworkX conventions - (see Notes). If flow_func is None, the default maximum - flow function (:meth:`preflow_push`) is used. See below for - alternative algorithms. The choice of the default function may change - from version to version and should not be relied on. Default value: - None. - - kwargs : Any other keyword parameter is passed to the function that - computes the maximum flow. - - Returns - ------- - flow_value : integer, float - Value of the maximum flow, i.e., net outflow from the source. - - Raises - ------ - NetworkXError - The algorithm does not support MultiGraph and MultiDiGraph. If - the input graph is an instance of one of these two classes, a - NetworkXError is raised. - - NetworkXUnbounded - If the graph has a path of infinite capacity, the value of a - feasible flow on the graph is unbounded above and the function - raises a NetworkXUnbounded. - - See also - -------- - :meth:`maximum_flow` - :meth:`minimum_cut` - :meth:`minimum_cut_value` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Notes - ----- - The function used in the flow_func parameter has to return a residual - network that follows NetworkX conventions: - - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. Reachability to :samp:`t` using - only edges :samp:`(u, v)` such that - :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Specific algorithms may store extra data in :samp:`R`. - - The function should supports an optional boolean parameter value_only. When - True, it can optionally terminate the algorithm as soon as the maximum flow - value and the minimum cut can be determined. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.DiGraph() - >>> G.add_edge('x','a', capacity=3.0) - >>> G.add_edge('x','b', capacity=1.0) - >>> G.add_edge('a','c', capacity=3.0) - >>> G.add_edge('b','c', capacity=5.0) - >>> G.add_edge('b','d', capacity=4.0) - >>> G.add_edge('d','e', capacity=2.0) - >>> G.add_edge('c','y', capacity=2.0) - >>> G.add_edge('e','y', capacity=3.0) - - maximum_flow_value computes only the value of the - maximum flow: - - >>> flow_value = nx.maximum_flow_value(G, 'x', 'y') - >>> flow_value - 3.0 - - You can also use alternative algorithms for computing the - maximum flow by using the flow_func parameter. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> flow_value == nx.maximum_flow_value(G, 'x', 'y', - ... flow_func=shortest_augmenting_path) - True - - """ - if flow_func is None: - if kwargs: - raise nx.NetworkXError("You have to explicitly set a flow_func if" - " you need to pass parameters via kwargs.") - flow_func = default_flow_func - - if not callable(flow_func): - raise nx.NetworkXError("flow_func has to be callable.") - - R = flow_func(flowG, _s, _t, capacity=capacity, value_only=True, **kwargs) - - return R.graph['flow_value'] - - -def minimum_cut(flowG, _s, _t, - capacity='capacity', flow_func=None, **kwargs): - """Compute the value and the node partition of a minimum (s, t)-cut. - - Use the max-flow min-cut theorem, i.e., the capacity of a minimum - capacity cut is equal to the flow value of a maximum flow. - - Parameters - ---------- - flowG : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - _s : node - Source node for the flow. - - _t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - flow_func : function - A function for computing the maximum flow among a pair of nodes - in a capacitated graph. The function has to accept at least three - parameters: a Graph or Digraph, a source node, and a target node. - And return a residual network that follows NetworkX conventions - (see Notes). If flow_func is None, the default maximum - flow function (:meth:`preflow_push`) is used. See below for - alternative algorithms. The choice of the default function may change - from version to version and should not be relied on. Default value: - None. - - kwargs : Any other keyword parameter is passed to the function that - computes the maximum flow. - - Returns - ------- - cut_value : integer, float - Value of the minimum cut. - - partition : pair of node sets - A partitioning of the nodes that defines a minimum cut. - - Raises - ------ - NetworkXUnbounded - If the graph has a path of infinite capacity, all cuts have - infinite capacity and the function raises a NetworkXError. - - See also - -------- - :meth:`maximum_flow` - :meth:`maximum_flow_value` - :meth:`minimum_cut_value` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Notes - ----- - The function used in the flow_func parameter has to return a residual - network that follows NetworkX conventions: - - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. Reachability to :samp:`t` using - only edges :samp:`(u, v)` such that - :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Specific algorithms may store extra data in :samp:`R`. - - The function should supports an optional boolean parameter value_only. When - True, it can optionally terminate the algorithm as soon as the maximum flow - value and the minimum cut can be determined. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.DiGraph() - >>> G.add_edge('x','a', capacity = 3.0) - >>> G.add_edge('x','b', capacity = 1.0) - >>> G.add_edge('a','c', capacity = 3.0) - >>> G.add_edge('b','c', capacity = 5.0) - >>> G.add_edge('b','d', capacity = 4.0) - >>> G.add_edge('d','e', capacity = 2.0) - >>> G.add_edge('c','y', capacity = 2.0) - >>> G.add_edge('e','y', capacity = 3.0) - - minimum_cut computes both the value of the - minimum cut and the node partition: - - >>> cut_value, partition = nx.minimum_cut(G, 'x', 'y') - >>> reachable, non_reachable = partition - - 'partition' here is a tuple with the two sets of nodes that define - the minimum cut. You can compute the cut set of edges that induce - the minimum cut as follows: - - >>> cutset = set() - >>> for u, nbrs in ((n, G[n]) for n in reachable): - ... cutset.update((u, v) for v in nbrs if v in non_reachable) - >>> print(sorted(cutset)) - [('c', 'y'), ('x', 'b')] - >>> cut_value == sum(G.edges[u, v]['capacity'] for (u, v) in cutset) - True - - You can also use alternative algorithms for computing the - minimum cut by using the flow_func parameter. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> cut_value == nx.minimum_cut(G, 'x', 'y', - ... flow_func=shortest_augmenting_path)[0] - True - - """ - if flow_func is None: - if kwargs: - raise nx.NetworkXError("You have to explicitly set a flow_func if" - " you need to pass parameters via kwargs.") - flow_func = default_flow_func - - if not callable(flow_func): - raise nx.NetworkXError("flow_func has to be callable.") - - if kwargs.get('cutoff') is not None and flow_func in flow_funcs: - raise nx.NetworkXError("cutoff should not be specified.") - - R = flow_func(flowG, _s, _t, capacity=capacity, value_only=True, **kwargs) - # Remove saturated edges from the residual network - cutset = [(u, v, d) for u, v, d in R.edges(data=True) - if d['flow'] == d['capacity']] - R.remove_edges_from(cutset) - - # Then, reachable and non reachable nodes from source in the - # residual network form the node partition that defines - # the minimum cut. - non_reachable = set(dict(nx.shortest_path_length(R, target=_t))) - partition = (set(flowG) - non_reachable, non_reachable) - # Finally add again cutset edges to the residual network to make - # sure that it is reusable. - if cutset is not None: - R.add_edges_from(cutset) - return (R.graph['flow_value'], partition) - - -def minimum_cut_value(flowG, _s, _t, - capacity='capacity', flow_func=None, **kwargs): - """Compute the value of a minimum (s, t)-cut. - - Use the max-flow min-cut theorem, i.e., the capacity of a minimum - capacity cut is equal to the flow value of a maximum flow. - - Parameters - ---------- - flowG : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - _s : node - Source node for the flow. - - _t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - flow_func : function - A function for computing the maximum flow among a pair of nodes - in a capacitated graph. The function has to accept at least three - parameters: a Graph or Digraph, a source node, and a target node. - And return a residual network that follows NetworkX conventions - (see Notes). If flow_func is None, the default maximum - flow function (:meth:`preflow_push`) is used. See below for - alternative algorithms. The choice of the default function may change - from version to version and should not be relied on. Default value: - None. - - kwargs : Any other keyword parameter is passed to the function that - computes the maximum flow. - - Returns - ------- - cut_value : integer, float - Value of the minimum cut. - - Raises - ------ - NetworkXUnbounded - If the graph has a path of infinite capacity, all cuts have - infinite capacity and the function raises a NetworkXError. - - See also - -------- - :meth:`maximum_flow` - :meth:`maximum_flow_value` - :meth:`minimum_cut` - :meth:`edmonds_karp` - :meth:`preflow_push` - :meth:`shortest_augmenting_path` - - Notes - ----- - The function used in the flow_func parameter has to return a residual - network that follows NetworkX conventions: - - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. Reachability to :samp:`t` using - only edges :samp:`(u, v)` such that - :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Specific algorithms may store extra data in :samp:`R`. - - The function should supports an optional boolean parameter value_only. When - True, it can optionally terminate the algorithm as soon as the maximum flow - value and the minimum cut can be determined. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.DiGraph() - >>> G.add_edge('x','a', capacity = 3.0) - >>> G.add_edge('x','b', capacity = 1.0) - >>> G.add_edge('a','c', capacity = 3.0) - >>> G.add_edge('b','c', capacity = 5.0) - >>> G.add_edge('b','d', capacity = 4.0) - >>> G.add_edge('d','e', capacity = 2.0) - >>> G.add_edge('c','y', capacity = 2.0) - >>> G.add_edge('e','y', capacity = 3.0) - - minimum_cut_value computes only the value of the - minimum cut: - - >>> cut_value = nx.minimum_cut_value(G, 'x', 'y') - >>> cut_value - 3.0 - - You can also use alternative algorithms for computing the - minimum cut by using the flow_func parameter. - - >>> from networkx.algorithms.flow import shortest_augmenting_path - >>> cut_value == nx.minimum_cut_value(G, 'x', 'y', - ... flow_func=shortest_augmenting_path) - True - - """ - if flow_func is None: - if kwargs: - raise nx.NetworkXError("You have to explicitly set a flow_func if" - " you need to pass parameters via kwargs.") - flow_func = default_flow_func - - if not callable(flow_func): - raise nx.NetworkXError("flow_func has to be callable.") - - if kwargs.get('cutoff') is not None and flow_func in flow_funcs: - raise nx.NetworkXError("cutoff should not be specified.") - - R = flow_func(flowG, _s, _t, capacity=capacity, value_only=True, **kwargs) - - return R.graph['flow_value'] diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/mincost.py b/extensions/fablabchemnitz/networkx/algorithms/flow/mincost.py deleted file mode 100644 index cf1a24ff..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/flow/mincost.py +++ /dev/null @@ -1,343 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Minimum cost flow algorithms on directed connected graphs. -""" - -__author__ = """Loïc Séguin-C. """ -# Copyright (C) 2010 Loïc Séguin-C. -# All rights reserved. -# BSD license. - - -__all__ = ['min_cost_flow_cost', - 'min_cost_flow', - 'cost_of_flow', - 'max_flow_min_cost'] - -import networkx as nx - - -def min_cost_flow_cost(G, demand='demand', capacity='capacity', - weight='weight'): - r"""Find the cost of a minimum cost flow satisfying all demands in digraph G. - - G is a digraph with edge costs and capacities and in which nodes - have demand, i.e., they want to send or receive some amount of - flow. A negative demand means that the node wants to send flow, a - positive demand means that the node want to receive flow. A flow on - the digraph G satisfies all demand if the net flow into each node - is equal to the demand of that node. - - Parameters - ---------- - G : NetworkX graph - DiGraph on which a minimum cost flow satisfying all demands is - to be found. - - demand : string - Nodes of the graph G are expected to have an attribute demand - that indicates how much flow a node wants to send (negative - demand) or receive (positive demand). Note that the sum of the - demands should be 0 otherwise the problem in not feasible. If - this attribute is not present, a node is considered to have 0 - demand. Default value: 'demand'. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - weight : string - Edges of the graph G are expected to have an attribute weight - that indicates the cost incurred by sending one unit of flow on - that edge. If not present, the weight is considered to be 0. - Default value: 'weight'. - - Returns - ------- - flowCost : integer, float - Cost of a minimum cost flow satisfying all demands. - - Raises - ------ - NetworkXError - This exception is raised if the input graph is not directed or - not connected. - - NetworkXUnfeasible - This exception is raised in the following situations: - - * The sum of the demands is not zero. Then, there is no - flow satisfying all demands. - * There is no flow satisfying all demand. - - NetworkXUnbounded - This exception is raised if the digraph G has a cycle of - negative cost and infinite capacity. Then, the cost of a flow - satisfying all demands is unbounded below. - - See also - -------- - cost_of_flow, max_flow_min_cost, min_cost_flow, network_simplex - - Notes - ----- - This algorithm is not guaranteed to work if edge weights or demands - are floating point numbers (overflows and roundoff errors can - cause problems). As a workaround you can use integer numbers by - multiplying the relevant edge attributes by a convenient - constant factor (eg 100). - - Examples - -------- - A simple example of a min cost flow problem. - - >>> import networkx as nx - >>> G = nx.DiGraph() - >>> G.add_node('a', demand = -5) - >>> G.add_node('d', demand = 5) - >>> G.add_edge('a', 'b', weight = 3, capacity = 4) - >>> G.add_edge('a', 'c', weight = 6, capacity = 10) - >>> G.add_edge('b', 'd', weight = 1, capacity = 9) - >>> G.add_edge('c', 'd', weight = 2, capacity = 5) - >>> flowCost = nx.min_cost_flow_cost(G) - >>> flowCost - 24 - """ - return nx.network_simplex(G, demand=demand, capacity=capacity, - weight=weight)[0] - - -def min_cost_flow(G, demand='demand', capacity='capacity', - weight='weight'): - r"""Returns a minimum cost flow satisfying all demands in digraph G. - - G is a digraph with edge costs and capacities and in which nodes - have demand, i.e., they want to send or receive some amount of - flow. A negative demand means that the node wants to send flow, a - positive demand means that the node want to receive flow. A flow on - the digraph G satisfies all demand if the net flow into each node - is equal to the demand of that node. - - Parameters - ---------- - G : NetworkX graph - DiGraph on which a minimum cost flow satisfying all demands is - to be found. - - demand : string - Nodes of the graph G are expected to have an attribute demand - that indicates how much flow a node wants to send (negative - demand) or receive (positive demand). Note that the sum of the - demands should be 0 otherwise the problem in not feasible. If - this attribute is not present, a node is considered to have 0 - demand. Default value: 'demand'. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - weight : string - Edges of the graph G are expected to have an attribute weight - that indicates the cost incurred by sending one unit of flow on - that edge. If not present, the weight is considered to be 0. - Default value: 'weight'. - - Returns - ------- - flowDict : dictionary - Dictionary of dictionaries keyed by nodes such that - flowDict[u][v] is the flow edge (u, v). - - Raises - ------ - NetworkXError - This exception is raised if the input graph is not directed or - not connected. - - NetworkXUnfeasible - This exception is raised in the following situations: - - * The sum of the demands is not zero. Then, there is no - flow satisfying all demands. - * There is no flow satisfying all demand. - - NetworkXUnbounded - This exception is raised if the digraph G has a cycle of - negative cost and infinite capacity. Then, the cost of a flow - satisfying all demands is unbounded below. - - See also - -------- - cost_of_flow, max_flow_min_cost, min_cost_flow_cost, network_simplex - - Notes - ----- - This algorithm is not guaranteed to work if edge weights or demands - are floating point numbers (overflows and roundoff errors can - cause problems). As a workaround you can use integer numbers by - multiplying the relevant edge attributes by a convenient - constant factor (eg 100). - - Examples - -------- - A simple example of a min cost flow problem. - - >>> import networkx as nx - >>> G = nx.DiGraph() - >>> G.add_node('a', demand = -5) - >>> G.add_node('d', demand = 5) - >>> G.add_edge('a', 'b', weight = 3, capacity = 4) - >>> G.add_edge('a', 'c', weight = 6, capacity = 10) - >>> G.add_edge('b', 'd', weight = 1, capacity = 9) - >>> G.add_edge('c', 'd', weight = 2, capacity = 5) - >>> flowDict = nx.min_cost_flow(G) - """ - return nx.network_simplex(G, demand=demand, capacity=capacity, - weight=weight)[1] - - -def cost_of_flow(G, flowDict, weight='weight'): - """Compute the cost of the flow given by flowDict on graph G. - - Note that this function does not check for the validity of the - flow flowDict. This function will fail if the graph G and the - flow don't have the same edge set. - - Parameters - ---------- - G : NetworkX graph - DiGraph on which a minimum cost flow satisfying all demands is - to be found. - - weight : string - Edges of the graph G are expected to have an attribute weight - that indicates the cost incurred by sending one unit of flow on - that edge. If not present, the weight is considered to be 0. - Default value: 'weight'. - - flowDict : dictionary - Dictionary of dictionaries keyed by nodes such that - flowDict[u][v] is the flow edge (u, v). - - Returns - ------- - cost : Integer, float - The total cost of the flow. This is given by the sum over all - edges of the product of the edge's flow and the edge's weight. - - See also - -------- - max_flow_min_cost, min_cost_flow, min_cost_flow_cost, network_simplex - - Notes - ----- - This algorithm is not guaranteed to work if edge weights or demands - are floating point numbers (overflows and roundoff errors can - cause problems). As a workaround you can use integer numbers by - multiplying the relevant edge attributes by a convenient - constant factor (eg 100). - """ - return sum((flowDict[u][v] * d.get(weight, 0) - for u, v, d in G.edges(data=True))) - - -def max_flow_min_cost(G, s, t, capacity='capacity', weight='weight'): - """Returns a maximum (s, t)-flow of minimum cost. - - G is a digraph with edge costs and capacities. There is a source - node s and a sink node t. This function finds a maximum flow from - s to t whose total cost is minimized. - - Parameters - ---------- - G : NetworkX graph - DiGraph on which a minimum cost flow satisfying all demands is - to be found. - - s: node label - Source of the flow. - - t: node label - Destination of the flow. - - capacity: string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - weight: string - Edges of the graph G are expected to have an attribute weight - that indicates the cost incurred by sending one unit of flow on - that edge. If not present, the weight is considered to be 0. - Default value: 'weight'. - - Returns - ------- - flowDict: dictionary - Dictionary of dictionaries keyed by nodes such that - flowDict[u][v] is the flow edge (u, v). - - Raises - ------ - NetworkXError - This exception is raised if the input graph is not directed or - not connected. - - NetworkXUnbounded - This exception is raised if there is an infinite capacity path - from s to t in G. In this case there is no maximum flow. This - exception is also raised if the digraph G has a cycle of - negative cost and infinite capacity. Then, the cost of a flow - is unbounded below. - - See also - -------- - cost_of_flow, min_cost_flow, min_cost_flow_cost, network_simplex - - Notes - ----- - This algorithm is not guaranteed to work if edge weights or demands - are floating point numbers (overflows and roundoff errors can - cause problems). As a workaround you can use integer numbers by - multiplying the relevant edge attributes by a convenient - constant factor (eg 100). - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_edges_from([(1, 2, {'capacity': 12, 'weight': 4}), - ... (1, 3, {'capacity': 20, 'weight': 6}), - ... (2, 3, {'capacity': 6, 'weight': -3}), - ... (2, 6, {'capacity': 14, 'weight': 1}), - ... (3, 4, {'weight': 9}), - ... (3, 5, {'capacity': 10, 'weight': 5}), - ... (4, 2, {'capacity': 19, 'weight': 13}), - ... (4, 5, {'capacity': 4, 'weight': 0}), - ... (5, 7, {'capacity': 28, 'weight': 2}), - ... (6, 5, {'capacity': 11, 'weight': 1}), - ... (6, 7, {'weight': 8}), - ... (7, 4, {'capacity': 6, 'weight': 6})]) - >>> mincostFlow = nx.max_flow_min_cost(G, 1, 7) - >>> mincost = nx.cost_of_flow(G, mincostFlow) - >>> mincost - 373 - >>> from networkx.algorithms.flow import maximum_flow - >>> maxFlow = maximum_flow(G, 1, 7)[1] - >>> nx.cost_of_flow(G, maxFlow) >= mincost - True - >>> mincostFlowValue = (sum((mincostFlow[u][7] for u in G.predecessors(7))) - ... - sum((mincostFlow[7][v] for v in G.successors(7)))) - >>> mincostFlowValue == nx.maximum_flow_value(G, 1, 7) - True - - """ - maxFlow = nx.maximum_flow_value(G, s, t, capacity=capacity) - H = nx.DiGraph(G) - H.add_node(s, demand=-maxFlow) - H.add_node(t, demand=maxFlow) - return min_cost_flow(H, capacity=capacity, weight=weight) diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/networksimplex.py b/extensions/fablabchemnitz/networkx/algorithms/flow/networksimplex.py deleted file mode 100644 index 9192c5bc..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/flow/networksimplex.py +++ /dev/null @@ -1,598 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Minimum cost flow algorithms on directed connected graphs. -""" - -__author__ = """Loïc Séguin-C. """ -# Copyright (C) 2010 Loïc Séguin-C. -# All rights reserved. -# BSD license. - -__all__ = ['network_simplex'] - -from itertools import chain, islice, repeat -from math import ceil, sqrt -import networkx as nx -from networkx.utils import not_implemented_for - -try: - from itertools import izip as zip -except ImportError: - pass -try: - range = xrange -except NameError: - pass - - -@not_implemented_for('undirected') -def network_simplex(G, demand='demand', capacity='capacity', weight='weight'): - r"""Find a minimum cost flow satisfying all demands in digraph G. - - This is a primal network simplex algorithm that uses the leaving - arc rule to prevent cycling. - - G is a digraph with edge costs and capacities and in which nodes - have demand, i.e., they want to send or receive some amount of - flow. A negative demand means that the node wants to send flow, a - positive demand means that the node want to receive flow. A flow on - the digraph G satisfies all demand if the net flow into each node - is equal to the demand of that node. - - Parameters - ---------- - G : NetworkX graph - DiGraph on which a minimum cost flow satisfying all demands is - to be found. - - demand : string - Nodes of the graph G are expected to have an attribute demand - that indicates how much flow a node wants to send (negative - demand) or receive (positive demand). Note that the sum of the - demands should be 0 otherwise the problem in not feasible. If - this attribute is not present, a node is considered to have 0 - demand. Default value: 'demand'. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - weight : string - Edges of the graph G are expected to have an attribute weight - that indicates the cost incurred by sending one unit of flow on - that edge. If not present, the weight is considered to be 0. - Default value: 'weight'. - - Returns - ------- - flowCost : integer, float - Cost of a minimum cost flow satisfying all demands. - - flowDict : dictionary - Dictionary of dictionaries keyed by nodes such that - flowDict[u][v] is the flow edge (u, v). - - Raises - ------ - NetworkXError - This exception is raised if the input graph is not directed, - not connected or is a multigraph. - - NetworkXUnfeasible - This exception is raised in the following situations: - - * The sum of the demands is not zero. Then, there is no - flow satisfying all demands. - * There is no flow satisfying all demand. - - NetworkXUnbounded - This exception is raised if the digraph G has a cycle of - negative cost and infinite capacity. Then, the cost of a flow - satisfying all demands is unbounded below. - - Notes - ----- - This algorithm is not guaranteed to work if edge weights or demands - are floating point numbers (overflows and roundoff errors can - cause problems). As a workaround you can use integer numbers by - multiplying the relevant edge attributes by a convenient - constant factor (eg 100). - - See also - -------- - cost_of_flow, max_flow_min_cost, min_cost_flow, min_cost_flow_cost - - Examples - -------- - A simple example of a min cost flow problem. - - >>> import networkx as nx - >>> G = nx.DiGraph() - >>> G.add_node('a', demand=-5) - >>> G.add_node('d', demand=5) - >>> G.add_edge('a', 'b', weight=3, capacity=4) - >>> G.add_edge('a', 'c', weight=6, capacity=10) - >>> G.add_edge('b', 'd', weight=1, capacity=9) - >>> G.add_edge('c', 'd', weight=2, capacity=5) - >>> flowCost, flowDict = nx.network_simplex(G) - >>> flowCost - 24 - >>> flowDict # doctest: +SKIP - {'a': {'c': 1, 'b': 4}, 'c': {'d': 1}, 'b': {'d': 4}, 'd': {}} - - The mincost flow algorithm can also be used to solve shortest path - problems. To find the shortest path between two nodes u and v, - give all edges an infinite capacity, give node u a demand of -1 and - node v a demand a 1. Then run the network simplex. The value of a - min cost flow will be the distance between u and v and edges - carrying positive flow will indicate the path. - - >>> G=nx.DiGraph() - >>> G.add_weighted_edges_from([('s', 'u' ,10), ('s' ,'x' ,5), - ... ('u', 'v' ,1), ('u' ,'x' ,2), - ... ('v', 'y' ,1), ('x' ,'u' ,3), - ... ('x', 'v' ,5), ('x' ,'y' ,2), - ... ('y', 's' ,7), ('y' ,'v' ,6)]) - >>> G.add_node('s', demand = -1) - >>> G.add_node('v', demand = 1) - >>> flowCost, flowDict = nx.network_simplex(G) - >>> flowCost == nx.shortest_path_length(G, 's', 'v', weight='weight') - True - >>> sorted([(u, v) for u in flowDict for v in flowDict[u] if flowDict[u][v] > 0]) - [('s', 'x'), ('u', 'v'), ('x', 'u')] - >>> nx.shortest_path(G, 's', 'v', weight = 'weight') - ['s', 'x', 'u', 'v'] - - It is possible to change the name of the attributes used for the - algorithm. - - >>> G = nx.DiGraph() - >>> G.add_node('p', spam=-4) - >>> G.add_node('q', spam=2) - >>> G.add_node('a', spam=-2) - >>> G.add_node('d', spam=-1) - >>> G.add_node('t', spam=2) - >>> G.add_node('w', spam=3) - >>> G.add_edge('p', 'q', cost=7, vacancies=5) - >>> G.add_edge('p', 'a', cost=1, vacancies=4) - >>> G.add_edge('q', 'd', cost=2, vacancies=3) - >>> G.add_edge('t', 'q', cost=1, vacancies=2) - >>> G.add_edge('a', 't', cost=2, vacancies=4) - >>> G.add_edge('d', 'w', cost=3, vacancies=4) - >>> G.add_edge('t', 'w', cost=4, vacancies=1) - >>> flowCost, flowDict = nx.network_simplex(G, demand='spam', - ... capacity='vacancies', - ... weight='cost') - >>> flowCost - 37 - >>> flowDict # doctest: +SKIP - {'a': {'t': 4}, 'd': {'w': 2}, 'q': {'d': 1}, 'p': {'q': 2, 'a': 2}, 't': {'q': 1, 'w': 1}, 'w': {}} - - References - ---------- - .. [1] Z. Kiraly, P. Kovacs. - Efficient implementation of minimum-cost flow algorithms. - Acta Universitatis Sapientiae, Informatica 4(1):67--118. 2012. - .. [2] R. Barr, F. Glover, D. Klingman. - Enhancement of spanning tree labeling procedures for network - optimization. - INFOR 17(1):16--34. 1979. - """ - ########################################################################### - # Problem essentials extraction and sanity check - ########################################################################### - - if len(G) == 0: - raise nx.NetworkXError('graph has no nodes') - - # Number all nodes and edges and hereafter reference them using ONLY their - # numbers - - N = list(G) # nodes - I = {u: i for i, u in enumerate(N)} # node indices - D = [G.nodes[u].get(demand, 0) for u in N] # node demands - - inf = float('inf') - for p, b in zip(N, D): - if abs(b) == inf: - raise nx.NetworkXError('node %r has infinite demand' % (p,)) - - multigraph = G.is_multigraph() - S = [] # edge sources - T = [] # edge targets - if multigraph: - K = [] # edge keys - E = {} # edge indices - U = [] # edge capacities - C = [] # edge weights - - if not multigraph: - edges = G.edges(data=True) - else: - edges = G.edges(data=True, keys=True) - edges = (e for e in edges - if e[0] != e[1] and e[-1].get(capacity, inf) != 0) - for i, e in enumerate(edges): - S.append(I[e[0]]) - T.append(I[e[1]]) - if multigraph: - K.append(e[2]) - E[e[:-1]] = i - U.append(e[-1].get(capacity, inf)) - C.append(e[-1].get(weight, 0)) - - for e, c in zip(E, C): - if abs(c) == inf: - raise nx.NetworkXError('edge %r has infinite weight' % (e,)) - if not multigraph: - edges = nx.selfloop_edges(G, data=True) - else: - edges = nx.selfloop_edges(G, data=True, keys=True) - for e in edges: - if abs(e[-1].get(weight, 0)) == inf: - raise nx.NetworkXError('edge %r has infinite weight' % (e[:-1],)) - - ########################################################################### - # Quick infeasibility detection - ########################################################################### - - if sum(D) != 0: - raise nx.NetworkXUnfeasible('total node demand is not zero') - for e, u in zip(E, U): - if u < 0: - raise nx.NetworkXUnfeasible('edge %r has negative capacity' % (e,)) - if not multigraph: - edges = nx.selfloop_edges(G, data=True) - else: - edges = nx.selfloop_edges(G, data=True, keys=True) - for e in edges: - if e[-1].get(capacity, inf) < 0: - raise nx.NetworkXUnfeasible( - 'edge %r has negative capacity' % (e[:-1],)) - - ########################################################################### - # Initialization - ########################################################################### - - # Add a dummy node -1 and connect all existing nodes to it with infinite- - # capacity dummy edges. Node -1 will serve as the root of the - # spanning tree of the network simplex method. The new edges will used to - # trivially satisfy the node demands and create an initial strongly - # feasible spanning tree. - n = len(N) # number of nodes - for p, d in enumerate(D): - if d > 0: # Must be greater-than here. Zero-demand nodes must have - # edges pointing towards the root to ensure strong - # feasibility. - S.append(-1) - T.append(p) - else: - S.append(p) - T.append(-1) - faux_inf = 3 * max(chain([sum(u for u in U if u < inf), - sum(abs(c) for c in C)], - (abs(d) for d in D))) or 1 - C.extend(repeat(faux_inf, n)) - U.extend(repeat(faux_inf, n)) - - # Construct the initial spanning tree. - e = len(E) # number of edges - x = list(chain(repeat(0, e), (abs(d) for d in D))) # edge flows - pi = [faux_inf if d <= 0 else -faux_inf for d in D] # node potentials - parent = list(chain(repeat(-1, n), [None])) # parent nodes - edge = list(range(e, e + n)) # edges to parents - size = list(chain(repeat(1, n), [n + 1])) # subtree sizes - next = list(chain(range(1, n), [-1, 0])) # next nodes in depth-first thread - prev = list(range(-1, n)) # previous nodes in depth-first thread - last = list(chain(range(n), [n - 1])) # last descendants in depth-first thread - - ########################################################################### - # Pivot loop - ########################################################################### - - def reduced_cost(i): - """Returns the reduced cost of an edge i. - """ - c = C[i] - pi[S[i]] + pi[T[i]] - return c if x[i] == 0 else -c - - def find_entering_edges(): - """Yield entering edges until none can be found. - """ - if e == 0: - return - - # Entering edges are found by combining Dantzig's rule and Bland's - # rule. The edges are cyclically grouped into blocks of size B. Within - # each block, Dantzig's rule is applied to find an entering edge. The - # blocks to search is determined following Bland's rule. - B = int(ceil(sqrt(e))) # pivot block size - M = (e + B - 1) // B # number of blocks needed to cover all edges - m = 0 # number of consecutive blocks without eligible - # entering edges - f = 0 # first edge in block - while m < M: - # Determine the next block of edges. - l = f + B - if l <= e: - edges = range(f, l) - else: - l -= e - edges = chain(range(f, e), range(l)) - f = l - # Find the first edge with the lowest reduced cost. - i = min(edges, key=reduced_cost) - c = reduced_cost(i) - if c >= 0: - # No entering edge found in the current block. - m += 1 - else: - # Entering edge found. - if x[i] == 0: - p = S[i] - q = T[i] - else: - p = T[i] - q = S[i] - yield i, p, q - m = 0 - # All edges have nonnegative reduced costs. The current flow is - # optimal. - - def find_apex(p, q): - """Find the lowest common ancestor of nodes p and q in the spanning - tree. - """ - size_p = size[p] - size_q = size[q] - while True: - while size_p < size_q: - p = parent[p] - size_p = size[p] - while size_p > size_q: - q = parent[q] - size_q = size[q] - if size_p == size_q: - if p != q: - p = parent[p] - size_p = size[p] - q = parent[q] - size_q = size[q] - else: - return p - - def trace_path(p, w): - """Returns the nodes and edges on the path from node p to its ancestor - w. - """ - Wn = [p] - We = [] - while p != w: - We.append(edge[p]) - p = parent[p] - Wn.append(p) - return Wn, We - - def find_cycle(i, p, q): - """Returns the nodes and edges on the cycle containing edge i == (p, q) - when the latter is added to the spanning tree. - - The cycle is oriented in the direction from p to q. - """ - w = find_apex(p, q) - Wn, We = trace_path(p, w) - Wn.reverse() - We.reverse() - if We != [i]: - We.append(i) - WnR, WeR = trace_path(q, w) - del WnR[-1] - Wn += WnR - We += WeR - return Wn, We - - def residual_capacity(i, p): - """Returns the residual capacity of an edge i in the direction away - from its endpoint p. - """ - return U[i] - x[i] if S[i] == p else x[i] - - def find_leaving_edge(Wn, We): - """Returns the leaving edge in a cycle represented by Wn and We. - """ - j, s = min(zip(reversed(We), reversed(Wn)), - key=lambda i_p: residual_capacity(*i_p)) - t = T[j] if S[j] == s else S[j] - return j, s, t - - def augment_flow(Wn, We, f): - """Augment f units of flow along a cycle represented by Wn and We. - """ - for i, p in zip(We, Wn): - if S[i] == p: - x[i] += f - else: - x[i] -= f - - def trace_subtree(p): - """Yield the nodes in the subtree rooted at a node p. - """ - yield p - l = last[p] - while p != l: - p = next[p] - yield p - - def remove_edge(s, t): - """Remove an edge (s, t) where parent[t] == s from the spanning tree. - """ - size_t = size[t] - prev_t = prev[t] - last_t = last[t] - next_last_t = next[last_t] - # Remove (s, t). - parent[t] = None - edge[t] = None - # Remove the subtree rooted at t from the depth-first thread. - next[prev_t] = next_last_t - prev[next_last_t] = prev_t - next[last_t] = t - prev[t] = last_t - # Update the subtree sizes and last descendants of the (old) acenstors - # of t. - while s is not None: - size[s] -= size_t - if last[s] == last_t: - last[s] = prev_t - s = parent[s] - - def make_root(q): - """Make a node q the root of its containing subtree. - """ - ancestors = [] - while q is not None: - ancestors.append(q) - q = parent[q] - ancestors.reverse() - for p, q in zip(ancestors, islice(ancestors, 1, None)): - size_p = size[p] - last_p = last[p] - prev_q = prev[q] - last_q = last[q] - next_last_q = next[last_q] - # Make p a child of q. - parent[p] = q - parent[q] = None - edge[p] = edge[q] - edge[q] = None - size[p] = size_p - size[q] - size[q] = size_p - # Remove the subtree rooted at q from the depth-first thread. - next[prev_q] = next_last_q - prev[next_last_q] = prev_q - next[last_q] = q - prev[q] = last_q - if last_p == last_q: - last[p] = prev_q - last_p = prev_q - # Add the remaining parts of the subtree rooted at p as a subtree - # of q in the depth-first thread. - prev[p] = last_q - next[last_q] = p - next[last_p] = q - prev[q] = last_p - last[q] = last_p - - def add_edge(i, p, q): - """Add an edge (p, q) to the spanning tree where q is the root of a - subtree. - """ - last_p = last[p] - next_last_p = next[last_p] - size_q = size[q] - last_q = last[q] - # Make q a child of p. - parent[q] = p - edge[q] = i - # Insert the subtree rooted at q into the depth-first thread. - next[last_p] = q - prev[q] = last_p - prev[next_last_p] = last_q - next[last_q] = next_last_p - # Update the subtree sizes and last descendants of the (new) ancestors - # of q. - while p is not None: - size[p] += size_q - if last[p] == last_p: - last[p] = last_q - p = parent[p] - - def update_potentials(i, p, q): - """Update the potentials of the nodes in the subtree rooted at a node - q connected to its parent p by an edge i. - """ - if q == T[i]: - d = pi[p] - C[i] - pi[q] - else: - d = pi[p] + C[i] - pi[q] - for q in trace_subtree(q): - pi[q] += d - - # Pivot loop - for i, p, q in find_entering_edges(): - Wn, We = find_cycle(i, p, q) - j, s, t = find_leaving_edge(Wn, We) - augment_flow(Wn, We, residual_capacity(j, s)) - if i != j: # Do nothing more if the entering edge is the same as the - # the leaving edge. - if parent[t] != s: - # Ensure that s is the parent of t. - s, t = t, s - if We.index(i) > We.index(j): - # Ensure that q is in the subtree rooted at t. - p, q = q, p - remove_edge(s, t) - make_root(q) - add_edge(i, p, q) - update_potentials(i, p, q) - - ########################################################################### - # Infeasibility and unboundedness detection - ########################################################################### - - if any(x[i] != 0 for i in range(-n, 0)): - raise nx.NetworkXUnfeasible('no flow satisfies all node demands') - - if (any(x[i] * 2 >= faux_inf for i in range(e)) or - any(e[-1].get(capacity, inf) == inf and e[-1].get(weight, 0) < 0 - for e in nx.selfloop_edges(G, data=True))): - raise nx.NetworkXUnbounded( - 'negative cycle with infinite capacity found') - - ########################################################################### - # Flow cost calculation and flow dict construction - ########################################################################### - - del x[e:] - flow_cost = sum(c * x for c, x in zip(C, x)) - flow_dict = {n: {} for n in N} - - def add_entry(e): - """Add a flow dict entry. - """ - d = flow_dict[e[0]] - for k in e[1:-2]: - try: - d = d[k] - except KeyError: - t = {} - d[k] = t - d = t - d[e[-2]] = e[-1] - - S = (N[s] for s in S) # Use original nodes. - T = (N[t] for t in T) # Use original nodes. - if not multigraph: - for e in zip(S, T, x): - add_entry(e) - edges = G.edges(data=True) - else: - for e in zip(S, T, K, x): - add_entry(e) - edges = G.edges(data=True, keys=True) - for e in edges: - if e[0] != e[1]: - if e[-1].get(capacity, inf) == 0: - add_entry(e[:-1] + (0,)) - else: - c = e[-1].get(weight, 0) - if c >= 0: - add_entry(e[:-1] + (0,)) - else: - u = e[-1][capacity] - flow_cost += c * u - add_entry(e[:-1] + (u,)) - - return flow_cost, flow_dict diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/preflowpush.py b/extensions/fablabchemnitz/networkx/algorithms/flow/preflowpush.py deleted file mode 100644 index 3a5a5105..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/flow/preflowpush.py +++ /dev/null @@ -1,430 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Highest-label preflow-push algorithm for maximum flow problems. -""" - -__author__ = """ysitu """ -# Copyright (C) 2014 ysitu -# All rights reserved. -# BSD license. - -from collections import deque -from itertools import islice -import networkx as nx -#from networkx.algorithms.flow.utils import * -from ...utils import arbitrary_element -from .utils import build_residual_network -from .utils import CurrentEdge -from .utils import detect_unboundedness -from .utils import GlobalRelabelThreshold -from .utils import Level - -__all__ = ['preflow_push'] - - -def preflow_push_impl(G, s, t, capacity, residual, global_relabel_freq, - value_only): - """Implementation of the highest-label preflow-push algorithm. - """ - if s not in G: - raise nx.NetworkXError('node %s not in graph' % str(s)) - if t not in G: - raise nx.NetworkXError('node %s not in graph' % str(t)) - if s == t: - raise nx.NetworkXError('source and sink are the same node') - - if global_relabel_freq is None: - global_relabel_freq = 0 - if global_relabel_freq < 0: - raise nx.NetworkXError('global_relabel_freq must be nonnegative.') - - if residual is None: - R = build_residual_network(G, capacity) - else: - R = residual - - detect_unboundedness(R, s, t) - - R_nodes = R.nodes - R_pred = R.pred - R_succ = R.succ - - # Initialize/reset the residual network. - for u in R: - R_nodes[u]['excess'] = 0 - for e in R_succ[u].values(): - e['flow'] = 0 - - def reverse_bfs(src): - """Perform a reverse breadth-first search from src in the residual - network. - """ - heights = {src: 0} - q = deque([(src, 0)]) - while q: - u, height = q.popleft() - height += 1 - for v, attr in R_pred[u].items(): - if v not in heights and attr['flow'] < attr['capacity']: - heights[v] = height - q.append((v, height)) - return heights - - # Initialize heights of the nodes. - heights = reverse_bfs(t) - - if s not in heights: - # t is not reachable from s in the residual network. The maximum flow - # must be zero. - R.graph['flow_value'] = 0 - return R - - n = len(R) - # max_height represents the height of the highest level below level n with - # at least one active node. - max_height = max(heights[u] for u in heights if u != s) - heights[s] = n - - grt = GlobalRelabelThreshold(n, R.size(), global_relabel_freq) - - # Initialize heights and 'current edge' data structures of the nodes. - for u in R: - R_nodes[u]['height'] = heights[u] if u in heights else n + 1 - R_nodes[u]['curr_edge'] = CurrentEdge(R_succ[u]) - - def push(u, v, flow): - """Push flow units of flow from u to v. - """ - R_succ[u][v]['flow'] += flow - R_succ[v][u]['flow'] -= flow - R_nodes[u]['excess'] -= flow - R_nodes[v]['excess'] += flow - - # The maximum flow must be nonzero now. Initialize the preflow by - # saturating all edges emanating from s. - for u, attr in R_succ[s].items(): - flow = attr['capacity'] - if flow > 0: - push(s, u, flow) - - # Partition nodes into levels. - levels = [Level() for i in range(2 * n)] - for u in R: - if u != s and u != t: - level = levels[R_nodes[u]['height']] - if R_nodes[u]['excess'] > 0: - level.active.add(u) - else: - level.inactive.add(u) - - def activate(v): - """Move a node from the inactive set to the active set of its level. - """ - if v != s and v != t: - level = levels[R_nodes[v]['height']] - if v in level.inactive: - level.inactive.remove(v) - level.active.add(v) - - def relabel(u): - """Relabel a node to create an admissible edge. - """ - grt.add_work(len(R_succ[u])) - return min(R_nodes[v]['height'] for v, attr in R_succ[u].items() - if attr['flow'] < attr['capacity']) + 1 - - def discharge(u, is_phase1): - """Discharge a node until it becomes inactive or, during phase 1 (see - below), its height reaches at least n. The node is known to have the - largest height among active nodes. - """ - height = R_nodes[u]['height'] - curr_edge = R_nodes[u]['curr_edge'] - # next_height represents the next height to examine after discharging - # the current node. During phase 1, it is capped to below n. - next_height = height - levels[height].active.remove(u) - while True: - v, attr = curr_edge.get() - if (height == R_nodes[v]['height'] + 1 and - attr['flow'] < attr['capacity']): - flow = min(R_nodes[u]['excess'], - attr['capacity'] - attr['flow']) - push(u, v, flow) - activate(v) - if R_nodes[u]['excess'] == 0: - # The node has become inactive. - levels[height].inactive.add(u) - break - try: - curr_edge.move_to_next() - except StopIteration: - # We have run off the end of the adjacency list, and there can - # be no more admissible edges. Relabel the node to create one. - height = relabel(u) - if is_phase1 and height >= n - 1: - # Although the node is still active, with a height at least - # n - 1, it is now known to be on the s side of the minimum - # s-t cut. Stop processing it until phase 2. - levels[height].active.add(u) - break - # The first relabel operation after global relabeling may not - # increase the height of the node since the 'current edge' data - # structure is not rewound. Use height instead of (height - 1) - # in case other active nodes at the same level are missed. - next_height = height - R_nodes[u]['height'] = height - return next_height - - def gap_heuristic(height): - """Apply the gap heuristic. - """ - # Move all nodes at levels (height + 1) to max_height to level n + 1. - for level in islice(levels, height + 1, max_height + 1): - for u in level.active: - R_nodes[u]['height'] = n + 1 - for u in level.inactive: - R_nodes[u]['height'] = n + 1 - levels[n + 1].active.update(level.active) - level.active.clear() - levels[n + 1].inactive.update(level.inactive) - level.inactive.clear() - - def global_relabel(from_sink): - """Apply the global relabeling heuristic. - """ - src = t if from_sink else s - heights = reverse_bfs(src) - if not from_sink: - # s must be reachable from t. Remove t explicitly. - del heights[t] - max_height = max(heights.values()) - if from_sink: - # Also mark nodes from which t is unreachable for relabeling. This - # serves the same purpose as the gap heuristic. - for u in R: - if u not in heights and R_nodes[u]['height'] < n: - heights[u] = n + 1 - else: - # Shift the computed heights because the height of s is n. - for u in heights: - heights[u] += n - max_height += n - del heights[src] - for u, new_height in heights.items(): - old_height = R_nodes[u]['height'] - if new_height != old_height: - if u in levels[old_height].active: - levels[old_height].active.remove(u) - levels[new_height].active.add(u) - else: - levels[old_height].inactive.remove(u) - levels[new_height].inactive.add(u) - R_nodes[u]['height'] = new_height - return max_height - - # Phase 1: Find the maximum preflow by pushing as much flow as possible to - # t. - - height = max_height - while height > 0: - # Discharge active nodes in the current level. - while True: - level = levels[height] - if not level.active: - # All active nodes in the current level have been discharged. - # Move to the next lower level. - height -= 1 - break - # Record the old height and level for the gap heuristic. - old_height = height - old_level = level - u = arbitrary_element(level.active) - height = discharge(u, True) - if grt.is_reached(): - # Global relabeling heuristic: Recompute the exact heights of - # all nodes. - height = global_relabel(True) - max_height = height - grt.clear_work() - elif not old_level.active and not old_level.inactive: - # Gap heuristic: If the level at old_height is empty (a 'gap'), - # a minimum cut has been identified. All nodes with heights - # above old_height can have their heights set to n + 1 and not - # be further processed before a maximum preflow is found. - gap_heuristic(old_height) - height = old_height - 1 - max_height = height - else: - # Update the height of the highest level with at least one - # active node. - max_height = max(max_height, height) - - # A maximum preflow has been found. The excess at t is the maximum flow - # value. - if value_only: - R.graph['flow_value'] = R_nodes[t]['excess'] - return R - - # Phase 2: Convert the maximum preflow into a maximum flow by returning the - # excess to s. - - # Relabel all nodes so that they have accurate heights. - height = global_relabel(False) - grt.clear_work() - - # Continue to discharge the active nodes. - while height > n: - # Discharge active nodes in the current level. - while True: - level = levels[height] - if not level.active: - # All active nodes in the current level have been discharged. - # Move to the next lower level. - height -= 1 - break - u = arbitrary_element(level.active) - height = discharge(u, False) - if grt.is_reached(): - # Global relabeling heuristic. - height = global_relabel(False) - grt.clear_work() - - R.graph['flow_value'] = R_nodes[t]['excess'] - return R - - -def preflow_push(G, s, t, capacity='capacity', residual=None, - global_relabel_freq=1, value_only=False): - r"""Find a maximum single-commodity flow using the highest-label - preflow-push algorithm. - - This function returns the residual network resulting after computing - the maximum flow. See below for details about the conventions - NetworkX uses for defining residual networks. - - This algorithm has a running time of $O(n^2 \sqrt{m})$ for $n$ nodes and - $m$ edges. - - - Parameters - ---------- - G : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - s : node - Source node for the flow. - - t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - residual : NetworkX graph - Residual network on which the algorithm is to be executed. If None, a - new residual network is created. Default value: None. - - global_relabel_freq : integer, float - Relative frequency of applying the global relabeling heuristic to speed - up the algorithm. If it is None, the heuristic is disabled. Default - value: 1. - - value_only : bool - If False, compute a maximum flow; otherwise, compute a maximum preflow - which is enough for computing the maximum flow value. Default value: - False. - - Returns - ------- - R : NetworkX DiGraph - Residual network after computing the maximum flow. - - Raises - ------ - NetworkXError - The algorithm does not support MultiGraph and MultiDiGraph. If - the input graph is an instance of one of these two classes, a - NetworkXError is raised. - - NetworkXUnbounded - If the graph has a path of infinite capacity, the value of a - feasible flow on the graph is unbounded above and the function - raises a NetworkXUnbounded. - - See also - -------- - :meth:`maximum_flow` - :meth:`minimum_cut` - :meth:`edmonds_karp` - :meth:`shortest_augmenting_path` - - Notes - ----- - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. For each node :samp:`u` in :samp:`R`, - :samp:`R.nodes[u]['excess']` represents the difference between flow into - :samp:`u` and flow out of :samp:`u`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. Reachability to :samp:`t` using - only edges :samp:`(u, v)` such that - :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Examples - -------- - >>> import networkx as nx - >>> from networkx.algorithms.flow import preflow_push - - The functions that implement flow algorithms and output a residual - network, such as this one, are not imported to the base NetworkX - namespace, so you have to explicitly import them from the flow package. - - >>> G = nx.DiGraph() - >>> G.add_edge('x','a', capacity=3.0) - >>> G.add_edge('x','b', capacity=1.0) - >>> G.add_edge('a','c', capacity=3.0) - >>> G.add_edge('b','c', capacity=5.0) - >>> G.add_edge('b','d', capacity=4.0) - >>> G.add_edge('d','e', capacity=2.0) - >>> G.add_edge('c','y', capacity=2.0) - >>> G.add_edge('e','y', capacity=3.0) - >>> R = preflow_push(G, 'x', 'y') - >>> flow_value = nx.maximum_flow_value(G, 'x', 'y') - >>> flow_value == R.graph['flow_value'] - True - >>> # preflow_push also stores the maximum flow value - >>> # in the excess attribute of the sink node t - >>> flow_value == R.nodes['y']['excess'] - True - >>> # For some problems, you might only want to compute a - >>> # maximum preflow. - >>> R = preflow_push(G, 'x', 'y', value_only=True) - >>> flow_value == R.graph['flow_value'] - True - >>> flow_value == R.nodes['y']['excess'] - True - - """ - R = preflow_push_impl(G, s, t, capacity, residual, global_relabel_freq, - value_only) - R.graph['algorithm'] = 'preflow_push' - return R diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/shortestaugmentingpath.py b/extensions/fablabchemnitz/networkx/algorithms/flow/shortestaugmentingpath.py deleted file mode 100644 index 8b811ed7..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/flow/shortestaugmentingpath.py +++ /dev/null @@ -1,302 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Shortest augmenting path algorithm for maximum flow problems. -""" - -__author__ = """ysitu """ -# Copyright (C) 2014 ysitu -# All rights reserved. -# BSD license. - -from collections import deque -import networkx as nx -from .utils import * -from .edmondskarp import edmonds_karp_core - -__all__ = ['shortest_augmenting_path'] - - -def shortest_augmenting_path_impl(G, s, t, capacity, residual, two_phase, - cutoff): - """Implementation of the shortest augmenting path algorithm. - """ - if s not in G: - raise nx.NetworkXError('node %s not in graph' % str(s)) - if t not in G: - raise nx.NetworkXError('node %s not in graph' % str(t)) - if s == t: - raise nx.NetworkXError('source and sink are the same node') - - if residual is None: - R = build_residual_network(G, capacity) - else: - R = residual - - R_nodes = R.nodes - R_pred = R.pred - R_succ = R.succ - - # Initialize/reset the residual network. - for u in R: - for e in R_succ[u].values(): - e['flow'] = 0 - - # Initialize heights of the nodes. - heights = {t: 0} - q = deque([(t, 0)]) - while q: - u, height = q.popleft() - height += 1 - for v, attr in R_pred[u].items(): - if v not in heights and attr['flow'] < attr['capacity']: - heights[v] = height - q.append((v, height)) - - if s not in heights: - # t is not reachable from s in the residual network. The maximum flow - # must be zero. - R.graph['flow_value'] = 0 - return R - - n = len(G) - m = R.size() / 2 - - # Initialize heights and 'current edge' data structures of the nodes. - for u in R: - R_nodes[u]['height'] = heights[u] if u in heights else n - R_nodes[u]['curr_edge'] = CurrentEdge(R_succ[u]) - - # Initialize counts of nodes in each level. - counts = [0] * (2 * n - 1) - for u in R: - counts[R_nodes[u]['height']] += 1 - - inf = R.graph['inf'] - - def augment(path): - """Augment flow along a path from s to t. - """ - # Determine the path residual capacity. - flow = inf - it = iter(path) - u = next(it) - for v in it: - attr = R_succ[u][v] - flow = min(flow, attr['capacity'] - attr['flow']) - u = v - if flow * 2 > inf: - raise nx.NetworkXUnbounded( - 'Infinite capacity path, flow unbounded above.') - # Augment flow along the path. - it = iter(path) - u = next(it) - for v in it: - R_succ[u][v]['flow'] += flow - R_succ[v][u]['flow'] -= flow - u = v - return flow - - def relabel(u): - """Relabel a node to create an admissible edge. - """ - height = n - 1 - for v, attr in R_succ[u].items(): - if attr['flow'] < attr['capacity']: - height = min(height, R_nodes[v]['height']) - return height + 1 - - if cutoff is None: - cutoff = float('inf') - - # Phase 1: Look for shortest augmenting paths using depth-first search. - - flow_value = 0 - path = [s] - u = s - d = n if not two_phase else int(min(m ** 0.5, 2 * n ** (2. / 3))) - done = R_nodes[s]['height'] >= d - while not done: - height = R_nodes[u]['height'] - curr_edge = R_nodes[u]['curr_edge'] - # Depth-first search for the next node on the path to t. - while True: - v, attr = curr_edge.get() - if (height == R_nodes[v]['height'] + 1 and - attr['flow'] < attr['capacity']): - # Advance to the next node following an admissible edge. - path.append(v) - u = v - break - try: - curr_edge.move_to_next() - except StopIteration: - counts[height] -= 1 - if counts[height] == 0: - # Gap heuristic: If relabeling causes a level to become - # empty, a minimum cut has been identified. The algorithm - # can now be terminated. - R.graph['flow_value'] = flow_value - return R - height = relabel(u) - if u == s and height >= d: - if not two_phase: - # t is disconnected from s in the residual network. No - # more augmenting paths exist. - R.graph['flow_value'] = flow_value - return R - else: - # t is at least d steps away from s. End of phase 1. - done = True - break - counts[height] += 1 - R_nodes[u]['height'] = height - if u != s: - # After relabeling, the last edge on the path is no longer - # admissible. Retreat one step to look for an alternative. - path.pop() - u = path[-1] - break - if u == t: - # t is reached. Augment flow along the path and reset it for a new - # depth-first search. - flow_value += augment(path) - if flow_value >= cutoff: - R.graph['flow_value'] = flow_value - return R - path = [s] - u = s - - # Phase 2: Look for shortest augmenting paths using breadth-first search. - flow_value += edmonds_karp_core(R, s, t, cutoff - flow_value) - - R.graph['flow_value'] = flow_value - return R - - -def shortest_augmenting_path(G, s, t, capacity='capacity', residual=None, - value_only=False, two_phase=False, cutoff=None): - r"""Find a maximum single-commodity flow using the shortest augmenting path - algorithm. - - This function returns the residual network resulting after computing - the maximum flow. See below for details about the conventions - NetworkX uses for defining residual networks. - - This algorithm has a running time of $O(n^2 m)$ for $n$ nodes and $m$ - edges. - - - Parameters - ---------- - G : NetworkX graph - Edges of the graph are expected to have an attribute called - 'capacity'. If this attribute is not present, the edge is - considered to have infinite capacity. - - s : node - Source node for the flow. - - t : node - Sink node for the flow. - - capacity : string - Edges of the graph G are expected to have an attribute capacity - that indicates how much flow the edge can support. If this - attribute is not present, the edge is considered to have - infinite capacity. Default value: 'capacity'. - - residual : NetworkX graph - Residual network on which the algorithm is to be executed. If None, a - new residual network is created. Default value: None. - - value_only : bool - If True compute only the value of the maximum flow. This parameter - will be ignored by this algorithm because it is not applicable. - - two_phase : bool - If True, a two-phase variant is used. The two-phase variant improves - the running time on unit-capacity networks from $O(nm)$ to - $O(\min(n^{2/3}, m^{1/2}) m)$. Default value: False. - - cutoff : integer, float - If specified, the algorithm will terminate when the flow value reaches - or exceeds the cutoff. In this case, it may be unable to immediately - determine a minimum cut. Default value: None. - - Returns - ------- - R : NetworkX DiGraph - Residual network after computing the maximum flow. - - Raises - ------ - NetworkXError - The algorithm does not support MultiGraph and MultiDiGraph. If - the input graph is an instance of one of these two classes, a - NetworkXError is raised. - - NetworkXUnbounded - If the graph has a path of infinite capacity, the value of a - feasible flow on the graph is unbounded above and the function - raises a NetworkXUnbounded. - - See also - -------- - :meth:`maximum_flow` - :meth:`minimum_cut` - :meth:`edmonds_karp` - :meth:`preflow_push` - - Notes - ----- - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. If :samp:`cutoff` is not - specified, reachability to :samp:`t` using only edges :samp:`(u, v)` such - that :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - Examples - -------- - >>> import networkx as nx - >>> from networkx.algorithms.flow import shortest_augmenting_path - - The functions that implement flow algorithms and output a residual - network, such as this one, are not imported to the base NetworkX - namespace, so you have to explicitly import them from the flow package. - - >>> G = nx.DiGraph() - >>> G.add_edge('x','a', capacity=3.0) - >>> G.add_edge('x','b', capacity=1.0) - >>> G.add_edge('a','c', capacity=3.0) - >>> G.add_edge('b','c', capacity=5.0) - >>> G.add_edge('b','d', capacity=4.0) - >>> G.add_edge('d','e', capacity=2.0) - >>> G.add_edge('c','y', capacity=2.0) - >>> G.add_edge('e','y', capacity=3.0) - >>> R = shortest_augmenting_path(G, 'x', 'y') - >>> flow_value = nx.maximum_flow_value(G, 'x', 'y') - >>> flow_value - 3.0 - >>> flow_value == R.graph['flow_value'] - True - - """ - R = shortest_augmenting_path_impl(G, s, t, capacity, residual, two_phase, - cutoff) - R.graph['algorithm'] = 'shortest_augmenting_path' - return R diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/flow/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/gl1.gpickle.bz2 b/extensions/fablabchemnitz/networkx/algorithms/flow/tests/gl1.gpickle.bz2 deleted file mode 100644 index e6ed5744..00000000 Binary files a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/gl1.gpickle.bz2 and /dev/null differ diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/gw1.gpickle.bz2 b/extensions/fablabchemnitz/networkx/algorithms/flow/tests/gw1.gpickle.bz2 deleted file mode 100644 index abd0e8a2..00000000 Binary files a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/gw1.gpickle.bz2 and /dev/null differ diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2 b/extensions/fablabchemnitz/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2 deleted file mode 100644 index cd3ea801..00000000 Binary files a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2 and /dev/null differ diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/test_gomory_hu.py b/extensions/fablabchemnitz/networkx/algorithms/flow/tests/test_gomory_hu.py deleted file mode 100644 index aadd38da..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/test_gomory_hu.py +++ /dev/null @@ -1,123 +0,0 @@ -from itertools import combinations -import pytest - -import networkx as nx -from networkx.algorithms.flow import boykov_kolmogorov -from networkx.algorithms.flow import edmonds_karp -from networkx.algorithms.flow import preflow_push -from networkx.algorithms.flow import shortest_augmenting_path -from networkx.algorithms.flow import dinitz - -flow_funcs = [ - boykov_kolmogorov, - dinitz, - edmonds_karp, - preflow_push, - shortest_augmenting_path, -] - - -class TestGomoryHuTree: - - def minimum_edge_weight(self, T, u, v): - path = nx.shortest_path(T, u, v, weight='weight') - return min((T[u][v]['weight'], (u, v)) for (u, v) in zip(path, path[1:])) - - def compute_cutset(self, G, T_orig, edge): - T = T_orig.copy() - T.remove_edge(*edge) - U, V = list(nx.connected_components(T)) - cutset = set() - for x, nbrs in ((n, G[n]) for n in U): - cutset.update((x, y) for y in nbrs if y in V) - return cutset - - def test_default_flow_function_karate_club_graph(self): - G = nx.karate_club_graph() - nx.set_edge_attributes(G, 1, 'capacity') - T = nx.gomory_hu_tree(G) - assert nx.is_tree(T) - for u, v in combinations(G, 2): - cut_value, edge = self.minimum_edge_weight(T, u, v) - assert (nx.minimum_cut_value(G, u, v) == - cut_value) - - def test_karate_club_graph(self): - G = nx.karate_club_graph() - nx.set_edge_attributes(G, 1, 'capacity') - for flow_func in flow_funcs: - T = nx.gomory_hu_tree(G, flow_func=flow_func) - assert nx.is_tree(T) - for u, v in combinations(G, 2): - cut_value, edge = self.minimum_edge_weight(T, u, v) - assert (nx.minimum_cut_value(G, u, v) == - cut_value) - - def test_davis_southern_women_graph(self): - G = nx.davis_southern_women_graph() - nx.set_edge_attributes(G, 1, 'capacity') - for flow_func in flow_funcs: - T = nx.gomory_hu_tree(G, flow_func=flow_func) - assert nx.is_tree(T) - for u, v in combinations(G, 2): - cut_value, edge = self.minimum_edge_weight(T, u, v) - assert (nx.minimum_cut_value(G, u, v) == - cut_value) - - def test_florentine_families_graph(self): - G = nx.florentine_families_graph() - nx.set_edge_attributes(G, 1, 'capacity') - for flow_func in flow_funcs: - T = nx.gomory_hu_tree(G, flow_func=flow_func) - assert nx.is_tree(T) - for u, v in combinations(G, 2): - cut_value, edge = self.minimum_edge_weight(T, u, v) - assert (nx.minimum_cut_value(G, u, v) == - cut_value) - - def test_les_miserables_graph_cutset(self): - G = nx.les_miserables_graph() - nx.set_edge_attributes(G, 1, 'capacity') - for flow_func in flow_funcs: - T = nx.gomory_hu_tree(G, flow_func=flow_func) - assert nx.is_tree(T) - for u, v in combinations(G, 2): - cut_value, edge = self.minimum_edge_weight(T, u, v) - assert (nx.minimum_cut_value(G, u, v) == - cut_value) - - def test_karate_club_graph_cutset(self): - G = nx.karate_club_graph() - nx.set_edge_attributes(G, 1, 'capacity') - T = nx.gomory_hu_tree(G) - assert nx.is_tree(T) - u, v = 0, 33 - cut_value, edge = self.minimum_edge_weight(T, u, v) - cutset = self.compute_cutset(G, T, edge) - assert cut_value == len(cutset) - - def test_wikipedia_example(self): - # Example from https://en.wikipedia.org/wiki/Gomory%E2%80%93Hu_tree - G = nx.Graph() - G.add_weighted_edges_from(( - (0, 1, 1), (0, 2, 7), (1, 2, 1), - (1, 3, 3), (1, 4, 2), (2, 4, 4), - (3, 4, 1), (3, 5, 6), (4, 5, 2), - )) - for flow_func in flow_funcs: - T = nx.gomory_hu_tree(G, capacity='weight', flow_func=flow_func) - assert nx.is_tree(T) - for u, v in combinations(G, 2): - cut_value, edge = self.minimum_edge_weight(T, u, v) - assert (nx.minimum_cut_value(G, u, v, capacity='weight') == - cut_value) - - def test_directed_raises(self): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.DiGraph() - T = nx.gomory_hu_tree(G) - - def test_empty_raises(self): - with pytest.raises(nx.NetworkXError): - G = nx.empty_graph() - T = nx.gomory_hu_tree(G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/test_maxflow.py b/extensions/fablabchemnitz/networkx/algorithms/flow/tests/test_maxflow.py deleted file mode 100644 index b0d8695d..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/test_maxflow.py +++ /dev/null @@ -1,503 +0,0 @@ -# -*- coding: utf-8 -*- -"""Maximum flow algorithms test suite. -""" -import pytest - -import networkx as nx -from networkx.algorithms.flow import build_flow_dict, build_residual_network -from networkx.algorithms.flow import boykov_kolmogorov -from networkx.algorithms.flow import edmonds_karp -from networkx.algorithms.flow import preflow_push -from networkx.algorithms.flow import shortest_augmenting_path -from networkx.algorithms.flow import dinitz - -flow_funcs = [boykov_kolmogorov, dinitz, edmonds_karp, preflow_push, shortest_augmenting_path] -max_min_funcs = [nx.maximum_flow, nx.minimum_cut] -flow_value_funcs = [nx.maximum_flow_value, nx.minimum_cut_value] -interface_funcs = sum([max_min_funcs, flow_value_funcs], []) -all_funcs = sum([flow_funcs, interface_funcs], []) - -msg = "Assertion failed in function: {0}" -msgi = "Assertion failed in function: {0} in interface {1}" - - -def compute_cutset(G, partition): - reachable, non_reachable = partition - cutset = set() - for u, nbrs in ((n, G[n]) for n in reachable): - cutset.update((u, v) for v in nbrs if v in non_reachable) - return cutset - - -def validate_flows(G, s, t, flowDict, solnValue, capacity, flow_func): - assert set(G) == set(flowDict), msg.format(flow_func.__name__) - for u in G: - assert set(G[u]) == set(flowDict[u]), msg.format(flow_func.__name__) - excess = {u: 0 for u in flowDict} - for u in flowDict: - for v, flow in flowDict[u].items(): - if capacity in G[u][v]: - assert flow <= G[u][v][capacity] - assert flow >= 0, msg.format(flow_func.__name__) - excess[u] -= flow - excess[v] += flow - for u, exc in excess.items(): - if u == s: - assert exc == -solnValue, msg.format(flow_func.__name__) - elif u == t: - assert exc == solnValue, msg.format(flow_func.__name__) - else: - assert exc == 0, msg.format(flow_func.__name__) - - -def validate_cuts(G, s, t, solnValue, partition, capacity, flow_func): - assert all(n in G for n in partition[0]), msg.format(flow_func.__name__) - assert all(n in G for n in partition[1]), msg.format(flow_func.__name__) - cutset = compute_cutset(G, partition) - assert all(G.has_edge(u, v) for (u, v) in cutset), msg.format(flow_func.__name__) - assert solnValue == sum(G[u][v][capacity] for (u, v) in cutset), msg.format(flow_func.__name__) - H = G.copy() - H.remove_edges_from(cutset) - if not G.is_directed(): - assert not nx.is_connected(H), msg.format(flow_func.__name__) - else: - assert not nx.is_strongly_connected(H), msg.format(flow_func.__name__) - - -def compare_flows_and_cuts(G, s, t, solnFlows, solnValue, capacity='capacity'): - for flow_func in flow_funcs: - R = flow_func(G, s, t, capacity) - # Test both legacy and new implementations. - flow_value = R.graph['flow_value'] - flow_dict = build_flow_dict(G, R) - assert flow_value == solnValue, msg.format(flow_func.__name__) - validate_flows(G, s, t, flow_dict, solnValue, capacity, flow_func) - # Minimum cut - cut_value, partition = nx.minimum_cut(G, s, t, capacity=capacity, - flow_func=flow_func) - validate_cuts(G, s, t, solnValue, partition, capacity, flow_func) - - -class TestMaxflowMinCutCommon: - - def test_graph1(self): - # Trivial undirected graph - G = nx.Graph() - G.add_edge(1, 2, capacity=1.0) - - solnFlows = {1: {2: 1.0}, - 2: {1: 1.0}} - - compare_flows_and_cuts(G, 1, 2, solnFlows, 1.0) - - def test_graph2(self): - # A more complex undirected graph - # adapted from www.topcoder.com/tc?module=Statc&d1=tutorials&d2=maxFlow - G = nx.Graph() - G.add_edge('x', 'a', capacity=3.0) - G.add_edge('x', 'b', capacity=1.0) - G.add_edge('a', 'c', capacity=3.0) - G.add_edge('b', 'c', capacity=5.0) - G.add_edge('b', 'd', capacity=4.0) - G.add_edge('d', 'e', capacity=2.0) - G.add_edge('c', 'y', capacity=2.0) - G.add_edge('e', 'y', capacity=3.0) - - H = {'x': {'a': 3, 'b': 1}, - 'a': {'c': 3, 'x': 3}, - 'b': {'c': 1, 'd': 2, 'x': 1}, - 'c': {'a': 3, 'b': 1, 'y': 2}, - 'd': {'b': 2, 'e': 2}, - 'e': {'d': 2, 'y': 2}, - 'y': {'c': 2, 'e': 2}} - - compare_flows_and_cuts(G, 'x', 'y', H, 4.0) - - def test_digraph1(self): - # The classic directed graph example - G = nx.DiGraph() - G.add_edge('a', 'b', capacity=1000.0) - G.add_edge('a', 'c', capacity=1000.0) - G.add_edge('b', 'c', capacity=1.0) - G.add_edge('b', 'd', capacity=1000.0) - G.add_edge('c', 'd', capacity=1000.0) - - H = {'a': {'b': 1000.0, 'c': 1000.0}, - 'b': {'c': 0, 'd': 1000.0}, - 'c': {'d': 1000.0}, - 'd': {}} - - compare_flows_and_cuts(G, 'a', 'd', H, 2000.0) - - def test_digraph2(self): - # An example in which some edges end up with zero flow. - G = nx.DiGraph() - G.add_edge('s', 'b', capacity=2) - G.add_edge('s', 'c', capacity=1) - G.add_edge('c', 'd', capacity=1) - G.add_edge('d', 'a', capacity=1) - G.add_edge('b', 'a', capacity=2) - G.add_edge('a', 't', capacity=2) - - H = {'s': {'b': 2, 'c': 0}, - 'c': {'d': 0}, - 'd': {'a': 0}, - 'b': {'a': 2}, - 'a': {'t': 2}, - 't': {}} - - compare_flows_and_cuts(G, 's', 't', H, 2) - - def test_digraph3(self): - # A directed graph example from Cormen et al. - G = nx.DiGraph() - G.add_edge('s', 'v1', capacity=16.0) - G.add_edge('s', 'v2', capacity=13.0) - G.add_edge('v1', 'v2', capacity=10.0) - G.add_edge('v2', 'v1', capacity=4.0) - G.add_edge('v1', 'v3', capacity=12.0) - G.add_edge('v3', 'v2', capacity=9.0) - G.add_edge('v2', 'v4', capacity=14.0) - G.add_edge('v4', 'v3', capacity=7.0) - G.add_edge('v3', 't', capacity=20.0) - G.add_edge('v4', 't', capacity=4.0) - - H = {'s': {'v1': 12.0, 'v2': 11.0}, - 'v2': {'v1': 0, 'v4': 11.0}, - 'v1': {'v2': 0, 'v3': 12.0}, - 'v3': {'v2': 0, 't': 19.0}, - 'v4': {'v3': 7.0, 't': 4.0}, - 't': {}} - - compare_flows_and_cuts(G, 's', 't', H, 23.0) - - def test_digraph4(self): - # A more complex directed graph - # from www.topcoder.com/tc?module=Statc&d1=tutorials&d2=maxFlow - G = nx.DiGraph() - G.add_edge('x', 'a', capacity=3.0) - G.add_edge('x', 'b', capacity=1.0) - G.add_edge('a', 'c', capacity=3.0) - G.add_edge('b', 'c', capacity=5.0) - G.add_edge('b', 'd', capacity=4.0) - G.add_edge('d', 'e', capacity=2.0) - G.add_edge('c', 'y', capacity=2.0) - G.add_edge('e', 'y', capacity=3.0) - - H = {'x': {'a': 2.0, 'b': 1.0}, - 'a': {'c': 2.0}, - 'b': {'c': 0, 'd': 1.0}, - 'c': {'y': 2.0}, - 'd': {'e': 1.0}, - 'e': {'y': 1.0}, - 'y': {}} - - compare_flows_and_cuts(G, 'x', 'y', H, 3.0) - - def test_wikipedia_dinitz_example(self): - # Nice example from https://en.wikipedia.org/wiki/Dinic's_algorithm - G = nx.DiGraph() - G.add_edge('s', 1, capacity=10) - G.add_edge('s', 2, capacity=10) - G.add_edge(1, 3, capacity=4) - G.add_edge(1, 4, capacity=8) - G.add_edge(1, 2, capacity=2) - G.add_edge(2, 4, capacity=9) - G.add_edge(3, 't', capacity=10) - G.add_edge(4, 3, capacity=6) - G.add_edge(4, 't', capacity=10) - - solnFlows = {1: {2: 0, 3: 4, 4: 6}, - 2: {4: 9}, - 3: {'t': 9}, - 4: {3: 5, 't': 10}, - 's': {1: 10, 2: 9}, - 't': {}} - - compare_flows_and_cuts(G, 's', 't', solnFlows, 19) - - def test_optional_capacity(self): - # Test optional capacity parameter. - G = nx.DiGraph() - G.add_edge('x', 'a', spam=3.0) - G.add_edge('x', 'b', spam=1.0) - G.add_edge('a', 'c', spam=3.0) - G.add_edge('b', 'c', spam=5.0) - G.add_edge('b', 'd', spam=4.0) - G.add_edge('d', 'e', spam=2.0) - G.add_edge('c', 'y', spam=2.0) - G.add_edge('e', 'y', spam=3.0) - - solnFlows = {'x': {'a': 2.0, 'b': 1.0}, - 'a': {'c': 2.0}, - 'b': {'c': 0, 'd': 1.0}, - 'c': {'y': 2.0}, - 'd': {'e': 1.0}, - 'e': {'y': 1.0}, - 'y': {}} - solnValue = 3.0 - s = 'x' - t = 'y' - - compare_flows_and_cuts(G, s, t, solnFlows, solnValue, capacity='spam') - - def test_digraph_infcap_edges(self): - # DiGraph with infinite capacity edges - G = nx.DiGraph() - G.add_edge('s', 'a') - G.add_edge('s', 'b', capacity=30) - G.add_edge('a', 'c', capacity=25) - G.add_edge('b', 'c', capacity=12) - G.add_edge('a', 't', capacity=60) - G.add_edge('c', 't') - - H = {'s': {'a': 85, 'b': 12}, - 'a': {'c': 25, 't': 60}, - 'b': {'c': 12}, - 'c': {'t': 37}, - 't': {}} - - compare_flows_and_cuts(G, 's', 't', H, 97) - - # DiGraph with infinite capacity digon - G = nx.DiGraph() - G.add_edge('s', 'a', capacity=85) - G.add_edge('s', 'b', capacity=30) - G.add_edge('a', 'c') - G.add_edge('c', 'a') - G.add_edge('b', 'c', capacity=12) - G.add_edge('a', 't', capacity=60) - G.add_edge('c', 't', capacity=37) - - H = {'s': {'a': 85, 'b': 12}, - 'a': {'c': 25, 't': 60}, - 'c': {'a': 0, 't': 37}, - 'b': {'c': 12}, - 't': {}} - - compare_flows_and_cuts(G, 's', 't', H, 97) - - def test_digraph_infcap_path(self): - # Graph with infinite capacity (s, t)-path - G = nx.DiGraph() - G.add_edge('s', 'a') - G.add_edge('s', 'b', capacity=30) - G.add_edge('a', 'c') - G.add_edge('b', 'c', capacity=12) - G.add_edge('a', 't', capacity=60) - G.add_edge('c', 't') - - for flow_func in all_funcs: - pytest.raises(nx.NetworkXUnbounded, - flow_func, G, 's', 't') - - def test_graph_infcap_edges(self): - # Undirected graph with infinite capacity edges - G = nx.Graph() - G.add_edge('s', 'a') - G.add_edge('s', 'b', capacity=30) - G.add_edge('a', 'c', capacity=25) - G.add_edge('b', 'c', capacity=12) - G.add_edge('a', 't', capacity=60) - G.add_edge('c', 't') - - H = {'s': {'a': 85, 'b': 12}, - 'a': {'c': 25, 's': 85, 't': 60}, - 'b': {'c': 12, 's': 12}, - 'c': {'a': 25, 'b': 12, 't': 37}, - 't': {'a': 60, 'c': 37}} - - compare_flows_and_cuts(G, 's', 't', H, 97) - - def test_digraph5(self): - # From ticket #429 by mfrasca. - G = nx.DiGraph() - G.add_edge('s', 'a', capacity=2) - G.add_edge('s', 'b', capacity=2) - G.add_edge('a', 'b', capacity=5) - G.add_edge('a', 't', capacity=1) - G.add_edge('b', 'a', capacity=1) - G.add_edge('b', 't', capacity=3) - flowSoln = {'a': {'b': 1, 't': 1}, - 'b': {'a': 0, 't': 3}, - 's': {'a': 2, 'b': 2}, - 't': {}} - compare_flows_and_cuts(G, 's', 't', flowSoln, 4) - - def test_disconnected(self): - G = nx.Graph() - G.add_weighted_edges_from([(0, 1, 1), (1, 2, 1), (2, 3, 1)], weight='capacity') - G.remove_node(1) - assert nx.maximum_flow_value(G, 0, 3) == 0 - flowSoln = {0: {}, 2: {3: 0}, 3: {2: 0}} - compare_flows_and_cuts(G, 0, 3, flowSoln, 0) - - def test_source_target_not_in_graph(self): - G = nx.Graph() - G.add_weighted_edges_from([(0, 1, 1), (1, 2, 1), (2, 3, 1)], weight='capacity') - G.remove_node(0) - for flow_func in all_funcs: - pytest.raises(nx.NetworkXError, flow_func, G, 0, 3) - G.add_weighted_edges_from([(0, 1, 1), (1, 2, 1), (2, 3, 1)], weight='capacity') - G.remove_node(3) - for flow_func in all_funcs: - pytest.raises(nx.NetworkXError, flow_func, G, 0, 3) - - def test_source_target_coincide(self): - G = nx.Graph() - G.add_node(0) - for flow_func in all_funcs: - pytest.raises(nx.NetworkXError, flow_func, G, 0, 0) - - def test_multigraphs_raise(self): - G = nx.MultiGraph() - M = nx.MultiDiGraph() - G.add_edges_from([(0, 1), (1, 0)], capacity=True) - for flow_func in all_funcs: - pytest.raises(nx.NetworkXError, flow_func, G, 0, 0) - - -class TestMaxFlowMinCutInterface: - - def setup(self): - G = nx.DiGraph() - G.add_edge('x', 'a', capacity=3.0) - G.add_edge('x', 'b', capacity=1.0) - G.add_edge('a', 'c', capacity=3.0) - G.add_edge('b', 'c', capacity=5.0) - G.add_edge('b', 'd', capacity=4.0) - G.add_edge('d', 'e', capacity=2.0) - G.add_edge('c', 'y', capacity=2.0) - G.add_edge('e', 'y', capacity=3.0) - self.G = G - H = nx.DiGraph() - H.add_edge(0, 1, capacity=1.0) - H.add_edge(1, 2, capacity=1.0) - self.H = H - - def test_flow_func_not_callable(self): - elements = ['this_should_be_callable', 10, set([1, 2, 3])] - G = nx.Graph() - G.add_weighted_edges_from([(0, 1, 1), (1, 2, 1), (2, 3, 1)], weight='capacity') - for flow_func in interface_funcs: - for element in elements: - pytest.raises(nx.NetworkXError, - flow_func, G, 0, 1, flow_func=element) - pytest.raises(nx.NetworkXError, - flow_func, G, 0, 1, flow_func=element) - - def test_flow_func_parameters(self): - G = self.G - fv = 3.0 - for interface_func in interface_funcs: - for flow_func in flow_funcs: - result = interface_func(G, 'x', 'y', flow_func=flow_func) - if interface_func in max_min_funcs: - result = result[0] - assert fv == result, msgi.format(flow_func.__name__, - interface_func.__name__) - - def test_minimum_cut_no_cutoff(self): - G = self.G - for flow_func in flow_funcs: - pytest.raises(nx.NetworkXError, nx.minimum_cut, G, 'x', 'y', - flow_func=flow_func, cutoff=1.0) - pytest.raises(nx.NetworkXError, nx.minimum_cut_value, G, 'x', 'y', - flow_func=flow_func, cutoff=1.0) - - def test_kwargs(self): - G = self.H - fv = 1.0 - to_test = ( - (shortest_augmenting_path, dict(two_phase=True)), - (preflow_push, dict(global_relabel_freq=5)), - ) - for interface_func in interface_funcs: - for flow_func, kwargs in to_test: - result = interface_func(G, 0, 2, flow_func=flow_func, **kwargs) - if interface_func in max_min_funcs: - result = result[0] - assert fv == result, msgi.format(flow_func.__name__, - interface_func.__name__) - - def test_kwargs_default_flow_func(self): - G = self.H - for interface_func in interface_funcs: - pytest.raises(nx.NetworkXError, interface_func, - G, 0, 1, global_relabel_freq=2) - - def test_reusing_residual(self): - G = self.G - fv = 3.0 - s, t = 'x', 'y' - R = build_residual_network(G, 'capacity') - for interface_func in interface_funcs: - for flow_func in flow_funcs: - for i in range(3): - result = interface_func(G, 'x', 'y', flow_func=flow_func, - residual=R) - if interface_func in max_min_funcs: - result = result[0] - assert fv == result, msgi.format(flow_func.__name__, - interface_func.__name__) - - -# Tests specific to one algorithm -def test_preflow_push_global_relabel_freq(): - G = nx.DiGraph() - G.add_edge(1, 2, capacity=1) - R = preflow_push(G, 1, 2, global_relabel_freq=None) - assert R.graph['flow_value'] == 1 - pytest.raises(nx.NetworkXError, preflow_push, G, 1, 2, - global_relabel_freq=-1) - - -def test_preflow_push_makes_enough_space(): - # From ticket #1542 - G = nx.DiGraph() - nx.add_path(G, [0, 1, 3], capacity=1) - nx.add_path(G, [1, 2, 3], capacity=1) - R = preflow_push(G, 0, 3, value_only=False) - assert R.graph['flow_value'] == 1 - - -def test_shortest_augmenting_path_two_phase(): - k = 5 - p = 1000 - G = nx.DiGraph() - for i in range(k): - G.add_edge('s', (i, 0), capacity=1) - nx.add_path(G, ((i, j) for j in range(p)), capacity=1) - G.add_edge((i, p - 1), 't', capacity=1) - R = shortest_augmenting_path(G, 's', 't', two_phase=True) - assert R.graph['flow_value'] == k - R = shortest_augmenting_path(G, 's', 't', two_phase=False) - assert R.graph['flow_value'] == k - - -class TestCutoff: - - def test_cutoff(self): - k = 5 - p = 1000 - G = nx.DiGraph() - for i in range(k): - G.add_edge('s', (i, 0), capacity=2) - nx.add_path(G, ((i, j) for j in range(p)), capacity=2) - G.add_edge((i, p - 1), 't', capacity=2) - R = shortest_augmenting_path(G, 's', 't', two_phase=True, cutoff=k) - assert k <= R.graph['flow_value'] <= (2 * k) - R = shortest_augmenting_path(G, 's', 't', two_phase=False, cutoff=k) - assert k <= R.graph['flow_value'] <= (2 * k) - R = edmonds_karp(G, 's', 't', cutoff=k) - assert k <= R.graph['flow_value'] <= (2 * k) - - def test_complete_graph_cutoff(self): - G = nx.complete_graph(5) - nx.set_edge_attributes(G, {(u, v): 1 for u, v in G.edges()}, - 'capacity') - for flow_func in [shortest_augmenting_path, edmonds_karp]: - for cutoff in [3, 2, 1]: - result = nx.maximum_flow_value(G, 0, 4, flow_func=flow_func, - cutoff=cutoff) - assert cutoff == result, "cutoff error in {0}".format(flow_func.__name__) diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/test_maxflow_large_graph.py b/extensions/fablabchemnitz/networkx/algorithms/flow/tests/test_maxflow_large_graph.py deleted file mode 100644 index 2dd82f20..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/test_maxflow_large_graph.py +++ /dev/null @@ -1,152 +0,0 @@ -# -*- coding: utf-8 -*- -"""Maximum flow algorithms test suite on large graphs. -""" - -__author__ = """Loïc Séguin-C. """ -# Copyright (C) 2010 Loïc Séguin-C. -# All rights reserved. -# BSD license. -import os - -import networkx as nx -from networkx.algorithms.flow import build_flow_dict, build_residual_network -from networkx.algorithms.flow import boykov_kolmogorov -from networkx.algorithms.flow import dinitz -from networkx.algorithms.flow import edmonds_karp -from networkx.algorithms.flow import preflow_push -from networkx.algorithms.flow import shortest_augmenting_path -from networkx.testing import almost_equal - -flow_funcs = [ - boykov_kolmogorov, - dinitz, - edmonds_karp, - preflow_push, - shortest_augmenting_path, -] - -msg = "Assertion failed in function: {0}" - - -def gen_pyramid(N): - # This graph admits a flow of value 1 for which every arc is at - # capacity (except the arcs incident to the sink which have - # infinite capacity). - G = nx.DiGraph() - - for i in range(N - 1): - cap = 1. / (i + 2) - for j in range(i + 1): - G.add_edge((i, j), (i + 1, j), - capacity=cap) - cap = 1. / (i + 1) - cap - G.add_edge((i, j), (i + 1, j + 1), - capacity=cap) - cap = 1. / (i + 2) - cap - - for j in range(N): - G.add_edge((N - 1, j), 't') - - return G - - -def read_graph(name): - dirname = os.path.dirname(__file__) - path = os.path.join(dirname, name + '.gpickle.bz2') - return nx.read_gpickle(path) - - -def validate_flows(G, s, t, soln_value, R, flow_func): - flow_value = R.graph['flow_value'] - flow_dict = build_flow_dict(G, R) - assert soln_value == flow_value, msg.format(flow_func.__name__) - assert set(G) == set(flow_dict), msg.format(flow_func.__name__) - for u in G: - assert set(G[u]) == set(flow_dict[u]), msg.format(flow_func.__name__) - excess = {u: 0 for u in flow_dict} - for u in flow_dict: - for v, flow in flow_dict[u].items(): - assert flow <= G[u][v].get('capacity', float('inf')), msg.format(flow_func.__name__) - assert flow >= 0, msg.format(flow_func.__name__) - excess[u] -= flow - excess[v] += flow - for u, exc in excess.items(): - if u == s: - assert exc == -soln_value, msg.format(flow_func.__name__) - elif u == t: - assert exc ==soln_value, msg.format(flow_func.__name__) - else: - assert exc == 0, msg.format(flow_func.__name__) - - -class TestMaxflowLargeGraph: - - def test_complete_graph(self): - N = 50 - G = nx.complete_graph(N) - nx.set_edge_attributes(G, 5, 'capacity') - R = build_residual_network(G, 'capacity') - kwargs = dict(residual=R) - - for flow_func in flow_funcs: - kwargs['flow_func'] = flow_func - flow_value = nx.maximum_flow_value(G, 1, 2, **kwargs) - assert flow_value == 5 * (N - 1), msg.format(flow_func.__name__) - - def test_pyramid(self): - N = 10 - # N = 100 # this gives a graph with 5051 nodes - G = gen_pyramid(N) - R = build_residual_network(G, 'capacity') - kwargs = dict(residual=R) - - for flow_func in flow_funcs: - kwargs['flow_func'] = flow_func - flow_value = nx.maximum_flow_value(G, (0, 0), 't', **kwargs) - assert almost_equal(flow_value, 1.), msg.format(flow_func.__name__) - - def test_gl1(self): - G = read_graph('gl1') - s = 1 - t = len(G) - R = build_residual_network(G, 'capacity') - kwargs = dict(residual=R) - - # do one flow_func to save time - flow_func = flow_funcs[0] - validate_flows(G, s, t, 156545, flow_func(G, s, t, **kwargs), - flow_func) -# for flow_func in flow_funcs: -# validate_flows(G, s, t, 156545, flow_func(G, s, t, **kwargs), -# flow_func) - - def test_gw1(self): - G = read_graph('gw1') - s = 1 - t = len(G) - R = build_residual_network(G, 'capacity') - kwargs = dict(residual=R) - - for flow_func in flow_funcs: - validate_flows(G, s, t, 1202018, flow_func(G, s, t, **kwargs), - flow_func) - - def test_wlm3(self): - G = read_graph('wlm3') - s = 1 - t = len(G) - R = build_residual_network(G, 'capacity') - kwargs = dict(residual=R) - - # do one flow_func to save time - flow_func = flow_funcs[0] - validate_flows(G, s, t, 11875108, flow_func(G, s, t, **kwargs), - flow_func) -# for flow_func in flow_funcs: -# validate_flows(G, s, t, 11875108, flow_func(G, s, t, **kwargs), -# flow_func) - - def test_preflow_push_global_relabel(self): - G = read_graph('gw1') - R = preflow_push(G, 1, len(G), global_relabel_freq=50) - assert R.graph['flow_value'] == 1202018 diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/test_mincost.py b/extensions/fablabchemnitz/networkx/algorithms/flow/tests/test_mincost.py deleted file mode 100644 index e4728100..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/test_mincost.py +++ /dev/null @@ -1,470 +0,0 @@ -# -*- coding: utf-8 -*- - -import networkx as nx -import pytest -import os - - -class TestMinCostFlow: - def test_simple_digraph(self): - G = nx.DiGraph() - G.add_node('a', demand=-5) - G.add_node('d', demand=5) - G.add_edge('a', 'b', weight=3, capacity=4) - G.add_edge('a', 'c', weight=6, capacity=10) - G.add_edge('b', 'd', weight=1, capacity=9) - G.add_edge('c', 'd', weight=2, capacity=5) - flowCost, H = nx.network_simplex(G) - soln = {'a': {'b': 4, 'c': 1}, - 'b': {'d': 4}, - 'c': {'d': 1}, - 'd': {}} - assert flowCost == 24 - assert nx.min_cost_flow_cost(G) == 24 - assert H == soln - assert nx.min_cost_flow(G) == soln - assert nx.cost_of_flow(G, H) == 24 - - flowCost, H = nx.capacity_scaling(G) - assert flowCost == 24 - assert nx.cost_of_flow(G, H) == 24 - assert H == soln - - def test_negcycle_infcap(self): - G = nx.DiGraph() - G.add_node('s', demand=-5) - G.add_node('t', demand=5) - G.add_edge('s', 'a', weight=1, capacity=3) - G.add_edge('a', 'b', weight=3) - G.add_edge('c', 'a', weight=-6) - G.add_edge('b', 'd', weight=1) - G.add_edge('d', 'c', weight=-2) - G.add_edge('d', 't', weight=1, capacity=3) - pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G) - pytest.raises(nx.NetworkXUnbounded, nx.capacity_scaling, G) - - def test_sum_demands_not_zero(self): - G = nx.DiGraph() - G.add_node('s', demand=-5) - G.add_node('t', demand=4) - G.add_edge('s', 'a', weight=1, capacity=3) - G.add_edge('a', 'b', weight=3) - G.add_edge('a', 'c', weight=-6) - G.add_edge('b', 'd', weight=1) - G.add_edge('c', 'd', weight=-2) - G.add_edge('d', 't', weight=1, capacity=3) - pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G) - pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G) - - def test_no_flow_satisfying_demands(self): - G = nx.DiGraph() - G.add_node('s', demand=-5) - G.add_node('t', demand=5) - G.add_edge('s', 'a', weight=1, capacity=3) - G.add_edge('a', 'b', weight=3) - G.add_edge('a', 'c', weight=-6) - G.add_edge('b', 'd', weight=1) - G.add_edge('c', 'd', weight=-2) - G.add_edge('d', 't', weight=1, capacity=3) - pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G) - pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G) - - def test_transshipment(self): - G = nx.DiGraph() - G.add_node('a', demand=1) - G.add_node('b', demand=-2) - G.add_node('c', demand=-2) - G.add_node('d', demand=3) - G.add_node('e', demand=-4) - G.add_node('f', demand=-4) - G.add_node('g', demand=3) - G.add_node('h', demand=2) - G.add_node('r', demand=3) - G.add_edge('a', 'c', weight=3) - G.add_edge('r', 'a', weight=2) - G.add_edge('b', 'a', weight=9) - G.add_edge('r', 'c', weight=0) - G.add_edge('b', 'r', weight=-6) - G.add_edge('c', 'd', weight=5) - G.add_edge('e', 'r', weight=4) - G.add_edge('e', 'f', weight=3) - G.add_edge('h', 'b', weight=4) - G.add_edge('f', 'd', weight=7) - G.add_edge('f', 'h', weight=12) - G.add_edge('g', 'd', weight=12) - G.add_edge('f', 'g', weight=-1) - G.add_edge('h', 'g', weight=-10) - flowCost, H = nx.network_simplex(G) - soln = {'a': {'c': 0}, - 'b': {'a': 0, 'r': 2}, - 'c': {'d': 3}, - 'd': {}, - 'e': {'r': 3, 'f': 1}, - 'f': {'d': 0, 'g': 3, 'h': 2}, - 'g': {'d': 0}, - 'h': {'b': 0, 'g': 0}, - 'r': {'a': 1, 'c': 1}} - assert flowCost == 41 - assert nx.min_cost_flow_cost(G) == 41 - assert H == soln - assert nx.min_cost_flow(G) == soln - assert nx.cost_of_flow(G, H) == 41 - - flowCost, H = nx.capacity_scaling(G) - assert flowCost == 41 - assert nx.cost_of_flow(G, H) == 41 - assert H == soln - - def test_max_flow_min_cost(self): - G = nx.DiGraph() - G.add_edge('s', 'a', bandwidth=6) - G.add_edge('s', 'c', bandwidth=10, cost=10) - G.add_edge('a', 'b', cost=6) - G.add_edge('b', 'd', bandwidth=8, cost=7) - G.add_edge('c', 'd', cost=10) - G.add_edge('d', 't', bandwidth=5, cost=5) - soln = {'s': {'a': 5, 'c': 0}, - 'a': {'b': 5}, - 'b': {'d': 5}, - 'c': {'d': 0}, - 'd': {'t': 5}, - 't': {}} - flow = nx.max_flow_min_cost(G, 's', 't', capacity='bandwidth', - weight='cost') - assert flow == soln - assert nx.cost_of_flow(G, flow, weight='cost') == 90 - - G.add_edge('t', 's', cost=-100) - flowCost, flow = nx.capacity_scaling(G, capacity='bandwidth', - weight='cost') - G.remove_edge('t', 's') - assert flowCost == -410 - assert flow['t']['s'] == 5 - del flow['t']['s'] - assert flow == soln - assert nx.cost_of_flow(G, flow, weight='cost') == 90 - - def test_digraph1(self): - # From Bradley, S. P., Hax, A. C. and Magnanti, T. L. Applied - # Mathematical Programming. Addison-Wesley, 1977. - G = nx.DiGraph() - G.add_node(1, demand=-20) - G.add_node(4, demand=5) - G.add_node(5, demand=15) - G.add_edges_from([(1, 2, {'capacity': 15, 'weight': 4}), - (1, 3, {'capacity': 8, 'weight': 4}), - (2, 3, {'weight': 2}), - (2, 4, {'capacity': 4, 'weight': 2}), - (2, 5, {'capacity': 10, 'weight': 6}), - (3, 4, {'capacity': 15, 'weight': 1}), - (3, 5, {'capacity': 5, 'weight': 3}), - (4, 5, {'weight': 2}), - (5, 3, {'capacity': 4, 'weight': 1})]) - flowCost, H = nx.network_simplex(G) - soln = {1: {2: 12, 3: 8}, - 2: {3: 8, 4: 4, 5: 0}, - 3: {4: 11, 5: 5}, - 4: {5: 10}, - 5: {3: 0}} - assert flowCost == 150 - assert nx.min_cost_flow_cost(G) == 150 - assert H == soln - assert nx.min_cost_flow(G) == soln - assert nx.cost_of_flow(G, H) == 150 - - flowCost, H = nx.capacity_scaling(G) - assert flowCost == 150 - assert H == soln - assert nx.cost_of_flow(G, H) == 150 - - def test_digraph2(self): - # Example from ticket #430 from mfrasca. Original source: - # http://www.cs.princeton.edu/courses/archive/spr03/cs226/lectures/mincost.4up.pdf, slide 11. - G = nx.DiGraph() - G.add_edge('s', 1, capacity=12) - G.add_edge('s', 2, capacity=6) - G.add_edge('s', 3, capacity=14) - G.add_edge(1, 2, capacity=11, weight=4) - G.add_edge(2, 3, capacity=9, weight=6) - G.add_edge(1, 4, capacity=5, weight=5) - G.add_edge(1, 5, capacity=2, weight=12) - G.add_edge(2, 5, capacity=4, weight=4) - G.add_edge(2, 6, capacity=2, weight=6) - G.add_edge(3, 6, capacity=31, weight=3) - G.add_edge(4, 5, capacity=18, weight=4) - G.add_edge(5, 6, capacity=9, weight=5) - G.add_edge(4, 't', capacity=3) - G.add_edge(5, 't', capacity=7) - G.add_edge(6, 't', capacity=22) - flow = nx.max_flow_min_cost(G, 's', 't') - soln = {1: {2: 6, 4: 5, 5: 1}, - 2: {3: 6, 5: 4, 6: 2}, - 3: {6: 20}, - 4: {5: 2, 't': 3}, - 5: {6: 0, 't': 7}, - 6: {'t': 22}, - 's': {1: 12, 2: 6, 3: 14}, - 't': {}} - assert flow == soln - - G.add_edge('t', 's', weight=-100) - flowCost, flow = nx.capacity_scaling(G) - G.remove_edge('t', 's') - assert flow['t']['s'] == 32 - assert flowCost == -3007 - del flow['t']['s'] - assert flow == soln - assert nx.cost_of_flow(G, flow) == 193 - - def test_digraph3(self): - """Combinatorial Optimization: Algorithms and Complexity, - Papadimitriou Steiglitz at page 140 has an example, 7.1, but that - admits multiple solutions, so I alter it a bit. From ticket #430 - by mfrasca.""" - - G = nx.DiGraph() - G.add_edge('s', 'a') - G['s']['a'].update({0: 2, 1: 4}) - G.add_edge('s', 'b') - G['s']['b'].update({0: 2, 1: 1}) - G.add_edge('a', 'b') - G['a']['b'].update({0: 5, 1: 2}) - G.add_edge('a', 't') - G['a']['t'].update({0: 1, 1: 5}) - G.add_edge('b', 'a') - G['b']['a'].update({0: 1, 1: 3}) - G.add_edge('b', 't') - G['b']['t'].update({0: 3, 1: 2}) - - "PS.ex.7.1: testing main function" - sol = nx.max_flow_min_cost(G, 's', 't', capacity=0, weight=1) - flow = sum(v for v in sol['s'].values()) - assert 4 == flow - assert 23 == nx.cost_of_flow(G, sol, weight=1) - assert sol['s'] == {'a': 2, 'b': 2} - assert sol['a'] == {'b': 1, 't': 1} - assert sol['b'] == {'a': 0, 't': 3} - assert sol['t'] == {} - - G.add_edge('t', 's') - G['t']['s'].update({1: -100}) - flowCost, sol = nx.capacity_scaling(G, capacity=0, weight=1) - G.remove_edge('t', 's') - flow = sum(v for v in sol['s'].values()) - assert 4 == flow - assert sol['t']['s'] == 4 - assert flowCost == -377 - del sol['t']['s'] - assert sol['s'] == {'a': 2, 'b': 2} - assert sol['a'] == {'b': 1, 't': 1} - assert sol['b'] == {'a': 0, 't': 3} - assert sol['t'] == {} - assert nx.cost_of_flow(G, sol, weight=1) == 23 - - def test_zero_capacity_edges(self): - """Address issue raised in ticket #617 by arv.""" - G = nx.DiGraph() - G.add_edges_from([(1, 2, {'capacity': 1, 'weight': 1}), - (1, 5, {'capacity': 1, 'weight': 1}), - (2, 3, {'capacity': 0, 'weight': 1}), - (2, 5, {'capacity': 1, 'weight': 1}), - (5, 3, {'capacity': 2, 'weight': 1}), - (5, 4, {'capacity': 0, 'weight': 1}), - (3, 4, {'capacity': 2, 'weight': 1})]) - G.nodes[1]['demand'] = -1 - G.nodes[2]['demand'] = -1 - G.nodes[4]['demand'] = 2 - - flowCost, H = nx.network_simplex(G) - soln = {1: {2: 0, 5: 1}, - 2: {3: 0, 5: 1}, - 3: {4: 2}, - 4: {}, - 5: {3: 2, 4: 0}} - assert flowCost == 6 - assert nx.min_cost_flow_cost(G) == 6 - assert H == soln - assert nx.min_cost_flow(G) == soln - assert nx.cost_of_flow(G, H) == 6 - - flowCost, H = nx.capacity_scaling(G) - assert flowCost == 6 - assert H == soln - assert nx.cost_of_flow(G, H) == 6 - - def test_digon(self): - """Check if digons are handled properly. Taken from ticket - #618 by arv.""" - nodes = [(1, {}), - (2, {'demand': -4}), - (3, {'demand': 4}), - ] - edges = [(1, 2, {'capacity': 3, 'weight': 600000}), - (2, 1, {'capacity': 2, 'weight': 0}), - (2, 3, {'capacity': 5, 'weight': 714285}), - (3, 2, {'capacity': 2, 'weight': 0}), - ] - G = nx.DiGraph(edges) - G.add_nodes_from(nodes) - flowCost, H = nx.network_simplex(G) - soln = {1: {2: 0}, - 2: {1: 0, 3: 4}, - 3: {2: 0}} - assert flowCost == 2857140 - assert nx.min_cost_flow_cost(G) == 2857140 - assert H == soln - assert nx.min_cost_flow(G) == soln - assert nx.cost_of_flow(G, H) == 2857140 - - flowCost, H = nx.capacity_scaling(G) - assert flowCost == 2857140 - assert H == soln - assert nx.cost_of_flow(G, H) == 2857140 - - def test_deadend(self): - """Check if one-node cycles are handled properly. Taken from ticket - #2906 from @sshraven.""" - G = nx.DiGraph() - - G.add_nodes_from(range(5), demand=0) - G.nodes[4]['demand'] = -13 - G.nodes[3]['demand'] = 13 - - G.add_edges_from([(0,2), (0, 3), (2, 1)], capacity=20, weight=0.1) - pytest.raises(nx.NetworkXUnfeasible, nx.min_cost_flow, G) - - def test_infinite_capacity_neg_digon(self): - """An infinite capacity negative cost digon results in an unbounded - instance.""" - nodes = [(1, {}), - (2, {'demand': -4}), - (3, {'demand': 4}), - ] - edges = [(1, 2, {'weight': -600}), - (2, 1, {'weight': 0}), - (2, 3, {'capacity': 5, 'weight': 714285}), - (3, 2, {'capacity': 2, 'weight': 0}), - ] - G = nx.DiGraph(edges) - G.add_nodes_from(nodes) - pytest.raises(nx.NetworkXUnbounded, nx.network_simplex, G) - pytest.raises(nx.NetworkXUnbounded, nx.capacity_scaling, G) - - def test_finite_capacity_neg_digon(self): - """The digon should receive the maximum amount of flow it can handle. - Taken from ticket #749 by @chuongdo.""" - G = nx.DiGraph() - G.add_edge('a', 'b', capacity=1, weight=-1) - G.add_edge('b', 'a', capacity=1, weight=-1) - min_cost = -2 - assert nx.min_cost_flow_cost(G) == min_cost - - flowCost, H = nx.capacity_scaling(G) - assert flowCost == -2 - assert H == {'a': {'b': 1}, 'b': {'a': 1}} - assert nx.cost_of_flow(G, H) == -2 - - def test_multidigraph(self): - """Multidigraphs are acceptable.""" - G = nx.MultiDiGraph() - G.add_weighted_edges_from([(1, 2, 1), (2, 3, 2)], weight='capacity') - flowCost, H = nx.network_simplex(G) - assert flowCost == 0 - assert H == {1: {2: {0: 0}}, 2: {3: {0: 0}}, 3: {}} - - flowCost, H = nx.capacity_scaling(G) - assert flowCost == 0 - assert H == {1: {2: {0: 0}}, 2: {3: {0: 0}}, 3: {}} - - def test_negative_selfloops(self): - """Negative selfloops should cause an exception if uncapacitated and - always be saturated otherwise. - """ - G = nx.DiGraph() - G.add_edge(1, 1, weight=-1) - pytest.raises(nx.NetworkXUnbounded, nx.network_simplex, G) - pytest.raises(nx.NetworkXUnbounded, nx.capacity_scaling, G) - G[1][1]['capacity'] = 2 - flowCost, H = nx.network_simplex(G) - assert flowCost == -2 - assert H == {1: {1: 2}} - flowCost, H = nx.capacity_scaling(G) - assert flowCost == -2 - assert H == {1: {1: 2}} - - G = nx.MultiDiGraph() - G.add_edge(1, 1, 'x', weight=-1) - G.add_edge(1, 1, 'y', weight=1) - pytest.raises(nx.NetworkXUnbounded, nx.network_simplex, G) - pytest.raises(nx.NetworkXUnbounded, nx.capacity_scaling, G) - G[1][1]['x']['capacity'] = 2 - flowCost, H = nx.network_simplex(G) - assert flowCost == -2 - assert H == {1: {1: {'x': 2, 'y': 0}}} - flowCost, H = nx.capacity_scaling(G) - assert flowCost == -2 - assert H == {1: {1: {'x': 2, 'y': 0}}} - - def test_bone_shaped(self): - # From #1283 - G = nx.DiGraph() - G.add_node(0, demand=-4) - G.add_node(1, demand=2) - G.add_node(2, demand=2) - G.add_node(3, demand=4) - G.add_node(4, demand=-2) - G.add_node(5, demand=-2) - G.add_edge(0, 1, capacity=4) - G.add_edge(0, 2, capacity=4) - G.add_edge(4, 3, capacity=4) - G.add_edge(5, 3, capacity=4) - G.add_edge(0, 3, capacity=0) - flowCost, H = nx.network_simplex(G) - assert flowCost == 0 - assert ( - H == {0: {1: 2, 2: 2, 3: 0}, 1: {}, 2: {}, 3: {}, 4: {3: 2}, 5: {3: 2}}) - flowCost, H = nx.capacity_scaling(G) - assert flowCost == 0 - assert ( - H == {0: {1: 2, 2: 2, 3: 0}, 1: {}, 2: {}, 3: {}, 4: {3: 2}, 5: {3: 2}}) - - def test_exceptions(self): - G = nx.Graph() - pytest.raises(nx.NetworkXNotImplemented, nx.network_simplex, G) - pytest.raises(nx.NetworkXNotImplemented, nx.capacity_scaling, G) - G = nx.MultiGraph() - pytest.raises(nx.NetworkXNotImplemented, nx.network_simplex, G) - pytest.raises(nx.NetworkXNotImplemented, nx.capacity_scaling, G) - G = nx.DiGraph() - pytest.raises(nx.NetworkXError, nx.network_simplex, G) - pytest.raises(nx.NetworkXError, nx.capacity_scaling, G) - G.add_node(0, demand=float('inf')) - pytest.raises(nx.NetworkXError, nx.network_simplex, G) - pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G) - G.nodes[0]['demand'] = 0 - G.add_node(1, demand=0) - G.add_edge(0, 1, weight=-float('inf')) - pytest.raises(nx.NetworkXError, nx.network_simplex, G) - pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G) - G[0][1]['weight'] = 0 - G.add_edge(0, 0, weight=float('inf')) - pytest.raises(nx.NetworkXError, nx.network_simplex, G) - #pytest.raises(nx.NetworkXError, nx.capacity_scaling, G) - G[0][0]['weight'] = 0 - G[0][1]['capacity'] = -1 - pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G) - #pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G) - G[0][1]['capacity'] = 0 - G[0][0]['capacity'] = -1 - pytest.raises(nx.NetworkXUnfeasible, nx.network_simplex, G) - #pytest.raises(nx.NetworkXUnfeasible, nx.capacity_scaling, G) - - def test_large(self): - fname = os.path.join(os.path.dirname(__file__), 'netgen-2.gpickle.bz2') - G = nx.read_gpickle(fname) - flowCost, flowDict = nx.network_simplex(G) - assert 6749969302 == flowCost - assert 6749969302 == nx.cost_of_flow(G, flowDict) - flowCost, flowDict = nx.capacity_scaling(G) - assert 6749969302 == flowCost - assert 6749969302 == nx.cost_of_flow(G, flowDict) diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/wlm3.gpickle.bz2 b/extensions/fablabchemnitz/networkx/algorithms/flow/tests/wlm3.gpickle.bz2 deleted file mode 100644 index 8ce935a8..00000000 Binary files a/extensions/fablabchemnitz/networkx/algorithms/flow/tests/wlm3.gpickle.bz2 and /dev/null differ diff --git a/extensions/fablabchemnitz/networkx/algorithms/flow/utils.py b/extensions/fablabchemnitz/networkx/algorithms/flow/utils.py deleted file mode 100644 index aea178cc..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/flow/utils.py +++ /dev/null @@ -1,170 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Utility classes and functions for network flow algorithms. -""" - -__author__ = """ysitu """ -# Copyright (C) 2014 ysitu -# All rights reserved. -# BSD license. - -from collections import deque -import networkx as nx - -__all__ = ['CurrentEdge', 'Level', 'GlobalRelabelThreshold', - 'build_residual_network', 'detect_unboundedness', 'build_flow_dict'] - - -class CurrentEdge(object): - """Mechanism for iterating over out-edges incident to a node in a circular - manner. StopIteration exception is raised when wraparound occurs. - """ - __slots__ = ('_edges', '_it', '_curr') - - def __init__(self, edges): - self._edges = edges - if self._edges: - self._rewind() - - def get(self): - return self._curr - - def move_to_next(self): - try: - self._curr = next(self._it) - except StopIteration: - self._rewind() - raise - - def _rewind(self): - self._it = iter(self._edges.items()) - self._curr = next(self._it) - - -class Level(object): - """Active and inactive nodes in a level. - """ - __slots__ = ('active', 'inactive') - - def __init__(self): - self.active = set() - self.inactive = set() - - -class GlobalRelabelThreshold(object): - """Measurement of work before the global relabeling heuristic should be - applied. - """ - - def __init__(self, n, m, freq): - self._threshold = (n + m) / freq if freq else float('inf') - self._work = 0 - - def add_work(self, work): - self._work += work - - def is_reached(self): - return self._work >= self._threshold - - def clear_work(self): - self._work = 0 - - -def build_residual_network(G, capacity): - """Build a residual network and initialize a zero flow. - - The residual network :samp:`R` from an input graph :samp:`G` has the - same nodes as :samp:`G`. :samp:`R` is a DiGraph that contains a pair - of edges :samp:`(u, v)` and :samp:`(v, u)` iff :samp:`(u, v)` is not a - self-loop, and at least one of :samp:`(u, v)` and :samp:`(v, u)` exists - in :samp:`G`. - - For each edge :samp:`(u, v)` in :samp:`R`, :samp:`R[u][v]['capacity']` - is equal to the capacity of :samp:`(u, v)` in :samp:`G` if it exists - in :samp:`G` or zero otherwise. If the capacity is infinite, - :samp:`R[u][v]['capacity']` will have a high arbitrary finite value - that does not affect the solution of the problem. This value is stored in - :samp:`R.graph['inf']`. For each edge :samp:`(u, v)` in :samp:`R`, - :samp:`R[u][v]['flow']` represents the flow function of :samp:`(u, v)` and - satisfies :samp:`R[u][v]['flow'] == -R[v][u]['flow']`. - - The flow value, defined as the total flow into :samp:`t`, the sink, is - stored in :samp:`R.graph['flow_value']`. If :samp:`cutoff` is not - specified, reachability to :samp:`t` using only edges :samp:`(u, v)` such - that :samp:`R[u][v]['flow'] < R[u][v]['capacity']` induces a minimum - :samp:`s`-:samp:`t` cut. - - """ - if G.is_multigraph(): - raise nx.NetworkXError( - 'MultiGraph and MultiDiGraph not supported (yet).') - - R = nx.DiGraph() - R.add_nodes_from(G) - - inf = float('inf') - # Extract edges with positive capacities. Self loops excluded. - edge_list = [(u, v, attr) for u, v, attr in G.edges(data=True) - if u != v and attr.get(capacity, inf) > 0] - # Simulate infinity with three times the sum of the finite edge capacities - # or any positive value if the sum is zero. This allows the - # infinite-capacity edges to be distinguished for unboundedness detection - # and directly participate in residual capacity calculation. If the maximum - # flow is finite, these edges cannot appear in the minimum cut and thus - # guarantee correctness. Since the residual capacity of an - # infinite-capacity edge is always at least 2/3 of inf, while that of an - # finite-capacity edge is at most 1/3 of inf, if an operation moves more - # than 1/3 of inf units of flow to t, there must be an infinite-capacity - # s-t path in G. - inf = 3 * sum(attr[capacity] for u, v, attr in edge_list - if capacity in attr and attr[capacity] != inf) or 1 - if G.is_directed(): - for u, v, attr in edge_list: - r = min(attr.get(capacity, inf), inf) - if not R.has_edge(u, v): - # Both (u, v) and (v, u) must be present in the residual - # network. - R.add_edge(u, v, capacity=r) - R.add_edge(v, u, capacity=0) - else: - # The edge (u, v) was added when (v, u) was visited. - R[u][v]['capacity'] = r - else: - for u, v, attr in edge_list: - # Add a pair of edges with equal residual capacities. - r = min(attr.get(capacity, inf), inf) - R.add_edge(u, v, capacity=r) - R.add_edge(v, u, capacity=r) - - # Record the value simulating infinity. - R.graph['inf'] = inf - - return R - - -def detect_unboundedness(R, s, t): - """Detect an infinite-capacity s-t path in R. - """ - q = deque([s]) - seen = set([s]) - inf = R.graph['inf'] - while q: - u = q.popleft() - for v, attr in R[u].items(): - if attr['capacity'] == inf and v not in seen: - if v == t: - raise nx.NetworkXUnbounded( - 'Infinite capacity path, flow unbounded above.') - seen.add(v) - q.append(v) - - -def build_flow_dict(G, R): - """Build a flow dictionary from a residual network. - """ - flow_dict = {} - for u in G: - flow_dict[u] = {v: 0 for v in G[u]} - flow_dict[u].update((v, attr['flow']) for v, attr in R[u].items() - if attr['flow'] > 0) - return flow_dict diff --git a/extensions/fablabchemnitz/networkx/algorithms/graphical.py b/extensions/fablabchemnitz/networkx/algorithms/graphical.py deleted file mode 100644 index ebcfbda1..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/graphical.py +++ /dev/null @@ -1,406 +0,0 @@ -# -*- coding: utf-8 -*- -"""Test sequences for graphiness. -""" -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -import heapq -import networkx as nx -__author__ = "\n".join(['Aric Hagberg (hagberg@lanl.gov)', - 'Pieter Swart (swart@lanl.gov)', - 'Dan Schult (dschult@colgate.edu)' - 'Joel Miller (joel.c.miller.research@gmail.com)' - 'Ben Edwards' - 'Brian Cloteaux ']) - -__all__ = ['is_graphical', - 'is_multigraphical', - 'is_pseudographical', - 'is_digraphical', - 'is_valid_degree_sequence_erdos_gallai', - 'is_valid_degree_sequence_havel_hakimi', - ] - - -def is_graphical(sequence, method='eg'): - """Returns True if sequence is a valid degree sequence. - - A degree sequence is valid if some graph can realize it. - - Parameters - ---------- - sequence : list or iterable container - A sequence of integer node degrees - - method : "eg" | "hh" (default: 'eg') - The method used to validate the degree sequence. - "eg" corresponds to the Erdős-Gallai algorithm, and - "hh" to the Havel-Hakimi algorithm. - - Returns - ------- - valid : bool - True if the sequence is a valid degree sequence and False if not. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> sequence = (d for n, d in G.degree()) - >>> nx.is_graphical(sequence) - True - - References - ---------- - Erdős-Gallai - [EG1960]_, [choudum1986]_ - - Havel-Hakimi - [havel1955]_, [hakimi1962]_, [CL1996]_ - """ - if method == 'eg': - valid = is_valid_degree_sequence_erdos_gallai(list(sequence)) - elif method == 'hh': - valid = is_valid_degree_sequence_havel_hakimi(list(sequence)) - else: - msg = "`method` must be 'eg' or 'hh'" - raise nx.NetworkXException(msg) - return valid - - -def _basic_graphical_tests(deg_sequence): - # Sort and perform some simple tests on the sequence - deg_sequence = nx.utils.make_list_of_ints(deg_sequence) - p = len(deg_sequence) - num_degs = [0] * p - dmax, dmin, dsum, n = 0, p, 0, 0 - for d in deg_sequence: - # Reject if degree is negative or larger than the sequence length - if d < 0 or d >= p: - raise nx.NetworkXUnfeasible - # Process only the non-zero integers - elif d > 0: - dmax, dmin, dsum, n = max(dmax, d), min(dmin, d), dsum + d, n + 1 - num_degs[d] += 1 - # Reject sequence if it has odd sum or is oversaturated - if dsum % 2 or dsum > n * (n - 1): - raise nx.NetworkXUnfeasible - return dmax, dmin, dsum, n, num_degs - - -def is_valid_degree_sequence_havel_hakimi(deg_sequence): - r"""Returns True if deg_sequence can be realized by a simple graph. - - The validation proceeds using the Havel-Hakimi theorem. - Worst-case run time is $O(s)$ where $s$ is the sum of the sequence. - - Parameters - ---------- - deg_sequence : list - A list of integers where each element specifies the degree of a node - in a graph. - - Returns - ------- - valid : bool - True if deg_sequence is graphical and False if not. - - Notes - ----- - The ZZ condition says that for the sequence d if - - .. math:: - |d| >= \frac{(\max(d) + \min(d) + 1)^2}{4*\min(d)} - - then d is graphical. This was shown in Theorem 6 in [1]_. - - References - ---------- - .. [1] I.E. Zverovich and V.E. Zverovich. "Contributions to the theory - of graphic sequences", Discrete Mathematics, 105, pp. 292-303 (1992). - - [havel1955]_, [hakimi1962]_, [CL1996]_ - - """ - try: - dmax, dmin, dsum, n, num_degs = _basic_graphical_tests(deg_sequence) - except nx.NetworkXUnfeasible: - return False - # Accept if sequence has no non-zero degrees or passes the ZZ condition - if n == 0 or 4 * dmin * n >= (dmax + dmin + 1) * (dmax + dmin + 1): - return True - - modstubs = [0] * (dmax + 1) - # Successively reduce degree sequence by removing the maximum degree - while n > 0: - # Retrieve the maximum degree in the sequence - while num_degs[dmax] == 0: - dmax -= 1 - # If there are not enough stubs to connect to, then the sequence is - # not graphical - if dmax > n - 1: - return False - - # Remove largest stub in list - num_degs[dmax], n = num_degs[dmax] - 1, n - 1 - # Reduce the next dmax largest stubs - mslen = 0 - k = dmax - for i in range(dmax): - while num_degs[k] == 0: - k -= 1 - num_degs[k], n = num_degs[k] - 1, n - 1 - if k > 1: - modstubs[mslen] = k - 1 - mslen += 1 - # Add back to the list any non-zero stubs that were removed - for i in range(mslen): - stub = modstubs[i] - num_degs[stub], n = num_degs[stub] + 1, n + 1 - return True - - -def is_valid_degree_sequence_erdos_gallai(deg_sequence): - r"""Returns True if deg_sequence can be realized by a simple graph. - - The validation is done using the Erdős-Gallai theorem [EG1960]_. - - Parameters - ---------- - deg_sequence : list - A list of integers - - Returns - ------- - valid : bool - True if deg_sequence is graphical and False if not. - - Notes - ----- - - This implementation uses an equivalent form of the Erdős-Gallai criterion. - Worst-case run time is $O(n)$ where $n$ is the length of the sequence. - - Specifically, a sequence d is graphical if and only if the - sum of the sequence is even and for all strong indices k in the sequence, - - .. math:: - - \sum_{i=1}^{k} d_i \leq k(k-1) + \sum_{j=k+1}^{n} \min(d_i,k) - = k(n-1) - ( k \sum_{j=0}^{k-1} n_j - \sum_{j=0}^{k-1} j n_j ) - - A strong index k is any index where d_k >= k and the value n_j is the - number of occurrences of j in d. The maximal strong index is called the - Durfee index. - - This particular rearrangement comes from the proof of Theorem 3 in [2]_. - - The ZZ condition says that for the sequence d if - - .. math:: - |d| >= \frac{(\max(d) + \min(d) + 1)^2}{4*\min(d)} - - then d is graphical. This was shown in Theorem 6 in [2]_. - - References - ---------- - .. [1] A. Tripathi and S. Vijay. "A note on a theorem of Erdős & Gallai", - Discrete Mathematics, 265, pp. 417-420 (2003). - .. [2] I.E. Zverovich and V.E. Zverovich. "Contributions to the theory - of graphic sequences", Discrete Mathematics, 105, pp. 292-303 (1992). - - [EG1960]_, [choudum1986]_ - """ - try: - dmax, dmin, dsum, n, num_degs = _basic_graphical_tests(deg_sequence) - except nx.NetworkXUnfeasible: - return False - # Accept if sequence has no non-zero degrees or passes the ZZ condition - if n == 0 or 4 * dmin * n >= (dmax + dmin + 1) * (dmax + dmin + 1): - return True - - # Perform the EG checks using the reformulation of Zverovich and Zverovich - k, sum_deg, sum_nj, sum_jnj = 0, 0, 0, 0 - for dk in range(dmax, dmin - 1, -1): - if dk < k + 1: # Check if already past Durfee index - return True - if num_degs[dk] > 0: - run_size = num_degs[dk] # Process a run of identical-valued degrees - if dk < k + run_size: # Check if end of run is past Durfee index - run_size = dk - k # Adjust back to Durfee index - sum_deg += run_size * dk - for v in range(run_size): - sum_nj += num_degs[k + v] - sum_jnj += (k + v) * num_degs[k + v] - k += run_size - if sum_deg > k * (n - 1) - k * sum_nj + sum_jnj: - return False - return True - - -def is_multigraphical(sequence): - """Returns True if some multigraph can realize the sequence. - - Parameters - ---------- - sequence : list - A list of integers - - Returns - ------- - valid : bool - True if deg_sequence is a multigraphic degree sequence and False if not. - - Notes - ----- - The worst-case run time is $O(n)$ where $n$ is the length of the sequence. - - References - ---------- - .. [1] S. L. Hakimi. "On the realizability of a set of integers as - degrees of the vertices of a linear graph", J. SIAM, 10, pp. 496-506 - (1962). - """ - try: - deg_sequence = nx.utils.make_list_of_ints(sequence) - except nx.NetworkXError: - return False - dsum, dmax = 0, 0 - for d in deg_sequence: - if d < 0: - return False - dsum, dmax = dsum + d, max(dmax, d) - if dsum % 2 or dsum < 2 * dmax: - return False - return True - - -def is_pseudographical(sequence): - """Returns True if some pseudograph can realize the sequence. - - Every nonnegative integer sequence with an even sum is pseudographical - (see [1]_). - - Parameters - ---------- - sequence : list or iterable container - A sequence of integer node degrees - - Returns - ------- - valid : bool - True if the sequence is a pseudographic degree sequence and False if not. - - Notes - ----- - The worst-case run time is $O(n)$ where n is the length of the sequence. - - References - ---------- - .. [1] F. Boesch and F. Harary. "Line removal algorithms for graphs - and their degree lists", IEEE Trans. Circuits and Systems, CAS-23(12), - pp. 778-782 (1976). - """ - try: - deg_sequence = nx.utils.make_list_of_ints(sequence) - except nx.NetworkXError: - return False - return sum(deg_sequence) % 2 == 0 and min(deg_sequence) >= 0 - - -def is_digraphical(in_sequence, out_sequence): - r"""Returns True if some directed graph can realize the in- and out-degree - sequences. - - Parameters - ---------- - in_sequence : list or iterable container - A sequence of integer node in-degrees - - out_sequence : list or iterable container - A sequence of integer node out-degrees - - Returns - ------- - valid : bool - True if in and out-sequences are digraphic False if not. - - Notes - ----- - This algorithm is from Kleitman and Wang [1]_. - The worst case runtime is $O(s \times \log n)$ where $s$ and $n$ are the - sum and length of the sequences respectively. - - References - ---------- - .. [1] D.J. Kleitman and D.L. Wang - Algorithms for Constructing Graphs and Digraphs with Given Valences - and Factors, Discrete Mathematics, 6(1), pp. 79-88 (1973) - """ - try: - in_deg_sequence = nx.utils.make_list_of_ints(in_sequence) - out_deg_sequence = nx.utils.make_list_of_ints(out_sequence) - except nx.NetworkXError: - return False - # Process the sequences and form two heaps to store degree pairs with - # either zero or non-zero out degrees - sumin, sumout, nin, nout = 0, 0, len(in_deg_sequence), len(out_deg_sequence) - maxn = max(nin, nout) - maxin = 0 - if maxn == 0: - return True - stubheap, zeroheap = [], [] - for n in range(maxn): - in_deg, out_deg = 0, 0 - if n < nout: - out_deg = out_deg_sequence[n] - if n < nin: - in_deg = in_deg_sequence[n] - if in_deg < 0 or out_deg < 0: - return False - sumin, sumout, maxin = sumin + in_deg, sumout + out_deg, max(maxin, in_deg) - if in_deg > 0: - stubheap.append((-1 * out_deg, -1 * in_deg)) - elif out_deg > 0: - zeroheap.append(-1 * out_deg) - if sumin != sumout: - return False - heapq.heapify(stubheap) - heapq.heapify(zeroheap) - - modstubs = [(0, 0)] * (maxin + 1) - # Successively reduce degree sequence by removing the maximum out degree - while stubheap: - # Take the first value in the sequence with non-zero in degree - (freeout, freein) = heapq.heappop(stubheap) - freein *= -1 - if freein > len(stubheap) + len(zeroheap): - return False - - # Attach out stubs to the nodes with the most in stubs - mslen = 0 - for i in range(freein): - if zeroheap and (not stubheap or stubheap[0][0] > zeroheap[0]): - stubout = heapq.heappop(zeroheap) - stubin = 0 - else: - (stubout, stubin) = heapq.heappop(stubheap) - if stubout == 0: - return False - # Check if target is now totally connected - if stubout + 1 < 0 or stubin < 0: - modstubs[mslen] = (stubout + 1, stubin) - mslen += 1 - - # Add back the nodes to the heap that still have available stubs - for i in range(mslen): - stub = modstubs[i] - if stub[1] < 0: - heapq.heappush(stubheap, stub) - else: - heapq.heappush(zeroheap, stub[0]) - if freeout < 0: - heapq.heappush(zeroheap, freeout) - return True diff --git a/extensions/fablabchemnitz/networkx/algorithms/hierarchy.py b/extensions/fablabchemnitz/networkx/algorithms/hierarchy.py deleted file mode 100644 index 45660b7a..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/hierarchy.py +++ /dev/null @@ -1,54 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Flow Hierarchy. -""" -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -import networkx as nx -__authors__ = "\n".join(['Ben Edwards (bedwards@cs.unm.edu)']) -__all__ = ['flow_hierarchy'] - - -def flow_hierarchy(G, weight=None): - """Returns the flow hierarchy of a directed network. - - Flow hierarchy is defined as the fraction of edges not participating - in cycles in a directed graph [1]_. - - Parameters - ---------- - G : DiGraph or MultiDiGraph - A directed graph - - weight : key,optional (default=None) - Attribute to use for node weights. If None the weight defaults to 1. - - Returns - ------- - h : float - Flow hierarchy value - - Notes - ----- - The algorithm described in [1]_ computes the flow hierarchy through - exponentiation of the adjacency matrix. This function implements an - alternative approach that finds strongly connected components. - An edge is in a cycle if and only if it is in a strongly connected - component, which can be found in $O(m)$ time using Tarjan's algorithm. - - References - ---------- - .. [1] Luo, J.; Magee, C.L. (2011), - Detecting evolving patterns of self-organizing networks by flow - hierarchy measurement, Complexity, Volume 16 Issue 6 53-61. - DOI: 10.1002/cplx.20368 - http://web.mit.edu/~cmagee/www/documents/28-DetectingEvolvingPatterns_FlowHierarchy.pdf - """ - if not G.is_directed(): - raise nx.NetworkXError("G must be a digraph in flow_hierarchy") - scc = nx.strongly_connected_components(G) - return 1. - sum(G.subgraph(c).size(weight) for c in scc) / float(G.size(weight)) diff --git a/extensions/fablabchemnitz/networkx/algorithms/hybrid.py b/extensions/fablabchemnitz/networkx/algorithms/hybrid.py deleted file mode 100644 index 51fa882c..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/hybrid.py +++ /dev/null @@ -1,202 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg (hagberg@lanl.gov) and Dan Schult (dschult@colgate.edu) -# -""" -Provides functions for finding and testing for locally `(k, l)`-connected -graphs. - -""" -import copy -import networkx as nx - -__all__ = ['kl_connected_subgraph', 'is_kl_connected'] - - -def kl_connected_subgraph(G, k, l, low_memory=False, same_as_graph=False): - """Returns the maximum locally `(k, l)`-connected subgraph of `G`. - - A graph is locally `(k, l)`-connected if for each edge `(u, v)` in the - graph there are at least `l` edge-disjoint paths of length at most `k` - joining `u` to `v`. - - Parameters - ---------- - G : NetworkX graph - The graph in which to find a maximum locally `(k, l)`-connected - subgraph. - - k : integer - The maximum length of paths to consider. A higher number means a looser - connectivity requirement. - - l : integer - The number of edge-disjoint paths. A higher number means a stricter - connectivity requirement. - - low_memory : bool - If this is True, this function uses an algorithm that uses slightly - more time but less memory. - - same_as_graph : bool - If True then return a tuple of the form `(H, is_same)`, - where `H` is the maximum locally `(k, l)`-connected subgraph and - `is_same` is a Boolean representing whether `G` is locally `(k, - l)`-connected (and hence, whether `H` is simply a copy of the input - graph `G`). - - Returns - ------- - NetworkX graph or two-tuple - If `same_as_graph` is True, then this function returns a - two-tuple as described above. Otherwise, it returns only the maximum - locally `(k, l)`-connected subgraph. - - See also - -------- - is_kl_connected - - References - ---------- - .. [1]: Chung, Fan and Linyuan Lu. "The Small World Phenomenon in Hybrid - Power Law Graphs." *Complex Networks*. Springer Berlin Heidelberg, - 2004. 89--104. - - """ - H = copy.deepcopy(G) # subgraph we construct by removing from G - - graphOK = True - deleted_some = True # hack to start off the while loop - while deleted_some: - deleted_some = False - # We use `for edge in list(H.edges()):` instead of - # `for edge in H.edges():` because we edit the graph `H` in - # the loop. Hence using an iterator will result in - # `RuntimeError: dictionary changed size during iteration` - for edge in list(H.edges()): - (u, v) = edge - # Get copy of graph needed for this search - if low_memory: - verts = set([u, v]) - for i in range(k): - for w in verts.copy(): - verts.update(G[w]) - G2 = G.subgraph(verts).copy() - else: - G2 = copy.deepcopy(G) - ### - path = [u, v] - cnt = 0 - accept = 0 - while path: - cnt += 1 # Found a path - if cnt >= l: - accept = 1 - break - # record edges along this graph - prev = u - for w in path: - if prev != w: - G2.remove_edge(prev, w) - prev = w -# path = shortest_path(G2, u, v, k) # ??? should "Cutoff" be k+1? - try: - path = nx.shortest_path(G2, u, v) # ??? should "Cutoff" be k+1? - except nx.NetworkXNoPath: - path = False - # No Other Paths - if accept == 0: - H.remove_edge(u, v) - deleted_some = True - if graphOK: - graphOK = False - # We looked through all edges and removed none of them. - # So, H is the maximal (k,l)-connected subgraph of G - if same_as_graph: - return (H, graphOK) - return H - - -def is_kl_connected(G, k, l, low_memory=False): - """Returns True if and only if `G` is locally `(k, l)`-connected. - - A graph is locally `(k, l)`-connected if for each edge `(u, v)` in the - graph there are at least `l` edge-disjoint paths of length at most `k` - joining `u` to `v`. - - Parameters - ---------- - G : NetworkX graph - The graph to test for local `(k, l)`-connectedness. - - k : integer - The maximum length of paths to consider. A higher number means a looser - connectivity requirement. - - l : integer - The number of edge-disjoint paths. A higher number means a stricter - connectivity requirement. - - low_memory : bool - If this is True, this function uses an algorithm that uses slightly - more time but less memory. - - Returns - ------- - bool - Whether the graph is locally `(k, l)`-connected subgraph. - - See also - -------- - kl_connected_subgraph - - References - ---------- - .. [1]: Chung, Fan and Linyuan Lu. "The Small World Phenomenon in Hybrid - Power Law Graphs." *Complex Networks*. Springer Berlin Heidelberg, - 2004. 89--104. - - """ - graphOK = True - for edge in G.edges(): - (u, v) = edge - # Get copy of graph needed for this search - if low_memory: - verts = set([u, v]) - for i in range(k): - [verts.update(G.neighbors(w)) for w in verts.copy()] - G2 = G.subgraph(verts) - else: - G2 = copy.deepcopy(G) - ### - path = [u, v] - cnt = 0 - accept = 0 - while path: - cnt += 1 # Found a path - if cnt >= l: - accept = 1 - break - # record edges along this graph - prev = u - for w in path: - if w != prev: - G2.remove_edge(prev, w) - prev = w -# path = shortest_path(G2, u, v, k) # ??? should "Cutoff" be k+1? - try: - path = nx.shortest_path(G2, u, v) # ??? should "Cutoff" be k+1? - except nx.NetworkXNoPath: - path = False - # No Other Paths - if accept == 0: - graphOK = False - break - # return status - return graphOK diff --git a/extensions/fablabchemnitz/networkx/algorithms/isolate.py b/extensions/fablabchemnitz/networkx/algorithms/isolate.py deleted file mode 100644 index 7d6171b7..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/isolate.py +++ /dev/null @@ -1,115 +0,0 @@ -# -*- encoding: utf-8 -*- -# Copyright 2015 NetworkX developers. -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -""" -Functions for identifying isolate (degree zero) nodes. -""" -import networkx as nx - -__author__ = """\n""".join(['Drew Conway ', - 'Aric Hagberg ']) - -__all__ = ['is_isolate', 'isolates', 'number_of_isolates'] - - -def is_isolate(G, n): - """Determines whether a node is an isolate. - - An *isolate* is a node with no neighbors (that is, with degree - zero). For directed graphs, this means no in-neighbors and no - out-neighbors. - - Parameters - ---------- - G : NetworkX graph - - n : node - A node in `G`. - - Returns - ------- - is_isolate : bool - True if and only if `n` has no neighbors. - - Examples - -------- - >>> G=nx.Graph() - >>> G.add_edge(1,2) - >>> G.add_node(3) - >>> nx.is_isolate(G,2) - False - >>> nx.is_isolate(G,3) - True - """ - return G.degree(n) == 0 - - -def isolates(G): - """Iterator over isolates in the graph. - - An *isolate* is a node with no neighbors (that is, with degree - zero). For directed graphs, this means no in-neighbors and no - out-neighbors. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - iterator - An iterator over the isolates of `G`. - - Examples - -------- - To get a list of all isolates of a graph, use the :class:`list` - constructor:: - - >>> G = nx.Graph() - >>> G.add_edge(1, 2) - >>> G.add_node(3) - >>> list(nx.isolates(G)) - [3] - - To remove all isolates in the graph, first create a list of the - isolates, then use :meth:`Graph.remove_nodes_from`:: - - >>> G.remove_nodes_from(list(nx.isolates(G))) - >>> list(G) - [1, 2] - - For digraphs, isolates have zero in-degree and zero out_degre:: - - >>> G = nx.DiGraph([(0, 1), (1, 2)]) - >>> G.add_node(3) - >>> list(nx.isolates(G)) - [3] - - """ - return (n for n, d in G.degree() if d == 0) - - -def number_of_isolates(G): - """Returns the number of isolates in the graph. - - An *isolate* is a node with no neighbors (that is, with degree - zero). For directed graphs, this means no in-neighbors and no - out-neighbors. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - int - The number of degree zero nodes in the graph `G`. - - """ - # TODO This can be parallelized. - return sum(1 for v in isolates(G)) diff --git a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/isomorphism/__init__.py deleted file mode 100644 index 1c4325ae..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from networkx.algorithms.isomorphism.isomorph import * -from networkx.algorithms.isomorphism.vf2userfunc import * -from networkx.algorithms.isomorphism.matchhelpers import * -from networkx.algorithms.isomorphism.temporalisomorphvf2 import * -from networkx.algorithms.isomorphism.ismags import * diff --git a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/ismags.py b/extensions/fablabchemnitz/networkx/algorithms/isomorphism/ismags.py deleted file mode 100644 index 7375e482..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/ismags.py +++ /dev/null @@ -1,1090 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -""" -**************** -ISMAGS Algorithm -**************** - -Provides a Python implementation of the ISMAGS algorithm. [1]_ - -It is capable of finding (subgraph) isomorphisms between two graphs, taking the -symmetry of the subgraph into account. In most cases the VF2 algorithm is -faster (at least on small graphs) than this implementation, but in some cases -there is an exponential number of isomorphisms that are symmetrically -equivalent. In that case, the ISMAGS algorithm will provide only one solution -per symmetry group. - ->>> import networkx as nx ->>> petersen = nx.petersen_graph() ->>> ismags = nx.isomorphism.ISMAGS(petersen, petersen) ->>> isomorphisms = list(ismags.isomorphisms_iter(symmetry=False)) ->>> len(isomorphisms) -120 ->>> isomorphisms = list(ismags.isomorphisms_iter(symmetry=True)) ->>> answer = [{0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7:7, 8: 8, 9: 9}] ->>> answer == isomorphisms -True - -In addition, this implementation also provides an interface to find the -largest common induced subgraph [2]_ between any two graphs, again taking -symmetry into account. Given `graph` and `subgraph` the algorithm will remove -nodes from the `subgraph` until `subgraph` is isomorphic to a subgraph of -`graph`. Since only the symmetry of `subgraph` is taken into account it is -worth thinking about how you provide your graphs: - ->>> graph1 = nx.path_graph(4) ->>> graph2 = nx.star_graph(3) ->>> ismags = nx.isomorphism.ISMAGS(graph1, graph2) ->>> ismags.is_isomorphic() -False ->>> largest_common_subgraph = list(ismags.largest_common_subgraph()) ->>> answer = [ -... {1: 0, 0: 1, 2: 2}, -... {2: 0, 1: 1, 3: 2} -... ] ->>> answer == largest_common_subgraph -True ->>> ismags2 = nx.isomorphism.ISMAGS(graph2, graph1) ->>> largest_common_subgraph = list(ismags2.largest_common_subgraph()) ->>> answer = [ -... {1: 0, 0: 1, 2: 2}, -... {1: 0, 0: 1, 3: 2}, -... {2: 0, 0: 1, 1: 2}, -... {2: 0, 0: 1, 3: 2}, -... {3: 0, 0: 1, 1: 2}, -... {3: 0, 0: 1, 2: 2} -... ] ->>> answer == largest_common_subgraph -True - -However, when not taking symmetry into account, it doesn't matter: - ->>> largest_common_subgraph = list(ismags.largest_common_subgraph(symmetry=False)) ->>> answer = [ -... {1: 0, 0: 1, 2: 2}, -... {1: 0, 2: 1, 0: 2}, -... {2: 0, 1: 1, 3: 2}, -... {2: 0, 3: 1, 1: 2}, -... {1: 0, 0: 1, 2: 3}, -... {1: 0, 2: 1, 0: 3}, -... {2: 0, 1: 1, 3: 3}, -... {2: 0, 3: 1, 1: 3}, -... {1: 0, 0: 2, 2: 3}, -... {1: 0, 2: 2, 0: 3}, -... {2: 0, 1: 2, 3: 3}, -... {2: 0, 3: 2, 1: 3} -... ] ->>> answer == largest_common_subgraph -True ->>> largest_common_subgraph = list(ismags2.largest_common_subgraph(symmetry=False)) ->>> answer = [ -... {1: 0, 0: 1, 2: 2}, -... {1: 0, 0: 1, 3: 2}, -... {2: 0, 0: 1, 1: 2}, -... {2: 0, 0: 1, 3: 2}, -... {3: 0, 0: 1, 1: 2}, -... {3: 0, 0: 1, 2: 2}, -... {1: 1, 0: 2, 2: 3}, -... {1: 1, 0: 2, 3: 3}, -... {2: 1, 0: 2, 1: 3}, -... {2: 1, 0: 2, 3: 3}, -... {3: 1, 0: 2, 1: 3}, -... {3: 1, 0: 2, 2: 3} -... ] ->>> answer == largest_common_subgraph -True - -Notes ------ - - The current implementation works for undirected graphs only. The algorithm - in general should work for directed graphs as well though. - - Node keys for both provided graphs need to be fully orderable as well as - hashable. - - Node and edge equality is assumed to be transitive: if A is equal to B, and - B is equal to C, then A is equal to C. - -References ----------- - .. [1] M. Houbraken, S. Demeyer, T. Michoel, P. Audenaert, D. Colle, - M. Pickavet, "The Index-Based Subgraph Matching Algorithm with General - Symmetries (ISMAGS): Exploiting Symmetry for Faster Subgraph - Enumeration", PLoS One 9(5): e97896, 2014. - https://doi.org/10.1371/journal.pone.0097896 - .. [2] https://en.wikipedia.org/wiki/Maximum_common_induced_subgraph -""" - -__author__ = 'P C Kroon (p.c.kroon@rug.nl)' -__all__ = ['ISMAGS'] - -from collections import defaultdict, Counter -from functools import reduce, wraps -import itertools - - -def are_all_equal(iterable): - """ - Returns ``True`` if and only if all elements in `iterable` are equal; and - ``False`` otherwise. - - Parameters - ---------- - iterable: collections.abc.Iterable - The container whose elements will be checked. - - Returns - ------- - bool - ``True`` iff all elements in `iterable` compare equal, ``False`` - otherwise. - """ - try: - shape = iterable.shape - except AttributeError: - pass - else: - if len(shape) > 1: - message = 'The function does not works on multidimension arrays.' - raise NotImplementedError(message) from None - - iterator = iter(iterable) - first = next(iterator, None) - return all(item == first for item in iterator) - - -def make_partitions(items, test): - """ - Partitions items into sets based on the outcome of ``test(item1, item2)``. - Pairs of items for which `test` returns `True` end up in the same set. - - Parameters - ---------- - items : collections.abc.Iterable[collections.abc.Hashable] - Items to partition - test : collections.abc.Callable[collections.abc.Hashable, collections.abc.Hashable] - A function that will be called with 2 arguments, taken from items. - Should return `True` if those 2 items need to end up in the same - partition, and `False` otherwise. - - Returns - ------- - list[set] - A list of sets, with each set containing part of the items in `items`, - such that ``all(test(*pair) for pair in itertools.combinations(set, 2)) - == True`` - - Notes - ----- - The function `test` is assumed to be transitive: if ``test(a, b)`` and - ``test(b, c)`` return ``True``, then ``test(a, c)`` must also be ``True``. - """ - partitions = [] - for item in items: - for partition in partitions: - p_item = next(iter(partition)) - if test(item, p_item): - partition.add(item) - break - else: # No break - partitions.append(set((item,))) - return partitions - - -def partition_to_color(partitions): - """ - Creates a dictionary with for every item in partition for every partition - in partitions the index of partition in partitions. - - Parameters - ---------- - partitions: collections.abc.Sequence[collections.abc.Iterable] - As returned by :func:`make_partitions`. - - Returns - ------- - dict - """ - colors = dict() - for color, keys in enumerate(partitions): - for key in keys: - colors[key] = color - return colors - - -def intersect(collection_of_sets): - """ - Given an collection of sets, returns the intersection of those sets. - - Parameters - ---------- - collection_of_sets: collections.abc.Collection[set] - A collection of sets. - - Returns - ------- - set - An intersection of all sets in `collection_of_sets`. Will have the same - type as the item initially taken from `collection_of_sets`. - """ - collection_of_sets = list(collection_of_sets) - first = collection_of_sets.pop() - out = reduce(set.intersection, collection_of_sets, set(first)) - return type(first)(out) - - -class ISMAGS: - """ - Implements the ISMAGS subgraph matching algorith. [1]_ ISMAGS stands for - "Index-based Subgraph Matching Algorithm with General Symmetries". As the - name implies, it is symmetry aware and will only generate non-symmetric - isomorphisms. - - Notes - ----- - The implementation imposes additional conditions compared to the VF2 - algorithm on the graphs provided and the comparison functions - (:attr:`node_equality` and :attr:`edge_equality`): - - - Node keys in both graphs must be orderable as well as hashable. - - Equality must be transitive: if A is equal to B, and B is equal to C, - then A must be equal to C. - - Attributes - ---------- - graph: networkx.Graph - subgraph: networkx.Graph - node_equality: collections.abc.Callable - The function called to see if two nodes should be considered equal. - It's signature looks like this: - ``f(graph1: networkx.Graph, node1, graph2: networkx.Graph, node2) -> bool``. - `node1` is a node in `graph1`, and `node2` a node in `graph2`. - Constructed from the argument `node_match`. - edge_equality: collections.abc.Callable - The function called to see if two edges should be considered equal. - It's signature looks like this: - ``f(graph1: networkx.Graph, edge1, graph2: networkx.Graph, edge2) -> bool``. - `edge1` is an edge in `graph1`, and `edge2` an edge in `graph2`. - Constructed from the argument `edge_match`. - - References - ---------- - .. [1] M. Houbraken, S. Demeyer, T. Michoel, P. Audenaert, D. Colle, - M. Pickavet, "The Index-Based Subgraph Matching Algorithm with General - Symmetries (ISMAGS): Exploiting Symmetry for Faster Subgraph - Enumeration", PLoS One 9(5): e97896, 2014. - https://doi.org/10.1371/journal.pone.0097896 - """ - def __init__(self, graph, subgraph, node_match=None, edge_match=None, - cache=None): - """ - Parameters - ---------- - graph: networkx.Graph - subgraph: networkx.Graph - node_match: collections.abc.Callable or None - Function used to determine whether two nodes are equivalent. Its - signature should look like ``f(n1: dict, n2: dict) -> bool``, with - `n1` and `n2` node property dicts. See also - :func:`~networkx.algorithms.isomorphism.categorical_node_match` and - friends. - If `None`, all nodes are considered equal. - edge_match: collections.abc.Callable or None - Function used to determine whether two edges are equivalent. Its - signature should look like ``f(e1: dict, e2: dict) -> bool``, with - `e1` and `e2` edge property dicts. See also - :func:`~networkx.algorithms.isomorphism.categorical_edge_match` and - friends. - If `None`, all edges are considered equal. - cache: collections.abc.Mapping - A cache used for caching graph symmetries. - """ - # TODO: graph and subgraph setter methods that invalidate the caches. - # TODO: allow for precomputed partitions and colors - self.graph = graph - self.subgraph = subgraph - self._symmetry_cache = cache - # Naming conventions are taken from the original paper. For your - # sanity: - # sg: subgraph - # g: graph - # e: edge(s) - # n: node(s) - # So: sgn means "subgraph nodes". - self._sgn_partitions_ = None - self._sge_partitions_ = None - - self._sgn_colors_ = None - self._sge_colors_ = None - - self._gn_partitions_ = None - self._ge_partitions_ = None - - self._gn_colors_ = None - self._ge_colors_ = None - - self._node_compat_ = None - self._edge_compat_ = None - - if node_match is None: - self.node_equality = self._node_match_maker(lambda n1, n2: True) - self._sgn_partitions_ = [set(self.subgraph.nodes)] - self._gn_partitions_ = [set(self.graph.nodes)] - self._node_compat_ = {0: 0} - else: - self.node_equality = self._node_match_maker(node_match) - if edge_match is None: - self.edge_equality = self._edge_match_maker(lambda e1, e2: True) - self._sge_partitions_ = [set(self.subgraph.edges)] - self._ge_partitions_ = [set(self.graph.edges)] - self._edge_compat_ = {0: 0} - else: - self.edge_equality = self._edge_match_maker(edge_match) - - @property - def _sgn_partitions(self): - if self._sgn_partitions_ is None: - def nodematch(node1, node2): - return self.node_equality(self.subgraph, node1, self.subgraph, node2) - self._sgn_partitions_ = make_partitions(self.subgraph.nodes, nodematch) - return self._sgn_partitions_ - - @property - def _sge_partitions(self): - if self._sge_partitions_ is None: - def edgematch(edge1, edge2): - return self.edge_equality(self.subgraph, edge1, self.subgraph, edge2) - self._sge_partitions_ = make_partitions(self.subgraph.edges, edgematch) - return self._sge_partitions_ - - @property - def _gn_partitions(self): - if self._gn_partitions_ is None: - def nodematch(node1, node2): - return self.node_equality(self.graph, node1, self.graph, node2) - self._gn_partitions_ = make_partitions(self.graph.nodes, nodematch) - return self._gn_partitions_ - - @property - def _ge_partitions(self): - if self._ge_partitions_ is None: - def edgematch(edge1, edge2): - return self.edge_equality(self.graph, edge1, self.graph, edge2) - self._ge_partitions_ = make_partitions(self.graph.edges, edgematch) - return self._ge_partitions_ - - @property - def _sgn_colors(self): - if self._sgn_colors_ is None: - self._sgn_colors_ = partition_to_color(self._sgn_partitions) - return self._sgn_colors_ - - @property - def _sge_colors(self): - if self._sge_colors_ is None: - self._sge_colors_ = partition_to_color(self._sge_partitions) - return self._sge_colors_ - - @property - def _gn_colors(self): - if self._gn_colors_ is None: - self._gn_colors_ = partition_to_color(self._gn_partitions) - return self._gn_colors_ - - @property - def _ge_colors(self): - if self._ge_colors_ is None: - self._ge_colors_ = partition_to_color(self._ge_partitions) - return self._ge_colors_ - - @property - def _node_compatibility(self): - if self._node_compat_ is not None: - return self._node_compat_ - self._node_compat_ = {} - for sgn_part_color, gn_part_color in itertools.product(range(len(self._sgn_partitions)), - range(len(self._gn_partitions))): - sgn = next(iter(self._sgn_partitions[sgn_part_color])) - gn = next(iter(self._gn_partitions[gn_part_color])) - if self.node_equality(self.subgraph, sgn, self.graph, gn): - self._node_compat_[sgn_part_color] = gn_part_color - return self._node_compat_ - - @property - def _edge_compatibility(self): - if self._edge_compat_ is not None: - return self._edge_compat_ - self._edge_compat_ = {} - for sge_part_color, ge_part_color in itertools.product(range(len(self._sge_partitions)), - range(len(self._ge_partitions))): - sge = next(iter(self._sge_partitions[sge_part_color])) - ge = next(iter(self._ge_partitions[ge_part_color])) - if self.edge_equality(self.subgraph, sge, self.graph, ge): - self._edge_compat_[sge_part_color] = ge_part_color - return self._edge_compat_ - - @staticmethod - def _node_match_maker(cmp): - @wraps(cmp) - def comparer(graph1, node1, graph2, node2): - return cmp(graph1.nodes[node1], graph2.nodes[node2]) - return comparer - - @staticmethod - def _edge_match_maker(cmp): - @wraps(cmp) - def comparer(graph1, edge1, graph2, edge2): - return cmp(graph1.edges[edge1], graph2.edges[edge2]) - return comparer - - def find_isomorphisms(self, symmetry=True): - """Find all subgraph isomorphisms between subgraph and graph - - Finds isomorphisms where :attr:`subgraph` <= :attr:`graph`. - - Parameters - ---------- - symmetry: bool - Whether symmetry should be taken into account. If False, found - isomorphisms may be symmetrically equivalent. - - Yields - ------ - dict - The found isomorphism mappings of {graph_node: subgraph_node}. - """ - # The networkx VF2 algorithm is slightly funny in when it yields an - # empty dict and when not. - if not self.subgraph: - yield {} - return - elif not self.graph: - return - elif len(self.graph) < len(self.subgraph): - return - - if symmetry: - _, cosets = self.analyze_symmetry(self.subgraph, - self._sgn_partitions, - self._sge_colors) - constraints = self._make_constraints(cosets) - else: - constraints = [] - - candidates = self._find_nodecolor_candidates() - la_candidates = self._get_lookahead_candidates() - for sgn in self.subgraph: - extra_candidates = la_candidates[sgn] - if extra_candidates: - candidates[sgn] = candidates[sgn] | {frozenset(extra_candidates)} - - if any(candidates.values()): - start_sgn = min(candidates, key=lambda n: min(candidates[n], key=len)) - candidates[start_sgn] = (intersect(candidates[start_sgn]),) - yield from self._map_nodes(start_sgn, candidates, constraints) - else: - return - - @staticmethod - def _find_neighbor_color_count(graph, node, node_color, edge_color): - """ - For `node` in `graph`, count the number of edges of a specific color - it has to nodes of a specific color. - """ - counts = Counter() - neighbors = graph[node] - for neighbor in neighbors: - n_color = node_color[neighbor] - if (node, neighbor) in edge_color: - e_color = edge_color[node, neighbor] - else: - e_color = edge_color[neighbor, node] - counts[e_color, n_color] += 1 - return counts - - def _get_lookahead_candidates(self): - """ - Returns a mapping of {subgraph node: collection of graph nodes} for - which the graph nodes are feasible candidates for the subgraph node, as - determined by looking ahead one edge. - """ - g_counts = {} - for gn in self.graph: - g_counts[gn] = self._find_neighbor_color_count(self.graph, gn, - self._gn_colors, - self._ge_colors) - candidates = defaultdict(set) - for sgn in self.subgraph: - sg_count = self._find_neighbor_color_count(self.subgraph, sgn, - self._sgn_colors, - self._sge_colors) - new_sg_count = Counter() - for (sge_color, sgn_color), count in sg_count.items(): - try: - ge_color = self._edge_compatibility[sge_color] - gn_color = self._node_compatibility[sgn_color] - except KeyError: - pass - else: - new_sg_count[ge_color, gn_color] = count - - for gn, g_count in g_counts.items(): - if all(new_sg_count[x] <= g_count[x] for x in new_sg_count): - # Valid candidate - candidates[sgn].add(gn) - return candidates - - def largest_common_subgraph(self, symmetry=True): - """ - Find the largest common induced subgraphs between :attr:`subgraph` and - :attr:`graph`. - - Parameters - ---------- - symmetry: bool - Whether symmetry should be taken into account. If False, found - largest common subgraphs may be symmetrically equivalent. - - Yields - ------ - dict - The found isomorphism mappings of {graph_node: subgraph_node}. - """ - # The networkx VF2 algorithm is slightly funny in when it yields an - # empty dict and when not. - if not self.subgraph: - yield {} - return - elif not self.graph: - return - - if symmetry: - _, cosets = self.analyze_symmetry(self.subgraph, - self._sgn_partitions, - self._sge_colors) - constraints = self._make_constraints(cosets) - else: - constraints = [] - - candidates = self._find_nodecolor_candidates() - - if any(candidates.values()): - yield from self._largest_common_subgraph(candidates, constraints) - else: - return - - def analyze_symmetry(self, graph, node_partitions, edge_colors): - """ - Find a minimal set of permutations and corresponding co-sets that - describe the symmetry of :attr:`subgraph`. - - Returns - ------- - set[frozenset] - The found permutations. This is a set of frozenset of pairs of node - keys which can be exchanged without changing :attr:`subgraph`. - dict[collections.abc.Hashable, set[collections.abc.Hashable]] - The found co-sets. The co-sets is a dictionary of {node key: - set of node keys}. Every key-value pair describes which `values` - can be interchanged without changing nodes less than `key`. - """ - if self._symmetry_cache is not None: - key = hash((tuple(graph.nodes), tuple(graph.edges), - tuple(map(tuple, node_partitions)), tuple(edge_colors.items()))) - if key in self._symmetry_cache: - return self._symmetry_cache[key] - node_partitions = list(self._refine_node_partitions(graph, - node_partitions, - edge_colors)) - assert len(node_partitions) == 1 - node_partitions = node_partitions[0] - permutations, cosets = self._process_ordered_pair_partitions(graph, - node_partitions, - node_partitions, - edge_colors) - if self._symmetry_cache is not None: - self._symmetry_cache[key] = permutations, cosets - return permutations, cosets - - def is_isomorphic(self, symmetry=False): - """ - Returns True if :attr:`graph` is isomorphic to :attr:`subgraph` and - False otherwise. - - Returns - ------- - bool - """ - return len(self.subgraph) == len(self.graph) and self.subgraph_is_isomorphic(symmetry) - - def subgraph_is_isomorphic(self, symmetry=False): - """ - Returns True if a subgraph of :attr:`graph` is isomorphic to - :attr:`subgraph` and False otherwise. - - Returns - ------- - bool - """ - # symmetry=False, since we only need to know whether there is any - # example; figuring out all symmetry elements probably costs more time - # than it gains. - isom = next(self.subgraph_isomorphisms_iter(symmetry=symmetry), None) - return isom is not None - - def isomorphisms_iter(self, symmetry=True): - """ - Does the same as :meth:`find_isomorphisms` if :attr:`graph` and - :attr:`subgraph` have the same number of nodes. - """ - if len(self.graph) == len(self.subgraph): - yield from self.subgraph_isomorphisms_iter(symmetry=symmetry) - - def subgraph_isomorphisms_iter(self, symmetry=True): - """Alternative name for :meth:`find_isomorphisms`.""" - return self.find_isomorphisms(symmetry) - - def _find_nodecolor_candidates(self): - """ - Per node in subgraph find all nodes in graph that have the same color. - """ - candidates = defaultdict(set) - for sgn in self.subgraph.nodes: - sgn_color = self._sgn_colors[sgn] - if sgn_color in self._node_compatibility: - gn_color = self._node_compatibility[sgn_color] - candidates[sgn].add(frozenset(self._gn_partitions[gn_color])) - else: - candidates[sgn].add(frozenset()) - candidates = dict(candidates) - for sgn, options in candidates.items(): - candidates[sgn] = frozenset(options) - return candidates - - @staticmethod - def _make_constraints(cosets): - """ - Turn cosets into constraints. - """ - constraints = [] - for node_i, node_ts in cosets.items(): - for node_t in node_ts: - if node_i != node_t: - # Node i must be smaller than node t. - constraints.append((node_i, node_t)) - return constraints - - @staticmethod - def _find_node_edge_color(graph, node_colors, edge_colors): - """ - For every node in graph, come up with a color that combines 1) the - color of the node, and 2) the number of edges of a color to each type - of node. - """ - counts = defaultdict(lambda: defaultdict(int)) - for node1, node2 in graph.edges: - if (node1, node2) in edge_colors: - # FIXME directed graphs - ecolor = edge_colors[node1, node2] - else: - ecolor = edge_colors[node2, node1] - # Count per node how many edges it has of what color to nodes of - # what color - counts[node1][ecolor, node_colors[node2]] += 1 - counts[node2][ecolor, node_colors[node1]] += 1 - - node_edge_colors = dict() - for node in graph.nodes: - node_edge_colors[node] = node_colors[node], set(counts[node].items()) - - return node_edge_colors - - @staticmethod - def _get_permutations_by_length(items): - """ - Get all permutations of items, but only permute items with the same - length. - - >>> found = list(ISMAGS._get_permutations_by_length([[1], [2], [3, 4], [4, 5]])) - >>> answer = [ - ... (([1], [2]), ([3, 4], [4, 5])), - ... (([1], [2]), ([4, 5], [3, 4])), - ... (([2], [1]), ([3, 4], [4, 5])), - ... (([2], [1]), ([4, 5], [3, 4])), - ... ] - >>> found == answer - True - """ - by_len = defaultdict(list) - for item in items: - by_len[len(item)].append(item) - - yield from itertools.product(*(itertools.permutations(by_len[l]) for l in sorted(by_len))) - - @classmethod - def _refine_node_partitions(cls, graph, node_partitions, edge_colors, branch=False): - """ - Given a partition of nodes in graph, make the partitions smaller such - that all nodes in a partition have 1) the same color, and 2) the same - number of edges to specific other partitions. - """ - def equal_color(node1, node2): - return node_edge_colors[node1] == node_edge_colors[node2] - - node_partitions = list(node_partitions) - node_colors = partition_to_color(node_partitions) - node_edge_colors = cls._find_node_edge_color(graph, node_colors, edge_colors) - if all(are_all_equal(node_edge_colors[node] for node in partition) - for partition in node_partitions): - yield node_partitions - return - - new_partitions = [] - output = [new_partitions] - for partition in node_partitions: - if not are_all_equal(node_edge_colors[node] for node in partition): - refined = make_partitions(partition, equal_color) - if (branch and len(refined) != 1 and - len({len(r) for r in refined}) != len([len(r) for r in refined])): - # This is where it breaks. There are multiple new cells - # in refined with the same length, and their order - # matters. - # So option 1) Hit it with a big hammer and simply make all - # orderings. - permutations = cls._get_permutations_by_length(refined) - new_output = [] - for n_p in output: - for permutation in permutations: - new_output.append(n_p + list(permutation[0])) - output = new_output - else: - for n_p in output: - n_p.extend(sorted(refined, key=len)) - else: - for n_p in output: - n_p.append(partition) - for n_p in output: - yield from cls._refine_node_partitions(graph, n_p, edge_colors, branch) - - def _edges_of_same_color(self, sgn1, sgn2): - """ - Returns all edges in :attr:`graph` that have the same colour as the - edge between sgn1 and sgn2 in :attr:`subgraph`. - """ - if (sgn1, sgn2) in self._sge_colors: - # FIXME directed graphs - sge_color = self._sge_colors[sgn1, sgn2] - else: - sge_color = self._sge_colors[sgn2, sgn1] - if sge_color in self._edge_compatibility: - ge_color = self._edge_compatibility[sge_color] - g_edges = self._ge_partitions[ge_color] - else: - g_edges = [] - return g_edges - - def _map_nodes(self, sgn, candidates, constraints, mapping=None, to_be_mapped=None): - """ - Find all subgraph isomorphisms honoring constraints. - """ - if mapping is None: - mapping = {} - else: - mapping = mapping.copy() - if to_be_mapped is None: - to_be_mapped = set(self.subgraph.nodes) - - # Note, we modify candidates here. Doesn't seem to affect results, but - # remember this. - #candidates = candidates.copy() - sgn_candidates = intersect(candidates[sgn]) - candidates[sgn] = frozenset([sgn_candidates]) - for gn in sgn_candidates: - # We're going to try to map sgn to gn. - if gn in mapping.values() or sgn not in to_be_mapped: - # gn is already mapped to something - continue # pragma: no cover - - # REDUCTION and COMBINATION - mapping[sgn] = gn - # BASECASE - if to_be_mapped == set(mapping.keys()): - yield {v: k for k, v in mapping.items()} - continue - left_to_map = to_be_mapped - set(mapping.keys()) - - new_candidates = candidates.copy() - sgn_neighbours = set(self.subgraph[sgn]) - not_gn_neighbours = set(self.graph.nodes) - set(self.graph[gn]) - for sgn2 in left_to_map: - if sgn2 not in sgn_neighbours: - gn2_options = not_gn_neighbours - else: - # Get all edges to gn of the right color: - g_edges = self._edges_of_same_color(sgn, sgn2) - # FIXME directed graphs - # And all nodes involved in those which are connected to gn - gn2_options = {n for e in g_edges for n in e if gn in e} - # Node color compatibility should be taken care of by the - # initial candidate lists made by find_subgraphs - - # Add gn2_options to the right collection. Since new_candidates - # is a dict of frozensets of frozensets of node indices it's - # a bit clunky. We can't do .add, and + also doesn't work. We - # could do |, but I deem union to be clearer. - new_candidates[sgn2] = new_candidates[sgn2].union([frozenset(gn2_options)]) - - if (sgn, sgn2) in constraints: - gn2_options = {gn2 for gn2 in self.graph if gn2 > gn} - elif (sgn2, sgn) in constraints: - gn2_options = {gn2 for gn2 in self.graph if gn2 < gn} - else: - continue # pragma: no cover - new_candidates[sgn2] = new_candidates[sgn2].union([frozenset(gn2_options)]) - - # The next node is the one that is unmapped and has fewest - # candidates - # Pylint disables because it's a one-shot function. - next_sgn = min(left_to_map, - key=lambda n: min(new_candidates[n], key=len)) # pylint: disable=cell-var-from-loop - yield from self._map_nodes(next_sgn, - new_candidates, - constraints, - mapping=mapping, - to_be_mapped=to_be_mapped) - # Unmap sgn-gn. Strictly not necessary since it'd get overwritten - # when making a new mapping for sgn. - #del mapping[sgn] - - def _largest_common_subgraph(self, candidates, constraints, - to_be_mapped=None): - """ - Find all largest common subgraphs honoring constraints. - """ - if to_be_mapped is None: - to_be_mapped = {frozenset(self.subgraph.nodes)} - - # The LCS problem is basically a repeated subgraph isomorphism problem - # with smaller and smaller subgraphs. We store the nodes that are - # "part of" the subgraph in to_be_mapped, and we make it a little - # smaller every iteration. - - # pylint disable becuase it's guarded against by default value - current_size = len(next(iter(to_be_mapped), [])) # pylint: disable=stop-iteration-return - - found_iso = False - if current_size <= len(self.graph): - # There's no point in trying to find isomorphisms of - # graph >= subgraph if subgraph has more nodes than graph. - - # Try the isomorphism first with the nodes with lowest ID. So sort - # them. Those are more likely to be part of the final - # correspondence. This makes finding the first answer(s) faster. In - # theory. - for nodes in sorted(to_be_mapped, key=sorted): - # Find the isomorphism between subgraph[to_be_mapped] <= graph - next_sgn = min(nodes, key=lambda n: min(candidates[n], key=len)) - isomorphs = self._map_nodes(next_sgn, candidates, constraints, - to_be_mapped=nodes) - - # This is effectively `yield from isomorphs`, except that we look - # whether an item was yielded. - try: - item = next(isomorphs) - except StopIteration: - pass - else: - yield item - yield from isomorphs - found_iso = True - - # BASECASE - if found_iso or current_size == 1: - # Shrinking has no point because either 1) we end up with a smaller - # common subgraph (and we want the largest), or 2) there'll be no - # more subgraph. - return - - left_to_be_mapped = set() - for nodes in to_be_mapped: - for sgn in nodes: - # We're going to remove sgn from to_be_mapped, but subject to - # symmetry constraints. We know that for every constraint we - # have those subgraph nodes are equal. So whenever we would - # remove the lower part of a constraint, remove the higher - # instead. This is all dealth with by _remove_node. And because - # left_to_be_mapped is a set, we don't do double work. - - # And finally, make the subgraph one node smaller. - # REDUCTION - new_nodes = self._remove_node(sgn, nodes, constraints) - left_to_be_mapped.add(new_nodes) - # COMBINATION - yield from self._largest_common_subgraph(candidates, constraints, - to_be_mapped=left_to_be_mapped) - - @staticmethod - def _remove_node(node, nodes, constraints): - """ - Returns a new set where node has been removed from nodes, subject to - symmetry constraints. We know, that for every constraint we have - those subgraph nodes are equal. So whenever we would remove the - lower part of a constraint, remove the higher instead. - """ - while True: - for low, high in constraints: - if low == node and high in nodes: - node = high - break - else: # no break, couldn't find node in constraints - break - return frozenset(nodes - {node}) - - @staticmethod - def _find_permutations(top_partitions, bottom_partitions): - """ - Return the pairs of top/bottom partitions where the partitions are - different. Ensures that all partitions in both top and bottom - partitions have size 1. - """ - # Find permutations - permutations = set() - for top, bot in zip(top_partitions, bottom_partitions): - # top and bot have only one element - if len(top) != 1 or len(bot) != 1: - raise IndexError("Not all nodes are coupled. This is" - " impossible: {}, {}".format(top_partitions, - bottom_partitions)) - if top != bot: - permutations.add(frozenset((next(iter(top)), next(iter(bot))))) - return permutations - - @staticmethod - def _update_orbits(orbits, permutations): - """ - Update orbits based on permutations. Orbits is modified in place. - For every pair of items in permutations their respective orbits are - merged. - """ - for permutation in permutations: - node, node2 = permutation - # Find the orbits that contain node and node2, and replace the - # orbit containing node with the union - first = second = None - for idx, orbit in enumerate(orbits): - if first is not None and second is not None: - break - if node in orbit: - first = idx - if node2 in orbit: - second = idx - if first != second: - orbits[first].update(orbits[second]) - del orbits[second] - - def _couple_nodes(self, top_partitions, bottom_partitions, pair_idx, - t_node, b_node, graph, edge_colors): - """ - Generate new partitions from top and bottom_partitions where t_node is - coupled to b_node. pair_idx is the index of the partitions where t_ and - b_node can be found. - """ - t_partition = top_partitions[pair_idx] - b_partition = bottom_partitions[pair_idx] - assert t_node in t_partition and b_node in b_partition - # Couple node to node2. This means they get their own partition - new_top_partitions = [top.copy() for top in top_partitions] - new_bottom_partitions = [bot.copy() for bot in bottom_partitions] - new_t_groups = {t_node}, t_partition - {t_node} - new_b_groups = {b_node}, b_partition - {b_node} - # Replace the old partitions with the coupled ones - del new_top_partitions[pair_idx] - del new_bottom_partitions[pair_idx] - new_top_partitions[pair_idx:pair_idx] = new_t_groups - new_bottom_partitions[pair_idx:pair_idx] = new_b_groups - - new_top_partitions = self._refine_node_partitions(graph, - new_top_partitions, - edge_colors) - new_bottom_partitions = self._refine_node_partitions(graph, - new_bottom_partitions, - edge_colors, branch=True) - new_top_partitions = list(new_top_partitions) - assert len(new_top_partitions) == 1 - new_top_partitions = new_top_partitions[0] - for bot in new_bottom_partitions: - yield list(new_top_partitions), bot - - def _process_ordered_pair_partitions(self, graph, top_partitions, - bottom_partitions, edge_colors, - orbits=None, cosets=None): - """ - Processes ordered pair partitions as per the reference paper. Finds and - returns all permutations and cosets that leave the graph unchanged. - """ - if orbits is None: - orbits = [{node} for node in graph.nodes] - else: - # Note that we don't copy orbits when we are given one. This means - # we leak information between the recursive branches. This is - # intentional! - orbits = orbits - if cosets is None: - cosets = {} - else: - cosets = cosets.copy() - - assert all(len(t_p) == len(b_p) for t_p, b_p in zip(top_partitions, bottom_partitions)) - - # BASECASE - if all(len(top) == 1 for top in top_partitions): - # All nodes are mapped - permutations = self._find_permutations(top_partitions, bottom_partitions) - self._update_orbits(orbits, permutations) - if permutations: - return [permutations], cosets - else: - return [], cosets - - permutations = [] - unmapped_nodes = {(node, idx) - for idx, t_partition in enumerate(top_partitions) - for node in t_partition if len(t_partition) > 1} - node, pair_idx = min(unmapped_nodes) - b_partition = bottom_partitions[pair_idx] - - for node2 in sorted(b_partition): - if len(b_partition) == 1: - # Can never result in symmetry - continue - if node != node2 and any(node in orbit and node2 in orbit for orbit in orbits): - # Orbit prune branch - continue - # REDUCTION - # Couple node to node2 - partitions = self._couple_nodes(top_partitions, bottom_partitions, - pair_idx, node, node2, graph, - edge_colors) - for opp in partitions: - new_top_partitions, new_bottom_partitions = opp - - new_perms, new_cosets = self._process_ordered_pair_partitions(graph, - new_top_partitions, - new_bottom_partitions, - edge_colors, - orbits, - cosets) - # COMBINATION - permutations += new_perms - cosets.update(new_cosets) - - mapped = {k for top, bottom in zip(top_partitions, bottom_partitions) - for k in top if len(top) == 1 and top == bottom} - ks = {k for k in graph.nodes if k < node} - # Have all nodes with ID < node been mapped? - find_coset = ks <= mapped and node not in cosets - if find_coset: - # Find the orbit that contains node - for orbit in orbits: - if node in orbit: - cosets[node] = orbit.copy() - return permutations, cosets diff --git a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/isomorph.py b/extensions/fablabchemnitz/networkx/algorithms/isomorphism/isomorph.py deleted file mode 100644 index e2a3e598..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/isomorph.py +++ /dev/null @@ -1,239 +0,0 @@ -""" -Graph isomorphism functions. -""" -import networkx as nx -from networkx.exception import NetworkXError -__author__ = """\n""".join(['Aric Hagberg (hagberg@lanl.gov)', - 'Pieter Swart (swart@lanl.gov)', - 'Christopher Ellison cellison@cse.ucdavis.edu)']) -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -__all__ = ['could_be_isomorphic', - 'fast_could_be_isomorphic', - 'faster_could_be_isomorphic', - 'is_isomorphic'] - - -def could_be_isomorphic(G1, G2): - """Returns False if graphs are definitely not isomorphic. - True does NOT guarantee isomorphism. - - Parameters - ---------- - G1, G2 : graphs - The two graphs G1 and G2 must be the same type. - - Notes - ----- - Checks for matching degree, triangle, and number of cliques sequences. - """ - - # Check global properties - if G1.order() != G2.order(): - return False - - # Check local properties - d1 = G1.degree() - t1 = nx.triangles(G1) - c1 = nx.number_of_cliques(G1) - props1 = [[d, t1[v], c1[v]] for v, d in d1] - props1.sort() - - d2 = G2.degree() - t2 = nx.triangles(G2) - c2 = nx.number_of_cliques(G2) - props2 = [[d, t2[v], c2[v]] for v, d in d2] - props2.sort() - - if props1 != props2: - return False - - # OK... - return True - - -graph_could_be_isomorphic = could_be_isomorphic - - -def fast_could_be_isomorphic(G1, G2): - """Returns False if graphs are definitely not isomorphic. - - True does NOT guarantee isomorphism. - - Parameters - ---------- - G1, G2 : graphs - The two graphs G1 and G2 must be the same type. - - Notes - ----- - Checks for matching degree and triangle sequences. - """ - # Check global properties - if G1.order() != G2.order(): - return False - - # Check local properties - d1 = G1.degree() - t1 = nx.triangles(G1) - props1 = [[d, t1[v]] for v, d in d1] - props1.sort() - - d2 = G2.degree() - t2 = nx.triangles(G2) - props2 = [[d, t2[v]] for v, d in d2] - props2.sort() - - if props1 != props2: - return False - - # OK... - return True - - -fast_graph_could_be_isomorphic = fast_could_be_isomorphic - - -def faster_could_be_isomorphic(G1, G2): - """Returns False if graphs are definitely not isomorphic. - - True does NOT guarantee isomorphism. - - Parameters - ---------- - G1, G2 : graphs - The two graphs G1 and G2 must be the same type. - - Notes - ----- - Checks for matching degree sequences. - """ - # Check global properties - if G1.order() != G2.order(): - return False - - # Check local properties - d1 = sorted(d for n, d in G1.degree()) - d2 = sorted(d for n, d in G2.degree()) - - if d1 != d2: - return False - - # OK... - return True - - -faster_graph_could_be_isomorphic = faster_could_be_isomorphic - - -def is_isomorphic(G1, G2, node_match=None, edge_match=None): - """Returns True if the graphs G1 and G2 are isomorphic and False otherwise. - - Parameters - ---------- - G1, G2: graphs - The two graphs G1 and G2 must be the same type. - - node_match : callable - A function that returns True if node n1 in G1 and n2 in G2 should - be considered equal during the isomorphism test. - If node_match is not specified then node attributes are not considered. - - The function will be called like - - node_match(G1.nodes[n1], G2.nodes[n2]). - - That is, the function will receive the node attribute dictionaries - for n1 and n2 as inputs. - - edge_match : callable - A function that returns True if the edge attribute dictionary - for the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should - be considered equal during the isomorphism test. If edge_match is - not specified then edge attributes are not considered. - - The function will be called like - - edge_match(G1[u1][v1], G2[u2][v2]). - - That is, the function will receive the edge attribute dictionaries - of the edges under consideration. - - Notes - ----- - Uses the vf2 algorithm [1]_. - - Examples - -------- - >>> import networkx.algorithms.isomorphism as iso - - For digraphs G1 and G2, using 'weight' edge attribute (default: 1) - - >>> G1 = nx.DiGraph() - >>> G2 = nx.DiGraph() - >>> nx.add_path(G1, [1,2,3,4], weight=1) - >>> nx.add_path(G2, [10,20,30,40], weight=2) - >>> em = iso.numerical_edge_match('weight', 1) - >>> nx.is_isomorphic(G1, G2) # no weights considered - True - >>> nx.is_isomorphic(G1, G2, edge_match=em) # match weights - False - - For multidigraphs G1 and G2, using 'fill' node attribute (default: '') - - >>> G1 = nx.MultiDiGraph() - >>> G2 = nx.MultiDiGraph() - >>> G1.add_nodes_from([1,2,3], fill='red') - >>> G2.add_nodes_from([10,20,30,40], fill='red') - >>> nx.add_path(G1, [1,2,3,4], weight=3, linewidth=2.5) - >>> nx.add_path(G2, [10,20,30,40], weight=3) - >>> nm = iso.categorical_node_match('fill', 'red') - >>> nx.is_isomorphic(G1, G2, node_match=nm) - True - - For multidigraphs G1 and G2, using 'weight' edge attribute (default: 7) - - >>> G1.add_edge(1,2, weight=7) - 1 - >>> G2.add_edge(10,20) - 1 - >>> em = iso.numerical_multiedge_match('weight', 7, rtol=1e-6) - >>> nx.is_isomorphic(G1, G2, edge_match=em) - True - - For multigraphs G1 and G2, using 'weight' and 'linewidth' edge attributes - with default values 7 and 2.5. Also using 'fill' node attribute with - default value 'red'. - - >>> em = iso.numerical_multiedge_match(['weight', 'linewidth'], [7, 2.5]) - >>> nm = iso.categorical_node_match('fill', 'red') - >>> nx.is_isomorphic(G1, G2, edge_match=em, node_match=nm) - True - - See Also - -------- - numerical_node_match, numerical_edge_match, numerical_multiedge_match - categorical_node_match, categorical_edge_match, categorical_multiedge_match - - References - ---------- - .. [1] L. P. Cordella, P. Foggia, C. Sansone, M. Vento, - "An Improved Algorithm for Matching Large Graphs", - 3rd IAPR-TC15 Workshop on Graph-based Representations in - Pattern Recognition, Cuen, pp. 149-159, 2001. - http://amalfi.dis.unina.it/graph/db/papers/vf-algorithm.pdf - """ - if G1.is_directed() and G2.is_directed(): - GM = nx.algorithms.isomorphism.DiGraphMatcher - elif (not G1.is_directed()) and (not G2.is_directed()): - GM = nx.algorithms.isomorphism.GraphMatcher - else: - raise NetworkXError("Graphs G1 and G2 are not of the same type.") - - gm = GM(G1, G2, node_match=node_match, edge_match=edge_match) - - return gm.is_isomorphic() diff --git a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/isomorphvf2.py b/extensions/fablabchemnitz/networkx/algorithms/isomorphism/isomorphvf2.py deleted file mode 100644 index 121dae0f..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/isomorphvf2.py +++ /dev/null @@ -1,1021 +0,0 @@ -# -*- coding: utf-8 -*- -""" -************* -VF2 Algorithm -************* - -An implementation of VF2 algorithm for graph ismorphism testing. - -The simplest interface to use this module is to call networkx.is_isomorphic(). - -Introduction ------------- - -The GraphMatcher and DiGraphMatcher are responsible for matching -graphs or directed graphs in a predetermined manner. This -usually means a check for an isomorphism, though other checks -are also possible. For example, a subgraph of one graph -can be checked for isomorphism to a second graph. - -Matching is done via syntactic feasibility. It is also possible -to check for semantic feasibility. Feasibility, then, is defined -as the logical AND of the two functions. - -To include a semantic check, the (Di)GraphMatcher class should be -subclassed, and the semantic_feasibility() function should be -redefined. By default, the semantic feasibility function always -returns True. The effect of this is that semantics are not -considered in the matching of G1 and G2. - -Examples --------- - -Suppose G1 and G2 are isomorphic graphs. Verification is as follows: - ->>> from networkx.algorithms import isomorphism ->>> G1 = nx.path_graph(4) ->>> G2 = nx.path_graph(4) ->>> GM = isomorphism.GraphMatcher(G1,G2) ->>> GM.is_isomorphic() -True - -GM.mapping stores the isomorphism mapping from G1 to G2. - ->>> GM.mapping -{0: 0, 1: 1, 2: 2, 3: 3} - - -Suppose G1 and G2 are isomorphic directed graphs -graphs. Verification is as follows: - ->>> G1 = nx.path_graph(4, create_using=nx.DiGraph()) ->>> G2 = nx.path_graph(4, create_using=nx.DiGraph()) ->>> DiGM = isomorphism.DiGraphMatcher(G1,G2) ->>> DiGM.is_isomorphic() -True - -DiGM.mapping stores the isomorphism mapping from G1 to G2. - ->>> DiGM.mapping -{0: 0, 1: 1, 2: 2, 3: 3} - - - -Subgraph Isomorphism --------------------- -Graph theory literature can be ambiguous about the meaning of the -above statement, and we seek to clarify it now. - -In the VF2 literature, a mapping M is said to be a graph-subgraph -isomorphism iff M is an isomorphism between G2 and a subgraph of G1. -Thus, to say that G1 and G2 are graph-subgraph isomorphic is to say -that a subgraph of G1 is isomorphic to G2. - -Other literature uses the phrase 'subgraph isomorphic' as in 'G1 does -not have a subgraph isomorphic to G2'. Another use is as an in adverb -for isomorphic. Thus, to say that G1 and G2 are subgraph isomorphic -is to say that a subgraph of G1 is isomorphic to G2. - -Finally, the term 'subgraph' can have multiple meanings. In this -context, 'subgraph' always means a 'node-induced subgraph'. Edge-induced -subgraph isomorphisms are not directly supported, but one should be -able to perform the check by making use of nx.line_graph(). For -subgraphs which are not induced, the term 'monomorphism' is preferred -over 'isomorphism'. - -Let G=(N,E) be a graph with a set of nodes N and set of edges E. - -If G'=(N',E') is a subgraph, then: - N' is a subset of N - E' is a subset of E - -If G'=(N',E') is a node-induced subgraph, then: - N' is a subset of N - E' is the subset of edges in E relating nodes in N' - -If G'=(N',E') is an edge-induced subgraph, then: - N' is the subset of nodes in N related by edges in E' - E' is a subset of E - -If G'=(N',E') is a monomorphism, then: - N' is a subset of N - E' is a subset of the set of edges in E relating nodes in N' - -Note that if G' is a node-induced subgraph of G, then it is always a -subgraph monomorphism of G, but the opposite is not always true, as a -monomorphism can have fewer edges. - -References ----------- -[1] Luigi P. Cordella, Pasquale Foggia, Carlo Sansone, Mario Vento, - "A (Sub)Graph Isomorphism Algorithm for Matching Large Graphs", - IEEE Transactions on Pattern Analysis and Machine Intelligence, - vol. 26, no. 10, pp. 1367-1372, Oct., 2004. - http://ieeexplore.ieee.org/iel5/34/29305/01323804.pdf - -[2] L. P. Cordella, P. Foggia, C. Sansone, M. Vento, "An Improved - Algorithm for Matching Large Graphs", 3rd IAPR-TC15 Workshop - on Graph-based Representations in Pattern Recognition, Cuen, - pp. 149-159, 2001. - http://amalfi.dis.unina.it/graph/db/papers/vf-algorithm.pdf - -See Also --------- -syntactic_feasibliity(), semantic_feasibility() - -Notes ------ - -The implementation handles both directed and undirected graphs as well -as multigraphs. - -In general, the subgraph isomorphism problem is NP-complete whereas the -graph isomorphism problem is most likely not NP-complete (although no -polynomial-time algorithm is known to exist). - -""" - -# Copyright (C) 2007-2009 by the NetworkX maintainers -# All rights reserved. -# BSD license. - -# This work was originally coded by Christopher Ellison -# as part of the Computational Mechanics Python (CMPy) project. -# James P. Crutchfield, principal investigator. -# Complexity Sciences Center and Physics Department, UC Davis. - -import sys -import networkx as nx - -__all__ = ['GraphMatcher', - 'DiGraphMatcher'] - - -class GraphMatcher(object): - """Implementation of VF2 algorithm for matching undirected graphs. - - Suitable for Graph and MultiGraph instances. - """ - - def __init__(self, G1, G2): - """Initialize GraphMatcher. - - Parameters - ---------- - G1,G2: NetworkX Graph or MultiGraph instances. - The two graphs to check for isomorphism or monomorphism. - - Examples - -------- - To create a GraphMatcher which checks for syntactic feasibility: - - >>> from networkx.algorithms import isomorphism - >>> G1 = nx.path_graph(4) - >>> G2 = nx.path_graph(4) - >>> GM = isomorphism.GraphMatcher(G1,G2) - """ - self.G1 = G1 - self.G2 = G2 - self.G1_nodes = set(G1.nodes()) - self.G2_nodes = set(G2.nodes()) - self.G2_node_order = {n: i for i, n in enumerate(G2)} - - # Set recursion limit. - self.old_recursion_limit = sys.getrecursionlimit() - expected_max_recursion_level = len(self.G2) - if self.old_recursion_limit < 1.5 * expected_max_recursion_level: - # Give some breathing room. - sys.setrecursionlimit(int(1.5 * expected_max_recursion_level)) - - # Declare that we will be searching for a graph-graph isomorphism. - self.test = 'graph' - - # Initialize state - self.initialize() - - def reset_recursion_limit(self): - """Restores the recursion limit.""" - # TODO: - # Currently, we use recursion and set the recursion level higher. - # It would be nice to restore the level, but because the - # (Di)GraphMatcher classes make use of cyclic references, garbage - # collection will never happen when we define __del__() to - # restore the recursion level. The result is a memory leak. - # So for now, we do not automatically restore the recursion level, - # and instead provide a method to do this manually. Eventually, - # we should turn this into a non-recursive implementation. - sys.setrecursionlimit(self.old_recursion_limit) - - def candidate_pairs_iter(self): - """Iterator over candidate pairs of nodes in G1 and G2.""" - - # All computations are done using the current state! - - G1_nodes = self.G1_nodes - G2_nodes = self.G2_nodes - min_key = self.G2_node_order.__getitem__ - - # First we compute the inout-terminal sets. - T1_inout = [node for node in self.inout_1 if node not in self.core_1] - T2_inout = [node for node in self.inout_2 if node not in self.core_2] - - # If T1_inout and T2_inout are both nonempty. - # P(s) = T1_inout x {min T2_inout} - if T1_inout and T2_inout: - node_2 = min(T2_inout, key=min_key) - for node_1 in T1_inout: - yield node_1, node_2 - - else: - # If T1_inout and T2_inout were both empty.... - # P(s) = (N_1 - M_1) x {min (N_2 - M_2)} - # if not (T1_inout or T2_inout): # as suggested by [2], incorrect - if 1: # as inferred from [1], correct - # First we determine the candidate node for G2 - other_node = min(G2_nodes - set(self.core_2), key=min_key) - for node in self.G1: - if node not in self.core_1: - yield node, other_node - - # For all other cases, we don't have any candidate pairs. - - def initialize(self): - """Reinitializes the state of the algorithm. - - This method should be redefined if using something other than GMState. - If only subclassing GraphMatcher, a redefinition is not necessary. - - """ - - # core_1[n] contains the index of the node paired with n, which is m, - # provided n is in the mapping. - # core_2[m] contains the index of the node paired with m, which is n, - # provided m is in the mapping. - self.core_1 = {} - self.core_2 = {} - - # See the paper for definitions of M_x and T_x^{y} - - # inout_1[n] is non-zero if n is in M_1 or in T_1^{inout} - # inout_2[m] is non-zero if m is in M_2 or in T_2^{inout} - # - # The value stored is the depth of the SSR tree when the node became - # part of the corresponding set. - self.inout_1 = {} - self.inout_2 = {} - # Practically, these sets simply store the nodes in the subgraph. - - self.state = GMState(self) - - # Provide a convenient way to access the isomorphism mapping. - self.mapping = self.core_1.copy() - - def is_isomorphic(self): - """Returns True if G1 and G2 are isomorphic graphs.""" - - # Let's do two very quick checks! - # QUESTION: Should we call faster_graph_could_be_isomorphic(G1,G2)? - # For now, I just copy the code. - - # Check global properties - if self.G1.order() != self.G2.order(): - return False - - # Check local properties - d1 = sorted(d for n, d in self.G1.degree()) - d2 = sorted(d for n, d in self.G2.degree()) - if d1 != d2: - return False - - try: - x = next(self.isomorphisms_iter()) - return True - except StopIteration: - return False - - def isomorphisms_iter(self): - """Generator over isomorphisms between G1 and G2.""" - # Declare that we are looking for a graph-graph isomorphism. - self.test = 'graph' - self.initialize() - for mapping in self.match(): - yield mapping - - def match(self): - """Extends the isomorphism mapping. - - This function is called recursively to determine if a complete - isomorphism can be found between G1 and G2. It cleans up the class - variables after each recursive call. If an isomorphism is found, - we yield the mapping. - - """ - if len(self.core_1) == len(self.G2): - # Save the final mapping, otherwise garbage collection deletes it. - self.mapping = self.core_1.copy() - # The mapping is complete. - yield self.mapping - else: - for G1_node, G2_node in self.candidate_pairs_iter(): - if self.syntactic_feasibility(G1_node, G2_node): - if self.semantic_feasibility(G1_node, G2_node): - # Recursive call, adding the feasible state. - newstate = self.state.__class__(self, G1_node, G2_node) - for mapping in self.match(): - yield mapping - - # restore data structures - newstate.restore() - - def semantic_feasibility(self, G1_node, G2_node): - """Returns True if adding (G1_node, G2_node) is symantically feasible. - - The semantic feasibility function should return True if it is - acceptable to add the candidate pair (G1_node, G2_node) to the current - partial isomorphism mapping. The logic should focus on semantic - information contained in the edge data or a formalized node class. - - By acceptable, we mean that the subsequent mapping can still become a - complete isomorphism mapping. Thus, if adding the candidate pair - definitely makes it so that the subsequent mapping cannot become a - complete isomorphism mapping, then this function must return False. - - The default semantic feasibility function always returns True. The - effect is that semantics are not considered in the matching of G1 - and G2. - - The semantic checks might differ based on the what type of test is - being performed. A keyword description of the test is stored in - self.test. Here is a quick description of the currently implemented - tests:: - - test='graph' - Indicates that the graph matcher is looking for a graph-graph - isomorphism. - - test='subgraph' - Indicates that the graph matcher is looking for a subgraph-graph - isomorphism such that a subgraph of G1 is isomorphic to G2. - - test='mono' - Indicates that the graph matcher is looking for a subgraph-graph - monomorphism such that a subgraph of G1 is monomorphic to G2. - - Any subclass which redefines semantic_feasibility() must maintain - the above form to keep the match() method functional. Implementations - should consider multigraphs. - """ - return True - - def subgraph_is_isomorphic(self): - """Returns True if a subgraph of G1 is isomorphic to G2.""" - try: - x = next(self.subgraph_isomorphisms_iter()) - return True - except StopIteration: - return False - - def subgraph_is_monomorphic(self): - """Returns True if a subgraph of G1 is monomorphic to G2.""" - try: - x = next(self.subgraph_monomorphisms_iter()) - return True - except StopIteration: - return False - -# subgraph_is_isomorphic.__doc__ += "\n" + subgraph.replace('\n','\n'+indent) - - def subgraph_isomorphisms_iter(self): - """Generator over isomorphisms between a subgraph of G1 and G2.""" - # Declare that we are looking for graph-subgraph isomorphism. - self.test = 'subgraph' - self.initialize() - for mapping in self.match(): - yield mapping - - def subgraph_monomorphisms_iter(self): - """Generator over monomorphisms between a subgraph of G1 and G2.""" - # Declare that we are looking for graph-subgraph monomorphism. - self.test = 'mono' - self.initialize() - for mapping in self.match(): - yield mapping - -# subgraph_isomorphisms_iter.__doc__ += "\n" + subgraph.replace('\n','\n'+indent) - - def syntactic_feasibility(self, G1_node, G2_node): - """Returns True if adding (G1_node, G2_node) is syntactically feasible. - - This function returns True if it is adding the candidate pair - to the current partial isomorphism/monomorphism mapping is allowable. - The addition is allowable if the inclusion of the candidate pair does - not make it impossible for an isomorphism/monomorphism to be found. - """ - - # The VF2 algorithm was designed to work with graphs having, at most, - # one edge connecting any two nodes. This is not the case when - # dealing with an MultiGraphs. - # - # Basically, when we test the look-ahead rules R_neighbor, we will - # make sure that the number of edges are checked. We also add - # a R_self check to verify that the number of selfloops is acceptable. - # - # Users might be comparing Graph instances with MultiGraph instances. - # So the generic GraphMatcher class must work with MultiGraphs. - # Care must be taken since the value in the innermost dictionary is a - # singlet for Graph instances. For MultiGraphs, the value in the - # innermost dictionary is a list. - - ### - # Test at each step to get a return value as soon as possible. - ### - - # Look ahead 0 - - # R_self - - # The number of selfloops for G1_node must equal the number of - # self-loops for G2_node. Without this check, we would fail on - # R_neighbor at the next recursion level. But it is good to prune the - # search tree now. - - if self.test == 'mono': - if self.G1.number_of_edges(G1_node, G1_node) < self.G2.number_of_edges(G2_node, G2_node): - return False - else: - if self.G1.number_of_edges(G1_node, G1_node) != self.G2.number_of_edges(G2_node, G2_node): - return False - - # R_neighbor - - # For each neighbor n' of n in the partial mapping, the corresponding - # node m' is a neighbor of m, and vice versa. Also, the number of - # edges must be equal. - if self.test != 'mono': - for neighbor in self.G1[G1_node]: - if neighbor in self.core_1: - if not (self.core_1[neighbor] in self.G2[G2_node]): - return False - elif self.G1.number_of_edges(neighbor, G1_node) != self.G2.number_of_edges(self.core_1[neighbor], G2_node): - return False - - for neighbor in self.G2[G2_node]: - if neighbor in self.core_2: - if not (self.core_2[neighbor] in self.G1[G1_node]): - return False - elif self.test == 'mono': - if self.G1.number_of_edges(self.core_2[neighbor], G1_node) < self.G2.number_of_edges(neighbor, G2_node): - return False - else: - if self.G1.number_of_edges(self.core_2[neighbor], G1_node) != self.G2.number_of_edges(neighbor, G2_node): - return False - - if self.test != 'mono': - # Look ahead 1 - - # R_terminout - # The number of neighbors of n in T_1^{inout} is equal to the - # number of neighbors of m that are in T_2^{inout}, and vice versa. - num1 = 0 - for neighbor in self.G1[G1_node]: - if (neighbor in self.inout_1) and (neighbor not in self.core_1): - num1 += 1 - num2 = 0 - for neighbor in self.G2[G2_node]: - if (neighbor in self.inout_2) and (neighbor not in self.core_2): - num2 += 1 - if self.test == 'graph': - if not (num1 == num2): - return False - else: # self.test == 'subgraph' - if not (num1 >= num2): - return False - - # Look ahead 2 - - # R_new - - # The number of neighbors of n that are neither in the core_1 nor - # T_1^{inout} is equal to the number of neighbors of m - # that are neither in core_2 nor T_2^{inout}. - num1 = 0 - for neighbor in self.G1[G1_node]: - if neighbor not in self.inout_1: - num1 += 1 - num2 = 0 - for neighbor in self.G2[G2_node]: - if neighbor not in self.inout_2: - num2 += 1 - if self.test == 'graph': - if not (num1 == num2): - return False - else: # self.test == 'subgraph' - if not (num1 >= num2): - return False - - # Otherwise, this node pair is syntactically feasible! - return True - - -class DiGraphMatcher(GraphMatcher): - """Implementation of VF2 algorithm for matching directed graphs. - - Suitable for DiGraph and MultiDiGraph instances. - """ -# __doc__ += "Notes\n%s-----" % (indent,) + sources.replace('\n','\n'+indent) - - def __init__(self, G1, G2): - """Initialize DiGraphMatcher. - - G1 and G2 should be nx.Graph or nx.MultiGraph instances. - - Examples - -------- - To create a GraphMatcher which checks for syntactic feasibility: - - >>> from networkx.algorithms import isomorphism - >>> G1 = nx.DiGraph(nx.path_graph(4, create_using=nx.DiGraph())) - >>> G2 = nx.DiGraph(nx.path_graph(4, create_using=nx.DiGraph())) - >>> DiGM = isomorphism.DiGraphMatcher(G1,G2) - """ - super(DiGraphMatcher, self).__init__(G1, G2) - - def candidate_pairs_iter(self): - """Iterator over candidate pairs of nodes in G1 and G2.""" - - # All computations are done using the current state! - - G1_nodes = self.G1_nodes - G2_nodes = self.G2_nodes - min_key = self.G2_node_order.__getitem__ - - # First we compute the out-terminal sets. - T1_out = [node for node in self.out_1 if node not in self.core_1] - T2_out = [node for node in self.out_2 if node not in self.core_2] - - # If T1_out and T2_out are both nonempty. - # P(s) = T1_out x {min T2_out} - if T1_out and T2_out: - node_2 = min(T2_out, key=min_key) - for node_1 in T1_out: - yield node_1, node_2 - - # If T1_out and T2_out were both empty.... - # We compute the in-terminal sets. - - # elif not (T1_out or T2_out): # as suggested by [2], incorrect - else: # as suggested by [1], correct - T1_in = [node for node in self.in_1 if node not in self.core_1] - T2_in = [node for node in self.in_2 if node not in self.core_2] - - # If T1_in and T2_in are both nonempty. - # P(s) = T1_out x {min T2_out} - if T1_in and T2_in: - node_2 = min(T2_in, key=min_key) - for node_1 in T1_in: - yield node_1, node_2 - - # If all terminal sets are empty... - # P(s) = (N_1 - M_1) x {min (N_2 - M_2)} - - # elif not (T1_in or T2_in): # as suggested by [2], incorrect - else: # as inferred from [1], correct - node_2 = min(G2_nodes - set(self.core_2), key=min_key) - for node_1 in G1_nodes: - if node_1 not in self.core_1: - yield node_1, node_2 - - # For all other cases, we don't have any candidate pairs. - - def initialize(self): - """Reinitializes the state of the algorithm. - - This method should be redefined if using something other than DiGMState. - If only subclassing GraphMatcher, a redefinition is not necessary. - """ - - # core_1[n] contains the index of the node paired with n, which is m, - # provided n is in the mapping. - # core_2[m] contains the index of the node paired with m, which is n, - # provided m is in the mapping. - self.core_1 = {} - self.core_2 = {} - - # See the paper for definitions of M_x and T_x^{y} - - # in_1[n] is non-zero if n is in M_1 or in T_1^{in} - # out_1[n] is non-zero if n is in M_1 or in T_1^{out} - # - # in_2[m] is non-zero if m is in M_2 or in T_2^{in} - # out_2[m] is non-zero if m is in M_2 or in T_2^{out} - # - # The value stored is the depth of the search tree when the node became - # part of the corresponding set. - self.in_1 = {} - self.in_2 = {} - self.out_1 = {} - self.out_2 = {} - - self.state = DiGMState(self) - - # Provide a convenient way to access the isomorphism mapping. - self.mapping = self.core_1.copy() - - def syntactic_feasibility(self, G1_node, G2_node): - """Returns True if adding (G1_node, G2_node) is syntactically feasible. - - This function returns True if it is adding the candidate pair - to the current partial isomorphism/monomorphism mapping is allowable. - The addition is allowable if the inclusion of the candidate pair does - not make it impossible for an isomorphism/monomorphism to be found. - """ - - # The VF2 algorithm was designed to work with graphs having, at most, - # one edge connecting any two nodes. This is not the case when - # dealing with an MultiGraphs. - # - # Basically, when we test the look-ahead rules R_pred and R_succ, we - # will make sure that the number of edges are checked. We also add - # a R_self check to verify that the number of selfloops is acceptable. - - # Users might be comparing DiGraph instances with MultiDiGraph - # instances. So the generic DiGraphMatcher class must work with - # MultiDiGraphs. Care must be taken since the value in the innermost - # dictionary is a singlet for DiGraph instances. For MultiDiGraphs, - # the value in the innermost dictionary is a list. - - ### - # Test at each step to get a return value as soon as possible. - ### - - # Look ahead 0 - - # R_self - - # The number of selfloops for G1_node must equal the number of - # self-loops for G2_node. Without this check, we would fail on R_pred - # at the next recursion level. This should prune the tree even further. - if self.test == 'mono': - if self.G1.number_of_edges(G1_node, G1_node) < self.G2.number_of_edges(G2_node, G2_node): - return False - else: - if self.G1.number_of_edges(G1_node, G1_node) != self.G2.number_of_edges(G2_node, G2_node): - return False - - # R_pred - - # For each predecessor n' of n in the partial mapping, the - # corresponding node m' is a predecessor of m, and vice versa. Also, - # the number of edges must be equal - if self.test != 'mono': - for predecessor in self.G1.pred[G1_node]: - if predecessor in self.core_1: - if not (self.core_1[predecessor] in self.G2.pred[G2_node]): - return False - elif self.G1.number_of_edges(predecessor, G1_node) != self.G2.number_of_edges(self.core_1[predecessor], G2_node): - return False - - for predecessor in self.G2.pred[G2_node]: - if predecessor in self.core_2: - if not (self.core_2[predecessor] in self.G1.pred[G1_node]): - return False - elif self.test == 'mono': - if self.G1.number_of_edges(self.core_2[predecessor], G1_node) < self.G2.number_of_edges(predecessor, G2_node): - return False - else: - if self.G1.number_of_edges(self.core_2[predecessor], G1_node) != self.G2.number_of_edges(predecessor, G2_node): - return False - - # R_succ - - # For each successor n' of n in the partial mapping, the corresponding - # node m' is a successor of m, and vice versa. Also, the number of - # edges must be equal. - if self.test != 'mono': - for successor in self.G1[G1_node]: - if successor in self.core_1: - if not (self.core_1[successor] in self.G2[G2_node]): - return False - elif self.G1.number_of_edges(G1_node, successor) != self.G2.number_of_edges(G2_node, self.core_1[successor]): - return False - - for successor in self.G2[G2_node]: - if successor in self.core_2: - if not (self.core_2[successor] in self.G1[G1_node]): - return False - elif self.test == 'mono': - if self.G1.number_of_edges(G1_node, self.core_2[successor]) < self.G2.number_of_edges(G2_node, successor): - return False - else: - if self.G1.number_of_edges(G1_node, self.core_2[successor]) != self.G2.number_of_edges(G2_node, successor): - return False - - if self.test != 'mono': - - # Look ahead 1 - - # R_termin - # The number of predecessors of n that are in T_1^{in} is equal to the - # number of predecessors of m that are in T_2^{in}. - num1 = 0 - for predecessor in self.G1.pred[G1_node]: - if (predecessor in self.in_1) and (predecessor not in self.core_1): - num1 += 1 - num2 = 0 - for predecessor in self.G2.pred[G2_node]: - if (predecessor in self.in_2) and (predecessor not in self.core_2): - num2 += 1 - if self.test == 'graph': - if not (num1 == num2): - return False - else: # self.test == 'subgraph' - if not (num1 >= num2): - return False - - # The number of successors of n that are in T_1^{in} is equal to the - # number of successors of m that are in T_2^{in}. - num1 = 0 - for successor in self.G1[G1_node]: - if (successor in self.in_1) and (successor not in self.core_1): - num1 += 1 - num2 = 0 - for successor in self.G2[G2_node]: - if (successor in self.in_2) and (successor not in self.core_2): - num2 += 1 - if self.test == 'graph': - if not (num1 == num2): - return False - else: # self.test == 'subgraph' - if not (num1 >= num2): - return False - - # R_termout - - # The number of predecessors of n that are in T_1^{out} is equal to the - # number of predecessors of m that are in T_2^{out}. - num1 = 0 - for predecessor in self.G1.pred[G1_node]: - if (predecessor in self.out_1) and (predecessor not in self.core_1): - num1 += 1 - num2 = 0 - for predecessor in self.G2.pred[G2_node]: - if (predecessor in self.out_2) and (predecessor not in self.core_2): - num2 += 1 - if self.test == 'graph': - if not (num1 == num2): - return False - else: # self.test == 'subgraph' - if not (num1 >= num2): - return False - - # The number of successors of n that are in T_1^{out} is equal to the - # number of successors of m that are in T_2^{out}. - num1 = 0 - for successor in self.G1[G1_node]: - if (successor in self.out_1) and (successor not in self.core_1): - num1 += 1 - num2 = 0 - for successor in self.G2[G2_node]: - if (successor in self.out_2) and (successor not in self.core_2): - num2 += 1 - if self.test == 'graph': - if not (num1 == num2): - return False - else: # self.test == 'subgraph' - if not (num1 >= num2): - return False - - # Look ahead 2 - - # R_new - - # The number of predecessors of n that are neither in the core_1 nor - # T_1^{in} nor T_1^{out} is equal to the number of predecessors of m - # that are neither in core_2 nor T_2^{in} nor T_2^{out}. - num1 = 0 - for predecessor in self.G1.pred[G1_node]: - if (predecessor not in self.in_1) and (predecessor not in self.out_1): - num1 += 1 - num2 = 0 - for predecessor in self.G2.pred[G2_node]: - if (predecessor not in self.in_2) and (predecessor not in self.out_2): - num2 += 1 - if self.test == 'graph': - if not (num1 == num2): - return False - else: # self.test == 'subgraph' - if not (num1 >= num2): - return False - - # The number of successors of n that are neither in the core_1 nor - # T_1^{in} nor T_1^{out} is equal to the number of successors of m - # that are neither in core_2 nor T_2^{in} nor T_2^{out}. - num1 = 0 - for successor in self.G1[G1_node]: - if (successor not in self.in_1) and (successor not in self.out_1): - num1 += 1 - num2 = 0 - for successor in self.G2[G2_node]: - if (successor not in self.in_2) and (successor not in self.out_2): - num2 += 1 - if self.test == 'graph': - if not (num1 == num2): - return False - else: # self.test == 'subgraph' - if not (num1 >= num2): - return False - - # Otherwise, this node pair is syntactically feasible! - return True - - -class GMState(object): - """Internal representation of state for the GraphMatcher class. - - This class is used internally by the GraphMatcher class. It is used - only to store state specific data. There will be at most G2.order() of - these objects in memory at a time, due to the depth-first search - strategy employed by the VF2 algorithm. - """ - - def __init__(self, GM, G1_node=None, G2_node=None): - """Initializes GMState object. - - Pass in the GraphMatcher to which this GMState belongs and the - new node pair that will be added to the GraphMatcher's current - isomorphism mapping. - """ - self.GM = GM - - # Initialize the last stored node pair. - self.G1_node = None - self.G2_node = None - self.depth = len(GM.core_1) - - if G1_node is None or G2_node is None: - # Then we reset the class variables - GM.core_1 = {} - GM.core_2 = {} - GM.inout_1 = {} - GM.inout_2 = {} - - # Watch out! G1_node == 0 should evaluate to True. - if G1_node is not None and G2_node is not None: - # Add the node pair to the isomorphism mapping. - GM.core_1[G1_node] = G2_node - GM.core_2[G2_node] = G1_node - - # Store the node that was added last. - self.G1_node = G1_node - self.G2_node = G2_node - - # Now we must update the other two vectors. - # We will add only if it is not in there already! - self.depth = len(GM.core_1) - - # First we add the new nodes... - if G1_node not in GM.inout_1: - GM.inout_1[G1_node] = self.depth - if G2_node not in GM.inout_2: - GM.inout_2[G2_node] = self.depth - - # Now we add every other node... - - # Updates for T_1^{inout} - new_nodes = set([]) - for node in GM.core_1: - new_nodes.update([neighbor for neighbor in GM.G1[node] if neighbor not in GM.core_1]) - for node in new_nodes: - if node not in GM.inout_1: - GM.inout_1[node] = self.depth - - # Updates for T_2^{inout} - new_nodes = set([]) - for node in GM.core_2: - new_nodes.update([neighbor for neighbor in GM.G2[node] if neighbor not in GM.core_2]) - for node in new_nodes: - if node not in GM.inout_2: - GM.inout_2[node] = self.depth - - def restore(self): - """Deletes the GMState object and restores the class variables.""" - # First we remove the node that was added from the core vectors. - # Watch out! G1_node == 0 should evaluate to True. - if self.G1_node is not None and self.G2_node is not None: - del self.GM.core_1[self.G1_node] - del self.GM.core_2[self.G2_node] - - # Now we revert the other two vectors. - # Thus, we delete all entries which have this depth level. - for vector in (self.GM.inout_1, self.GM.inout_2): - for node in list(vector.keys()): - if vector[node] == self.depth: - del vector[node] - - -class DiGMState(object): - """Internal representation of state for the DiGraphMatcher class. - - This class is used internally by the DiGraphMatcher class. It is used - only to store state specific data. There will be at most G2.order() of - these objects in memory at a time, due to the depth-first search - strategy employed by the VF2 algorithm. - - """ - - def __init__(self, GM, G1_node=None, G2_node=None): - """Initializes DiGMState object. - - Pass in the DiGraphMatcher to which this DiGMState belongs and the - new node pair that will be added to the GraphMatcher's current - isomorphism mapping. - """ - self.GM = GM - - # Initialize the last stored node pair. - self.G1_node = None - self.G2_node = None - self.depth = len(GM.core_1) - - if G1_node is None or G2_node is None: - # Then we reset the class variables - GM.core_1 = {} - GM.core_2 = {} - GM.in_1 = {} - GM.in_2 = {} - GM.out_1 = {} - GM.out_2 = {} - - # Watch out! G1_node == 0 should evaluate to True. - if G1_node is not None and G2_node is not None: - # Add the node pair to the isomorphism mapping. - GM.core_1[G1_node] = G2_node - GM.core_2[G2_node] = G1_node - - # Store the node that was added last. - self.G1_node = G1_node - self.G2_node = G2_node - - # Now we must update the other four vectors. - # We will add only if it is not in there already! - self.depth = len(GM.core_1) - - # First we add the new nodes... - for vector in (GM.in_1, GM.out_1): - if G1_node not in vector: - vector[G1_node] = self.depth - for vector in (GM.in_2, GM.out_2): - if G2_node not in vector: - vector[G2_node] = self.depth - - # Now we add every other node... - - # Updates for T_1^{in} - new_nodes = set([]) - for node in GM.core_1: - new_nodes.update([predecessor for predecessor in GM.G1.predecessors(node) - if predecessor not in GM.core_1]) - for node in new_nodes: - if node not in GM.in_1: - GM.in_1[node] = self.depth - - # Updates for T_2^{in} - new_nodes = set([]) - for node in GM.core_2: - new_nodes.update([predecessor for predecessor in GM.G2.predecessors(node) - if predecessor not in GM.core_2]) - for node in new_nodes: - if node not in GM.in_2: - GM.in_2[node] = self.depth - - # Updates for T_1^{out} - new_nodes = set([]) - for node in GM.core_1: - new_nodes.update([successor for successor in GM.G1.successors(node) if successor not in GM.core_1]) - for node in new_nodes: - if node not in GM.out_1: - GM.out_1[node] = self.depth - - # Updates for T_2^{out} - new_nodes = set([]) - for node in GM.core_2: - new_nodes.update([successor for successor in GM.G2.successors(node) if successor not in GM.core_2]) - for node in new_nodes: - if node not in GM.out_2: - GM.out_2[node] = self.depth - - def restore(self): - """Deletes the DiGMState object and restores the class variables.""" - - # First we remove the node that was added from the core vectors. - # Watch out! G1_node == 0 should evaluate to True. - if self.G1_node is not None and self.G2_node is not None: - del self.GM.core_1[self.G1_node] - del self.GM.core_2[self.G2_node] - - # Now we revert the other four vectors. - # Thus, we delete all entries which have this depth level. - for vector in (self.GM.in_1, self.GM.in_2, self.GM.out_1, self.GM.out_2): - for node in list(vector.keys()): - if vector[node] == self.depth: - del vector[node] diff --git a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/matchhelpers.py b/extensions/fablabchemnitz/networkx/algorithms/isomorphism/matchhelpers.py deleted file mode 100644 index dc20a43f..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/matchhelpers.py +++ /dev/null @@ -1,380 +0,0 @@ -"""Functions which help end users define customize node_match and -edge_match functions to use during isomorphism checks. -""" -from itertools import permutations -import types -import networkx as nx - -__all__ = ['categorical_node_match', - 'categorical_edge_match', - 'categorical_multiedge_match', - 'numerical_node_match', - 'numerical_edge_match', - 'numerical_multiedge_match', - 'generic_node_match', - 'generic_edge_match', - 'generic_multiedge_match', - ] - - -def copyfunc(f, name=None): - """Returns a deepcopy of a function.""" - try: - # Python <3 - return types.FunctionType(f.func_code, f.func_globals, - name or f.__name__, f.func_defaults, - f.func_closure) - except AttributeError: - # Python >=3 - return types.FunctionType(f.__code__, f.__globals__, - name or f.__name__, f.__defaults__, - f.__closure__) - - -def allclose(x, y, rtol=1.0000000000000001e-05, atol=1e-08): - """Returns True if x and y are sufficiently close, elementwise. - - Parameters - ---------- - rtol : float - The relative error tolerance. - atol : float - The absolute error tolerance. - - """ - # assume finite weights, see numpy.allclose() for reference - for xi, yi in zip(x, y): - if not (abs(xi - yi) <= atol + rtol * abs(yi)): - return False - return True - - -def close(x, y, rtol=1.0000000000000001e-05, atol=1e-08): - """Returns True if x and y are sufficiently close. - - Parameters - ---------- - rtol : float - The relative error tolerance. - atol : float - The absolute error tolerance. - - """ - # assume finite weights, see numpy.allclose() for reference - return abs(x - y) <= atol + rtol * abs(y) - - -categorical_doc = """ -Returns a comparison function for a categorical node attribute. - -The value(s) of the attr(s) must be hashable and comparable via the == -operator since they are placed into a set([]) object. If the sets from -G1 and G2 are the same, then the constructed function returns True. - -Parameters ----------- -attr : string | list - The categorical node attribute to compare, or a list of categorical - node attributes to compare. -default : value | list - The default value for the categorical node attribute, or a list of - default values for the categorical node attributes. - -Returns -------- -match : function - The customized, categorical `node_match` function. - -Examples --------- ->>> import networkx.algorithms.isomorphism as iso ->>> nm = iso.categorical_node_match('size', 1) ->>> nm = iso.categorical_node_match(['color', 'size'], ['red', 2]) - -""" - - -def categorical_node_match(attr, default): - if nx.utils.is_string_like(attr): - def match(data1, data2): - return data1.get(attr, default) == data2.get(attr, default) - else: - attrs = list(zip(attr, default)) # Python 3 - - def match(data1, data2): - return all(data1.get(attr, d) == data2.get(attr, d) for attr, d in attrs) - return match - - -try: - categorical_edge_match = copyfunc(categorical_node_match, 'categorical_edge_match') -except NotImplementedError: - # IronPython lacks support for types.FunctionType. - # https://github.com/networkx/networkx/issues/949 - # https://github.com/networkx/networkx/issues/1127 - def categorical_edge_match(*args, **kwargs): - return categorical_node_match(*args, **kwargs) - - -def categorical_multiedge_match(attr, default): - if nx.utils.is_string_like(attr): - def match(datasets1, datasets2): - values1 = set([data.get(attr, default) for data in datasets1.values()]) - values2 = set([data.get(attr, default) for data in datasets2.values()]) - return values1 == values2 - else: - attrs = list(zip(attr, default)) # Python 3 - - def match(datasets1, datasets2): - values1 = set([]) - for data1 in datasets1.values(): - x = tuple(data1.get(attr, d) for attr, d in attrs) - values1.add(x) - values2 = set([]) - for data2 in datasets2.values(): - x = tuple(data2.get(attr, d) for attr, d in attrs) - values2.add(x) - return values1 == values2 - return match - - -# Docstrings for categorical functions. -categorical_node_match.__doc__ = categorical_doc -categorical_edge_match.__doc__ = categorical_doc.replace('node', 'edge') -tmpdoc = categorical_doc.replace('node', 'edge') -tmpdoc = tmpdoc.replace('categorical_edge_match', 'categorical_multiedge_match') -categorical_multiedge_match.__doc__ = tmpdoc - - -numerical_doc = """ -Returns a comparison function for a numerical node attribute. - -The value(s) of the attr(s) must be numerical and sortable. If the -sorted list of values from G1 and G2 are the same within some -tolerance, then the constructed function returns True. - -Parameters ----------- -attr : string | list - The numerical node attribute to compare, or a list of numerical - node attributes to compare. -default : value | list - The default value for the numerical node attribute, or a list of - default values for the numerical node attributes. -rtol : float - The relative error tolerance. -atol : float - The absolute error tolerance. - -Returns -------- -match : function - The customized, numerical `node_match` function. - -Examples --------- ->>> import networkx.algorithms.isomorphism as iso ->>> nm = iso.numerical_node_match('weight', 1.0) ->>> nm = iso.numerical_node_match(['weight', 'linewidth'], [.25, .5]) - -""" - - -def numerical_node_match(attr, default, rtol=1.0000000000000001e-05, atol=1e-08): - if nx.utils.is_string_like(attr): - def match(data1, data2): - return close(data1.get(attr, default), - data2.get(attr, default), - rtol=rtol, atol=atol) - else: - attrs = list(zip(attr, default)) # Python 3 - - def match(data1, data2): - values1 = [data1.get(attr, d) for attr, d in attrs] - values2 = [data2.get(attr, d) for attr, d in attrs] - return allclose(values1, values2, rtol=rtol, atol=atol) - return match - - -try: - numerical_edge_match = copyfunc(numerical_node_match, 'numerical_edge_match') -except NotImplementedError: - # IronPython lacks support for types.FunctionType. - # https://github.com/networkx/networkx/issues/949 - # https://github.com/networkx/networkx/issues/1127 - def numerical_edge_match(*args, **kwargs): - return numerical_node_match(*args, **kwargs) - - -def numerical_multiedge_match(attr, default, rtol=1.0000000000000001e-05, atol=1e-08): - if nx.utils.is_string_like(attr): - def match(datasets1, datasets2): - values1 = sorted([data.get(attr, default) for data in datasets1.values()]) - values2 = sorted([data.get(attr, default) for data in datasets2.values()]) - return allclose(values1, values2, rtol=rtol, atol=atol) - else: - attrs = list(zip(attr, default)) # Python 3 - - def match(datasets1, datasets2): - values1 = [] - for data1 in datasets1.values(): - x = tuple(data1.get(attr, d) for attr, d in attrs) - values1.append(x) - values2 = [] - for data2 in datasets2.values(): - x = tuple(data2.get(attr, d) for attr, d in attrs) - values2.append(x) - values1.sort() - values2.sort() - for xi, yi in zip(values1, values2): - if not allclose(xi, yi, rtol=rtol, atol=atol): - return False - else: - return True - return match - - -# Docstrings for numerical functions. -numerical_node_match.__doc__ = numerical_doc -numerical_edge_match.__doc__ = numerical_doc.replace('node', 'edge') -tmpdoc = numerical_doc.replace('node', 'edge') -tmpdoc = tmpdoc.replace('numerical_edge_match', 'numerical_multiedge_match') -numerical_multiedge_match.__doc__ = tmpdoc - - -generic_doc = """ -Returns a comparison function for a generic attribute. - -The value(s) of the attr(s) are compared using the specified -operators. If all the attributes are equal, then the constructed -function returns True. - -Parameters ----------- -attr : string | list - The node attribute to compare, or a list of node attributes - to compare. -default : value | list - The default value for the node attribute, or a list of - default values for the node attributes. -op : callable | list - The operator to use when comparing attribute values, or a list - of operators to use when comparing values for each attribute. - -Returns -------- -match : function - The customized, generic `node_match` function. - -Examples --------- ->>> from operator import eq ->>> from networkx.algorithms.isomorphism.matchhelpers import close ->>> from networkx.algorithms.isomorphism import generic_node_match ->>> nm = generic_node_match('weight', 1.0, close) ->>> nm = generic_node_match('color', 'red', eq) ->>> nm = generic_node_match(['weight', 'color'], [1.0, 'red'], [close, eq]) - -""" - - -def generic_node_match(attr, default, op): - if nx.utils.is_string_like(attr): - def match(data1, data2): - return op(data1.get(attr, default), data2.get(attr, default)) - else: - attrs = list(zip(attr, default, op)) # Python 3 - - def match(data1, data2): - for attr, d, operator in attrs: - if not operator(data1.get(attr, d), data2.get(attr, d)): - return False - else: - return True - return match - - -try: - generic_edge_match = copyfunc(generic_node_match, 'generic_edge_match') -except NotImplementedError: - # IronPython lacks support for types.FunctionType. - # https://github.com/networkx/networkx/issues/949 - # https://github.com/networkx/networkx/issues/1127 - def generic_edge_match(*args, **kwargs): - return generic_node_match(*args, **kwargs) - - -def generic_multiedge_match(attr, default, op): - """Returns a comparison function for a generic attribute. - - The value(s) of the attr(s) are compared using the specified - operators. If all the attributes are equal, then the constructed - function returns True. Potentially, the constructed edge_match - function can be slow since it must verify that no isomorphism - exists between the multiedges before it returns False. - - Parameters - ---------- - attr : string | list - The edge attribute to compare, or a list of node attributes - to compare. - default : value | list - The default value for the edge attribute, or a list of - default values for the dgeattributes. - op : callable | list - The operator to use when comparing attribute values, or a list - of operators to use when comparing values for each attribute. - - Returns - ------- - match : function - The customized, generic `edge_match` function. - - Examples - -------- - >>> from operator import eq - >>> from networkx.algorithms.isomorphism.matchhelpers import close - >>> from networkx.algorithms.isomorphism import generic_node_match - >>> nm = generic_node_match('weight', 1.0, close) - >>> nm = generic_node_match('color', 'red', eq) - >>> nm = generic_node_match(['weight', 'color'], - ... [1.0, 'red'], - ... [close, eq]) - ... - - """ - - # This is slow, but generic. - # We must test every possible isomorphism between the edges. - if nx.utils.is_string_like(attr): - attr = [attr] - default = [default] - op = [op] - attrs = list(zip(attr, default)) # Python 3 - - def match(datasets1, datasets2): - values1 = [] - for data1 in datasets1.values(): - x = tuple(data1.get(attr, d) for attr, d in attrs) - values1.append(x) - values2 = [] - for data2 in datasets2.values(): - x = tuple(data2.get(attr, d) for attr, d in attrs) - values2.append(x) - for vals2 in permutations(values2): - for xi, yi in zip(values1, vals2): - if not all(map(lambda x, y, z: z(x, y), xi, yi, op)): - # This is not an isomorphism, go to next permutation. - break - else: - # Then we found an isomorphism. - return True - else: - # Then there are no isomorphisms between the multiedges. - return False - return match - - -# Docstrings for numerical functions. -generic_node_match.__doc__ = generic_doc -generic_edge_match.__doc__ = generic_doc.replace('node', 'edge') diff --git a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/temporalisomorphvf2.py b/extensions/fablabchemnitz/networkx/algorithms/isomorphism/temporalisomorphvf2.py deleted file mode 100644 index 940497d2..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/temporalisomorphvf2.py +++ /dev/null @@ -1,269 +0,0 @@ -# -*- coding: utf-8 -*- -""" -***************************** -Time-respecting VF2 Algorithm -***************************** - -An extension of the VF2 algorithm for time-respecting graph ismorphism -testing in temporal graphs. - -A temporal graph is one in which edges contain a datetime attribute, -denoting when interaction occurred between the incident nodes. A -time-respecting subgraph of a temporal graph is a subgraph such that -all interactions incident to a node occurred within a time threshold, -delta, of each other. A directed time-respecting subgraph has the -added constraint that incoming interactions to a node must precede -outgoing interactions from the same node - this enforces a sense of -directed flow. - -Introduction ------------- - -The TimeRespectingGraphMatcher and TimeRespectingDiGraphMatcher -extend the GraphMatcher and DiGraphMatcher classes, respectively, -to include temporal constraints on matches. This is achieved through -a semantic check, via the semantic_feasibility() function. - -As well as including G1 (the graph in which to seek embeddings) and -G2 (the subgraph structure of interest), the name of the temporal -attribute on the edges and the time threshold, delta, must be supplied -as arguments to the matching constructors. - -A delta of zero is the strictest temporal constraint on the match - -only embeddings in which all interactions occur at the same time will -be returned. A delta of one day will allow embeddings in which -adjacent interactions occur up to a day apart. - -Examples --------- - -Examples will be provided when the datetime type has been incorporated. - - -Temporal Subgraph Isomorphism ------------------------------ - -A brief discussion of the somewhat diverse current literature will be -included here. - -References ----------- - -[1] Redmond, U. and Cunningham, P. Temporal subgraph isomorphism. In: -The 2013 IEEE/ACM International Conference on Advances in Social -Networks Analysis and Mining (ASONAM). Niagara Falls, Canada; 2013: -pages 1451 - 1452. [65] - -For a discussion of the literature on temporal networks: - -[3] P. Holme and J. Saramaki. Temporal networks. Physics Reports, -519(3):97–125, 2012. - -Notes ------ - -Handles directed and undirected graphs and graphs with parallel edges. - -""" - -import networkx as nx -from datetime import datetime, timedelta -from .isomorphvf2 import GraphMatcher, DiGraphMatcher - -__all__ = ['TimeRespectingGraphMatcher', - 'TimeRespectingDiGraphMatcher'] - - -class TimeRespectingGraphMatcher(GraphMatcher): - - def __init__(self, G1, G2, temporal_attribute_name, delta): - """Initialize TimeRespectingGraphMatcher. - - G1 and G2 should be nx.Graph or nx.MultiGraph instances. - - Examples - -------- - To create a TimeRespectingGraphMatcher which checks for - syntactic and semantic feasibility: - - >>> from networkx.algorithms import isomorphism - >>> G1 = nx.Graph(nx.path_graph(4, create_using=nx.Graph())) - - >>> G2 = nx.Graph(nx.path_graph(4, create_using=nx.Graph())) - - >>> GM = isomorphism.TimeRespectingGraphMatcher(G1, G2, 'date', timedelta(days=1)) - """ - self.temporal_attribute_name = temporal_attribute_name - self.delta = delta - super(TimeRespectingGraphMatcher, self).__init__(G1, G2) - - def one_hop(self, Gx, Gx_node, neighbors): - """ - Edges one hop out from a node in the mapping should be - time-respecting with respect to each other. - """ - dates = [] - for n in neighbors: - if type(Gx) == type(nx.Graph()): # Graph G[u][v] returns the data dictionary. - dates.append(Gx[Gx_node][n][self.temporal_attribute_name]) - else: # MultiGraph G[u][v] returns a dictionary of key -> data dictionary. - for edge in Gx[Gx_node][n].values(): # Iterates all edges between node pair. - dates.append(edge[self.temporal_attribute_name]) - if any(x is None for x in dates): - raise ValueError('Datetime not supplied for at least one edge.') - return not dates or max(dates) - min(dates) <= self.delta - - def two_hop(self, Gx, core_x, Gx_node, neighbors): - """ - Paths of length 2 from Gx_node should be time-respecting. - """ - return all(self.one_hop(Gx, v, [n for n in Gx[v] if n in core_x] + [Gx_node]) for v in neighbors) - - def semantic_feasibility(self, G1_node, G2_node): - """Returns True if adding (G1_node, G2_node) is semantically - feasible. - - Any subclass which redefines semantic_feasibility() must - maintain the self.tests if needed, to keep the match() method - functional. Implementations should consider multigraphs. - """ - neighbors = [n for n in self.G1[G1_node] if n in self.core_1] - if not self.one_hop(self.G1, G1_node, neighbors): # Fail fast on first node. - return False - if not self.two_hop(self.G1, self.core_1, G1_node, neighbors): - return False - # Otherwise, this node is semantically feasible! - return True - - -class TimeRespectingDiGraphMatcher(DiGraphMatcher): - - def __init__(self, G1, G2, temporal_attribute_name, delta): - """Initialize TimeRespectingDiGraphMatcher. - - G1 and G2 should be nx.DiGraph or nx.MultiDiGraph instances. - - Examples - -------- - To create a TimeRespectingDiGraphMatcher which checks for - syntactic and semantic feasibility: - - >>> from networkx.algorithms import isomorphism - >>> G1 = nx.DiGraph(nx.path_graph(4, create_using=nx.DiGraph())) - - >>> G2 = nx.DiGraph(nx.path_graph(4, create_using=nx.DiGraph())) - - >>> GM = isomorphism.TimeRespectingDiGraphMatcher(G1, G2, 'date', timedelta(days=1)) - """ - self.temporal_attribute_name = temporal_attribute_name - self.delta = delta - super(TimeRespectingDiGraphMatcher, self).__init__(G1, G2) - - def get_pred_dates(self, Gx, Gx_node, core_x, pred): - """ - Get the dates of edges from predecessors. - """ - pred_dates = [] - if type(Gx) == type(nx.DiGraph()): # Graph G[u][v] returns the data dictionary. - for n in pred: - pred_dates.append(Gx[n][Gx_node][self.temporal_attribute_name]) - else: # MultiGraph G[u][v] returns a dictionary of key -> data dictionary. - for n in pred: - for edge in Gx[n][Gx_node].values(): # Iterates all edge data between node pair. - pred_dates.append(edge[self.temporal_attribute_name]) - return pred_dates - - def get_succ_dates(self, Gx, Gx_node, core_x, succ): - """ - Get the dates of edges to successors. - """ - succ_dates = [] - if type(Gx) == type(nx.DiGraph()): # Graph G[u][v] returns the data dictionary. - for n in succ: - succ_dates.append(Gx[Gx_node][n][self.temporal_attribute_name]) - else: # MultiGraph G[u][v] returns a dictionary of key -> data dictionary. - for n in succ: - for edge in Gx[Gx_node][n].values(): # Iterates all edge data between node pair. - succ_dates.append(edge[self.temporal_attribute_name]) - return succ_dates - - def one_hop(self, Gx, Gx_node, core_x, pred, succ): - """ - The ego node. - """ - pred_dates = self.get_pred_dates(Gx, Gx_node, core_x, pred) - succ_dates = self.get_succ_dates(Gx, Gx_node, core_x, succ) - return self.test_one(pred_dates, succ_dates) and self.test_two(pred_dates, succ_dates) - - def two_hop_pred(self, Gx, Gx_node, core_x, pred): - """ - The predeccessors of the ego node. - """ - return all(self.one_hop(Gx, p, core_x, self.preds(Gx, core_x, p), self.succs(Gx, core_x, p, Gx_node)) for p in pred) - - def two_hop_succ(self, Gx, Gx_node, core_x, succ): - """ - The successors of the ego node. - """ - return all(self.one_hop(Gx, s, core_x, self.preds(Gx, core_x, s, Gx_node), self.succs(Gx, core_x, s)) for s in succ) - - def preds(self, Gx, core_x, v, Gx_node=None): - pred = [n for n in Gx.predecessors(v) if n in core_x] - if Gx_node: - pred.append(Gx_node) - return pred - - def succs(self, Gx, core_x, v, Gx_node=None): - succ = [n for n in Gx.successors(v) if n in core_x] - if Gx_node: - succ.append(Gx_node) - return succ - - def test_one(self, pred_dates, succ_dates): - """ - Edges one hop out from Gx_node in the mapping should be - time-respecting with respect to each other, regardless of - direction. - """ - time_respecting = True - dates = pred_dates + succ_dates - - if any(x is None for x in dates): - raise ValueError('Date or datetime not supplied for at least one edge.') - - dates.sort() # Small to large. - if 0 < len(dates) and not (dates[-1] - dates[0] <= self.delta): - time_respecting = False - return time_respecting - - def test_two(self, pred_dates, succ_dates): - """ - Edges from a dual Gx_node in the mapping should be ordered in - a time-respecting manner. - """ - time_respecting = True - pred_dates.sort() - succ_dates.sort() - # First out before last in; negative of the necessary condition for time-respect. - if 0 < len(succ_dates) and 0 < len(pred_dates) and succ_dates[0] < pred_dates[-1]: - time_respecting = False - return time_respecting - - def semantic_feasibility(self, G1_node, G2_node): - """Returns True if adding (G1_node, G2_node) is semantically - feasible. - - Any subclass which redefines semantic_feasibility() must - maintain the self.tests if needed, to keep the match() method - functional. Implementations should consider multigraphs. - """ - pred, succ = [n for n in self.G1.predecessors(G1_node) if n in self.core_1], [ - n for n in self.G1.successors(G1_node) if n in self.core_1] - if not self.one_hop(self.G1, G1_node, self.core_1, pred, succ): # Fail fast on first node. - return False - if not self.two_hop_pred(self.G1, G1_node, self.core_1, pred): - return False - if not self.two_hop_succ(self.G1, G1_node, self.core_1, succ): - return False - # Otherwise, this node is semantically feasible! - return True diff --git a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/iso_r01_s80.A99 b/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/iso_r01_s80.A99 deleted file mode 100644 index dac54f00..00000000 Binary files a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/iso_r01_s80.A99 and /dev/null differ diff --git a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/iso_r01_s80.B99 b/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/iso_r01_s80.B99 deleted file mode 100644 index 6c6af680..00000000 Binary files a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/iso_r01_s80.B99 and /dev/null differ diff --git a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/si2_b06_m200.A99 b/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/si2_b06_m200.A99 deleted file mode 100644 index 60c3a3ce..00000000 Binary files a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/si2_b06_m200.A99 and /dev/null differ diff --git a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/si2_b06_m200.B99 b/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/si2_b06_m200.B99 deleted file mode 100644 index 02368720..00000000 Binary files a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/si2_b06_m200.B99 and /dev/null differ diff --git a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/test_ismags.py b/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/test_ismags.py deleted file mode 100644 index 5999210b..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/test_ismags.py +++ /dev/null @@ -1,271 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" - Tests for ISMAGS isomorphism algorithm. -""" - -import pytest -import networkx as nx -from networkx.algorithms import isomorphism as iso - - -def _matches_to_sets(matches): - """ - Helper function to facilitate comparing collections of dictionaries in - which order does not matter. - """ - return set(map(lambda m: frozenset(m.items()), matches)) - - -class TestSelfIsomorphism(object): - data = [ - ( - [(0, dict(name='a')), - (1, dict(name='a')), - (2, dict(name='b')), - (3, dict(name='b')), - (4, dict(name='a')), - (5, dict(name='a'))], - [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)] - ), - ( - range(1, 5), - [(1, 2), (2, 4), (4, 3), (3, 1)] - ), - ( - [], - [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 0), (0, 6), (6, 7), - (2, 8), (8, 9), (4, 10), (10, 11)] - ), - ( - [], - [(0, 1), (1, 2), (1, 4), (2, 3), (3, 5), (3, 6)] - ), - ] - - def test_self_isomorphism(self): - """ - For some small, symmetric graphs, make sure that 1) they are isomorphic - to themselves, and 2) that only the identity mapping is found. - """ - for node_data, edge_data in self.data: - graph = nx.Graph() - graph.add_nodes_from(node_data) - graph.add_edges_from(edge_data) - - ismags = iso.ISMAGS(graph, graph, node_match=iso.categorical_node_match('name', None)) - assert ismags.is_isomorphic() - assert ismags.subgraph_is_isomorphic() - assert (list(ismags.subgraph_isomorphisms_iter(symmetry=True)) == - [{n: n for n in graph.nodes}]) - - def test_edgecase_self_isomorphism(self): - """ - This edgecase is one of the cases in which it is hard to find all - symmetry elements. - """ - graph = nx.Graph() - nx.add_path(graph, range(5)) - graph.add_edges_from([(2, 5), (5, 6)]) - - ismags = iso.ISMAGS(graph, graph) - ismags_answer = list(ismags.find_isomorphisms(True)) - assert ismags_answer == [{n: n for n in graph.nodes}] - - graph = nx.relabel_nodes(graph, {0: 0, 1: 1, 2: 2, 3: 3, 4: 6, 5: 4, 6: 5}) - ismags = iso.ISMAGS(graph, graph) - ismags_answer = list(ismags.find_isomorphisms(True)) - assert ismags_answer == [{n: n for n in graph.nodes}] - - @pytest.mark.skip() - def test_directed_self_isomorphism(self): - """ - For some small, directed, symmetric graphs, make sure that 1) they are - isomorphic to themselves, and 2) that only the identity mapping is - found. - """ - for node_data, edge_data in self.data: - graph = nx.Graph() - graph.add_nodes_from(node_data) - graph.add_edges_from(edge_data) - - ismags = iso.ISMAGS(graph, graph, node_match=iso.categorical_node_match('name', None)) - assert ismags.is_isomorphic() - assert ismags.subgraph_is_isomorphic() - assert (list(ismags.subgraph_isomorphisms_iter(symmetry=True)) == - [{n: n for n in graph.nodes}]) - - -class TestSubgraphIsomorphism(object): - def test_isomorphism(self): - g1 = nx.Graph() - nx.add_cycle(g1, range(4)) - - g2 = nx.Graph() - nx.add_cycle(g2, range(4)) - g2.add_edges_from([(n, m) for n, m in zip(g2, range(4, 8))]) - ismags = iso.ISMAGS(g2, g1) - assert (list(ismags.subgraph_isomorphisms_iter(symmetry=True)) == - [{n: n for n in g1.nodes}]) - - def test_isomorphism2(self): - g1 = nx.Graph() - nx.add_path(g1, range(3)) - - g2 = g1.copy() - g2.add_edge(1, 3) - - ismags = iso.ISMAGS(g2, g1) - matches = ismags.subgraph_isomorphisms_iter(symmetry=True) - expected_symmetric = [{0: 0, 1: 1, 2: 2}, - {0: 0, 1: 1, 3: 2}, - {2: 0, 1: 1, 3: 2}] - assert (_matches_to_sets(matches) == - _matches_to_sets(expected_symmetric)) - - matches = ismags.subgraph_isomorphisms_iter(symmetry=False) - expected_asymmetric = [{0: 2, 1: 1, 2: 0}, - {0: 2, 1: 1, 3: 0}, - {2: 2, 1: 1, 3: 0}] - assert (_matches_to_sets(matches) == - _matches_to_sets(expected_symmetric + expected_asymmetric)) - - def test_labeled_nodes(self): - g1 = nx.Graph() - nx.add_cycle(g1, range(3)) - g1.nodes[1]['attr'] = True - - g2 = g1.copy() - g2.add_edge(1, 3) - ismags = iso.ISMAGS(g2, g1, node_match=lambda x, y: x == y) - matches = ismags.subgraph_isomorphisms_iter(symmetry=True) - expected_symmetric = [{0: 0, 1: 1, 2: 2}] - assert (_matches_to_sets(matches) == - _matches_to_sets(expected_symmetric)) - - matches = ismags.subgraph_isomorphisms_iter(symmetry=False) - expected_asymmetric = [{0: 2, 1: 1, 2: 0}] - assert (_matches_to_sets(matches) == - _matches_to_sets(expected_symmetric + expected_asymmetric)) - - def test_labeled_edges(self): - g1 = nx.Graph() - nx.add_cycle(g1, range(3)) - g1.edges[1, 2]['attr'] = True - - g2 = g1.copy() - g2.add_edge(1, 3) - ismags = iso.ISMAGS(g2, g1, edge_match=lambda x, y: x == y) - matches = ismags.subgraph_isomorphisms_iter(symmetry=True) - expected_symmetric = [{0: 0, 1: 1, 2: 2}] - assert (_matches_to_sets(matches) == - _matches_to_sets(expected_symmetric)) - - matches = ismags.subgraph_isomorphisms_iter(symmetry=False) - expected_asymmetric = [{1: 2, 0: 0, 2: 1}] - assert (_matches_to_sets(matches) == - _matches_to_sets(expected_symmetric + expected_asymmetric)) - - -class TestWikipediaExample(object): - # Nodes 'a', 'b', 'c' and 'd' form a column. - # Nodes 'g', 'h', 'i' and 'j' form a column. - g1edges = [['a', 'g'], ['a', 'h'], ['a', 'i'], - ['b', 'g'], ['b', 'h'], ['b', 'j'], - ['c', 'g'], ['c', 'i'], ['c', 'j'], - ['d', 'h'], ['d', 'i'], ['d', 'j']] - - # Nodes 1,2,3,4 form the clockwise corners of a large square. - # Nodes 5,6,7,8 form the clockwise corners of a small square - g2edges = [[1, 2], [2, 3], [3, 4], [4, 1], - [5, 6], [6, 7], [7, 8], [8, 5], - [1, 5], [2, 6], [3, 7], [4, 8]] - - def test_graph(self): - g1 = nx.Graph() - g2 = nx.Graph() - g1.add_edges_from(self.g1edges) - g2.add_edges_from(self.g2edges) - gm = iso.ISMAGS(g1, g2) - assert gm.is_isomorphic() - - -class TestLargestCommonSubgraph(object): - def test_mcis(self): - # Example graphs from DOI: 10.1002/spe.588 - graph1 = nx.Graph() - graph1.add_edges_from([(1, 2), (2, 3), (2, 4), (3, 4), (4, 5)]) - graph1.nodes[1]['color'] = 0 - - graph2 = nx.Graph() - graph2.add_edges_from([(1, 2), (2, 3), (2, 4), (3, 4), (3, 5), - (5, 6), (5, 7), (6, 7)]) - graph2.nodes[1]['color'] = 1 - graph2.nodes[6]['color'] = 2 - graph2.nodes[7]['color'] = 2 - - ismags = iso.ISMAGS(graph1, graph2, node_match=iso.categorical_node_match('color', None)) - assert list(ismags.subgraph_isomorphisms_iter(True)) == [] - assert list(ismags.subgraph_isomorphisms_iter(False)) == [] - found_mcis = _matches_to_sets(ismags.largest_common_subgraph()) - expected = _matches_to_sets([{2: 2, 3: 4, 4: 3, 5: 5}, - {2: 4, 3: 2, 4: 3, 5: 5}]) - assert expected == found_mcis - - ismags = iso.ISMAGS(graph2, graph1, node_match=iso.categorical_node_match('color', None)) - assert list(ismags.subgraph_isomorphisms_iter(True)) == [] - assert list(ismags.subgraph_isomorphisms_iter(False)) == [] - found_mcis = _matches_to_sets(ismags.largest_common_subgraph()) - # Same answer, but reversed. - expected = _matches_to_sets([{2: 2, 3: 4, 4: 3, 5: 5}, - {4: 2, 2: 3, 3: 4, 5: 5}]) - assert expected == found_mcis - - def test_symmetry_mcis(self): - graph1 = nx.Graph() - nx.add_path(graph1, range(4)) - - graph2 = nx.Graph() - nx.add_path(graph2, range(3)) - graph2.add_edge(1, 3) - - # Only the symmetry of graph2 is taken into account here. - ismags1 = iso.ISMAGS(graph1, graph2, node_match=iso.categorical_node_match('color', None)) - assert list(ismags1.subgraph_isomorphisms_iter(True)) == [] - found_mcis = _matches_to_sets(ismags1.largest_common_subgraph()) - expected = _matches_to_sets([{0: 0, 1: 1, 2: 2}, - {1: 0, 3: 2, 2: 1}]) - assert expected == found_mcis - - # Only the symmetry of graph1 is taken into account here. - ismags2 = iso.ISMAGS(graph2, graph1, node_match=iso.categorical_node_match('color', None)) - assert list(ismags2.subgraph_isomorphisms_iter(True)) == [] - found_mcis = _matches_to_sets(ismags2.largest_common_subgraph()) - expected = _matches_to_sets([{3: 2, 0: 0, 1: 1}, - {2: 0, 0: 2, 1: 1}, - {3: 0, 0: 2, 1: 1}, - {3: 0, 1: 1, 2: 2}, - {0: 0, 1: 1, 2: 2}, - {2: 0, 3: 2, 1: 1}]) - - assert expected == found_mcis - - found_mcis1 = _matches_to_sets(ismags1.largest_common_subgraph(False)) - found_mcis2 = ismags2.largest_common_subgraph(False) - found_mcis2 = [{v: k for k, v in d.items()} for d in found_mcis2] - found_mcis2 = _matches_to_sets(found_mcis2) - - expected = _matches_to_sets([{3: 2, 1: 3, 2: 1}, - {2: 0, 0: 2, 1: 1}, - {1: 2, 3: 3, 2: 1}, - {3: 0, 1: 3, 2: 1}, - {0: 2, 2: 3, 1: 1}, - {3: 0, 1: 2, 2: 1}, - {2: 0, 0: 3, 1: 1}, - {0: 0, 2: 3, 1: 1}, - {1: 0, 3: 3, 2: 1}, - {1: 0, 3: 2, 2: 1}, - {0: 3, 1: 1, 2: 2}, - {0: 0, 1: 1, 2: 2}]) - assert expected == found_mcis1 - assert expected == found_mcis2 diff --git a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/test_isomorphism.py b/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/test_isomorphism.py deleted file mode 100644 index e82fac76..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/test_isomorphism.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python -import networkx as nx -from networkx.algorithms import isomorphism as iso - - -class TestIsomorph: - - @classmethod - def setup_class(cls): - cls.G1 = nx.Graph() - cls.G2 = nx.Graph() - cls.G3 = nx.Graph() - cls.G4 = nx.Graph() - cls.G1.add_edges_from([[1, 2], [1, 3], [1, 5], [2, 3]]) - cls.G2.add_edges_from([[10, 20], [20, 30], [10, 30], [10, 50]]) - cls.G3.add_edges_from([[1, 2], [1, 3], [1, 5], [2, 5]]) - cls.G4.add_edges_from([[1, 2], [1, 3], [1, 5], [2, 4]]) - - def test_could_be_isomorphic(self): - assert iso.could_be_isomorphic(self.G1, self.G2) - assert iso.could_be_isomorphic(self.G1, self.G3) - assert not iso.could_be_isomorphic(self.G1, self.G4) - assert iso.could_be_isomorphic(self.G3, self.G2) - - def test_fast_could_be_isomorphic(self): - assert iso.fast_could_be_isomorphic(self.G3, self.G2) - - def test_faster_could_be_isomorphic(self): - assert iso.faster_could_be_isomorphic(self.G3, self.G2) - - def test_is_isomorphic(self): - assert iso.is_isomorphic(self.G1, self.G2) - assert not iso.is_isomorphic(self.G1, self.G4) diff --git a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/test_isomorphvf2.py b/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/test_isomorphvf2.py deleted file mode 100644 index 788cc913..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/isomorphism/tests/test_isomorphvf2.py +++ /dev/null @@ -1,320 +0,0 @@ -""" - Tests for VF2 isomorphism algorithm. -""" - -import os -import struct -import random - -import pytest -import networkx as nx -from networkx.algorithms import isomorphism as iso - - -class TestWikipediaExample(object): - # Source: https://en.wikipedia.org/wiki/Graph_isomorphism - - # Nodes 'a', 'b', 'c' and 'd' form a column. - # Nodes 'g', 'h', 'i' and 'j' form a column. - g1edges = [['a', 'g'], ['a', 'h'], ['a', 'i'], - ['b', 'g'], ['b', 'h'], ['b', 'j'], - ['c', 'g'], ['c', 'i'], ['c', 'j'], - ['d', 'h'], ['d', 'i'], ['d', 'j']] - - # Nodes 1,2,3,4 form the clockwise corners of a large square. - # Nodes 5,6,7,8 form the clockwise corners of a small square - g2edges = [[1, 2], [2, 3], [3, 4], [4, 1], - [5, 6], [6, 7], [7, 8], [8, 5], - [1, 5], [2, 6], [3, 7], [4, 8]] - - def test_graph(self): - g1 = nx.Graph() - g2 = nx.Graph() - g1.add_edges_from(self.g1edges) - g2.add_edges_from(self.g2edges) - gm = iso.GraphMatcher(g1, g2) - assert gm.is_isomorphic() - #Just testing some cases - assert gm.subgraph_is_monomorphic() - - mapping = sorted(gm.mapping.items()) -# this mapping is only one of the possibilies -# so this test needs to be reconsidered -# isomap = [('a', 1), ('b', 6), ('c', 3), ('d', 8), -# ('g', 2), ('h', 5), ('i', 4), ('j', 7)] -# assert_equal(mapping, isomap) - - def test_subgraph(self): - g1 = nx.Graph() - g2 = nx.Graph() - g1.add_edges_from(self.g1edges) - g2.add_edges_from(self.g2edges) - g3 = g2.subgraph([1, 2, 3, 4]) - gm = iso.GraphMatcher(g1, g3) - assert gm.subgraph_is_isomorphic() - - - def test_subgraph_mono(self): - g1 = nx.Graph() - g2 = nx.Graph() - g1.add_edges_from(self.g1edges) - g2.add_edges_from([[1, 2], [2, 3], [3, 4]]) - gm = iso.GraphMatcher(g1, g2) - assert gm.subgraph_is_monomorphic() - - -class TestVF2GraphDB(object): - # http://amalfi.dis.unina.it/graph/db/ - - @staticmethod - def create_graph(filename): - """Creates a Graph instance from the filename.""" - - # The file is assumed to be in the format from the VF2 graph database. - # Each file is composed of 16-bit numbers (unsigned short int). - # So we will want to read 2 bytes at a time. - - # We can read the number as follows: - # number = struct.unpack(' -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# NetworkX:http://networkx.github.io/ -import networkx as nx -__author__ = """Aric Hagberg (hagberg@lanl.gov)""" -__all__ = ['hits', 'hits_numpy', 'hits_scipy', 'authority_matrix', 'hub_matrix'] - - -def hits(G, max_iter=100, tol=1.0e-8, nstart=None, normalized=True): - """Returns HITS hubs and authorities values for nodes. - - The HITS algorithm computes two numbers for a node. - Authorities estimates the node value based on the incoming links. - Hubs estimates the node value based on outgoing links. - - Parameters - ---------- - G : graph - A NetworkX graph - - max_iter : integer, optional - Maximum number of iterations in power method. - - tol : float, optional - Error tolerance used to check convergence in power method iteration. - - nstart : dictionary, optional - Starting value of each node for power method iteration. - - normalized : bool (default=True) - Normalize results by the sum of all of the values. - - Returns - ------- - (hubs,authorities) : two-tuple of dictionaries - Two dictionaries keyed by node containing the hub and authority - values. - - Raises - ------ - PowerIterationFailedConvergence - If the algorithm fails to converge to the specified tolerance - within the specified number of iterations of the power iteration - method. - - Examples - -------- - >>> G=nx.path_graph(4) - >>> h,a=nx.hits(G) - - Notes - ----- - The eigenvector calculation is done by the power iteration method - and has no guarantee of convergence. The iteration will stop - after max_iter iterations or an error tolerance of - number_of_nodes(G)*tol has been reached. - - The HITS algorithm was designed for directed graphs but this - algorithm does not check if the input graph is directed and will - execute on undirected graphs. - - References - ---------- - .. [1] A. Langville and C. Meyer, - "A survey of eigenvector methods of web information retrieval." - http://citeseer.ist.psu.edu/713792.html - .. [2] Jon Kleinberg, - Authoritative sources in a hyperlinked environment - Journal of the ACM 46 (5): 604-32, 1999. - doi:10.1145/324133.324140. - http://www.cs.cornell.edu/home/kleinber/auth.pdf. - """ - if type(G) == nx.MultiGraph or type(G) == nx.MultiDiGraph: - raise Exception("hits() not defined for graphs with multiedges.") - if len(G) == 0: - return {}, {} - # choose fixed starting vector if not given - if nstart is None: - h = dict.fromkeys(G, 1.0 / G.number_of_nodes()) - else: - h = nstart - # normalize starting vector - s = 1.0 / sum(h.values()) - for k in h: - h[k] *= s - for _ in range(max_iter): # power iteration: make up to max_iter iterations - hlast = h - h = dict.fromkeys(hlast.keys(), 0) - a = dict.fromkeys(hlast.keys(), 0) - # this "matrix multiply" looks odd because it is - # doing a left multiply a^T=hlast^T*G - for n in h: - for nbr in G[n]: - a[nbr] += hlast[n] * G[n][nbr].get('weight', 1) - # now multiply h=Ga - for n in h: - for nbr in G[n]: - h[n] += a[nbr] * G[n][nbr].get('weight', 1) - # normalize vector - s = 1.0 / max(h.values()) - for n in h: - h[n] *= s - # normalize vector - s = 1.0 / max(a.values()) - for n in a: - a[n] *= s - # check convergence, l1 norm - err = sum([abs(h[n] - hlast[n]) for n in h]) - if err < tol: - break - else: - raise nx.PowerIterationFailedConvergence(max_iter) - if normalized: - s = 1.0 / sum(a.values()) - for n in a: - a[n] *= s - s = 1.0 / sum(h.values()) - for n in h: - h[n] *= s - return h, a - - -def authority_matrix(G, nodelist=None): - """Returns the HITS authority matrix.""" - M = nx.to_numpy_matrix(G, nodelist=nodelist) - return M.T * M - - -def hub_matrix(G, nodelist=None): - """Returns the HITS hub matrix.""" - M = nx.to_numpy_matrix(G, nodelist=nodelist) - return M * M.T - - -def hits_numpy(G, normalized=True): - """Returns HITS hubs and authorities values for nodes. - - The HITS algorithm computes two numbers for a node. - Authorities estimates the node value based on the incoming links. - Hubs estimates the node value based on outgoing links. - - Parameters - ---------- - G : graph - A NetworkX graph - - normalized : bool (default=True) - Normalize results by the sum of all of the values. - - Returns - ------- - (hubs,authorities) : two-tuple of dictionaries - Two dictionaries keyed by node containing the hub and authority - values. - - Examples - -------- - >>> G=nx.path_graph(4) - >>> h,a=nx.hits(G) - - Notes - ----- - The eigenvector calculation uses NumPy's interface to LAPACK. - - The HITS algorithm was designed for directed graphs but this - algorithm does not check if the input graph is directed and will - execute on undirected graphs. - - References - ---------- - .. [1] A. Langville and C. Meyer, - "A survey of eigenvector methods of web information retrieval." - http://citeseer.ist.psu.edu/713792.html - .. [2] Jon Kleinberg, - Authoritative sources in a hyperlinked environment - Journal of the ACM 46 (5): 604-32, 1999. - doi:10.1145/324133.324140. - http://www.cs.cornell.edu/home/kleinber/auth.pdf. - """ - try: - import numpy as np - except ImportError: - raise ImportError( - "hits_numpy() requires NumPy: http://scipy.org/") - if len(G) == 0: - return {}, {} - H = nx.hub_matrix(G, list(G)) - e, ev = np.linalg.eig(H) - m = e.argsort()[-1] # index of maximum eigenvalue - h = np.array(ev[:, m]).flatten() - A = nx.authority_matrix(G, list(G)) - e, ev = np.linalg.eig(A) - m = e.argsort()[-1] # index of maximum eigenvalue - a = np.array(ev[:, m]).flatten() - if normalized: - h = h / h.sum() - a = a / a.sum() - else: - h = h / h.max() - a = a / a.max() - hubs = dict(zip(G, map(float, h))) - authorities = dict(zip(G, map(float, a))) - return hubs, authorities - - -def hits_scipy(G, max_iter=100, tol=1.0e-6, normalized=True): - """Returns HITS hubs and authorities values for nodes. - - The HITS algorithm computes two numbers for a node. - Authorities estimates the node value based on the incoming links. - Hubs estimates the node value based on outgoing links. - - Parameters - ---------- - G : graph - A NetworkX graph - - max_iter : integer, optional - Maximum number of iterations in power method. - - tol : float, optional - Error tolerance used to check convergence in power method iteration. - - nstart : dictionary, optional - Starting value of each node for power method iteration. - - normalized : bool (default=True) - Normalize results by the sum of all of the values. - - Returns - ------- - (hubs,authorities) : two-tuple of dictionaries - Two dictionaries keyed by node containing the hub and authority - values. - - Examples - -------- - >>> G=nx.path_graph(4) - >>> h,a=nx.hits(G) - - Notes - ----- - This implementation uses SciPy sparse matrices. - - The eigenvector calculation is done by the power iteration method - and has no guarantee of convergence. The iteration will stop - after max_iter iterations or an error tolerance of - number_of_nodes(G)*tol has been reached. - - The HITS algorithm was designed for directed graphs but this - algorithm does not check if the input graph is directed and will - execute on undirected graphs. - - Raises - ------ - PowerIterationFailedConvergence - If the algorithm fails to converge to the specified tolerance - within the specified number of iterations of the power iteration - method. - - References - ---------- - .. [1] A. Langville and C. Meyer, - "A survey of eigenvector methods of web information retrieval." - http://citeseer.ist.psu.edu/713792.html - .. [2] Jon Kleinberg, - Authoritative sources in a hyperlinked environment - Journal of the ACM 46 (5): 604-632, 1999. - doi:10.1145/324133.324140. - http://www.cs.cornell.edu/home/kleinber/auth.pdf. - """ - try: - import scipy.sparse - import numpy as np - except ImportError: - raise ImportError( - "hits_scipy() requires SciPy: http://scipy.org/") - if len(G) == 0: - return {}, {} - M = nx.to_scipy_sparse_matrix(G, nodelist=list(G)) - (n, m) = M.shape # should be square - A = M.T * M # authority matrix - x = scipy.ones((n, 1)) / n # initial guess - # power iteration on authority matrix - i = 0 - while True: - xlast = x - x = A * x - x = x / x.max() - # check convergence, l1 norm - err = scipy.absolute(x - xlast).sum() - if err < tol: - break - if i > max_iter: - raise nx.PowerIterationFailedConvergence(max_iter) - i += 1 - - a = np.asarray(x).flatten() - # h=M*a - h = np.asarray(M * a).flatten() - if normalized: - h = h / h.sum() - a = a / a.sum() - hubs = dict(zip(G, map(float, h))) - authorities = dict(zip(G, map(float, a))) - return hubs, authorities - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/link_analysis/pagerank_alg.py b/extensions/fablabchemnitz/networkx/algorithms/link_analysis/pagerank_alg.py deleted file mode 100644 index 8ad45b9f..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/link_analysis/pagerank_alg.py +++ /dev/null @@ -1,477 +0,0 @@ -"""PageRank analysis of graph structure. """ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# NetworkX:http://networkx.github.io/ -import networkx as nx -from networkx.utils import not_implemented_for -__author__ = """\n""".join(["Aric Hagberg ", - "Brandon Liu >> G = nx.DiGraph(nx.path_graph(4)) - >>> pr = nx.pagerank(G, alpha=0.9) - - Notes - ----- - The eigenvector calculation is done by the power iteration method - and has no guarantee of convergence. The iteration will stop after - an error tolerance of ``len(G) * tol`` has been reached. If the - number of iterations exceed `max_iter`, a - :exc:`networkx.exception.PowerIterationFailedConvergence` exception - is raised. - - The PageRank algorithm was designed for directed graphs but this - algorithm does not check if the input graph is directed and will - execute on undirected graphs by converting each edge in the - directed graph to two edges. - - See Also - -------- - pagerank_numpy, pagerank_scipy, google_matrix - - Raises - ------ - PowerIterationFailedConvergence - If the algorithm fails to converge to the specified tolerance - within the specified number of iterations of the power iteration - method. - - References - ---------- - .. [1] A. Langville and C. Meyer, - "A survey of eigenvector methods of web information retrieval." - http://citeseer.ist.psu.edu/713792.html - .. [2] Page, Lawrence; Brin, Sergey; Motwani, Rajeev and Winograd, Terry, - The PageRank citation ranking: Bringing order to the Web. 1999 - http://dbpubs.stanford.edu:8090/pub/showDoc.Fulltext?lang=en&doc=1999-66&format=pdf - - """ - if len(G) == 0: - return {} - - if not G.is_directed(): - D = G.to_directed() - else: - D = G - - # Create a copy in (right) stochastic form - W = nx.stochastic_graph(D, weight=weight) - N = W.number_of_nodes() - - # Choose fixed starting vector if not given - if nstart is None: - x = dict.fromkeys(W, 1.0 / N) - else: - # Normalized nstart vector - s = float(sum(nstart.values())) - x = dict((k, v / s) for k, v in nstart.items()) - - if personalization is None: - # Assign uniform personalization vector if not given - p = dict.fromkeys(W, 1.0 / N) - else: - s = float(sum(personalization.values())) - p = dict((k, v / s) for k, v in personalization.items()) - - if dangling is None: - # Use personalization vector if dangling vector not specified - dangling_weights = p - else: - s = float(sum(dangling.values())) - dangling_weights = dict((k, v / s) for k, v in dangling.items()) - dangling_nodes = [n for n in W if W.out_degree(n, weight=weight) == 0.0] - - # power iteration: make up to max_iter iterations - for _ in range(max_iter): - xlast = x - x = dict.fromkeys(xlast.keys(), 0) - danglesum = alpha * sum(xlast[n] for n in dangling_nodes) - for n in x: - # this matrix multiply looks odd because it is - # doing a left multiply x^T=xlast^T*W - for nbr in W[n]: - x[nbr] += alpha * xlast[n] * W[n][nbr][weight] - x[n] += danglesum * dangling_weights.get(n, 0) + (1.0 - alpha) * p.get(n, 0) - # check convergence, l1 norm - err = sum([abs(x[n] - xlast[n]) for n in x]) - if err < N * tol: - return x - raise nx.PowerIterationFailedConvergence(max_iter) - - -def google_matrix(G, alpha=0.85, personalization=None, - nodelist=None, weight='weight', dangling=None): - """Returns the Google matrix of the graph. - - Parameters - ---------- - G : graph - A NetworkX graph. Undirected graphs will be converted to a directed - graph with two directed edges for each undirected edge. - - alpha : float - The damping factor. - - personalization: dict, optional - The "personalization vector" consisting of a dictionary with a - key some subset of graph nodes and personalization value each of those. - At least one personalization value must be non-zero. - If not specfiied, a nodes personalization value will be zero. - By default, a uniform distribution is used. - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : key, optional - Edge data key to use as weight. If None weights are set to 1. - - dangling: dict, optional - The outedges to be assigned to any "dangling" nodes, i.e., nodes without - any outedges. The dict key is the node the outedge points to and the dict - value is the weight of that outedge. By default, dangling nodes are given - outedges according to the personalization vector (uniform if not - specified) This must be selected to result in an irreducible transition - matrix (see notes below). It may be common to have the dangling dict to - be the same as the personalization dict. - - Returns - ------- - A : NumPy matrix - Google matrix of the graph - - Notes - ----- - The matrix returned represents the transition matrix that describes the - Markov chain used in PageRank. For PageRank to converge to a unique - solution (i.e., a unique stationary distribution in a Markov chain), the - transition matrix must be irreducible. In other words, it must be that - there exists a path between every pair of nodes in the graph, or else there - is the potential of "rank sinks." - - This implementation works with Multi(Di)Graphs. For multigraphs the - weight between two nodes is set to be the sum of all edge weights - between those nodes. - - See Also - -------- - pagerank, pagerank_numpy, pagerank_scipy - """ - import numpy as np - - if nodelist is None: - nodelist = list(G) - - M = nx.to_numpy_matrix(G, nodelist=nodelist, weight=weight) - N = len(G) - if N == 0: - return M - - # Personalization vector - if personalization is None: - p = np.repeat(1.0 / N, N) - else: - p = np.array([personalization.get(n, 0) for n in nodelist], dtype=float) - p /= p.sum() - - # Dangling nodes - if dangling is None: - dangling_weights = p - else: - # Convert the dangling dictionary into an array in nodelist order - dangling_weights = np.array([dangling.get(n, 0) for n in nodelist], - dtype=float) - dangling_weights /= dangling_weights.sum() - dangling_nodes = np.where(M.sum(axis=1) == 0)[0] - - # Assign dangling_weights to any dangling nodes (nodes with no out links) - for node in dangling_nodes: - M[node] = dangling_weights - - M /= M.sum(axis=1) # Normalize rows to sum to 1 - - return alpha * M + (1 - alpha) * p - - -def pagerank_numpy(G, alpha=0.85, personalization=None, weight='weight', - dangling=None): - """Returns the PageRank of the nodes in the graph. - - PageRank computes a ranking of the nodes in the graph G based on - the structure of the incoming links. It was originally designed as - an algorithm to rank web pages. - - Parameters - ---------- - G : graph - A NetworkX graph. Undirected graphs will be converted to a directed - graph with two directed edges for each undirected edge. - - alpha : float, optional - Damping parameter for PageRank, default=0.85. - - personalization: dict, optional - The "personalization vector" consisting of a dictionary with a - key some subset of graph nodes and personalization value each of those. - At least one personalization value must be non-zero. - If not specfiied, a nodes personalization value will be zero. - By default, a uniform distribution is used. - - weight : key, optional - Edge data key to use as weight. If None weights are set to 1. - - dangling: dict, optional - The outedges to be assigned to any "dangling" nodes, i.e., nodes without - any outedges. The dict key is the node the outedge points to and the dict - value is the weight of that outedge. By default, dangling nodes are given - outedges according to the personalization vector (uniform if not - specified) This must be selected to result in an irreducible transition - matrix (see notes under google_matrix). It may be common to have the - dangling dict to be the same as the personalization dict. - - Returns - ------- - pagerank : dictionary - Dictionary of nodes with PageRank as value. - - Examples - -------- - >>> G = nx.DiGraph(nx.path_graph(4)) - >>> pr = nx.pagerank_numpy(G, alpha=0.9) - - Notes - ----- - The eigenvector calculation uses NumPy's interface to the LAPACK - eigenvalue solvers. This will be the fastest and most accurate - for small graphs. - - This implementation works with Multi(Di)Graphs. For multigraphs the - weight between two nodes is set to be the sum of all edge weights - between those nodes. - - See Also - -------- - pagerank, pagerank_scipy, google_matrix - - References - ---------- - .. [1] A. Langville and C. Meyer, - "A survey of eigenvector methods of web information retrieval." - http://citeseer.ist.psu.edu/713792.html - .. [2] Page, Lawrence; Brin, Sergey; Motwani, Rajeev and Winograd, Terry, - The PageRank citation ranking: Bringing order to the Web. 1999 - http://dbpubs.stanford.edu:8090/pub/showDoc.Fulltext?lang=en&doc=1999-66&format=pdf - """ - import numpy as np - if len(G) == 0: - return {} - M = google_matrix(G, alpha, personalization=personalization, - weight=weight, dangling=dangling) - # use numpy LAPACK solver - eigenvalues, eigenvectors = np.linalg.eig(M.T) - ind = np.argmax(eigenvalues) - # eigenvector of largest eigenvalue is at ind, normalized - largest = np.array(eigenvectors[:, ind]).flatten().real - norm = float(largest.sum()) - return dict(zip(G, map(float, largest / norm))) - - -def pagerank_scipy(G, alpha=0.85, personalization=None, - max_iter=100, tol=1.0e-6, nstart=None, weight='weight', - dangling=None): - """Returns the PageRank of the nodes in the graph. - - PageRank computes a ranking of the nodes in the graph G based on - the structure of the incoming links. It was originally designed as - an algorithm to rank web pages. - - Parameters - ---------- - G : graph - A NetworkX graph. Undirected graphs will be converted to a directed - graph with two directed edges for each undirected edge. - - alpha : float, optional - Damping parameter for PageRank, default=0.85. - - personalization: dict, optional - The "personalization vector" consisting of a dictionary with a - key some subset of graph nodes and personalization value each of those. - At least one personalization value must be non-zero. - If not specfiied, a nodes personalization value will be zero. - By default, a uniform distribution is used. - - max_iter : integer, optional - Maximum number of iterations in power method eigenvalue solver. - - tol : float, optional - Error tolerance used to check convergence in power method solver. - - nstart : dictionary, optional - Starting value of PageRank iteration for each node. - - weight : key, optional - Edge data key to use as weight. If None weights are set to 1. - - dangling: dict, optional - The outedges to be assigned to any "dangling" nodes, i.e., nodes without - any outedges. The dict key is the node the outedge points to and the dict - value is the weight of that outedge. By default, dangling nodes are given - outedges according to the personalization vector (uniform if not - specified) This must be selected to result in an irreducible transition - matrix (see notes under google_matrix). It may be common to have the - dangling dict to be the same as the personalization dict. - - Returns - ------- - pagerank : dictionary - Dictionary of nodes with PageRank as value - - Examples - -------- - >>> G = nx.DiGraph(nx.path_graph(4)) - >>> pr = nx.pagerank_scipy(G, alpha=0.9) - - Notes - ----- - The eigenvector calculation uses power iteration with a SciPy - sparse matrix representation. - - This implementation works with Multi(Di)Graphs. For multigraphs the - weight between two nodes is set to be the sum of all edge weights - between those nodes. - - See Also - -------- - pagerank, pagerank_numpy, google_matrix - - Raises - ------ - PowerIterationFailedConvergence - If the algorithm fails to converge to the specified tolerance - within the specified number of iterations of the power iteration - method. - - References - ---------- - .. [1] A. Langville and C. Meyer, - "A survey of eigenvector methods of web information retrieval." - http://citeseer.ist.psu.edu/713792.html - .. [2] Page, Lawrence; Brin, Sergey; Motwani, Rajeev and Winograd, Terry, - The PageRank citation ranking: Bringing order to the Web. 1999 - http://dbpubs.stanford.edu:8090/pub/showDoc.Fulltext?lang=en&doc=1999-66&format=pdf - """ - import scipy.sparse - - N = len(G) - if N == 0: - return {} - - nodelist = list(G) - M = nx.to_scipy_sparse_matrix(G, nodelist=nodelist, weight=weight, - dtype=float) - S = scipy.array(M.sum(axis=1)).flatten() - S[S != 0] = 1.0 / S[S != 0] - Q = scipy.sparse.spdiags(S.T, 0, *M.shape, format='csr') - M = Q * M - - # initial vector - if nstart is None: - x = scipy.repeat(1.0 / N, N) - else: - x = scipy.array([nstart.get(n, 0) for n in nodelist], dtype=float) - x = x / x.sum() - - # Personalization vector - if personalization is None: - p = scipy.repeat(1.0 / N, N) - else: - p = scipy.array([personalization.get(n, 0) for n in nodelist], dtype=float) - p = p / p.sum() - - # Dangling nodes - if dangling is None: - dangling_weights = p - else: - # Convert the dangling dictionary into an array in nodelist order - dangling_weights = scipy.array([dangling.get(n, 0) for n in nodelist], - dtype=float) - dangling_weights /= dangling_weights.sum() - is_dangling = scipy.where(S == 0)[0] - - # power iteration: make up to max_iter iterations - for _ in range(max_iter): - xlast = x - x = alpha * (x * M + sum(x[is_dangling]) * dangling_weights) + \ - (1 - alpha) * p - # check convergence, l1 norm - err = scipy.absolute(x - xlast).sum() - if err < N * tol: - return dict(zip(nodelist, map(float, x))) - raise nx.PowerIterationFailedConvergence(max_iter) - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/link_analysis/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/link_analysis/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/link_analysis/tests/test_hits.py b/extensions/fablabchemnitz/networkx/algorithms/link_analysis/tests/test_hits.py deleted file mode 100644 index 8634cadb..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/link_analysis/tests/test_hits.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python -import pytest - - -import networkx -from networkx.testing import almost_equal - -# Example from -# A. Langville and C. Meyer, "A survey of eigenvector methods of web -# information retrieval." http://citeseer.ist.psu.edu/713792.html - - -class TestHITS: - - @classmethod - def setup_class(cls): - - G = networkx.DiGraph() - - edges = [(1, 3), (1, 5), - (2, 1), - (3, 5), - (5, 4), (5, 3), - (6, 5)] - - G.add_edges_from(edges, weight=1) - cls.G = G - cls.G.a = dict(zip(sorted(G), [0.000000, 0.000000, 0.366025, - 0.133975, 0.500000, 0.000000])) - cls.G.h = dict(zip(sorted(G), [0.366025, 0.000000, 0.211325, - 0.000000, 0.211325, 0.211325])) - - def test_hits(self): - G = self.G - h, a = networkx.hits(G, tol=1.e-08) - for n in G: - assert almost_equal(h[n], G.h[n], places=4) - for n in G: - assert almost_equal(a[n], G.a[n], places=4) - - def test_hits_nstart(self): - G = self.G - nstart = dict([(i, 1. / 2) for i in G]) - h, a = networkx.hits(G, nstart=nstart) - - def test_hits_numpy(self): - numpy = pytest.importorskip('numpy') - G = self.G - h, a = networkx.hits_numpy(G) - for n in G: - assert almost_equal(h[n], G.h[n], places=4) - for n in G: - assert almost_equal(a[n], G.a[n], places=4) - - def test_hits_scipy(self): - sp = pytest.importorskip('scipy') - G = self.G - h, a = networkx.hits_scipy(G, tol=1.e-08) - for n in G: - assert almost_equal(h[n], G.h[n], places=4) - for n in G: - assert almost_equal(a[n], G.a[n], places=4) - - def test_empty(self): - numpy = pytest.importorskip('numpy') - G = networkx.Graph() - assert networkx.hits(G) == ({}, {}) - assert networkx.hits_numpy(G) == ({}, {}) - assert networkx.authority_matrix(G).shape == (0, 0) - assert networkx.hub_matrix(G).shape == (0, 0) - - def test_empty_scipy(self): - scipy = pytest.importorskip('scipy') - G = networkx.Graph() - assert networkx.hits_scipy(G) == ({}, {}) - - def test_hits_not_convergent(self): - with pytest.raises(networkx.PowerIterationFailedConvergence): - G = self.G - networkx.hits(G, max_iter=0) diff --git a/extensions/fablabchemnitz/networkx/algorithms/link_analysis/tests/test_pagerank.py b/extensions/fablabchemnitz/networkx/algorithms/link_analysis/tests/test_pagerank.py deleted file mode 100644 index 57c5a839..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/link_analysis/tests/test_pagerank.py +++ /dev/null @@ -1,165 +0,0 @@ -#!/usr/bin/env python -import random - -import networkx -import pytest -import pytest -numpy = pytest.importorskip('numpy') -scipy = pytest.importorskip('scipy') - -from networkx.testing import almost_equal - -# Example from -# A. Langville and C. Meyer, "A survey of eigenvector methods of web -# information retrieval." http://citeseer.ist.psu.edu/713792.html - - -class TestPageRank(object): - - @classmethod - def setup_class(cls): - G = networkx.DiGraph() - edges = [(1, 2), (1, 3), - # 2 is a dangling node - (3, 1), (3, 2), (3, 5), - (4, 5), (4, 6), - (5, 4), (5, 6), - (6, 4)] - G.add_edges_from(edges) - cls.G = G - cls.G.pagerank = dict(zip(sorted(G), - [0.03721197, 0.05395735, 0.04150565, - 0.37508082, 0.20599833, 0.28624589])) - cls.dangling_node_index = 1 - cls.dangling_edges = {1: 2, 2: 3, - 3: 0, 4: 0, 5: 0, 6: 0} - cls.G.dangling_pagerank = dict(zip(sorted(G), - [0.10844518, 0.18618601, 0.0710892, - 0.2683668, 0.15919783, 0.20671497])) - - def test_pagerank(self): - G = self.G - p = networkx.pagerank(G, alpha=0.9, tol=1.e-08) - for n in G: - assert almost_equal(p[n], G.pagerank[n], places=4) - - nstart = dict((n, random.random()) for n in G) - p = networkx.pagerank(G, alpha=0.9, tol=1.e-08, nstart=nstart) - for n in G: - assert almost_equal(p[n], G.pagerank[n], places=4) - - def test_pagerank_max_iter(self): - with pytest.raises(networkx.PowerIterationFailedConvergence): - networkx.pagerank(self.G, max_iter=0) - - def test_numpy_pagerank(self): - G = self.G - p = networkx.pagerank_numpy(G, alpha=0.9) - for n in G: - assert almost_equal(p[n], G.pagerank[n], places=4) - personalize = dict((n, random.random()) for n in G) - p = networkx.pagerank_numpy(G, alpha=0.9, personalization=personalize) - - def test_google_matrix(self): - G = self.G - M = networkx.google_matrix(G, alpha=0.9, nodelist=sorted(G)) - e, ev = numpy.linalg.eig(M.T) - p = numpy.array(ev[:, 0] / ev[:, 0].sum())[:, 0] - for (a, b) in zip(p, self.G.pagerank.values()): - assert almost_equal(a, b) - - def test_personalization(self): - G = networkx.complete_graph(4) - personalize = {0: 1, 1: 1, 2: 4, 3: 4} - answer = {0: 0.23246732615667579, 1: 0.23246732615667579, 2: 0.267532673843324, 3: 0.2675326738433241} - p = networkx.pagerank(G, alpha=0.85, personalization=personalize) - for n in G: - assert almost_equal(p[n], answer[n], places=4) - - def test_zero_personalization_vector(self): - G = networkx.complete_graph(4) - personalize = {0: 0, 1: 0, 2: 0, 3: 0} - pytest.raises(ZeroDivisionError, networkx.pagerank, G, - personalization=personalize) - - def test_one_nonzero_personalization_value(self): - G = networkx.complete_graph(4) - personalize = {0: 0, 1: 0, 2: 0, 3: 1} - answer = {0: 0.22077931820379187, 1: 0.22077931820379187, 2: 0.22077931820379187, 3: 0.3376620453886241} - p = networkx.pagerank(G, alpha=0.85, personalization=personalize) - for n in G: - assert almost_equal(p[n], answer[n], places=4) - - def test_incomplete_personalization(self): - G = networkx.complete_graph(4) - personalize = {3: 1} - answer = {0: 0.22077931820379187, 1: 0.22077931820379187, 2: 0.22077931820379187, 3: 0.3376620453886241} - p = networkx.pagerank(G, alpha=0.85, personalization=personalize) - for n in G: - assert almost_equal(p[n], answer[n], places=4) - - def test_dangling_matrix(self): - """ - Tests that the google_matrix doesn't change except for the dangling - nodes. - """ - G = self.G - dangling = self.dangling_edges - dangling_sum = float(sum(dangling.values())) - M1 = networkx.google_matrix(G, personalization=dangling) - M2 = networkx.google_matrix(G, personalization=dangling, - dangling=dangling) - for i in range(len(G)): - for j in range(len(G)): - if i == self.dangling_node_index and (j + 1) in dangling: - assert almost_equal(M2[i, j], - dangling[j + 1] / dangling_sum, - places=4) - else: - assert almost_equal(M2[i, j], M1[i, j], places=4) - - def test_dangling_pagerank(self): - pr = networkx.pagerank(self.G, dangling=self.dangling_edges) - for n in self.G: - assert almost_equal(pr[n], self.G.dangling_pagerank[n], places=4) - - def test_dangling_numpy_pagerank(self): - pr = networkx.pagerank_numpy(self.G, dangling=self.dangling_edges) - for n in self.G: - assert almost_equal(pr[n], self.G.dangling_pagerank[n], places=4) - - def test_empty(self): - G = networkx.Graph() - assert networkx.pagerank(G) == {} - assert networkx.pagerank_numpy(G) == {} - assert networkx.google_matrix(G).shape == (0, 0) - - -class TestPageRankScipy(TestPageRank): - - def test_scipy_pagerank(self): - G = self.G - p = networkx.pagerank_scipy(G, alpha=0.9, tol=1.e-08) - for n in G: - assert almost_equal(p[n], G.pagerank[n], places=4) - personalize = dict((n, random.random()) for n in G) - p = networkx.pagerank_scipy(G, alpha=0.9, tol=1.e-08, - personalization=personalize) - - nstart = dict((n, random.random()) for n in G) - p = networkx.pagerank_scipy(G, alpha=0.9, tol=1.e-08, nstart=nstart) - for n in G: - assert almost_equal(p[n], G.pagerank[n], places=4) - - def test_scipy_pagerank_max_iter(self): - with pytest.raises(networkx.PowerIterationFailedConvergence): - networkx.pagerank_scipy(self.G, max_iter=0) - - def test_dangling_scipy_pagerank(self): - pr = networkx.pagerank_scipy(self.G, dangling=self.dangling_edges) - for n in self.G: - assert almost_equal(pr[n], self.G.dangling_pagerank[n], places=4) - - def test_empty_scipy(self): - G = networkx.Graph() - assert networkx.pagerank_scipy(G) == {} diff --git a/extensions/fablabchemnitz/networkx/algorithms/link_prediction.py b/extensions/fablabchemnitz/networkx/algorithms/link_prediction.py deleted file mode 100644 index b7a13e5b..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/link_prediction.py +++ /dev/null @@ -1,498 +0,0 @@ -""" -Link prediction algorithms. -""" - - -from math import log - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ['resource_allocation_index', - 'jaccard_coefficient', - 'adamic_adar_index', - 'preferential_attachment', - 'cn_soundarajan_hopcroft', - 'ra_index_soundarajan_hopcroft', - 'within_inter_cluster'] - - -def _apply_prediction(G, func, ebunch=None): - """Applies the given function to each edge in the specified iterable - of edges. - - `G` is an instance of :class:`networkx.Graph`. - - `func` is a function on two inputs, each of which is a node in the - graph. The function can return anything, but it should return a - value representing a prediction of the likelihood of a "link" - joining the two nodes. - - `ebunch` is an iterable of pairs of nodes. If not specified, all - non-edges in the graph `G` will be used. - - """ - if ebunch is None: - ebunch = nx.non_edges(G) - return ((u, v, func(u, v)) for u, v in ebunch) - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def resource_allocation_index(G, ebunch=None): - r"""Compute the resource allocation index of all node pairs in ebunch. - - Resource allocation index of `u` and `v` is defined as - - .. math:: - - \sum_{w \in \Gamma(u) \cap \Gamma(v)} \frac{1}{|\Gamma(w)|} - - where $\Gamma(u)$ denotes the set of neighbors of $u$. - - Parameters - ---------- - G : graph - A NetworkX undirected graph. - - ebunch : iterable of node pairs, optional (default = None) - Resource allocation index will be computed for each pair of - nodes given in the iterable. The pairs must be given as - 2-tuples (u, v) where u and v are nodes in the graph. If ebunch - is None then all non-existent edges in the graph will be used. - Default value: None. - - Returns - ------- - piter : iterator - An iterator of 3-tuples in the form (u, v, p) where (u, v) is a - pair of nodes and p is their resource allocation index. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.complete_graph(5) - >>> preds = nx.resource_allocation_index(G, [(0, 1), (2, 3)]) - >>> for u, v, p in preds: - ... '(%d, %d) -> %.8f' % (u, v, p) - ... - '(0, 1) -> 0.75000000' - '(2, 3) -> 0.75000000' - - References - ---------- - .. [1] T. Zhou, L. Lu, Y.-C. Zhang. - Predicting missing links via local information. - Eur. Phys. J. B 71 (2009) 623. - https://arxiv.org/pdf/0901.0553.pdf - """ - def predict(u, v): - return sum(1 / G.degree(w) for w in nx.common_neighbors(G, u, v)) - return _apply_prediction(G, predict, ebunch) - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def jaccard_coefficient(G, ebunch=None): - r"""Compute the Jaccard coefficient of all node pairs in ebunch. - - Jaccard coefficient of nodes `u` and `v` is defined as - - .. math:: - - \frac{|\Gamma(u) \cap \Gamma(v)|}{|\Gamma(u) \cup \Gamma(v)|} - - where $\Gamma(u)$ denotes the set of neighbors of $u$. - - Parameters - ---------- - G : graph - A NetworkX undirected graph. - - ebunch : iterable of node pairs, optional (default = None) - Jaccard coefficient will be computed for each pair of nodes - given in the iterable. The pairs must be given as 2-tuples - (u, v) where u and v are nodes in the graph. If ebunch is None - then all non-existent edges in the graph will be used. - Default value: None. - - Returns - ------- - piter : iterator - An iterator of 3-tuples in the form (u, v, p) where (u, v) is a - pair of nodes and p is their Jaccard coefficient. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.complete_graph(5) - >>> preds = nx.jaccard_coefficient(G, [(0, 1), (2, 3)]) - >>> for u, v, p in preds: - ... '(%d, %d) -> %.8f' % (u, v, p) - ... - '(0, 1) -> 0.60000000' - '(2, 3) -> 0.60000000' - - References - ---------- - .. [1] D. Liben-Nowell, J. Kleinberg. - The Link Prediction Problem for Social Networks (2004). - http://www.cs.cornell.edu/home/kleinber/link-pred.pdf - """ - def predict(u, v): - union_size = len(set(G[u]) | set(G[v])) - if union_size == 0: - return 0 - return len(list(nx.common_neighbors(G, u, v))) / union_size - return _apply_prediction(G, predict, ebunch) - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def adamic_adar_index(G, ebunch=None): - r"""Compute the Adamic-Adar index of all node pairs in ebunch. - - Adamic-Adar index of `u` and `v` is defined as - - .. math:: - - \sum_{w \in \Gamma(u) \cap \Gamma(v)} \frac{1}{\log |\Gamma(w)|} - - where $\Gamma(u)$ denotes the set of neighbors of $u$. - This index leads to zero-division for nodes only connected via self-loops. - It is intended to be used when no self-loops are present. - - Parameters - ---------- - G : graph - NetworkX undirected graph. - - ebunch : iterable of node pairs, optional (default = None) - Adamic-Adar index will be computed for each pair of nodes given - in the iterable. The pairs must be given as 2-tuples (u, v) - where u and v are nodes in the graph. If ebunch is None then all - non-existent edges in the graph will be used. - Default value: None. - - Returns - ------- - piter : iterator - An iterator of 3-tuples in the form (u, v, p) where (u, v) is a - pair of nodes and p is their Adamic-Adar index. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.complete_graph(5) - >>> preds = nx.adamic_adar_index(G, [(0, 1), (2, 3)]) - >>> for u, v, p in preds: - ... '(%d, %d) -> %.8f' % (u, v, p) - ... - '(0, 1) -> 2.16404256' - '(2, 3) -> 2.16404256' - - References - ---------- - .. [1] D. Liben-Nowell, J. Kleinberg. - The Link Prediction Problem for Social Networks (2004). - http://www.cs.cornell.edu/home/kleinber/link-pred.pdf - """ - def predict(u, v): - return sum(1 / log(G.degree(w)) for w in nx.common_neighbors(G, u, v)) - return _apply_prediction(G, predict, ebunch) - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def preferential_attachment(G, ebunch=None): - r"""Compute the preferential attachment score of all node pairs in ebunch. - - Preferential attachment score of `u` and `v` is defined as - - .. math:: - - |\Gamma(u)| |\Gamma(v)| - - where $\Gamma(u)$ denotes the set of neighbors of $u$. - - Parameters - ---------- - G : graph - NetworkX undirected graph. - - ebunch : iterable of node pairs, optional (default = None) - Preferential attachment score will be computed for each pair of - nodes given in the iterable. The pairs must be given as - 2-tuples (u, v) where u and v are nodes in the graph. If ebunch - is None then all non-existent edges in the graph will be used. - Default value: None. - - Returns - ------- - piter : iterator - An iterator of 3-tuples in the form (u, v, p) where (u, v) is a - pair of nodes and p is their preferential attachment score. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.complete_graph(5) - >>> preds = nx.preferential_attachment(G, [(0, 1), (2, 3)]) - >>> for u, v, p in preds: - ... '(%d, %d) -> %d' % (u, v, p) - ... - '(0, 1) -> 16' - '(2, 3) -> 16' - - References - ---------- - .. [1] D. Liben-Nowell, J. Kleinberg. - The Link Prediction Problem for Social Networks (2004). - http://www.cs.cornell.edu/home/kleinber/link-pred.pdf - """ - def predict(u, v): - return G.degree(u) * G.degree(v) - return _apply_prediction(G, predict, ebunch) - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def cn_soundarajan_hopcroft(G, ebunch=None, community='community'): - r"""Count the number of common neighbors of all node pairs in ebunch - using community information. - - For two nodes $u$ and $v$, this function computes the number of - common neighbors and bonus one for each common neighbor belonging to - the same community as $u$ and $v$. Mathematically, - - .. math:: - - |\Gamma(u) \cap \Gamma(v)| + \sum_{w \in \Gamma(u) \cap \Gamma(v)} f(w) - - where $f(w)$ equals 1 if $w$ belongs to the same community as $u$ - and $v$ or 0 otherwise and $\Gamma(u)$ denotes the set of - neighbors of $u$. - - Parameters - ---------- - G : graph - A NetworkX undirected graph. - - ebunch : iterable of node pairs, optional (default = None) - The score will be computed for each pair of nodes given in the - iterable. The pairs must be given as 2-tuples (u, v) where u - and v are nodes in the graph. If ebunch is None then all - non-existent edges in the graph will be used. - Default value: None. - - community : string, optional (default = 'community') - Nodes attribute name containing the community information. - G[u][community] identifies which community u belongs to. Each - node belongs to at most one community. Default value: 'community'. - - Returns - ------- - piter : iterator - An iterator of 3-tuples in the form (u, v, p) where (u, v) is a - pair of nodes and p is their score. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.path_graph(3) - >>> G.nodes[0]['community'] = 0 - >>> G.nodes[1]['community'] = 0 - >>> G.nodes[2]['community'] = 0 - >>> preds = nx.cn_soundarajan_hopcroft(G, [(0, 2)]) - >>> for u, v, p in preds: - ... '(%d, %d) -> %d' % (u, v, p) - '(0, 2) -> 2' - - References - ---------- - .. [1] Sucheta Soundarajan and John Hopcroft. - Using community information to improve the precision of link - prediction methods. - In Proceedings of the 21st international conference companion on - World Wide Web (WWW '12 Companion). ACM, New York, NY, USA, 607-608. - http://doi.acm.org/10.1145/2187980.2188150 - """ - def predict(u, v): - Cu = _community(G, u, community) - Cv = _community(G, v, community) - cnbors = list(nx.common_neighbors(G, u, v)) - neighbors = (sum(_community(G, w, community) == Cu for w in cnbors) - if Cu == Cv else 0) - return len(cnbors) + neighbors - return _apply_prediction(G, predict, ebunch) - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def ra_index_soundarajan_hopcroft(G, ebunch=None, community='community'): - r"""Compute the resource allocation index of all node pairs in - ebunch using community information. - - For two nodes $u$ and $v$, this function computes the resource - allocation index considering only common neighbors belonging to the - same community as $u$ and $v$. Mathematically, - - .. math:: - - \sum_{w \in \Gamma(u) \cap \Gamma(v)} \frac{f(w)}{|\Gamma(w)|} - - where $f(w)$ equals 1 if $w$ belongs to the same community as $u$ - and $v$ or 0 otherwise and $\Gamma(u)$ denotes the set of - neighbors of $u$. - - Parameters - ---------- - G : graph - A NetworkX undirected graph. - - ebunch : iterable of node pairs, optional (default = None) - The score will be computed for each pair of nodes given in the - iterable. The pairs must be given as 2-tuples (u, v) where u - and v are nodes in the graph. If ebunch is None then all - non-existent edges in the graph will be used. - Default value: None. - - community : string, optional (default = 'community') - Nodes attribute name containing the community information. - G[u][community] identifies which community u belongs to. Each - node belongs to at most one community. Default value: 'community'. - - Returns - ------- - piter : iterator - An iterator of 3-tuples in the form (u, v, p) where (u, v) is a - pair of nodes and p is their score. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.Graph() - >>> G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - >>> G.nodes[0]['community'] = 0 - >>> G.nodes[1]['community'] = 0 - >>> G.nodes[2]['community'] = 1 - >>> G.nodes[3]['community'] = 0 - >>> preds = nx.ra_index_soundarajan_hopcroft(G, [(0, 3)]) - >>> for u, v, p in preds: - ... '(%d, %d) -> %.8f' % (u, v, p) - '(0, 3) -> 0.50000000' - - References - ---------- - .. [1] Sucheta Soundarajan and John Hopcroft. - Using community information to improve the precision of link - prediction methods. - In Proceedings of the 21st international conference companion on - World Wide Web (WWW '12 Companion). ACM, New York, NY, USA, 607-608. - http://doi.acm.org/10.1145/2187980.2188150 - """ - def predict(u, v): - Cu = _community(G, u, community) - Cv = _community(G, v, community) - if Cu != Cv: - return 0 - cnbors = nx.common_neighbors(G, u, v) - return sum(1 / G.degree(w) for w in cnbors - if _community(G, w, community) == Cu) - return _apply_prediction(G, predict, ebunch) - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def within_inter_cluster(G, ebunch=None, delta=0.001, community='community'): - """Compute the ratio of within- and inter-cluster common neighbors - of all node pairs in ebunch. - - For two nodes `u` and `v`, if a common neighbor `w` belongs to the - same community as them, `w` is considered as within-cluster common - neighbor of `u` and `v`. Otherwise, it is considered as - inter-cluster common neighbor of `u` and `v`. The ratio between the - size of the set of within- and inter-cluster common neighbors is - defined as the WIC measure. [1]_ - - Parameters - ---------- - G : graph - A NetworkX undirected graph. - - ebunch : iterable of node pairs, optional (default = None) - The WIC measure will be computed for each pair of nodes given in - the iterable. The pairs must be given as 2-tuples (u, v) where - u and v are nodes in the graph. If ebunch is None then all - non-existent edges in the graph will be used. - Default value: None. - - delta : float, optional (default = 0.001) - Value to prevent division by zero in case there is no - inter-cluster common neighbor between two nodes. See [1]_ for - details. Default value: 0.001. - - community : string, optional (default = 'community') - Nodes attribute name containing the community information. - G[u][community] identifies which community u belongs to. Each - node belongs to at most one community. Default value: 'community'. - - Returns - ------- - piter : iterator - An iterator of 3-tuples in the form (u, v, p) where (u, v) is a - pair of nodes and p is their WIC measure. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.Graph() - >>> G.add_edges_from([(0, 1), (0, 2), (0, 3), (1, 4), (2, 4), (3, 4)]) - >>> G.nodes[0]['community'] = 0 - >>> G.nodes[1]['community'] = 1 - >>> G.nodes[2]['community'] = 0 - >>> G.nodes[3]['community'] = 0 - >>> G.nodes[4]['community'] = 0 - >>> preds = nx.within_inter_cluster(G, [(0, 4)]) - >>> for u, v, p in preds: - ... '(%d, %d) -> %.8f' % (u, v, p) - ... - '(0, 4) -> 1.99800200' - >>> preds = nx.within_inter_cluster(G, [(0, 4)], delta=0.5) - >>> for u, v, p in preds: - ... '(%d, %d) -> %.8f' % (u, v, p) - ... - '(0, 4) -> 1.33333333' - - References - ---------- - .. [1] Jorge Carlos Valverde-Rebaza and Alneu de Andrade Lopes. - Link prediction in complex networks based on cluster information. - In Proceedings of the 21st Brazilian conference on Advances in - Artificial Intelligence (SBIA'12) - https://doi.org/10.1007/978-3-642-34459-6_10 - """ - if delta <= 0: - raise nx.NetworkXAlgorithmError('Delta must be greater than zero') - - def predict(u, v): - Cu = _community(G, u, community) - Cv = _community(G, v, community) - if Cu != Cv: - return 0 - cnbors = set(nx.common_neighbors(G, u, v)) - within = set(w for w in cnbors - if _community(G, w, community) == Cu) - inter = cnbors - within - return len(within) / (len(inter) + delta) - - return _apply_prediction(G, predict, ebunch) - - -def _community(G, u, community): - """Get the community of the given node.""" - node_u = G.nodes[u] - try: - return node_u[community] - except KeyError: - raise nx.NetworkXAlgorithmError('No community information') diff --git a/extensions/fablabchemnitz/networkx/algorithms/lowest_common_ancestors.py b/extensions/fablabchemnitz/networkx/algorithms/lowest_common_ancestors.py deleted file mode 100644 index 37047f11..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/lowest_common_ancestors.py +++ /dev/null @@ -1,366 +0,0 @@ -# Copyright (C) 2013 by -# Alex Roper -# Copyright (C) 2017 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# -# All rights reserved. -# BSD license. -# -# Author: Alex Roper -"""Algorithms for finding the lowest common ancestor of trees and DAGs.""" -from collections import defaultdict -from collections.abc import Mapping, Set -from itertools import chain, count - -import networkx as nx -from networkx.utils import arbitrary_element, not_implemented_for, \ - UnionFind, generate_unique_node - -__all__ = ["all_pairs_lowest_common_ancestor", - "tree_all_pairs_lowest_common_ancestor", - "lowest_common_ancestor"] - - -@not_implemented_for("undirected") -@not_implemented_for("multigraph") -def tree_all_pairs_lowest_common_ancestor(G, root=None, pairs=None): - r"""Yield the lowest common ancestor for sets of pairs in a tree. - - Parameters - ---------- - G : NetworkX directed graph (must be a tree) - - root : node, optional (default: None) - The root of the subtree to operate on. - If None, assume the entire graph has exactly one source and use that. - - pairs : iterable or iterator of pairs of nodes, optional (default: None) - The pairs of interest. If None, Defaults to all pairs of nodes - under `root` that have a lowest common ancestor. - - Returns - ------- - lcas : generator of tuples `((u, v), lca)` where `u` and `v` are nodes - in `pairs` and `lca` is their lowest common ancestor. - - Notes - ----- - Only defined on non-null trees represented with directed edges from - parents to children. Uses Tarjan's off-line lowest-common-ancestors - algorithm. Runs in time $O(4 \times (V + E + P))$ time, where 4 is the largest - value of the inverse Ackermann function likely to ever come up in actual - use, and $P$ is the number of pairs requested (or $V^2$ if all are needed). - - Tarjan, R. E. (1979), "Applications of path compression on balanced trees", - Journal of the ACM 26 (4): 690-715, doi:10.1145/322154.322161. - - See Also - -------- - all_pairs_lowest_common_ancestor (similar routine for general DAGs) - lowest_common_ancestor (just a single pair for general DAGs) - """ - if len(G) == 0: - raise nx.NetworkXPointlessConcept("LCA meaningless on null graphs.") - elif None in G: - raise nx.NetworkXError("None is not a valid node.") - - # Index pairs of interest for efficient lookup from either side. - if pairs is not None: - pair_dict = defaultdict(set) - # See note on all_pairs_lowest_common_ancestor. - if not isinstance(pairs, (Mapping, Set)): - pairs = set(pairs) - for u, v in pairs: - for n in (u, v): - if n not in G: - msg = "The node %s is not in the digraph." % str(n) - raise nx.NodeNotFound(msg) - pair_dict[u].add(v) - pair_dict[v].add(u) - - # If root is not specified, find the exactly one node with in degree 0 and - # use it. Raise an error if none are found, or more than one is. Also check - # for any nodes with in degree larger than 1, which would imply G is not a - # tree. - if root is None: - for n, deg in G.in_degree: - if deg == 0: - if root is not None: - msg = "No root specified and tree has multiple sources." - raise nx.NetworkXError(msg) - root = n - elif deg > 1: - msg = "Tree LCA only defined on trees; use DAG routine." - raise nx.NetworkXError(msg) - if root is None: - raise nx.NetworkXError("Graph contains a cycle.") - - # Iterative implementation of Tarjan's offline lca algorithm - # as described in CLRS on page 521 (2nd edition)/page 584 (3rd edition) - uf = UnionFind() - ancestors = {} - for node in G: - ancestors[node] = uf[node] - - colors = defaultdict(bool) - for node in nx.dfs_postorder_nodes(G, root): - colors[node] = True - for v in (pair_dict[node] if pairs is not None else G): - if colors[v]: - # If the user requested both directions of a pair, give it. - # Otherwise, just give one. - if pairs is not None and (node, v) in pairs: - yield (node, v), ancestors[uf[v]] - if pairs is None or (v, node) in pairs: - yield (v, node), ancestors[uf[v]] - if node != root: - parent = arbitrary_element(G.pred[node]) - uf.union(parent, node) - ancestors[uf[parent]] = parent - - -@not_implemented_for("undirected") -@not_implemented_for("multigraph") -def lowest_common_ancestor(G, node1, node2, default=None): - """Compute the lowest common ancestor of the given pair of nodes. - - Parameters - ---------- - G : NetworkX directed graph - - node1, node2 : nodes in the graph. - - default : object - Returned if no common ancestor between `node1` and `node2` - - Returns - ------- - The lowest common ancestor of node1 and node2, - or default if they have no common ancestors. - - Notes - ----- - Only defined on non-null directed acyclic graphs. - Takes n log(n) time in the size of the graph. - See `all_pairs_lowest_common_ancestor` when you have - more than one pair of nodes of interest. - - See Also - -------- - tree_all_pairs_lowest_common_ancestor - all_pairs_lowest_common_ancestor - """ - ans = list(all_pairs_lowest_common_ancestor(G, pairs=[(node1, node2)])) - if ans: - assert len(ans) == 1 - return ans[0][1] - else: - return default - - -@not_implemented_for("undirected") -@not_implemented_for("multigraph") -def all_pairs_lowest_common_ancestor(G, pairs=None): - """Compute the lowest common ancestor for pairs of nodes. - - Parameters - ---------- - G : NetworkX directed graph - - pairs : iterable of pairs of nodes, optional (default: all pairs) - The pairs of nodes of interest. - If None, will find the LCA of all pairs of nodes. - - Returns - ------- - An iterator over ((node1, node2), lca) where (node1, node2) are - the pairs specified and lca is a lowest common ancestor of the pair. - Note that for the default of all pairs in G, we consider - unordered pairs, e.g. you will not get both (b, a) and (a, b). - - Notes - ----- - Only defined on non-null directed acyclic graphs. - - Uses the $O(n^3)$ ancestor-list algorithm from: - M. A. Bender, M. Farach-Colton, G. Pemmasani, S. Skiena, P. Sumazin. - "Lowest common ancestors in trees and directed acyclic graphs." - Journal of Algorithms, 57(2): 75-94, 2005. - - See Also - -------- - tree_all_pairs_lowest_common_ancestor - lowest_common_ancestor - """ - if not nx.is_directed_acyclic_graph(G): - raise nx.NetworkXError("LCA only defined on directed acyclic graphs.") - elif len(G) == 0: - raise nx.NetworkXPointlessConcept("LCA meaningless on null graphs.") - elif None in G: - raise nx.NetworkXError("None is not a valid node.") - - # The copy isn't ideal, neither is the switch-on-type, but without it users - # passing an iterable will encounter confusing errors, and itertools.tee - # does not appear to handle builtin types efficiently (IE, it materializes - # another buffer rather than just creating listoperators at the same - # offset). The Python documentation notes use of tee is unadvised when one - # is consumed before the other. - # - # This will always produce correct results and avoid unnecessary - # copies in many common cases. - # - if (not isinstance(pairs, (Mapping, Set)) and pairs is not None): - pairs = set(pairs) - - # Convert G into a dag with a single root by adding a node with edges to - # all sources iff necessary. - sources = [n for n, deg in G.in_degree if deg == 0] - if len(sources) == 1: - root = sources[0] - super_root = None - else: - G = G.copy() - super_root = root = generate_unique_node() - for source in sources: - G.add_edge(root, source) - - # Start by computing a spanning tree, and the DAG of all edges not in it. - # We will then use the tree lca algorithm on the spanning tree, and use - # the DAG to figure out the set of tree queries necessary. - spanning_tree = nx.dfs_tree(G, root) - dag = nx.DiGraph((u, v) for u, v in G.edges - if u not in spanning_tree or v not in spanning_tree[u]) - - # Ensure that both the dag and the spanning tree contains all nodes in G, - # even nodes that are disconnected in the dag. - spanning_tree.add_nodes_from(G) - dag.add_nodes_from(G) - - counter = count() - - # Necessary to handle graphs consisting of a single node and no edges. - root_distance = {root: next(counter)} - - for edge in nx.bfs_edges(spanning_tree, root): - for node in edge: - if node not in root_distance: - root_distance[node] = next(counter) - - # Index the position of all nodes in the Euler tour so we can efficiently - # sort lists and merge in tour order. - euler_tour_pos = {} - for node in nx.depth_first_search.dfs_preorder_nodes(G, root): - if node not in euler_tour_pos: - euler_tour_pos[node] = next(counter) - - # Generate the set of all nodes of interest in the pairs. - pairset = set() - if pairs is not None: - pairset = set(chain.from_iterable(pairs)) - - for n in pairset: - if n not in G: - msg = "The node %s is not in the digraph." % str(n) - raise nx.NodeNotFound(msg) - - # Generate the transitive closure over the dag (not G) of all nodes, and - # sort each node's closure set by order of first appearance in the Euler - # tour. - ancestors = {} - for v in dag: - if pairs is None or v in pairset: - my_ancestors = nx.dag.ancestors(dag, v) - my_ancestors.add(v) - ancestors[v] = sorted(my_ancestors, key=euler_tour_pos.get) - - def _compute_dag_lca_from_tree_values(tree_lca, dry_run): - """Iterate through the in-order merge for each pair of interest. - - We do this to answer the user's query, but it is also used to - avoid generating unnecessary tree entries when the user only - needs some pairs. - """ - for (node1, node2) in pairs if pairs is not None else tree_lca: - best_root_distance = None - best = None - - indices = [0, 0] - ancestors_by_index = [ancestors[node1], ancestors[node2]] - - def get_next_in_merged_lists(indices): - """Returns index of the list containing the next item - - Next order refers to the merged order. - Index can be 0 or 1 (or None if exhausted). - """ - index1, index2 = indices - if (index1 >= len(ancestors[node1]) and - index2 >= len(ancestors[node2])): - return None - elif index1 >= len(ancestors[node1]): - return 1 - elif index2 >= len(ancestors[node2]): - return 0 - elif (euler_tour_pos[ancestors[node1][index1]] < - euler_tour_pos[ancestors[node2][index2]]): - return 0 - else: - return 1 - - # Find the LCA by iterating through the in-order merge of the two - # nodes of interests' ancestor sets. In principle, we need to - # consider all pairs in the Cartesian product of the ancestor sets, - # but by the restricted min range query reduction we are guaranteed - # that one of the pairs of interest is adjacent in the merged list - # iff one came from each list. - i = get_next_in_merged_lists(indices) - cur = ancestors_by_index[i][indices[i]], i - while i is not None: - prev = cur - indices[i] += 1 - i = get_next_in_merged_lists(indices) - if i is not None: - cur = ancestors_by_index[i][indices[i]], i - - # Two adjacent entries must not be from the same list - # in order for their tree LCA to be considered. - if cur[1] != prev[1]: - tree_node1, tree_node2 = prev[0], cur[0] - if (tree_node1, tree_node2) in tree_lca: - ans = tree_lca[tree_node1, tree_node2] - else: - ans = tree_lca[tree_node2, tree_node1] - if not dry_run and (best is None or - root_distance[ans] > best_root_distance): - best_root_distance = root_distance[ans] - best = ans - - # If the LCA is super_root, there is no LCA in the user's graph. - if not dry_run and (super_root is None or best != super_root): - yield (node1, node2), best - - # Generate the spanning tree lca for all pairs. This doesn't make sense to - # do incrementally since we are using a linear time offline algorithm for - # tree lca. - if pairs is None: - # We want all pairs so we'll need the entire tree. - tree_lca = dict(tree_all_pairs_lowest_common_ancestor(spanning_tree, - root)) - else: - # We only need the merged adjacent pairs by seeing which queries the - # algorithm needs then generating them in a single pass. - tree_lca = defaultdict(int) - for _ in _compute_dag_lca_from_tree_values(tree_lca, True): - pass - - # Replace the bogus default tree values with the real ones. - for (pair, lca) in tree_all_pairs_lowest_common_ancestor(spanning_tree, - root, - tree_lca): - tree_lca[pair] = lca - - # All precomputations complete. Now we just need to give the user the pairs - # they asked for, or all pairs if they want them all. - return _compute_dag_lca_from_tree_values(tree_lca, False) diff --git a/extensions/fablabchemnitz/networkx/algorithms/matching.py b/extensions/fablabchemnitz/networkx/algorithms/matching.py deleted file mode 100644 index 4cb3d941..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/matching.py +++ /dev/null @@ -1,969 +0,0 @@ -# Copyright 2016 NetworkX developers. -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# -# Copyright (C) 2008 by -# Joris van Rantwijk. -# -# Copyright (C) 2011 by -# Nicholas Mancuso -# -# All rights reserved. -# BSD license. -"""Functions for computing and verifying matchings in a graph.""" -from collections import Counter -from itertools import combinations -from itertools import repeat - -__all__ = ['is_matching', 'is_maximal_matching', 'is_perfect_matching', - 'max_weight_matching', 'maximal_matching'] - - -def maximal_matching(G): - r"""Find a maximal matching in the graph. - - A matching is a subset of edges in which no node occurs more than once. - A maximal matching cannot add more edges and still be a matching. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - Returns - ------- - matching : set - A maximal matching of the graph. - - Notes - ----- - The algorithm greedily selects a maximal matching M of the graph G - (i.e. no superset of M exists). It runs in $O(|E|)$ time. - """ - matching = set() - nodes = set() - for u, v in G.edges(): - # If the edge isn't covered, add it to the matching - # then remove neighborhood of u and v from consideration. - if u not in nodes and v not in nodes and u != v: - matching.add((u, v)) - nodes.add(u) - nodes.add(v) - return matching - - -def matching_dict_to_set(matching): - """Converts a dictionary representing a matching (as returned by - :func:`max_weight_matching`) to a set representing a matching (as - returned by :func:`maximal_matching`). - - In the definition of maximal matching adopted by NetworkX, - self-loops are not allowed, so the provided dictionary is expected - to never have any mapping from a key to itself. However, the - dictionary is expected to have mirrored key/value pairs, for - example, key ``u`` with value ``v`` and key ``v`` with value ``u``. - - """ - # Need to compensate for the fact that both pairs (u, v) and (v, u) - # appear in `matching.items()`, so we use a set of sets. This way, - # only the (frozen)set `{u, v}` appears as an element in the - # returned set. - - return set((u, v) for (u, v) in set(map(frozenset, matching.items()))) - - -def is_matching(G, matching): - """Decides whether the given set or dictionary represents a valid - matching in ``G``. - - A *matching* in a graph is a set of edges in which no two distinct - edges share a common endpoint. - - Parameters - ---------- - G : NetworkX graph - - matching : dict or set - A dictionary or set representing a matching. If a dictionary, it - must have ``matching[u] == v`` and ``matching[v] == u`` for each - edge ``(u, v)`` in the matching. If a set, it must have elements - of the form ``(u, v)``, where ``(u, v)`` is an edge in the - matching. - - Returns - ------- - bool - Whether the given set or dictionary represents a valid matching - in the graph. - - """ - if isinstance(matching, dict): - matching = matching_dict_to_set(matching) - # TODO This is parallelizable. - return all(len(set(e1) & set(e2)) == 0 - for e1, e2 in combinations(matching, 2)) - - -def is_maximal_matching(G, matching): - """Decides whether the given set or dictionary represents a valid - maximal matching in ``G``. - - A *maximal matching* in a graph is a matching in which adding any - edge would cause the set to no longer be a valid matching. - - Parameters - ---------- - G : NetworkX graph - - matching : dict or set - A dictionary or set representing a matching. If a dictionary, it - must have ``matching[u] == v`` and ``matching[v] == u`` for each - edge ``(u, v)`` in the matching. If a set, it must have elements - of the form ``(u, v)``, where ``(u, v)`` is an edge in the - matching. - - Returns - ------- - bool - Whether the given set or dictionary represents a valid maximal - matching in the graph. - - """ - if isinstance(matching, dict): - matching = matching_dict_to_set(matching) - # If the given set is not a matching, then it is not a maximal matching. - if not is_matching(G, matching): - return False - # A matching is maximal if adding any unmatched edge to it causes - # the resulting set to *not* be a valid matching. - # - # HACK Since the `matching_dict_to_set` function returns a set of - # sets, we need to convert the list of edges to a set of sets in - # order for the set difference function to work. Ideally, we would - # just be able to do `set(G.edges()) - matching`. - all_edges = set(map(frozenset, G.edges())) - matched_edges = set(map(frozenset, matching)) - unmatched_edges = all_edges - matched_edges - # TODO This is parallelizable. - return all(not is_matching(G, matching | {e}) for e in unmatched_edges) - - -def is_perfect_matching(G, matching): - """Decides whether the given set represents a valid perfect matching in - ``G``. - - A *perfect matching* in a graph is a matching in which exactly one edge - is incident upon each vertex. - - Parameters - ---------- - G : NetworkX graph - - matching : dict or set - A dictionary or set representing a matching. If a dictionary, it - must have ``matching[u] == v`` and ``matching[v] == u`` for each - edge ``(u, v)`` in the matching. If a set, it must have elements - of the form ``(u, v)``, where ``(u, v)`` is an edge in the - matching. - - Returns - ------- - bool - Whether the given set or dictionary represents a valid perfect - matching in the graph. - - """ - if isinstance(matching, dict): - matching = matching_dict_to_set(matching) - - if not is_matching(G, matching): - return False - - counts = Counter(sum(matching, ())) - - return all(counts[v] == 1 for v in G) - - -def max_weight_matching(G, maxcardinality=False, weight='weight'): - """Compute a maximum-weighted matching of G. - - A matching is a subset of edges in which no node occurs more than once. - The weight of a matching is the sum of the weights of its edges. - A maximal matching cannot add more edges and still be a matching. - The cardinality of a matching is the number of matched edges. - - Parameters - ---------- - G : NetworkX graph - Undirected graph - - maxcardinality: bool, optional (default=False) - If maxcardinality is True, compute the maximum-cardinality matching - with maximum weight among all maximum-cardinality matchings. - - weight: string, optional (default='weight') - Edge data key corresponding to the edge weight. - If key not found, uses 1 as weight. - - - Returns - ------- - matching : set - A maximal matching of the graph. - - Notes - ----- - If G has edges with weight attributes the edge data are used as - weight values else the weights are assumed to be 1. - - This function takes time O(number_of_nodes ** 3). - - If all edge weights are integers, the algorithm uses only integer - computations. If floating point weights are used, the algorithm - could return a slightly suboptimal matching due to numeric - precision errors. - - This method is based on the "blossom" method for finding augmenting - paths and the "primal-dual" method for finding a matching of maximum - weight, both methods invented by Jack Edmonds [1]_. - - Bipartite graphs can also be matched using the functions present in - :mod:`networkx.algorithms.bipartite.matching`. - - References - ---------- - .. [1] "Efficient Algorithms for Finding Maximum Matching in Graphs", - Zvi Galil, ACM Computing Surveys, 1986. - """ - # - # The algorithm is taken from "Efficient Algorithms for Finding Maximum - # Matching in Graphs" by Zvi Galil, ACM Computing Surveys, 1986. - # It is based on the "blossom" method for finding augmenting paths and - # the "primal-dual" method for finding a matching of maximum weight, both - # methods invented by Jack Edmonds. - # - # A C program for maximum weight matching by Ed Rothberg was used - # extensively to validate this new code. - # - # Many terms used in the code comments are explained in the paper - # by Galil. You will probably need the paper to make sense of this code. - # - - class NoNode: - """Dummy value which is different from any node.""" - pass - - class Blossom: - """Representation of a non-trivial blossom or sub-blossom.""" - - __slots__ = ['childs', 'edges', 'mybestedges'] - - # b.childs is an ordered list of b's sub-blossoms, starting with - # the base and going round the blossom. - - # b.edges is the list of b's connecting edges, such that - # b.edges[i] = (v, w) where v is a vertex in b.childs[i] - # and w is a vertex in b.childs[wrap(i+1)]. - - # If b is a top-level S-blossom, - # b.mybestedges is a list of least-slack edges to neighbouring - # S-blossoms, or None if no such list has been computed yet. - # This is used for efficient computation of delta3. - - # Generate the blossom's leaf vertices. - def leaves(self): - for t in self.childs: - if isinstance(t, Blossom): - for v in t.leaves(): - yield v - else: - yield t - - # Get a list of vertices. - gnodes = list(G) - if not gnodes: - return set() # don't bother with empty graphs - - # Find the maximum edge weight. - maxweight = 0 - allinteger = True - for i, j, d in G.edges(data=True): - wt = d.get(weight, 1) - if i != j and wt > maxweight: - maxweight = wt - allinteger = allinteger and (str(type(wt)).split("'")[1] - in ('int', 'long')) - - # If v is a matched vertex, mate[v] is its partner vertex. - # If v is a single vertex, v does not occur as a key in mate. - # Initially all vertices are single; updated during augmentation. - mate = {} - - # If b is a top-level blossom, - # label.get(b) is None if b is unlabeled (free), - # 1 if b is an S-blossom, - # 2 if b is a T-blossom. - # The label of a vertex is found by looking at the label of its top-level - # containing blossom. - # If v is a vertex inside a T-blossom, label[v] is 2 iff v is reachable - # from an S-vertex outside the blossom. - # Labels are assigned during a stage and reset after each augmentation. - label = {} - - # If b is a labeled top-level blossom, - # labeledge[b] = (v, w) is the edge through which b obtained its label - # such that w is a vertex in b, or None if b's base vertex is single. - # If w is a vertex inside a T-blossom and label[w] == 2, - # labeledge[w] = (v, w) is an edge through which w is reachable from - # outside the blossom. - labeledge = {} - - # If v is a vertex, inblossom[v] is the top-level blossom to which v - # belongs. - # If v is a top-level vertex, inblossom[v] == v since v is itself - # a (trivial) top-level blossom. - # Initially all vertices are top-level trivial blossoms. - inblossom = dict(zip(gnodes, gnodes)) - - # If b is a sub-blossom, - # blossomparent[b] is its immediate parent (sub-)blossom. - # If b is a top-level blossom, blossomparent[b] is None. - blossomparent = dict(zip(gnodes, repeat(None))) - - # If b is a (sub-)blossom, - # blossombase[b] is its base VERTEX (i.e. recursive sub-blossom). - blossombase = dict(zip(gnodes, gnodes)) - - # If w is a free vertex (or an unreached vertex inside a T-blossom), - # bestedge[w] = (v, w) is the least-slack edge from an S-vertex, - # or None if there is no such edge. - # If b is a (possibly trivial) top-level S-blossom, - # bestedge[b] = (v, w) is the least-slack edge to a different S-blossom - # (v inside b), or None if there is no such edge. - # This is used for efficient computation of delta2 and delta3. - bestedge = {} - - # If v is a vertex, - # dualvar[v] = 2 * u(v) where u(v) is the v's variable in the dual - # optimization problem (if all edge weights are integers, multiplication - # by two ensures that all values remain integers throughout the algorithm). - # Initially, u(v) = maxweight / 2. - dualvar = dict(zip(gnodes, repeat(maxweight))) - - # If b is a non-trivial blossom, - # blossomdual[b] = z(b) where z(b) is b's variable in the dual - # optimization problem. - blossomdual = {} - - # If (v, w) in allowedge or (w, v) in allowedg, then the edge - # (v, w) is known to have zero slack in the optimization problem; - # otherwise the edge may or may not have zero slack. - allowedge = {} - - # Queue of newly discovered S-vertices. - queue = [] - - # Return 2 * slack of edge (v, w) (does not work inside blossoms). - def slack(v, w): - return dualvar[v] + dualvar[w] - 2 * G[v][w].get(weight, 1) - - # Assign label t to the top-level blossom containing vertex w, - # coming through an edge from vertex v. - def assignLabel(w, t, v): - b = inblossom[w] - assert label.get(w) is None and label.get(b) is None - label[w] = label[b] = t - if v is not None: - labeledge[w] = labeledge[b] = (v, w) - else: - labeledge[w] = labeledge[b] = None - bestedge[w] = bestedge[b] = None - if t == 1: - # b became an S-vertex/blossom; add it(s vertices) to the queue. - if isinstance(b, Blossom): - queue.extend(b.leaves()) - else: - queue.append(b) - elif t == 2: - # b became a T-vertex/blossom; assign label S to its mate. - # (If b is a non-trivial blossom, its base is the only vertex - # with an external mate.) - base = blossombase[b] - assignLabel(mate[base], 1, base) - - # Trace back from vertices v and w to discover either a new blossom - # or an augmenting path. Return the base vertex of the new blossom, - # or NoNode if an augmenting path was found. - def scanBlossom(v, w): - # Trace back from v and w, placing breadcrumbs as we go. - path = [] - base = NoNode - while v is not NoNode: - # Look for a breadcrumb in v's blossom or put a new breadcrumb. - b = inblossom[v] - if label[b] & 4: - base = blossombase[b] - break - assert label[b] == 1 - path.append(b) - label[b] = 5 - # Trace one step back. - if labeledge[b] is None: - # The base of blossom b is single; stop tracing this path. - assert blossombase[b] not in mate - v = NoNode - else: - assert labeledge[b][0] == mate[blossombase[b]] - v = labeledge[b][0] - b = inblossom[v] - assert label[b] == 2 - # b is a T-blossom; trace one more step back. - v = labeledge[b][0] - # Swap v and w so that we alternate between both paths. - if w is not NoNode: - v, w = w, v - # Remove breadcrumbs. - for b in path: - label[b] = 1 - # Return base vertex, if we found one. - return base - - # Construct a new blossom with given base, through S-vertices v and w. - # Label the new blossom as S; set its dual variable to zero; - # relabel its T-vertices to S and add them to the queue. - def addBlossom(base, v, w): - bb = inblossom[base] - bv = inblossom[v] - bw = inblossom[w] - # Create blossom. - b = Blossom() - blossombase[b] = base - blossomparent[b] = None - blossomparent[bb] = b - # Make list of sub-blossoms and their interconnecting edge endpoints. - b.childs = path = [] - b.edges = edgs = [(v, w)] - # Trace back from v to base. - while bv != bb: - # Add bv to the new blossom. - blossomparent[bv] = b - path.append(bv) - edgs.append(labeledge[bv]) - assert label[bv] == 2 or (label[bv] == 1 and labeledge[ - bv][0] == mate[blossombase[bv]]) - # Trace one step back. - v = labeledge[bv][0] - bv = inblossom[v] - # Add base sub-blossom; reverse lists. - path.append(bb) - path.reverse() - edgs.reverse() - # Trace back from w to base. - while bw != bb: - # Add bw to the new blossom. - blossomparent[bw] = b - path.append(bw) - edgs.append((labeledge[bw][1], labeledge[bw][0])) - assert label[bw] == 2 or (label[bw] == 1 and labeledge[ - bw][0] == mate[blossombase[bw]]) - # Trace one step back. - w = labeledge[bw][0] - bw = inblossom[w] - # Set label to S. - assert label[bb] == 1 - label[b] = 1 - labeledge[b] = labeledge[bb] - # Set dual variable to zero. - blossomdual[b] = 0 - # Relabel vertices. - for v in b.leaves(): - if label[inblossom[v]] == 2: - # This T-vertex now turns into an S-vertex because it becomes - # part of an S-blossom; add it to the queue. - queue.append(v) - inblossom[v] = b - # Compute b.mybestedges. - bestedgeto = {} - for bv in path: - if isinstance(bv, Blossom): - if bv.mybestedges is not None: - # Walk this subblossom's least-slack edges. - nblist = bv.mybestedges - # The sub-blossom won't need this data again. - bv.mybestedges = None - else: - # This subblossom does not have a list of least-slack - # edges; get the information from the vertices. - nblist = [(v, w) - for v in bv.leaves() - for w in G.neighbors(v) - if v != w] - else: - nblist = [(bv, w) - for w in G.neighbors(bv) - if bv != w] - for k in nblist: - (i, j) = k - if inblossom[j] == b: - i, j = j, i - bj = inblossom[j] - if (bj != b and label.get(bj) == 1 and - ((bj not in bestedgeto) or - slack(i, j) < slack(*bestedgeto[bj]))): - bestedgeto[bj] = k - # Forget about least-slack edge of the subblossom. - bestedge[bv] = None - b.mybestedges = list(bestedgeto.values()) - # Select bestedge[b]. - mybestedge = None - bestedge[b] = None - for k in b.mybestedges: - kslack = slack(*k) - if mybestedge is None or kslack < mybestslack: - mybestedge = k - mybestslack = kslack - bestedge[b] = mybestedge - - # Expand the given top-level blossom. - def expandBlossom(b, endstage): - # Convert sub-blossoms into top-level blossoms. - for s in b.childs: - blossomparent[s] = None - if isinstance(s, Blossom): - if endstage and blossomdual[s] == 0: - # Recursively expand this sub-blossom. - expandBlossom(s, endstage) - else: - for v in s.leaves(): - inblossom[v] = s - else: - inblossom[s] = s - # If we expand a T-blossom during a stage, its sub-blossoms must be - # relabeled. - if (not endstage) and label.get(b) == 2: - # Start at the sub-blossom through which the expanding - # blossom obtained its label, and relabel sub-blossoms untili - # we reach the base. - # Figure out through which sub-blossom the expanding blossom - # obtained its label initially. - entrychild = inblossom[labeledge[b][1]] - # Decide in which direction we will go round the blossom. - j = b.childs.index(entrychild) - if j & 1: - # Start index is odd; go forward and wrap. - j -= len(b.childs) - jstep = 1 - else: - # Start index is even; go backward. - jstep = -1 - # Move along the blossom until we get to the base. - v, w = labeledge[b] - while j != 0: - # Relabel the T-sub-blossom. - if jstep == 1: - p, q = b.edges[j] - else: - q, p = b.edges[j - 1] - label[w] = None - label[q] = None - assignLabel(w, 2, v) - # Step to the next S-sub-blossom and note its forward edge. - allowedge[(p, q)] = allowedge[(q, p)] = True - j += jstep - if jstep == 1: - v, w = b.edges[j] - else: - w, v = b.edges[j - 1] - # Step to the next T-sub-blossom. - allowedge[(v, w)] = allowedge[(w, v)] = True - j += jstep - # Relabel the base T-sub-blossom WITHOUT stepping through to - # its mate (so don't call assignLabel). - bw = b.childs[j] - label[w] = label[bw] = 2 - labeledge[w] = labeledge[bw] = (v, w) - bestedge[bw] = None - # Continue along the blossom until we get back to entrychild. - j += jstep - while b.childs[j] != entrychild: - # Examine the vertices of the sub-blossom to see whether - # it is reachable from a neighbouring S-vertex outside the - # expanding blossom. - bv = b.childs[j] - if label.get(bv) == 1: - # This sub-blossom just got label S through one of its - # neighbours; leave it be. - j += jstep - continue - if isinstance(bv, Blossom): - for v in bv.leaves(): - if label.get(v): - break - else: - v = bv - # If the sub-blossom contains a reachable vertex, assign - # label T to the sub-blossom. - if label.get(v): - assert label[v] == 2 - assert inblossom[v] == bv - label[v] = None - label[mate[blossombase[bv]]] = None - assignLabel(v, 2, labeledge[v][0]) - j += jstep - # Remove the expanded blossom entirely. - label.pop(b, None) - labeledge.pop(b, None) - bestedge.pop(b, None) - del blossomparent[b] - del blossombase[b] - del blossomdual[b] - - # Swap matched/unmatched edges over an alternating path through blossom b - # between vertex v and the base vertex. Keep blossom bookkeeping - # consistent. - def augmentBlossom(b, v): - # Bubble up through the blossom tree from vertex v to an immediate - # sub-blossom of b. - t = v - while blossomparent[t] != b: - t = blossomparent[t] - # Recursively deal with the first sub-blossom. - if isinstance(t, Blossom): - augmentBlossom(t, v) - # Decide in which direction we will go round the blossom. - i = j = b.childs.index(t) - if i & 1: - # Start index is odd; go forward and wrap. - j -= len(b.childs) - jstep = 1 - else: - # Start index is even; go backward. - jstep = -1 - # Move along the blossom until we get to the base. - while j != 0: - # Step to the next sub-blossom and augment it recursively. - j += jstep - t = b.childs[j] - if jstep == 1: - w, x = b.edges[j] - else: - x, w = b.edges[j - 1] - if isinstance(t, Blossom): - augmentBlossom(t, w) - # Step to the next sub-blossom and augment it recursively. - j += jstep - t = b.childs[j] - if isinstance(t, Blossom): - augmentBlossom(t, x) - # Match the edge connecting those sub-blossoms. - mate[w] = x - mate[x] = w - # Rotate the list of sub-blossoms to put the new base at the front. - b.childs = b.childs[i:] + b.childs[:i] - b.edges = b.edges[i:] + b.edges[:i] - blossombase[b] = blossombase[b.childs[0]] - assert blossombase[b] == v - - # Swap matched/unmatched edges over an alternating path between two - # single vertices. The augmenting path runs through S-vertices v and w. - def augmentMatching(v, w): - for (s, j) in ((v, w), (w, v)): - # Match vertex s to vertex j. Then trace back from s - # until we find a single vertex, swapping matched and unmatched - # edges as we go. - while 1: - bs = inblossom[s] - assert label[bs] == 1 - assert ( - labeledge[bs] is None and blossombase[bs] not in mate)\ - or (labeledge[bs][0] == mate[blossombase[bs]]) - # Augment through the S-blossom from s to base. - if isinstance(bs, Blossom): - augmentBlossom(bs, s) - # Update mate[s] - mate[s] = j - # Trace one step back. - if labeledge[bs] is None: - # Reached single vertex; stop. - break - t = labeledge[bs][0] - bt = inblossom[t] - assert label[bt] == 2 - # Trace one more step back. - s, j = labeledge[bt] - # Augment through the T-blossom from j to base. - assert blossombase[bt] == t - if isinstance(bt, Blossom): - augmentBlossom(bt, j) - # Update mate[j] - mate[j] = s - - # Verify that the optimum solution has been reached. - def verifyOptimum(): - if maxcardinality: - # Vertices may have negative dual; - # find a constant non-negative number to add to all vertex duals. - vdualoffset = max(0, -min(dualvar.values())) - else: - vdualoffset = 0 - # 0. all dual variables are non-negative - assert min(dualvar.values()) + vdualoffset >= 0 - assert len(blossomdual) == 0 or min(blossomdual.values()) >= 0 - # 0. all edges have non-negative slack and - # 1. all matched edges have zero slack; - for i, j, d in G.edges(data=True): - wt = d.get(weight, 1) - if i == j: - continue # ignore self-loops - s = dualvar[i] + dualvar[j] - 2 * wt - iblossoms = [i] - jblossoms = [j] - while blossomparent[iblossoms[-1]] is not None: - iblossoms.append(blossomparent[iblossoms[-1]]) - while blossomparent[jblossoms[-1]] is not None: - jblossoms.append(blossomparent[jblossoms[-1]]) - iblossoms.reverse() - jblossoms.reverse() - for (bi, bj) in zip(iblossoms, jblossoms): - if bi != bj: - break - s += 2 * blossomdual[bi] - assert s >= 0 - if mate.get(i) == j or mate.get(j) == i: - assert mate[i] == j and mate[j] == i - assert s == 0 - # 2. all single vertices have zero dual value; - for v in gnodes: - assert (v in mate) or dualvar[v] + vdualoffset == 0 - # 3. all blossoms with positive dual value are full. - for b in blossomdual: - if blossomdual[b] > 0: - assert len(b.edges) % 2 == 1 - for (i, j) in b.edges[1::2]: - assert mate[i] == j and mate[j] == i - # Ok. - - # Main loop: continue until no further improvement is possible. - while 1: - - # Each iteration of this loop is a "stage". - # A stage finds an augmenting path and uses that to improve - # the matching. - - # Remove labels from top-level blossoms/vertices. - label.clear() - labeledge.clear() - - # Forget all about least-slack edges. - bestedge.clear() - for b in blossomdual: - b.mybestedges = None - - # Loss of labeling means that we can not be sure that currently - # allowable edges remain allowable throughout this stage. - allowedge.clear() - - # Make queue empty. - queue[:] = [] - - # Label single blossoms/vertices with S and put them in the queue. - for v in gnodes: - if (v not in mate) and label.get(inblossom[v]) is None: - assignLabel(v, 1, None) - - # Loop until we succeed in augmenting the matching. - augmented = 0 - while 1: - - # Each iteration of this loop is a "substage". - # A substage tries to find an augmenting path; - # if found, the path is used to improve the matching and - # the stage ends. If there is no augmenting path, the - # primal-dual method is used to pump some slack out of - # the dual variables. - - # Continue labeling until all vertices which are reachable - # through an alternating path have got a label. - while queue and not augmented: - - # Take an S vertex from the queue. - v = queue.pop() - assert label[inblossom[v]] == 1 - - # Scan its neighbours: - for w in G.neighbors(v): - if w == v: - continue # ignore self-loops - # w is a neighbour to v - bv = inblossom[v] - bw = inblossom[w] - if bv == bw: - # this edge is internal to a blossom; ignore it - continue - if (v, w) not in allowedge: - kslack = slack(v, w) - if kslack <= 0: - # edge k has zero slack => it is allowable - allowedge[(v, w)] = allowedge[(w, v)] = True - if (v, w) in allowedge: - if label.get(bw) is None: - # (C1) w is a free vertex; - # label w with T and label its mate with S (R12). - assignLabel(w, 2, v) - elif label.get(bw) == 1: - # (C2) w is an S-vertex (not in the same blossom); - # follow back-links to discover either an - # augmenting path or a new blossom. - base = scanBlossom(v, w) - if base is not NoNode: - # Found a new blossom; add it to the blossom - # bookkeeping and turn it into an S-blossom. - addBlossom(base, v, w) - else: - # Found an augmenting path; augment the - # matching and end this stage. - augmentMatching(v, w) - augmented = 1 - break - elif label.get(w) is None: - # w is inside a T-blossom, but w itself has not - # yet been reached from outside the blossom; - # mark it as reached (we need this to relabel - # during T-blossom expansion). - assert label[bw] == 2 - label[w] = 2 - labeledge[w] = (v, w) - elif label.get(bw) == 1: - # keep track of the least-slack non-allowable edge to - # a different S-blossom. - if bestedge.get(bv) is None or \ - kslack < slack(*bestedge[bv]): - bestedge[bv] = (v, w) - elif label.get(w) is None: - # w is a free vertex (or an unreached vertex inside - # a T-blossom) but we can not reach it yet; - # keep track of the least-slack edge that reaches w. - if bestedge.get(w) is None or \ - kslack < slack(*bestedge[w]): - bestedge[w] = (v, w) - - if augmented: - break - - # There is no augmenting path under these constraints; - # compute delta and reduce slack in the optimization problem. - # (Note that our vertex dual variables, edge slacks and delta's - # are pre-multiplied by two.) - deltatype = -1 - delta = deltaedge = deltablossom = None - - # Compute delta1: the minimum value of any vertex dual. - if not maxcardinality: - deltatype = 1 - delta = min(dualvar.values()) - - # Compute delta2: the minimum slack on any edge between - # an S-vertex and a free vertex. - for v in G.nodes(): - if label.get(inblossom[v]) is None and \ - bestedge.get(v) is not None: - d = slack(*bestedge[v]) - if deltatype == -1 or d < delta: - delta = d - deltatype = 2 - deltaedge = bestedge[v] - - # Compute delta3: half the minimum slack on any edge between - # a pair of S-blossoms. - for b in blossomparent: - if (blossomparent[b] is None and label.get(b) == 1 and - bestedge.get(b) is not None): - kslack = slack(*bestedge[b]) - if allinteger: - assert (kslack % 2) == 0 - d = kslack // 2 - else: - d = kslack / 2.0 - if deltatype == -1 or d < delta: - delta = d - deltatype = 3 - deltaedge = bestedge[b] - - # Compute delta4: minimum z variable of any T-blossom. - for b in blossomdual: - if (blossomparent[b] is None and label.get(b) == 2 and - (deltatype == -1 or blossomdual[b] < delta)): - delta = blossomdual[b] - deltatype = 4 - deltablossom = b - - if deltatype == -1: - # No further improvement possible; max-cardinality optimum - # reached. Do a final delta update to make the optimum - # verifyable. - assert maxcardinality - deltatype = 1 - delta = max(0, min(dualvar.values())) - - # Update dual variables according to delta. - for v in gnodes: - if label.get(inblossom[v]) == 1: - # S-vertex: 2*u = 2*u - 2*delta - dualvar[v] -= delta - elif label.get(inblossom[v]) == 2: - # T-vertex: 2*u = 2*u + 2*delta - dualvar[v] += delta - for b in blossomdual: - if blossomparent[b] is None: - if label.get(b) == 1: - # top-level S-blossom: z = z + 2*delta - blossomdual[b] += delta - elif label.get(b) == 2: - # top-level T-blossom: z = z - 2*delta - blossomdual[b] -= delta - - # Take action at the point where minimum delta occurred. - if deltatype == 1: - # No further improvement possible; optimum reached. - break - elif deltatype == 2: - # Use the least-slack edge to continue the search. - (v, w) = deltaedge - assert label[inblossom[v]] == 1 - allowedge[(v, w)] = allowedge[(w, v)] = True - queue.append(v) - elif deltatype == 3: - # Use the least-slack edge to continue the search. - (v, w) = deltaedge - allowedge[(v, w)] = allowedge[(w, v)] = True - assert label[inblossom[v]] == 1 - queue.append(v) - elif deltatype == 4: - # Expand the least-z blossom. - expandBlossom(deltablossom, False) - - # End of a this substage. - - # Paranoia check that the matching is symmetric. - for v in mate: - assert mate[mate[v]] == v - - # Stop when no more augmenting path can be found. - if not augmented: - break - - # End of a stage; expand all S-blossoms which have zero dual. - for b in list(blossomdual.keys()): - if b not in blossomdual: - continue # already expanded - if (blossomparent[b] is None and label.get(b) == 1 and - blossomdual[b] == 0): - expandBlossom(b, True) - - # Verify that we reached the optimum solution (only for integer weights). - if allinteger: - verifyOptimum() - - return matching_dict_to_set(mate) diff --git a/extensions/fablabchemnitz/networkx/algorithms/minors.py b/extensions/fablabchemnitz/networkx/algorithms/minors.py deleted file mode 100644 index 3c46cdf5..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/minors.py +++ /dev/null @@ -1,453 +0,0 @@ -# minors.py - functions for computing minors of graphs -# -# Copyright 2015 Jeffrey Finkelstein . -# Copyright 2010 Drew Conway -# Copyright 2010 Aric Hagberg -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Provides functions for computing minors of a graph.""" -from itertools import chain -from itertools import combinations -from itertools import permutations -from itertools import product - -import networkx as nx -from networkx import density -from networkx.exception import NetworkXException -from networkx.utils import arbitrary_element - -__all__ = ['contracted_edge', 'contracted_nodes', - 'identified_nodes', 'quotient_graph'] - -chaini = chain.from_iterable - - -def equivalence_classes(iterable, relation): - """Returns the set of equivalence classes of the given `iterable` under - the specified equivalence relation. - - `relation` must be a Boolean-valued function that takes two argument. It - must represent an equivalence relation (that is, the relation induced by - the function must be reflexive, symmetric, and transitive). - - The return value is a set of sets. It is a partition of the elements of - `iterable`; duplicate elements will be ignored so it makes the most sense - for `iterable` to be a :class:`set`. - - """ - # For simplicity of implementation, we initialize the return value as a - # list of lists, then convert it to a set of sets at the end of the - # function. - blocks = [] - # Determine the equivalence class for each element of the iterable. - for y in iterable: - # Each element y must be in *exactly one* equivalence class. - # - # Each block is guaranteed to be non-empty - for block in blocks: - x = arbitrary_element(block) - if relation(x, y): - block.append(y) - break - else: - # If the element y is not part of any known equivalence class, it - # must be in its own, so we create a new singleton equivalence - # class for it. - blocks.append([y]) - return {frozenset(block) for block in blocks} - - -def quotient_graph(G, partition, edge_relation=None, node_data=None, - edge_data=None, relabel=False, create_using=None): - """Returns the quotient graph of `G` under the specified equivalence - relation on nodes. - - Parameters - ---------- - G : NetworkX graph - The graph for which to return the quotient graph with the - specified node relation. - - partition : function or list of sets - If a function, this function must represent an equivalence - relation on the nodes of `G`. It must take two arguments *u* - and *v* and return True exactly when *u* and *v* are in the - same equivalence class. The equivalence classes form the nodes - in the returned graph. - - If a list of sets, the list must form a valid partition of - the nodes of the graph. That is, each node must be in exactly - one block of the partition. - - edge_relation : Boolean function with two arguments - This function must represent an edge relation on the *blocks* of - `G` in the partition induced by `node_relation`. It must - take two arguments, *B* and *C*, each one a set of nodes, and - return True exactly when there should be an edge joining - block *B* to block *C* in the returned graph. - - If `edge_relation` is not specified, it is assumed to be the - following relation. Block *B* is related to block *C* if and - only if some node in *B* is adjacent to some node in *C*, - according to the edge set of `G`. - - edge_data : function - This function takes two arguments, *B* and *C*, each one a set - of nodes, and must return a dictionary representing the edge - data attributes to set on the edge joining *B* and *C*, should - there be an edge joining *B* and *C* in the quotient graph (if - no such edge occurs in the quotient graph as determined by - `edge_relation`, then the output of this function is ignored). - - If the quotient graph would be a multigraph, this function is - not applied, since the edge data from each edge in the graph - `G` appears in the edges of the quotient graph. - - node_data : function - This function takes one argument, *B*, a set of nodes in `G`, - and must return a dictionary representing the node data - attributes to set on the node representing *B* in the quotient graph. - If None, the following node attributes will be set: - - * 'graph', the subgraph of the graph `G` that this block - represents, - * 'nnodes', the number of nodes in this block, - * 'nedges', the number of edges within this block, - * 'density', the density of the subgraph of `G` that this - block represents. - - relabel : bool - If True, relabel the nodes of the quotient graph to be - nonnegative integers. Otherwise, the nodes are identified with - :class:`frozenset` instances representing the blocks given in - `partition`. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - NetworkX graph - The quotient graph of `G` under the equivalence relation - specified by `partition`. If the partition were given as a - list of :class:`set` instances and `relabel` is False, - each node will be a :class:`frozenset` corresponding to the same - :class:`set`. - - Raises - ------ - NetworkXException - If the given partition is not a valid partition of the nodes of - `G`. - - Examples - -------- - The quotient graph of the complete bipartite graph under the "same - neighbors" equivalence relation is `K_2`. Under this relation, two nodes - are equivalent if they are not adjacent but have the same neighbor set:: - - >>> import networkx as nx - >>> G = nx.complete_bipartite_graph(2, 3) - >>> same_neighbors = lambda u, v: (u not in G[v] and v not in G[u] - ... and G[u] == G[v]) - >>> Q = nx.quotient_graph(G, same_neighbors) - >>> K2 = nx.complete_graph(2) - >>> nx.is_isomorphic(Q, K2) - True - - The quotient graph of a directed graph under the "same strongly connected - component" equivalence relation is the condensation of the graph (see - :func:`condensation`). This example comes from the Wikipedia article - *`Strongly connected component`_*:: - - >>> import networkx as nx - >>> G = nx.DiGraph() - >>> edges = ['ab', 'be', 'bf', 'bc', 'cg', 'cd', 'dc', 'dh', 'ea', - ... 'ef', 'fg', 'gf', 'hd', 'hf'] - >>> G.add_edges_from(tuple(x) for x in edges) - >>> components = list(nx.strongly_connected_components(G)) - >>> sorted(sorted(component) for component in components) - [['a', 'b', 'e'], ['c', 'd', 'h'], ['f', 'g']] - >>> - >>> C = nx.condensation(G, components) - >>> component_of = C.graph['mapping'] - >>> same_component = lambda u, v: component_of[u] == component_of[v] - >>> Q = nx.quotient_graph(G, same_component) - >>> nx.is_isomorphic(C, Q) - True - - Node identification can be represented as the quotient of a graph under the - equivalence relation that places the two nodes in one block and each other - node in its own singleton block:: - - >>> import networkx as nx - >>> K24 = nx.complete_bipartite_graph(2, 4) - >>> K34 = nx.complete_bipartite_graph(3, 4) - >>> C = nx.contracted_nodes(K34, 1, 2) - >>> nodes = {1, 2} - >>> is_contracted = lambda u, v: u in nodes and v in nodes - >>> Q = nx.quotient_graph(K34, is_contracted) - >>> nx.is_isomorphic(Q, C) - True - >>> nx.is_isomorphic(Q, K24) - True - - The blockmodeling technique described in [1]_ can be implemented as a - quotient graph:: - - >>> G = nx.path_graph(6) - >>> partition = [{0, 1}, {2, 3}, {4, 5}] - >>> M = nx.quotient_graph(G, partition, relabel=True) - >>> list(M.edges()) - [(0, 1), (1, 2)] - - .. _Strongly connected component: https://en.wikipedia.org/wiki/Strongly_connected_component - - References - ---------- - .. [1] Patrick Doreian, Vladimir Batagelj, and Anuska Ferligoj. - *Generalized Blockmodeling*. - Cambridge University Press, 2004. - - """ - # If the user provided an equivalence relation as a function compute - # the blocks of the partition on the nodes of G induced by the - # equivalence relation. - if callable(partition): - # equivalence_classes always return partition of whole G. - partition = equivalence_classes(G, partition) - return _quotient_graph(G, partition, edge_relation, node_data, - edge_data, relabel, create_using) - - # If the user provided partition as a collection of sets. Then we - # need to check if partition covers all of G nodes. If the answer - # is 'No' then we need to prepare suitable subgraph view. - partition_nodes = set().union(*partition) - if len(partition_nodes) != len(G): - G = G.subgraph(partition_nodes) - return _quotient_graph(G, partition, edge_relation, node_data, - edge_data, relabel, create_using) - - -def _quotient_graph(G, partition, edge_relation=None, node_data=None, - edge_data=None, relabel=False, create_using=None): - # Each node in the graph must be in exactly one block. - if any(sum(1 for b in partition if v in b) != 1 for v in G): - raise NetworkXException('each node must be in exactly one block') - if create_using is None: - H = G.__class__() - else: - H = nx.empty_graph(0, create_using) - # By default set some basic information about the subgraph that each block - # represents on the nodes in the quotient graph. - if node_data is None: - def node_data(b): - S = G.subgraph(b) - return dict(graph=S, nnodes=len(S), nedges=S.number_of_edges(), - density=density(S)) - # Each block of the partition becomes a node in the quotient graph. - partition = [frozenset(b) for b in partition] - H.add_nodes_from((b, node_data(b)) for b in partition) - # By default, the edge relation is the relation defined as follows. B is - # adjacent to C if a node in B is adjacent to a node in C, according to the - # edge set of G. - # - # This is not a particularly efficient implementation of this relation: - # there are O(n^2) pairs to check and each check may require O(log n) time - # (to check set membership). This can certainly be parallelized. - if edge_relation is None: - def edge_relation(b, c): - return any(v in G[u] for u, v in product(b, c)) - # By default, sum the weights of the edges joining pairs of nodes across - # blocks to get the weight of the edge joining those two blocks. - if edge_data is None: - def edge_data(b, c): - edgedata = (d for u, v, d in G.edges(b | c, data=True) - if (u in b and v in c) or (u in c and v in b)) - return {'weight': sum(d.get('weight', 1) for d in edgedata)} - block_pairs = permutations(H, 2) if H.is_directed() else combinations(H, 2) - # In a multigraph, add one edge in the quotient graph for each edge - # in the original graph. - if H.is_multigraph(): - edges = chaini(((b, c, G.get_edge_data(u, v, default={})) - for u, v in product(b, c) if v in G[u]) - for b, c in block_pairs if edge_relation(b, c)) - # In a simple graph, apply the edge data function to each pair of - # blocks to determine the edge data attributes to apply to each edge - # in the quotient graph. - else: - edges = ((b, c, edge_data(b, c)) for (b, c) in block_pairs - if edge_relation(b, c)) - H.add_edges_from(edges) - # If requested by the user, relabel the nodes to be integers, - # numbered in increasing order from zero in the same order as the - # iteration order of `partition`. - if relabel: - # Can't use nx.convert_node_labels_to_integers() here since we - # want the order of iteration to be the same for backward - # compatibility with the nx.blockmodel() function. - labels = {b: i for i, b in enumerate(partition)} - H = nx.relabel_nodes(H, labels) - return H - - -def contracted_nodes(G, u, v, self_loops=True): - """Returns the graph that results from contracting `u` and `v`. - - Node contraction identifies the two nodes as a single node incident to any - edge that was incident to the original two nodes. - - Parameters - ---------- - G : NetworkX graph - The graph whose nodes will be contracted. - - u, v : nodes - Must be nodes in `G`. - - self_loops : Boolean - If this is True, any edges joining `u` and `v` in `G` become - self-loops on the new node in the returned graph. - - Returns - ------- - Networkx graph - A new graph object of the same type as `G` (leaving `G` unmodified) - with `u` and `v` identified in a single node. The right node `v` - will be merged into the node `u`, so only `u` will appear in the - returned graph. - - Notes - ----- - For multigraphs, the edge keys for the realigned edges may - not be the same as the edge keys for the old edges. This is - natural because edge keys are unique only within each pair of nodes. - - Examples - -------- - Contracting two nonadjacent nodes of the cycle graph on four nodes `C_4` - yields the path graph (ignoring parallel edges):: - - >>> G = nx.cycle_graph(4) - >>> M = nx.contracted_nodes(G, 1, 3) - >>> P3 = nx.path_graph(3) - >>> nx.is_isomorphic(M, P3) - True - - >>> G = nx.MultiGraph(P3) - >>> M = nx.contracted_nodes(G, 0, 2) - >>> M.edges - MultiEdgeView([(0, 1, 0), (0, 1, 1)]) - - >>> G = nx.Graph([(1,2), (2,2)]) - >>> H = nx.contracted_nodes(G, 1, 2, self_loops=False) - >>> list(H.nodes()) - [1] - >>> list(H.edges()) - [(1, 1)] - - See also - -------- - contracted_edge - quotient_graph - - Notes - ----- - This function is also available as `identified_nodes`. - """ - H = G.copy() - # edge code uses G.edges(v) instead of G.adj[v] to handle multiedges - if H.is_directed(): - in_edges = ((w if w != v else u, u, d) - for w, x, d in G.in_edges(v, data=True) - if self_loops or w != u) - out_edges = ((u, w if w != v else u, d) - for x, w, d in G.out_edges(v, data=True) - if self_loops or w != u) - new_edges = chain(in_edges, out_edges) - else: - new_edges = ((u, w if w != v else u, d) - for x, w, d in G.edges(v, data=True) - if self_loops or w != u) - v_data = H.nodes[v] - H.remove_node(v) - H.add_edges_from(new_edges) - - if 'contraction' in H.nodes[u]: - H.nodes[u]['contraction'][v] = v_data - else: - H.nodes[u]['contraction'] = {v: v_data} - return H - - -identified_nodes = contracted_nodes - - -def contracted_edge(G, edge, self_loops=True): - """Returns the graph that results from contracting the specified edge. - - Edge contraction identifies the two endpoints of the edge as a single node - incident to any edge that was incident to the original two nodes. A graph - that results from edge contraction is called a *minor* of the original - graph. - - Parameters - ---------- - G : NetworkX graph - The graph whose edge will be contracted. - - edge : tuple - Must be a pair of nodes in `G`. - - self_loops : Boolean - If this is True, any edges (including `edge`) joining the - endpoints of `edge` in `G` become self-loops on the new node in the - returned graph. - - Returns - ------- - Networkx graph - A new graph object of the same type as `G` (leaving `G` unmodified) - with endpoints of `edge` identified in a single node. The right node - of `edge` will be merged into the left one, so only the left one will - appear in the returned graph. - - Raises - ------ - ValueError - If `edge` is not an edge in `G`. - - Examples - -------- - Attempting to contract two nonadjacent nodes yields an error:: - - >>> import networkx as nx - >>> G = nx.cycle_graph(4) - >>> nx.contracted_edge(G, (1, 3)) - Traceback (most recent call last): - ... - ValueError: Edge (1, 3) does not exist in graph G; cannot contract it - - Contracting two adjacent nodes in the cycle graph on *n* nodes yields the - cycle graph on *n - 1* nodes:: - - >>> import networkx as nx - >>> C5 = nx.cycle_graph(5) - >>> C4 = nx.cycle_graph(4) - >>> M = nx.contracted_edge(C5, (0, 1), self_loops=False) - >>> nx.is_isomorphic(M, C4) - True - - See also - -------- - contracted_nodes - quotient_graph - - """ - if not G.has_edge(*edge): - raise ValueError('Edge {0} does not exist in graph G; cannot contract' - ' it'.format(edge)) - return contracted_nodes(G, *edge, self_loops=self_loops) diff --git a/extensions/fablabchemnitz/networkx/algorithms/mis.py b/extensions/fablabchemnitz/networkx/algorithms/mis.py deleted file mode 100644 index 054e8dce..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/mis.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- coding: utf-8 -*- -# $Id: maximalIndependentSet.py 576 2011-03-01 05:50:34Z lleeoo $ -# Leo Lopes -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Leo Lopes -# Loïc Séguin-C. -""" -Algorithm to find a maximal (not maximum) independent set. - -""" -import networkx as nx -from networkx.utils import not_implemented_for -from networkx.utils import py_random_state - -__all__ = ['maximal_independent_set'] - - -@py_random_state(2) -@not_implemented_for('directed') -def maximal_independent_set(G, nodes=None, seed=None): - """Returns a random maximal independent set guaranteed to contain - a given set of nodes. - - An independent set is a set of nodes such that the subgraph - of G induced by these nodes contains no edges. A maximal - independent set is an independent set such that it is not possible - to add a new node and still get an independent set. - - Parameters - ---------- - G : NetworkX graph - - nodes : list or iterable - Nodes that must be part of the independent set. This set of nodes - must be independent. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - indep_nodes : list - List of nodes that are part of a maximal independent set. - - Raises - ------ - NetworkXUnfeasible - If the nodes in the provided list are not part of the graph or - do not form an independent set, an exception is raised. - - NetworkXNotImplemented - If `G` is directed. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> nx.maximal_independent_set(G) # doctest: +SKIP - [4, 0, 2] - >>> nx.maximal_independent_set(G, [1]) # doctest: +SKIP - [1, 3] - - Notes - ----- - This algorithm does not solve the maximum independent set problem. - - """ - if not nodes: - nodes = set([seed.choice(list(G))]) - else: - nodes = set(nodes) - if not nodes.issubset(G): - raise nx.NetworkXUnfeasible( - "%s is not a subset of the nodes of G" % nodes) - neighbors = set.union(*[set(G.adj[v]) for v in nodes]) - if set.intersection(neighbors, nodes): - raise nx.NetworkXUnfeasible( - "%s is not an independent set of G" % nodes) - indep_nodes = list(nodes) - available_nodes = set(G.nodes()).difference(neighbors.union(nodes)) - while available_nodes: - node = seed.choice(list(available_nodes)) - indep_nodes.append(node) - available_nodes.difference_update(list(G.adj[node]) + [node]) - return indep_nodes diff --git a/extensions/fablabchemnitz/networkx/algorithms/moral.py b/extensions/fablabchemnitz/networkx/algorithms/moral.py deleted file mode 100644 index bf6daa6f..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/moral.py +++ /dev/null @@ -1,57 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2011-2019 by -# Julien Klaus -# All rights reserved. -# BSD license. -# Copyright 2016-2019 NetworkX developers. -# NetworkX is distributed under a BSD license -# -# Authors: Julien Klaus -r"""Function for computing the moral graph of a directed graph.""" - -import networkx as nx -from networkx.utils import not_implemented_for -import itertools - -__all__ = ['moral_graph'] - - -@not_implemented_for('undirected') -def moral_graph(G): - r"""Return the Moral Graph - - Returns the moralized graph of a given directed graph. - - Parameters - ---------- - G : NetworkX graph - Directed graph - - Returns - ------- - H : NetworkX graph - The undirected moralized graph of G - - Notes - ------ - A moral graph is an undirected graph H = (V, E) generated from a - directed Graph, where if a node has more than one parent node, edges - between these parent nodes are inserted and all directed edges become - undirected. - - https://en.wikipedia.org/wiki/Moral_graph - - References - ---------- - .. [1] Wray L. Buntine. 1995. Chain graphs for learning. - In Proceedings of the Eleventh conference on Uncertainty - in artificial intelligence (UAI'95) - """ - if G is None: - raise ValueError("Expected NetworkX graph!") - - H = G.to_undirected() - for preds in G.pred.values(): - predecessors_combinations = itertools.combinations(preds, r=2) - H.add_edges_from(predecessors_combinations) - return H diff --git a/extensions/fablabchemnitz/networkx/algorithms/node_classification/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/node_classification/__init__.py deleted file mode 100644 index 7e75837e..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/node_classification/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -""" This module provides the functions for node classification problem. - -The functions in this module are not imported -into the top level `networkx` namespace. -You can access these functions by importing -the `networkx.algorithms.node_classification` modules, -then accessing the functions as attributes of `node_classification`. -For example: - - >>> import networkx as nx - >>> from networkx.algorithms import node_classification - >>> G = nx.path_graph(4) - >>> G.edges() - EdgeView([(0, 1), (1, 2), (2, 3)]) - >>> G.nodes[0]['label'] = 'A' - >>> G.nodes[3]['label'] = 'B' - >>> node_classification.harmonic_function(G) # doctest: +SKIP - ['A', 'A', 'B', 'B'] - -""" - -from networkx.algorithms.node_classification.hmn import * -from networkx.algorithms.node_classification.lgc import * diff --git a/extensions/fablabchemnitz/networkx/algorithms/node_classification/hmn.py b/extensions/fablabchemnitz/networkx/algorithms/node_classification/hmn.py deleted file mode 100644 index 41182249..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/node_classification/hmn.py +++ /dev/null @@ -1,151 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Author: Yuto Yamaguchi -"""Function for computing Harmonic function algorithm by Zhu et al. - -References ----------- -Zhu, X., Ghahramani, Z., & Lafferty, J. (2003, August). -Semi-supervised learning using gaussian fields and harmonic functions. -In ICML (Vol. 3, pp. 912-919). -""" -import networkx as nx - -from networkx.utils.decorators import not_implemented_for -from networkx.algorithms.node_classification.utils import ( - _get_label_info, - _init_label_matrix, - _propagate, - _predict, -) - -__all__ = ['harmonic_function'] - - -@not_implemented_for('directed') -def harmonic_function(G, max_iter=30, label_name='label'): - """Node classification by Harmonic function - - Parameters - ---------- - G : NetworkX Graph - max_iter : int - maximum number of iterations allowed - label_name : string - name of target labels to predict - - Raises - ---------- - `NetworkXError` if no nodes on `G` has `label_name`. - - Returns - ---------- - predicted : array, shape = [n_samples] - Array of predicted labels - - Examples - -------- - >>> from networkx.algorithms import node_classification - >>> G = nx.path_graph(4) - >>> G.nodes[0]['label'] = 'A' - >>> G.nodes[3]['label'] = 'B' - >>> G.nodes(data=True) - NodeDataView({0: {'label': 'A'}, 1: {}, 2: {}, 3: {'label': 'B'}}) - >>> G.edges() - EdgeView([(0, 1), (1, 2), (2, 3)]) - >>> predicted = node_classification.harmonic_function(G) - >>> predicted - ['A', 'A', 'B', 'B'] - - References - ---------- - Zhu, X., Ghahramani, Z., & Lafferty, J. (2003, August). - Semi-supervised learning using gaussian fields and harmonic functions. - In ICML (Vol. 3, pp. 912-919). - """ - try: - import numpy as np - except ImportError: - raise ImportError( - "harmonic_function() requires numpy: http://scipy.org/ ") - try: - from scipy import sparse - except ImportError: - raise ImportError( - "harmonic_function() requires scipy: http://scipy.org/ ") - - def _build_propagation_matrix(X, labels): - """Build propagation matrix of Harmonic function - - Parameters - ---------- - X : scipy sparse matrix, shape = [n_samples, n_samples] - Adjacency matrix - labels : array, shape = [n_samples, 2] - Array of pairs of node id and label id - - Returns - ---------- - P : scipy sparse matrix, shape = [n_samples, n_samples] - Propagation matrix - - """ - degrees = X.sum(axis=0).A[0] - degrees[degrees == 0] = 1 # Avoid division by 0 - D = sparse.diags((1.0 / degrees), offsets=0) - P = D.dot(X).tolil() - P[labels[:, 0]] = 0 # labels[:, 0] indicates IDs of labeled nodes - return P - - def _build_base_matrix(X, labels, n_classes): - """Build base matrix of Harmonic function - - Parameters - ---------- - X : scipy sparse matrix, shape = [n_samples, n_samples] - Adjacency matrix - labels : array, shape = [n_samples, 2] - Array of pairs of node id and label id - n_classes : integer - The number of classes (distinct labels) on the input graph - - Returns - ---------- - B : array, shape = [n_samples, n_classes] - Base matrix - """ - n_samples = X.shape[0] - B = np.zeros((n_samples, n_classes)) - B[labels[:, 0], labels[:, 1]] = 1 - return B - - X = nx.to_scipy_sparse_matrix(G) # adjacency matrix - labels, label_dict = _get_label_info(G, label_name) - - if labels.shape[0] == 0: - raise nx.NetworkXError( - "No node on the input graph is labeled by '" + label_name + "'.") - - n_samples = X.shape[0] - n_classes = label_dict.shape[0] - - F = _init_label_matrix(n_samples, n_classes) - - P = _build_propagation_matrix(X, labels) - B = _build_base_matrix(X, labels, n_classes) - - remaining_iter = max_iter - while remaining_iter > 0: - F = _propagate(P, F, B) - remaining_iter -= 1 - - predicted = _predict(F, label_dict) - - return predicted - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/node_classification/lgc.py b/extensions/fablabchemnitz/networkx/algorithms/node_classification/lgc.py deleted file mode 100644 index 8ae934bd..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/node_classification/lgc.py +++ /dev/null @@ -1,161 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Author: Yuto Yamaguchi -"""Function for computing Local and global consistency algorithm by Zhou et al. - -References ----------- -Zhou, D., Bousquet, O., Lal, T. N., Weston, J., & Schölkopf, B. (2004). -Learning with local and global consistency. -Advances in neural information processing systems, 16(16), 321-328. -""" -import networkx as nx - -from networkx.utils.decorators import not_implemented_for -from networkx.algorithms.node_classification.utils import ( - _get_label_info, - _init_label_matrix, - _propagate, - _predict, -) - -__all__ = ['local_and_global_consistency'] - - -@not_implemented_for('directed') -def local_and_global_consistency(G, alpha=0.99, - max_iter=30, - label_name='label'): - """Node classification by Local and Global Consistency - - Parameters - ---------- - G : NetworkX Graph - alpha : float - Clamping factor - max_iter : int - Maximum number of iterations allowed - label_name : string - Name of target labels to predict - - Raises - ---------- - `NetworkXError` if no nodes on `G` has `label_name`. - - Returns - ---------- - predicted : array, shape = [n_samples] - Array of predicted labels - - Examples - -------- - >>> from networkx.algorithms import node_classification - >>> G = nx.path_graph(4) - >>> G.nodes[0]['label'] = 'A' - >>> G.nodes[3]['label'] = 'B' - >>> G.nodes(data=True) - NodeDataView({0: {'label': 'A'}, 1: {}, 2: {}, 3: {'label': 'B'}}) - >>> G.edges() - EdgeView([(0, 1), (1, 2), (2, 3)]) - >>> predicted = node_classification.local_and_global_consistency(G) - >>> predicted - ['A', 'A', 'B', 'B'] - - - References - ---------- - Zhou, D., Bousquet, O., Lal, T. N., Weston, J., & Schölkopf, B. (2004). - Learning with local and global consistency. - Advances in neural information processing systems, 16(16), 321-328. - """ - try: - import numpy as np - except ImportError: - raise ImportError( - "local_and_global_consistency() requires numpy: ", - "http://scipy.org/ ") - try: - from scipy import sparse - except ImportError: - raise ImportError( - "local_and_global_consistensy() requires scipy: ", - "http://scipy.org/ ") - - def _build_propagation_matrix(X, labels, alpha): - """Build propagation matrix of Local and global consistency - - Parameters - ---------- - X : scipy sparse matrix, shape = [n_samples, n_samples] - Adjacency matrix - labels : array, shape = [n_samples, 2] - Array of pairs of node id and label id - alpha : float - Clamping factor - - Returns - ---------- - S : scipy sparse matrix, shape = [n_samples, n_samples] - Propagation matrix - - """ - degrees = X.sum(axis=0).A[0] - degrees[degrees == 0] = 1 # Avoid division by 0 - D2 = np.sqrt(sparse.diags((1.0 / degrees), offsets=0)) - S = alpha * D2.dot(X).dot(D2) - return S - - def _build_base_matrix(X, labels, alpha, n_classes): - """Build base matrix of Local and global consistency - - Parameters - ---------- - X : scipy sparse matrix, shape = [n_samples, n_samples] - Adjacency matrix - labels : array, shape = [n_samples, 2] - Array of pairs of node id and label id - alpha : float - Clamping factor - n_classes : integer - The number of classes (distinct labels) on the input graph - - Returns - ---------- - B : array, shape = [n_samples, n_classes] - Base matrix - """ - - n_samples = X.shape[0] - B = np.zeros((n_samples, n_classes)) - B[labels[:, 0], labels[:, 1]] = 1 - alpha - return B - - X = nx.to_scipy_sparse_matrix(G) # adjacency matrix - labels, label_dict = _get_label_info(G, label_name) - - if labels.shape[0] == 0: - raise nx.NetworkXError( - "No node on the input graph is labeled by '" + label_name + "'.") - - n_samples = X.shape[0] - n_classes = label_dict.shape[0] - F = _init_label_matrix(n_samples, n_classes) - - P = _build_propagation_matrix(X, labels, alpha) - B = _build_base_matrix(X, labels, alpha, n_classes) - - remaining_iter = max_iter - while remaining_iter > 0: - F = _propagate(P, F, B) - remaining_iter -= 1 - - predicted = _predict(F, label_dict) - - return predicted - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/node_classification/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/node_classification/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/node_classification/tests/test_harmonic_function.py b/extensions/fablabchemnitz/networkx/algorithms/node_classification/tests/test_harmonic_function.py deleted file mode 100644 index 9e879526..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/node_classification/tests/test_harmonic_function.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env python -import pytest -numpy = pytest.importorskip('numpy') -scipy = pytest.importorskip('scipy') - -import networkx as nx -from networkx.algorithms import node_classification - - -class TestHarmonicFunction: - - def test_path_graph(self): - G = nx.path_graph(4) - label_name = 'label' - G.nodes[0][label_name] = 'A' - G.nodes[3][label_name] = 'B' - predicted = node_classification.harmonic_function( - G, label_name=label_name) - assert predicted[0] == 'A' - assert predicted[1] == 'A' - assert predicted[2] == 'B' - assert predicted[3] == 'B' - - @pytest.mark.xfail(nx.NetworkXError) - def test_no_labels(self): - G = nx.path_graph(4) - node_classification.harmonic_function(G) - - @pytest.mark.xfail(nx.NetworkXError) - def test_no_nodes(self): - G = nx.Graph() - node_classification.harmonic_function(G) - - @pytest.mark.xfail(nx.NetworkXError) - def test_no_edges(self): - G = nx.Graph() - G.add_node(1) - G.add_node(2) - node_classification.harmonic_function(G) - - @pytest.mark.xfail(nx.NetworkXNotImplemented) - def test_digraph(self): - G = nx.DiGraph() - G.add_edge(0, 1) - G.add_edge(1, 2) - G.add_edge(2, 3) - label_name = 'label' - G.nodes[0][label_name] = 'A' - G.nodes[3][label_name] = 'B' - node_classification.harmonic_function(G) - - def test_one_labeled_node(self): - G = nx.path_graph(4) - label_name = 'label' - G.nodes[0][label_name] = 'A' - predicted = node_classification.harmonic_function( - G, label_name=label_name) - assert predicted[0] == 'A' - assert predicted[1] == 'A' - assert predicted[2] == 'A' - assert predicted[3] == 'A' - - def test_nodes_all_labeled(self): - G = nx.karate_club_graph() - label_name = 'club' - predicted = node_classification.harmonic_function( - G, label_name=label_name) - for i in range(len(G)): - assert predicted[i] == G.nodes[i][label_name] - - def test_labeled_nodes_are_not_changed(self): - G = nx.karate_club_graph() - label_name = 'club' - label_removed = set([0, 1, 2, 3, 4, 5, 6, 7]) - for i in label_removed: - del G.nodes[i][label_name] - predicted = node_classification.harmonic_function( - G, label_name=label_name) - label_not_removed = set(list(range(len(G)))) - label_removed - for i in label_not_removed: - assert predicted[i] == G.nodes[i][label_name] diff --git a/extensions/fablabchemnitz/networkx/algorithms/node_classification/tests/test_local_and_global_consistency.py b/extensions/fablabchemnitz/networkx/algorithms/node_classification/tests/test_local_and_global_consistency.py deleted file mode 100644 index d5fbedab..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/node_classification/tests/test_local_and_global_consistency.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python -import pytest -import pytest -numpy = pytest.importorskip('numpy') -scipy = pytest.importorskip('scipy') - - -import networkx as nx -from networkx.algorithms import node_classification - - -class TestLocalAndGlobalConsistency: - - def test_path_graph(self): - G = nx.path_graph(4) - label_name = 'label' - G.nodes[0][label_name] = 'A' - G.nodes[3][label_name] = 'B' - predicted = node_classification.local_and_global_consistency( - G, label_name=label_name) - assert predicted[0] == 'A' - assert predicted[1] == 'A' - assert predicted[2] == 'B' - assert predicted[3] == 'B' - - def test_no_labels(self): - with pytest.raises(nx.NetworkXError): - G = nx.path_graph(4) - node_classification.local_and_global_consistency(G) - - def test_no_nodes(self): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - node_classification.local_and_global_consistency(G) - - def test_no_edges(self): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - G.add_node(1) - G.add_node(2) - node_classification.local_and_global_consistency(G) - - def test_digraph(self): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.DiGraph() - G.add_edge(0, 1) - G.add_edge(1, 2) - G.add_edge(2, 3) - label_name = 'label' - G.nodes[0][label_name] = 'A' - G.nodes[3][label_name] = 'B' - node_classification.harmonic_function(G) - - def test_one_labeled_node(self): - G = nx.path_graph(4) - label_name = 'label' - G.nodes[0][label_name] = 'A' - predicted = node_classification.local_and_global_consistency( - G, label_name=label_name) - assert predicted[0] == 'A' - assert predicted[1] == 'A' - assert predicted[2] == 'A' - assert predicted[3] == 'A' - - def test_nodes_all_labeled(self): - G = nx.karate_club_graph() - label_name = 'club' - predicted = node_classification.local_and_global_consistency( - G, alpha=0, label_name=label_name) - for i in range(len(G)): - assert predicted[i] == G.nodes[i][label_name] diff --git a/extensions/fablabchemnitz/networkx/algorithms/node_classification/utils.py b/extensions/fablabchemnitz/networkx/algorithms/node_classification/utils.py deleted file mode 100644 index 39d5d3cd..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/node_classification/utils.py +++ /dev/null @@ -1,102 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Author: Yuto Yamaguchi - -def _propagate(P, F, B): - """Propagate labels by one step - - Parameters - ---------- - P : scipy sparse matrix, shape = [n_samples, n_samples] - Propagation matrix - F : numpy array, shape = [n_samples, n_classes] - Label matrix - B : numpy array, shape = [n_samples, n_classes] - Base matrix - - Returns - ---------- - F_new : array, shape = [n_samples, n_classes] - Label matrix - """ - F_new = P.dot(F) + B - return F_new - - -def _get_label_info(G, label_name): - """Get and return information of labels from the input graph - - Parameters - ---------- - G : Network X graph - label_name : string - Name of the target label - - Returns - ---------- - labels : numpy array, shape = [n_labeled_samples, 2] - Array of pairs of labeled node ID and label ID - label_dict : numpy array, shape = [n_classes] - Array of labels - i-th element contains the label corresponding label ID `i` - """ - import numpy as np - - labels = [] - label_to_id = {} - lid = 0 - for i, n in enumerate(G.nodes(data=True)): - if label_name in n[1]: - label = n[1][label_name] - if label not in label_to_id: - label_to_id[label] = lid - lid += 1 - labels.append([i, label_to_id[label]]) - labels = np.array(labels) - label_dict = np.array([label for label, _ in sorted( - label_to_id.items(), key=lambda x:x[1])]) - return (labels, label_dict) - - -def _init_label_matrix(n_samples, n_classes): - """Create and return zero matrix - - Parameters - ---------- - n_samples : integer - The number of nodes (samples) on the input graph - n_classes : integer - The number of classes (distinct labels) on the input graph - - Returns - ---------- - F : numpy array, shape = [n_samples, n_classes] - Label matrix - """ - import numpy as np - - F = np.zeros((n_samples, n_classes)) - return F - - -def _predict(F, label_dict): - """Predict labels by learnt label matrix - - Parameters - ---------- - F : numpy array, shape = [n_samples, n_classes] - Learnt (resulting) label matrix - label_dict : numpy array, shape = [n_classes] - Array of labels - i-th element contains the label corresponding label ID `i` - - Returns - ---------- - predicted : numpy array, shape = [n_samples] - Array of predicted labels - """ - import numpy as np - - predicted_label_ids = np.argmax(F, axis=1) - predicted = label_dict[predicted_label_ids].tolist() - return predicted diff --git a/extensions/fablabchemnitz/networkx/algorithms/non_randomness.py b/extensions/fablabchemnitz/networkx/algorithms/non_randomness.py deleted file mode 100644 index 8846fc65..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/non_randomness.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Erwan Le Merrer (erwan.le-merrer@inria.fr) - -r""" Computation of graph non-randomness -""" - -import math -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ['non_randomness'] - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def non_randomness(G, k=None): - """Compute the non-randomness of graph G. - - The first returned value nr is the sum of non-randomness values of all - edges within the graph (where the non-randomness of an edge tends to be - small when the two nodes linked by that edge are from two different - communities). - - The second computed value nr_rd is a relative measure that indicates - to what extent graph G is different from random graphs in terms - of probability. When it is close to 0, the graph tends to be more - likely generated by an Erdos Renyi model. - - Parameters - ---------- - G : NetworkX graph - Graph must be binary, symmetric, connected, and without self-loops. - - k : int - The number of communities in G. - If k is not set, the function will use a default community - detection algorithm to set it. - - Returns - ------- - non-randomness : (float, float) tuple - Non-randomness, Relative non-randomness w.r.t. - Erdos Renyi random graphs. - - Examples - -------- - >>> G = nx.karate_club_graph() - >>> nr, nr_rd = nx.non_randomness(G, 2) - - Notes - ----- - This computes Eq. (4.4) and (4.5) in Ref. [1]_. - - References - ---------- - .. [1] Xiaowei Ying and Xintao Wu, - On Randomness Measures for Social Networks, - SIAM International Conference on Data Mining. 2009 - """ - - if not nx.is_connected(G): - raise nx.NetworkXException("Non connected graph.") - if len(list(nx.selfloop_edges(G))) > 0: - raise nx.NetworkXError('Graph must not contain self-loops') - - if k is None: - k = len(tuple(nx.community.label_propagation_communities(G))) - - try: - import numpy as np - except ImportError: - msg = "non_randomness requires NumPy: http://scipy.org/" - raise ImportError(msg) - - # eq. 4.4 - nr = np.real(np.sum(np.linalg.eigvals(nx.to_numpy_matrix(G))[:k])) - - n = G.number_of_nodes() - m = G.number_of_edges() - p = (2 * k * m) / (n * (n - k)) - - # eq. 4.5 - nr_rd = (nr - ((n - 2 * k) * p + k)) / math.sqrt(2 * k * p * (1 - p)) - - return nr, nr_rd - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/operators/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/operators/__init__.py deleted file mode 100644 index 0ebc6ab9..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/operators/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from networkx.algorithms.operators.all import * -from networkx.algorithms.operators.binary import * -from networkx.algorithms.operators.product import * -from networkx.algorithms.operators.unary import * diff --git a/extensions/fablabchemnitz/networkx/algorithms/operators/all.py b/extensions/fablabchemnitz/networkx/algorithms/operators/all.py deleted file mode 100644 index 3d5d50fc..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/operators/all.py +++ /dev/null @@ -1,176 +0,0 @@ -"""Operations on many graphs. -""" -# Copyright (C) 2013 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -try: - from itertools import izip_longest as zip_longest -except ImportError: # Python3 has zip_longest - from itertools import zip_longest -import networkx as nx - -__author__ = """\n""".join(['Robert King ', - 'Aric Hagberg ']) - -__all__ = ['union_all', 'compose_all', 'disjoint_union_all', - 'intersection_all'] - - -def union_all(graphs, rename=(None,)): - """Returns the union of all graphs. - - The graphs must be disjoint, otherwise an exception is raised. - - Parameters - ---------- - graphs : list of graphs - List of NetworkX graphs - - rename : bool , default=(None, None) - Node names of G and H can be changed by specifying the tuple - rename=('G-','H-') (for example). Node "u" in G is then renamed - "G-u" and "v" in H is renamed "H-v". - - Returns - ------- - U : a graph with the same type as the first graph in list - - Raises - ------ - ValueError - If `graphs` is an empty list. - - Notes - ----- - To force a disjoint union with node relabeling, use - disjoint_union_all(G,H) or convert_node_labels_to integers(). - - Graph, edge, and node attributes are propagated to the union graph. - If a graph attribute is present in multiple graphs, then the value - from the last graph in the list with that attribute is used. - - See Also - -------- - union - disjoint_union_all - """ - if not graphs: - raise ValueError('cannot apply union_all to an empty list') - graphs_names = zip_longest(graphs, rename) - U, gname = next(graphs_names) - for H, hname in graphs_names: - U = nx.union(U, H, (gname, hname)) - gname = None - return U - - -def disjoint_union_all(graphs): - """Returns the disjoint union of all graphs. - - This operation forces distinct integer node labels starting with 0 - for the first graph in the list and numbering consecutively. - - Parameters - ---------- - graphs : list - List of NetworkX graphs - - Returns - ------- - U : A graph with the same type as the first graph in list - - Raises - ------ - ValueError - If `graphs` is an empty list. - - Notes - ----- - It is recommended that the graphs be either all directed or all undirected. - - Graph, edge, and node attributes are propagated to the union graph. - If a graph attribute is present in multiple graphs, then the value - from the last graph in the list with that attribute is used. - """ - if not graphs: - raise ValueError('cannot apply disjoint_union_all to an empty list') - graphs = iter(graphs) - U = next(graphs) - for H in graphs: - U = nx.disjoint_union(U, H) - return U - - -def compose_all(graphs): - """Returns the composition of all graphs. - - Composition is the simple union of the node sets and edge sets. - The node sets of the supplied graphs need not be disjoint. - - Parameters - ---------- - graphs : list - List of NetworkX graphs - - Returns - ------- - C : A graph with the same type as the first graph in list - - Raises - ------ - ValueError - If `graphs` is an empty list. - - Notes - ----- - It is recommended that the supplied graphs be either all directed or all - undirected. - - Graph, edge, and node attributes are propagated to the union graph. - If a graph attribute is present in multiple graphs, then the value - from the last graph in the list with that attribute is used. - """ - if not graphs: - raise ValueError('cannot apply compose_all to an empty list') - graphs = iter(graphs) - C = next(graphs) - for H in graphs: - C = nx.compose(C, H) - return C - - -def intersection_all(graphs): - """Returns a new graph that contains only the edges that exist in - all graphs. - - All supplied graphs must have the same node set. - - Parameters - ---------- - graphs : list - List of NetworkX graphs - - Returns - ------- - R : A new graph with the same type as the first graph in list - - Raises - ------ - ValueError - If `graphs` is an empty list. - - Notes - ----- - Attributes from the graph, nodes, and edges are not copied to the new - graph. - """ - if not graphs: - raise ValueError('cannot apply intersection_all to an empty list') - graphs = iter(graphs) - R = next(graphs) - for H in graphs: - R = nx.intersection(R, H) - return R diff --git a/extensions/fablabchemnitz/networkx/algorithms/operators/binary.py b/extensions/fablabchemnitz/networkx/algorithms/operators/binary.py deleted file mode 100644 index b0b97f88..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/operators/binary.py +++ /dev/null @@ -1,401 +0,0 @@ -""" -Operations on graphs including union, intersection, difference. -""" -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -import networkx as nx -from networkx.utils import is_string_like -__author__ = """\n""".join(['Aric Hagberg ', - 'Pieter Swart (swart@lanl.gov)', - 'Dan Schult(dschult@colgate.edu)']) -__all__ = ['union', 'compose', 'disjoint_union', 'intersection', - 'difference', 'symmetric_difference', 'full_join'] - - -def union(G, H, rename=(None, None), name=None): - """ Return the union of graphs G and H. - - Graphs G and H must be disjoint, otherwise an exception is raised. - - Parameters - ---------- - G,H : graph - A NetworkX graph - - rename : bool , default=(None, None) - Node names of G and H can be changed by specifying the tuple - rename=('G-','H-') (for example). Node "u" in G is then renamed - "G-u" and "v" in H is renamed "H-v". - - name : string - Specify the name for the union graph - - Returns - ------- - U : A union graph with the same type as G. - - Notes - ----- - To force a disjoint union with node relabeling, use - disjoint_union(G,H) or convert_node_labels_to integers(). - - Graph, edge, and node attributes are propagated from G and H - to the union graph. If a graph attribute is present in both - G and H the value from H is used. - - See Also - -------- - disjoint_union - """ - if not G.is_multigraph() == H.is_multigraph(): - raise nx.NetworkXError('G and H must both be graphs or multigraphs.') - # Union is the same type as G - R = G.__class__() - # add graph attributes, H attributes take precedent over G attributes - R.graph.update(G.graph) - R.graph.update(H.graph) - - # rename graph to obtain disjoint node labels - def add_prefix(graph, prefix): - if prefix is None: - return graph - - def label(x): - if is_string_like(x): - name = prefix + x - else: - name = prefix + repr(x) - return name - return nx.relabel_nodes(graph, label) - G = add_prefix(G, rename[0]) - H = add_prefix(H, rename[1]) - if set(G) & set(H): - raise nx.NetworkXError('The node sets of G and H are not disjoint.', - 'Use appropriate rename=(Gprefix,Hprefix)' - 'or use disjoint_union(G,H).') - if G.is_multigraph(): - G_edges = G.edges(keys=True, data=True) - else: - G_edges = G.edges(data=True) - if H.is_multigraph(): - H_edges = H.edges(keys=True, data=True) - else: - H_edges = H.edges(data=True) - - # add nodes - R.add_nodes_from(G) - R.add_edges_from(G_edges) - # add edges - R.add_nodes_from(H) - R.add_edges_from(H_edges) - # add node attributes - for n in G: - R.nodes[n].update(G.nodes[n]) - for n in H: - R.nodes[n].update(H.nodes[n]) - - return R - - -def disjoint_union(G, H): - """ Return the disjoint union of graphs G and H. - - This algorithm forces distinct integer node labels. - - Parameters - ---------- - G,H : graph - A NetworkX graph - - Returns - ------- - U : A union graph with the same type as G. - - Notes - ----- - A new graph is created, of the same class as G. It is recommended - that G and H be either both directed or both undirected. - - The nodes of G are relabeled 0 to len(G)-1, and the nodes of H are - relabeled len(G) to len(G)+len(H)-1. - - Graph, edge, and node attributes are propagated from G and H - to the union graph. If a graph attribute is present in both - G and H the value from H is used. - """ - R1 = nx.convert_node_labels_to_integers(G) - R2 = nx.convert_node_labels_to_integers(H, first_label=len(R1)) - R = union(R1, R2) - R.graph.update(G.graph) - R.graph.update(H.graph) - return R - - -def intersection(G, H): - """Returns a new graph that contains only the edges that exist in - both G and H. - - The node sets of H and G must be the same. - - Parameters - ---------- - G,H : graph - A NetworkX graph. G and H must have the same node sets. - - Returns - ------- - GH : A new graph with the same type as G. - - Notes - ----- - Attributes from the graph, nodes, and edges are not copied to the new - graph. If you want a new graph of the intersection of G and H - with the attributes (including edge data) from G use remove_nodes_from() - as follows - - >>> G=nx.path_graph(3) - >>> H=nx.path_graph(5) - >>> R=G.copy() - >>> R.remove_nodes_from(n for n in G if n not in H) - """ - # create new graph - R = nx.create_empty_copy(G) - - if not G.is_multigraph() == H.is_multigraph(): - raise nx.NetworkXError('G and H must both be graphs or multigraphs.') - if set(G) != set(H): - raise nx.NetworkXError("Node sets of graphs are not equal") - - if G.number_of_edges() <= H.number_of_edges(): - if G.is_multigraph(): - edges = G.edges(keys=True) - else: - edges = G.edges() - for e in edges: - if H.has_edge(*e): - R.add_edge(*e) - else: - if H.is_multigraph(): - edges = H.edges(keys=True) - else: - edges = H.edges() - for e in edges: - if G.has_edge(*e): - R.add_edge(*e) - return R - - -def difference(G, H): - """Returns a new graph that contains the edges that exist in G but not in H. - - The node sets of H and G must be the same. - - Parameters - ---------- - G,H : graph - A NetworkX graph. G and H must have the same node sets. - - Returns - ------- - D : A new graph with the same type as G. - - Notes - ----- - Attributes from the graph, nodes, and edges are not copied to the new - graph. If you want a new graph of the difference of G and H with - with the attributes (including edge data) from G use remove_nodes_from() - as follows: - - >>> G = nx.path_graph(3) - >>> H = nx.path_graph(5) - >>> R = G.copy() - >>> R.remove_nodes_from(n for n in G if n in H) - """ - # create new graph - if not G.is_multigraph() == H.is_multigraph(): - raise nx.NetworkXError('G and H must both be graphs or multigraphs.') - R = nx.create_empty_copy(G) - - if set(G) != set(H): - raise nx.NetworkXError("Node sets of graphs not equal") - - if G.is_multigraph(): - edges = G.edges(keys=True) - else: - edges = G.edges() - for e in edges: - if not H.has_edge(*e): - R.add_edge(*e) - return R - - -def symmetric_difference(G, H): - """Returns new graph with edges that exist in either G or H but not both. - - The node sets of H and G must be the same. - - Parameters - ---------- - G,H : graph - A NetworkX graph. G and H must have the same node sets. - - Returns - ------- - D : A new graph with the same type as G. - - Notes - ----- - Attributes from the graph, nodes, and edges are not copied to the new - graph. - """ - # create new graph - if not G.is_multigraph() == H.is_multigraph(): - raise nx.NetworkXError('G and H must both be graphs or multigraphs.') - R = nx.create_empty_copy(G) - - if set(G) != set(H): - raise nx.NetworkXError("Node sets of graphs not equal") - - gnodes = set(G) # set of nodes in G - hnodes = set(H) # set of nodes in H - nodes = gnodes.symmetric_difference(hnodes) - R.add_nodes_from(nodes) - - if G.is_multigraph(): - edges = G.edges(keys=True) - else: - edges = G.edges() - # we could copy the data here but then this function doesn't - # match intersection and difference - for e in edges: - if not H.has_edge(*e): - R.add_edge(*e) - - if H.is_multigraph(): - edges = H.edges(keys=True) - else: - edges = H.edges() - for e in edges: - if not G.has_edge(*e): - R.add_edge(*e) - return R - - -def compose(G, H): - """Returns a new graph of G composed with H. - - Composition is the simple union of the node sets and edge sets. - The node sets of G and H do not need to be disjoint. - - Parameters - ---------- - G, H : graph - A NetworkX graph - - Returns - ------- - C: A new graph with the same type as G - - Notes - ----- - It is recommended that G and H be either both directed or both undirected. - Attributes from H take precedent over attributes from G. - - For MultiGraphs, the edges are identified by incident nodes AND edge-key. - This can cause surprises (i.e., edge `(1, 2)` may or may not be the same - in two graphs) if you use MultiGraph without keeping track of edge keys. - """ - if not G.is_multigraph() == H.is_multigraph(): - raise nx.NetworkXError('G and H must both be graphs or multigraphs.') - - R = G.__class__() - # add graph attributes, H attributes take precedent over G attributes - R.graph.update(G.graph) - R.graph.update(H.graph) - - R.add_nodes_from(G.nodes(data=True)) - R.add_nodes_from(H.nodes(data=True)) - - if G.is_multigraph(): - R.add_edges_from(G.edges(keys=True, data=True)) - else: - R.add_edges_from(G.edges(data=True)) - if H.is_multigraph(): - R.add_edges_from(H.edges(keys=True, data=True)) - else: - R.add_edges_from(H.edges(data=True)) - return R - - -def full_join(G, H, rename=(None, None)): - """Returns the full join of graphs G and H. - - Full join is the union of G and H in which all edges between - G and H are added. - The node sets of G and H must be disjoint, - otherwise an exception is raised. - - Parameters - ---------- - G, H : graph - A NetworkX graph - - rename : bool , default=(None, None) - Node names of G and H can be changed by specifying the tuple - rename=('G-','H-') (for example). Node "u" in G is then renamed - "G-u" and "v" in H is renamed "H-v". - - Returns - ------- - U : The full join graph with the same type as G. - - Notes - ----- - It is recommended that G and H be either both directed or both undirected. - - If G is directed, then edges from G to H are added as well as from H to G. - - Note that full_join() does not produce parallel edges for MultiGraphs. - - The full join operation of graphs G and H is the same as getting - their complement, performing a disjoint union, and finally getting - the complement of the resulting graph. - - Graph, edge, and node attributes are propagated from G and H - to the union graph. If a graph attribute is present in both - G and H the value from H is used. - - See Also - -------- - union - disjoint_union - """ - R = union(G, H, rename) - - def add_prefix(graph, prefix): - if prefix is None: - return graph - - def label(x): - if is_string_like(x): - name = prefix + x - else: - name = prefix + repr(x) - return name - return nx.relabel_nodes(graph, label) - G = add_prefix(G, rename[0]) - H = add_prefix(H, rename[1]) - - for i in G: - for j in H: - R.add_edge(i, j) - if R.is_directed(): - for i in H: - for j in G: - R.add_edge(i, j) - - return R diff --git a/extensions/fablabchemnitz/networkx/algorithms/operators/product.py b/extensions/fablabchemnitz/networkx/algorithms/operators/product.py deleted file mode 100644 index b8696116..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/operators/product.py +++ /dev/null @@ -1,468 +0,0 @@ -# Copyright (C) 2011 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: -# Aric Hagberg -# Pieter Swart -# Dan Schult -# Ben Edwards -""" -Graph products. -""" -from itertools import product - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ['tensor_product', 'cartesian_product', - 'lexicographic_product', 'strong_product', 'power', - 'rooted_product'] - - -def _dict_product(d1, d2): - return dict((k, (d1.get(k), d2.get(k))) for k in set(d1) | set(d2)) - - -# Generators for producting graph products -def _node_product(G, H): - for u, v in product(G, H): - yield ((u, v), _dict_product(G.nodes[u], H.nodes[v])) - - -def _directed_edges_cross_edges(G, H): - if not G.is_multigraph() and not H.is_multigraph(): - for u, v, c in G.edges(data=True): - for x, y, d in H.edges(data=True): - yield (u, x), (v, y), _dict_product(c, d) - if not G.is_multigraph() and H.is_multigraph(): - for u, v, c in G.edges(data=True): - for x, y, k, d in H.edges(data=True, keys=True): - yield (u, x), (v, y), k, _dict_product(c, d) - if G.is_multigraph() and not H.is_multigraph(): - for u, v, k, c in G.edges(data=True, keys=True): - for x, y, d in H.edges(data=True): - yield (u, x), (v, y), k, _dict_product(c, d) - if G.is_multigraph() and H.is_multigraph(): - for u, v, j, c in G.edges(data=True, keys=True): - for x, y, k, d in H.edges(data=True, keys=True): - yield (u, x), (v, y), (j, k), _dict_product(c, d) - - -def _undirected_edges_cross_edges(G, H): - if not G.is_multigraph() and not H.is_multigraph(): - for u, v, c in G.edges(data=True): - for x, y, d in H.edges(data=True): - yield (v, x), (u, y), _dict_product(c, d) - if not G.is_multigraph() and H.is_multigraph(): - for u, v, c in G.edges(data=True): - for x, y, k, d in H.edges(data=True, keys=True): - yield (v, x), (u, y), k, _dict_product(c, d) - if G.is_multigraph() and not H.is_multigraph(): - for u, v, k, c in G.edges(data=True, keys=True): - for x, y, d in H.edges(data=True): - yield (v, x), (u, y), k, _dict_product(c, d) - if G.is_multigraph() and H.is_multigraph(): - for u, v, j, c in G.edges(data=True, keys=True): - for x, y, k, d in H.edges(data=True, keys=True): - yield (v, x), (u, y), (j, k), _dict_product(c, d) - - -def _edges_cross_nodes(G, H): - if G.is_multigraph(): - for u, v, k, d in G.edges(data=True, keys=True): - for x in H: - yield (u, x), (v, x), k, d - else: - for u, v, d in G.edges(data=True): - for x in H: - if H.is_multigraph(): - yield (u, x), (v, x), None, d - else: - yield (u, x), (v, x), d - - -def _nodes_cross_edges(G, H): - if H.is_multigraph(): - for x in G: - for u, v, k, d in H.edges(data=True, keys=True): - yield (x, u), (x, v), k, d - else: - for x in G: - for u, v, d in H.edges(data=True): - if G.is_multigraph(): - yield (x, u), (x, v), None, d - else: - yield (x, u), (x, v), d - - -def _edges_cross_nodes_and_nodes(G, H): - if G.is_multigraph(): - for u, v, k, d in G.edges(data=True, keys=True): - for x in H: - for y in H: - yield (u, x), (v, y), k, d - else: - for u, v, d in G.edges(data=True): - for x in H: - for y in H: - if H.is_multigraph(): - yield (u, x), (v, y), None, d - else: - yield (u, x), (v, y), d - - -def _init_product_graph(G, H): - if not G.is_directed() == H.is_directed(): - msg = "G and H must be both directed or both undirected" - raise nx.NetworkXError(msg) - if G.is_multigraph() or H.is_multigraph(): - GH = nx.MultiGraph() - else: - GH = nx.Graph() - if G.is_directed(): - GH = GH.to_directed() - return GH - - -def tensor_product(G, H): - r"""Returns the tensor product of G and H. - - The tensor product $P$ of the graphs $G$ and $H$ has a node set that - is the tensor product of the node sets, $V(P)=V(G) \times V(H)$. - $P$ has an edge $((u,v), (x,y))$ if and only if $(u,x)$ is an edge in $G$ - and $(v,y)$ is an edge in $H$. - - Tensor product is sometimes also referred to as the categorical product, - direct product, cardinal product or conjunction. - - - Parameters - ---------- - G, H: graphs - Networkx graphs. - - Returns - ------- - P: NetworkX graph - The tensor product of G and H. P will be a multi-graph if either G - or H is a multi-graph, will be a directed if G and H are directed, - and undirected if G and H are undirected. - - Raises - ------ - NetworkXError - If G and H are not both directed or both undirected. - - Notes - ----- - Node attributes in P are two-tuple of the G and H node attributes. - Missing attributes are assigned None. - - Examples - -------- - >>> G = nx.Graph() - >>> H = nx.Graph() - >>> G.add_node(0, a1=True) - >>> H.add_node('a', a2='Spam') - >>> P = nx.tensor_product(G, H) - >>> list(P) - [(0, 'a')] - - Edge attributes and edge keys (for multigraphs) are also copied to the - new product graph - """ - GH = _init_product_graph(G, H) - GH.add_nodes_from(_node_product(G, H)) - GH.add_edges_from(_directed_edges_cross_edges(G, H)) - if not GH.is_directed(): - GH.add_edges_from(_undirected_edges_cross_edges(G, H)) - return GH - - -def cartesian_product(G, H): - r"""Returns the Cartesian product of G and H. - - The Cartesian product $P$ of the graphs $G$ and $H$ has a node set that - is the Cartesian product of the node sets, $V(P)=V(G) \times V(H)$. - $P$ has an edge $((u,v),(x,y))$ if and only if either $u$ is equal to $x$ - and both $v$ and $y$ are adjacent in $H$ or if $v$ is equal to $y$ and - both $u$ and $x$ are adjacent in $G$. - - Parameters - ---------- - G, H: graphs - Networkx graphs. - - Returns - ------- - P: NetworkX graph - The Cartesian product of G and H. P will be a multi-graph if either G - or H is a multi-graph. Will be a directed if G and H are directed, - and undirected if G and H are undirected. - - Raises - ------ - NetworkXError - If G and H are not both directed or both undirected. - - Notes - ----- - Node attributes in P are two-tuple of the G and H node attributes. - Missing attributes are assigned None. - - Examples - -------- - >>> G = nx.Graph() - >>> H = nx.Graph() - >>> G.add_node(0, a1=True) - >>> H.add_node('a', a2='Spam') - >>> P = nx.cartesian_product(G, H) - >>> list(P) - [(0, 'a')] - - Edge attributes and edge keys (for multigraphs) are also copied to the - new product graph - """ - GH = _init_product_graph(G, H) - GH.add_nodes_from(_node_product(G, H)) - GH.add_edges_from(_edges_cross_nodes(G, H)) - GH.add_edges_from(_nodes_cross_edges(G, H)) - return GH - - -def lexicographic_product(G, H): - r"""Returns the lexicographic product of G and H. - - The lexicographical product $P$ of the graphs $G$ and $H$ has a node set - that is the Cartesian product of the node sets, $V(P)=V(G) \times V(H)$. - $P$ has an edge $((u,v), (x,y))$ if and only if $(u,v)$ is an edge in $G$ - or $u==v$ and $(x,y)$ is an edge in $H$. - - Parameters - ---------- - G, H: graphs - Networkx graphs. - - Returns - ------- - P: NetworkX graph - The Cartesian product of G and H. P will be a multi-graph if either G - or H is a multi-graph. Will be a directed if G and H are directed, - and undirected if G and H are undirected. - - Raises - ------ - NetworkXError - If G and H are not both directed or both undirected. - - Notes - ----- - Node attributes in P are two-tuple of the G and H node attributes. - Missing attributes are assigned None. - - Examples - -------- - >>> G = nx.Graph() - >>> H = nx.Graph() - >>> G.add_node(0, a1=True) - >>> H.add_node('a', a2='Spam') - >>> P = nx.lexicographic_product(G, H) - >>> list(P) - [(0, 'a')] - - Edge attributes and edge keys (for multigraphs) are also copied to the - new product graph - """ - GH = _init_product_graph(G, H) - GH.add_nodes_from(_node_product(G, H)) - # Edges in G regardless of H designation - GH.add_edges_from(_edges_cross_nodes_and_nodes(G, H)) - # For each x in G, only if there is an edge in H - GH.add_edges_from(_nodes_cross_edges(G, H)) - return GH - - -def strong_product(G, H): - r"""Returns the strong product of G and H. - - The strong product $P$ of the graphs $G$ and $H$ has a node set that - is the Cartesian product of the node sets, $V(P)=V(G) \times V(H)$. - $P$ has an edge $((u,v), (x,y))$ if and only if - $u==v$ and $(x,y)$ is an edge in $H$, or - $x==y$ and $(u,v)$ is an edge in $G$, or - $(u,v)$ is an edge in $G$ and $(x,y)$ is an edge in $H$. - - Parameters - ---------- - G, H: graphs - Networkx graphs. - - Returns - ------- - P: NetworkX graph - The Cartesian product of G and H. P will be a multi-graph if either G - or H is a multi-graph. Will be a directed if G and H are directed, - and undirected if G and H are undirected. - - Raises - ------ - NetworkXError - If G and H are not both directed or both undirected. - - Notes - ----- - Node attributes in P are two-tuple of the G and H node attributes. - Missing attributes are assigned None. - - Examples - -------- - >>> G = nx.Graph() - >>> H = nx.Graph() - >>> G.add_node(0, a1=True) - >>> H.add_node('a', a2='Spam') - >>> P = nx.strong_product(G, H) - >>> list(P) - [(0, 'a')] - - Edge attributes and edge keys (for multigraphs) are also copied to the - new product graph - """ - GH = _init_product_graph(G, H) - GH.add_nodes_from(_node_product(G, H)) - GH.add_edges_from(_nodes_cross_edges(G, H)) - GH.add_edges_from(_edges_cross_nodes(G, H)) - GH.add_edges_from(_directed_edges_cross_edges(G, H)) - if not GH.is_directed(): - GH.add_edges_from(_undirected_edges_cross_edges(G, H)) - return GH - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def power(G, k): - """Returns the specified power of a graph. - - The $k$th power of a simple graph $G$, denoted $G^k$, is a - graph on the same set of nodes in which two distinct nodes $u$ and - $v$ are adjacent in $G^k$ if and only if the shortest path - distance between $u$ and $v$ in $G$ is at most $k$. - - Parameters - ---------- - G : graph - A NetworkX simple graph object. - - k : positive integer - The power to which to raise the graph `G`. - - Returns - ------- - NetworkX simple graph - `G` to the power `k`. - - Raises - ------ - ValueError - If the exponent `k` is not positive. - - NetworkXNotImplemented - If `G` is not a simple graph. - - Examples - -------- - The number of edges will never decrease when taking successive - powers: - - >>> G = nx.path_graph(4) - >>> list(nx.power(G, 2).edges) - [(0, 1), (0, 2), (1, 2), (1, 3), (2, 3)] - >>> list(nx.power(G, 3).edges) - [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)] - - The `k`th power of a cycle graph on *n* nodes is the complete graph - on *n* nodes, if `k` is at least ``n // 2``: - - >>> G = nx.cycle_graph(5) - >>> H = nx.complete_graph(5) - >>> nx.is_isomorphic(nx.power(G, 2), H) - True - >>> G = nx.cycle_graph(8) - >>> H = nx.complete_graph(8) - >>> nx.is_isomorphic(nx.power(G, 4), H) - True - - References - ---------- - .. [1] J. A. Bondy, U. S. R. Murty, *Graph Theory*. Springer, 2008. - - Notes - ----- - This definition of "power graph" comes from Exercise 3.1.6 of - *Graph Theory* by Bondy and Murty [1]_. - - """ - if k <= 0: - raise ValueError('k must be a positive integer') - H = nx.Graph() - H.add_nodes_from(G) - # update BFS code to ignore self loops. - for n in G: - seen = {} # level (number of hops) when seen in BFS - level = 1 # the current level - nextlevel = G[n] - while nextlevel: - thislevel = nextlevel # advance to next level - nextlevel = {} # and start a new list (fringe) - for v in thislevel: - if v == n: # avoid self loop - continue - if v not in seen: - seen[v] = level # set the level of vertex v - nextlevel.update(G[v]) # add neighbors of v - if k <= level: - break - level += 1 - H.add_edges_from((n, nbr) for nbr in seen) - return H - - -@not_implemented_for('multigraph') -def rooted_product(G, H, root): - """ Return the rooted product of graphs G and H rooted at root in H. - - A new graph is constructed representing the rooted product of - the inputted graphs, G and H, with a root in H. - A rooted product duplicates H for each nodes in G with the root - of H corresponding to the node in G. Nodes are renamed as the direct - product of G and H. The result is a subgraph of the cartesian product. - - Parameters - ---------- - G,H : graph - A NetworkX graph - root : node - A node in H - - Returns - ------- - R : The rooted product of G and H with a specified root in H - - Notes - ----- - The nodes of R are the Cartesian Product of the nodes of G and H. - The nodes of G and H are not relabeled. - """ - if root not in H: - raise nx.NetworkXError('root must be a vertex in H') - - R = nx.Graph() - R.add_nodes_from(product(G, H)) - - R.add_edges_from(((e[0], root), (e[1], root)) for e in G.edges()) - R.add_edges_from(((g, e[0]), (g, e[1])) for g in G for e in H.edges()) - - return R diff --git a/extensions/fablabchemnitz/networkx/algorithms/operators/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/operators/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/operators/tests/test_all.py b/extensions/fablabchemnitz/networkx/algorithms/operators/tests/test_all.py deleted file mode 100644 index 094a99aa..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/operators/tests/test_all.py +++ /dev/null @@ -1,221 +0,0 @@ -import pytest -import networkx as nx -from networkx.testing import * - - -def test_union_all_attributes(): - g = nx.Graph() - g.add_node(0, x=4) - g.add_node(1, x=5) - g.add_edge(0, 1, size=5) - g.graph['name'] = 'g' - - h = g.copy() - h.graph['name'] = 'h' - h.graph['attr'] = 'attr' - h.nodes[0]['x'] = 7 - - j = g.copy() - j.graph['name'] = 'j' - j.graph['attr'] = 'attr' - j.nodes[0]['x'] = 7 - - ghj = nx.union_all([g, h, j], rename=('g', 'h', 'j')) - assert set(ghj.nodes()) == set(['h0', 'h1', 'g0', 'g1', 'j0', 'j1']) - for n in ghj: - graph, node = n - assert ghj.nodes[n] == eval(graph).nodes[int(node)] - - assert ghj.graph['attr'] == 'attr' - assert ghj.graph['name'] == 'j' # j graph attributes take precendent - - -def test_intersection_all(): - G = nx.Graph() - H = nx.Graph() - R = nx.Graph() - G.add_nodes_from([1, 2, 3, 4]) - G.add_edge(1, 2) - G.add_edge(2, 3) - H.add_nodes_from([1, 2, 3, 4]) - H.add_edge(2, 3) - H.add_edge(3, 4) - R.add_nodes_from([1, 2, 3, 4]) - R.add_edge(2, 3) - R.add_edge(4, 1) - I = nx.intersection_all([G, H, R]) - assert set(I.nodes()) == set([1, 2, 3, 4]) - assert sorted(I.edges()) == [(2, 3)] - - -def test_intersection_all_attributes(): - g = nx.Graph() - g.add_node(0, x=4) - g.add_node(1, x=5) - g.add_edge(0, 1, size=5) - g.graph['name'] = 'g' - - h = g.copy() - h.graph['name'] = 'h' - h.graph['attr'] = 'attr' - h.nodes[0]['x'] = 7 - - gh = nx.intersection_all([g, h]) - assert set(gh.nodes()) == set(g.nodes()) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == sorted(g.edges()) - - h.remove_node(0) - pytest.raises(nx.NetworkXError, nx.intersection, g, h) - - -def test_intersection_all_multigraph_attributes(): - g = nx.MultiGraph() - g.add_edge(0, 1, key=0) - g.add_edge(0, 1, key=1) - g.add_edge(0, 1, key=2) - h = nx.MultiGraph() - h.add_edge(0, 1, key=0) - h.add_edge(0, 1, key=3) - gh = nx.intersection_all([g, h]) - assert set(gh.nodes()) == set(g.nodes()) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == [(0, 1)] - assert sorted(gh.edges(keys=True)) == [(0, 1, 0)] - - -def test_union_all_and_compose_all(): - K3 = nx.complete_graph(3) - P3 = nx.path_graph(3) - - G1 = nx.DiGraph() - G1.add_edge('A', 'B') - G1.add_edge('A', 'C') - G1.add_edge('A', 'D') - G2 = nx.DiGraph() - G2.add_edge('1', '2') - G2.add_edge('1', '3') - G2.add_edge('1', '4') - - G = nx.union_all([G1, G2]) - H = nx.compose_all([G1, G2]) - assert_edges_equal(G.edges(), H.edges()) - assert not G.has_edge('A', '1') - pytest.raises(nx.NetworkXError, nx.union, K3, P3) - H1 = nx.union_all([H, G1], rename=('H', 'G1')) - assert (sorted(H1.nodes()) == - ['G1A', 'G1B', 'G1C', 'G1D', - 'H1', 'H2', 'H3', 'H4', 'HA', 'HB', 'HC', 'HD']) - - H2 = nx.union_all([H, G2], rename=("H", "")) - assert (sorted(H2.nodes()) == - ['1', '2', '3', '4', - 'H1', 'H2', 'H3', 'H4', 'HA', 'HB', 'HC', 'HD']) - - assert not H1.has_edge('NB', 'NA') - - G = nx.compose_all([G, G]) - assert_edges_equal(G.edges(), H.edges()) - - G2 = nx.union_all([G2, G2], rename=('', 'copy')) - assert (sorted(G2.nodes()) == - ['1', '2', '3', '4', 'copy1', 'copy2', 'copy3', 'copy4']) - - assert sorted(G2.neighbors('copy4')) == [] - assert sorted(G2.neighbors('copy1')) == ['copy2', 'copy3', 'copy4'] - assert len(G) == 8 - assert nx.number_of_edges(G) == 6 - - E = nx.disjoint_union_all([G, G]) - assert len(E) == 16 - assert nx.number_of_edges(E) == 12 - - E = nx.disjoint_union_all([G1, G2]) - assert sorted(E.nodes()) == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] - - G1 = nx.DiGraph() - G1.add_edge('A', 'B') - G2 = nx.DiGraph() - G2.add_edge(1, 2) - G3 = nx.DiGraph() - G3.add_edge(11, 22) - G4 = nx.union_all([G1, G2, G3], rename=("G1", "G2", "G3")) - assert (sorted(G4.nodes()) == - ['G1A', 'G1B', 'G21', 'G22', - 'G311', 'G322']) - - -def test_union_all_multigraph(): - G = nx.MultiGraph() - G.add_edge(1, 2, key=0) - G.add_edge(1, 2, key=1) - H = nx.MultiGraph() - H.add_edge(3, 4, key=0) - H.add_edge(3, 4, key=1) - GH = nx.union_all([G, H]) - assert set(GH) == set(G) | set(H) - assert (set(GH.edges(keys=True)) == - set(G.edges(keys=True)) | set(H.edges(keys=True))) - - -def test_input_output(): - l = [nx.Graph([(1, 2)]), nx.Graph([(3, 4)])] - U = nx.disjoint_union_all(l) - assert len(l) == 2 - C = nx.compose_all(l) - assert len(l) == 2 - l = [nx.Graph([(1, 2)]), nx.Graph([(1, 2)])] - R = nx.intersection_all(l) - assert len(l) == 2 - - -def test_mixed_type_union(): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - H = nx.MultiGraph() - I = nx.Graph() - U = nx.union_all([G, H, I]) - - -def test_mixed_type_disjoint_union(): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - H = nx.MultiGraph() - I = nx.Graph() - U = nx.disjoint_union_all([G, H, I]) - - -def test_mixed_type_intersection(): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - H = nx.MultiGraph() - I = nx.Graph() - U = nx.intersection_all([G, H, I]) - - -def test_mixed_type_compose(): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - H = nx.MultiGraph() - I = nx.Graph() - U = nx.compose_all([G, H, I]) - - -def test_empty_union(): - with pytest.raises(ValueError): - nx.union_all([]) - - -def test_empty_disjoint_union(): - with pytest.raises(ValueError): - nx.disjoint_union_all([]) - - -def test_empty_compose_all(): - with pytest.raises(ValueError): - nx.compose_all([]) - - -def test_empty_intersection_all(): - with pytest.raises(ValueError): - nx.intersection_all([]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/operators/tests/test_binary.py b/extensions/fablabchemnitz/networkx/algorithms/operators/tests/test_binary.py deleted file mode 100644 index b27f26c0..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/operators/tests/test_binary.py +++ /dev/null @@ -1,383 +0,0 @@ -import pytest -import networkx as nx -from networkx.testing import assert_edges_equal - - -def test_union_attributes(): - g = nx.Graph() - g.add_node(0, x=4) - g.add_node(1, x=5) - g.add_edge(0, 1, size=5) - g.graph['name'] = 'g' - - h = g.copy() - h.graph['name'] = 'h' - h.graph['attr'] = 'attr' - h.nodes[0]['x'] = 7 - - gh = nx.union(g, h, rename=('g', 'h')) - assert set(gh.nodes()) == set(['h0', 'h1', 'g0', 'g1']) - for n in gh: - graph, node = n - assert gh.nodes[n] == eval(graph).nodes[int(node)] - - assert gh.graph['attr'] == 'attr' - assert gh.graph['name'] == 'h' # h graph attributes take precendent - - -def test_intersection(): - G = nx.Graph() - H = nx.Graph() - G.add_nodes_from([1, 2, 3, 4]) - G.add_edge(1, 2) - G.add_edge(2, 3) - H.add_nodes_from([1, 2, 3, 4]) - H.add_edge(2, 3) - H.add_edge(3, 4) - I = nx.intersection(G, H) - assert set(I.nodes()) == set([1, 2, 3, 4]) - assert sorted(I.edges()) == [(2, 3)] - - -def test_intersection_attributes(): - g = nx.Graph() - g.add_node(0, x=4) - g.add_node(1, x=5) - g.add_edge(0, 1, size=5) - g.graph['name'] = 'g' - - h = g.copy() - h.graph['name'] = 'h' - h.graph['attr'] = 'attr' - h.nodes[0]['x'] = 7 - - gh = nx.intersection(g, h) - assert set(gh.nodes()) == set(g.nodes()) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == sorted(g.edges()) - - h.remove_node(0) - pytest.raises(nx.NetworkXError, nx.intersection, g, h) - - -def test_intersection_multigraph_attributes(): - g = nx.MultiGraph() - g.add_edge(0, 1, key=0) - g.add_edge(0, 1, key=1) - g.add_edge(0, 1, key=2) - h = nx.MultiGraph() - h.add_edge(0, 1, key=0) - h.add_edge(0, 1, key=3) - gh = nx.intersection(g, h) - assert set(gh.nodes()) == set(g.nodes()) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == [(0, 1)] - assert sorted(gh.edges(keys=True)) == [(0, 1, 0)] - - -def test_difference(): - G = nx.Graph() - H = nx.Graph() - G.add_nodes_from([1, 2, 3, 4]) - G.add_edge(1, 2) - G.add_edge(2, 3) - H.add_nodes_from([1, 2, 3, 4]) - H.add_edge(2, 3) - H.add_edge(3, 4) - D = nx.difference(G, H) - assert set(D.nodes()) == set([1, 2, 3, 4]) - assert sorted(D.edges()) == [(1, 2)] - D = nx.difference(H, G) - assert set(D.nodes()) == set([1, 2, 3, 4]) - assert sorted(D.edges()) == [(3, 4)] - D = nx.symmetric_difference(G, H) - assert set(D.nodes()) == set([1, 2, 3, 4]) - assert sorted(D.edges()) == [(1, 2), (3, 4)] - - -def test_difference2(): - G = nx.Graph() - H = nx.Graph() - G.add_nodes_from([1, 2, 3, 4]) - H.add_nodes_from([1, 2, 3, 4]) - G.add_edge(1, 2) - H.add_edge(1, 2) - G.add_edge(2, 3) - D = nx.difference(G, H) - assert set(D.nodes()) == set([1, 2, 3, 4]) - assert sorted(D.edges()) == [(2, 3)] - D = nx.difference(H, G) - assert set(D.nodes()) == set([1, 2, 3, 4]) - assert sorted(D.edges()) == [] - H.add_edge(3, 4) - D = nx.difference(H, G) - assert set(D.nodes()) == set([1, 2, 3, 4]) - assert sorted(D.edges()) == [(3, 4)] - - -def test_difference_attributes(): - g = nx.Graph() - g.add_node(0, x=4) - g.add_node(1, x=5) - g.add_edge(0, 1, size=5) - g.graph['name'] = 'g' - - h = g.copy() - h.graph['name'] = 'h' - h.graph['attr'] = 'attr' - h.nodes[0]['x'] = 7 - - gh = nx.difference(g, h) - assert set(gh.nodes()) == set(g.nodes()) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == [] - - h.remove_node(0) - pytest.raises(nx.NetworkXError, nx.intersection, g, h) - - -def test_difference_multigraph_attributes(): - g = nx.MultiGraph() - g.add_edge(0, 1, key=0) - g.add_edge(0, 1, key=1) - g.add_edge(0, 1, key=2) - h = nx.MultiGraph() - h.add_edge(0, 1, key=0) - h.add_edge(0, 1, key=3) - gh = nx.difference(g, h) - assert set(gh.nodes()) == set(g.nodes()) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == [(0, 1), (0, 1)] - assert sorted(gh.edges(keys=True)) == [(0, 1, 1), (0, 1, 2)] - - -def test_difference_raise(): - G = nx.path_graph(4) - H = nx.path_graph(3) - pytest.raises(nx.NetworkXError, nx.difference, G, H) - pytest.raises(nx.NetworkXError, nx.symmetric_difference, G, H) - - -def test_symmetric_difference_multigraph(): - g = nx.MultiGraph() - g.add_edge(0, 1, key=0) - g.add_edge(0, 1, key=1) - g.add_edge(0, 1, key=2) - h = nx.MultiGraph() - h.add_edge(0, 1, key=0) - h.add_edge(0, 1, key=3) - gh = nx.symmetric_difference(g, h) - assert set(gh.nodes()) == set(g.nodes()) - assert set(gh.nodes()) == set(h.nodes()) - assert sorted(gh.edges()) == 3 * [(0, 1)] - assert (sorted(sorted(e) for e in gh.edges(keys=True)) == - [[0, 1, 1], [0, 1, 2], [0, 1, 3]]) - - -def test_union_and_compose(): - K3 = nx.complete_graph(3) - P3 = nx.path_graph(3) - - G1 = nx.DiGraph() - G1.add_edge('A', 'B') - G1.add_edge('A', 'C') - G1.add_edge('A', 'D') - G2 = nx.DiGraph() - G2.add_edge('1', '2') - G2.add_edge('1', '3') - G2.add_edge('1', '4') - - G = nx.union(G1, G2) - H = nx.compose(G1, G2) - assert_edges_equal(G.edges(), H.edges()) - assert not G.has_edge('A', 1) - pytest.raises(nx.NetworkXError, nx.union, K3, P3) - H1 = nx.union(H, G1, rename=('H', 'G1')) - assert (sorted(H1.nodes()) == - ['G1A', 'G1B', 'G1C', 'G1D', - 'H1', 'H2', 'H3', 'H4', 'HA', 'HB', 'HC', 'HD']) - - H2 = nx.union(H, G2, rename=("H", "")) - assert (sorted(H2.nodes()) == - ['1', '2', '3', '4', - 'H1', 'H2', 'H3', 'H4', 'HA', 'HB', 'HC', 'HD']) - - assert not H1.has_edge('NB', 'NA') - - G = nx.compose(G, G) - assert_edges_equal(G.edges(), H.edges()) - - G2 = nx.union(G2, G2, rename=('', 'copy')) - assert (sorted(G2.nodes()) == - ['1', '2', '3', '4', 'copy1', 'copy2', 'copy3', 'copy4']) - - assert sorted(G2.neighbors('copy4')) == [] - assert sorted(G2.neighbors('copy1')) == ['copy2', 'copy3', 'copy4'] - assert len(G) == 8 - assert nx.number_of_edges(G) == 6 - - E = nx.disjoint_union(G, G) - assert len(E) == 16 - assert nx.number_of_edges(E) == 12 - - E = nx.disjoint_union(G1, G2) - assert sorted(E.nodes()) == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] - - G = nx.Graph() - H = nx.Graph() - G.add_nodes_from([(1, {'a1': 1})]) - H.add_nodes_from([(1, {'b1': 1})]) - R = nx.compose(G, H) - assert R.nodes == {1: {'a1': 1, 'b1': 1}} - - -def test_union_multigraph(): - G = nx.MultiGraph() - G.add_edge(1, 2, key=0) - G.add_edge(1, 2, key=1) - H = nx.MultiGraph() - H.add_edge(3, 4, key=0) - H.add_edge(3, 4, key=1) - GH = nx.union(G, H) - assert set(GH) == set(G) | set(H) - assert (set(GH.edges(keys=True)) == - set(G.edges(keys=True)) | set(H.edges(keys=True))) - - -def test_disjoint_union_multigraph(): - G = nx.MultiGraph() - G.add_edge(0, 1, key=0) - G.add_edge(0, 1, key=1) - H = nx.MultiGraph() - H.add_edge(2, 3, key=0) - H.add_edge(2, 3, key=1) - GH = nx.disjoint_union(G, H) - assert set(GH) == set(G) | set(H) - assert (set(GH.edges(keys=True)) == - set(G.edges(keys=True)) | set(H.edges(keys=True))) - - -def test_compose_multigraph(): - G = nx.MultiGraph() - G.add_edge(1, 2, key=0) - G.add_edge(1, 2, key=1) - H = nx.MultiGraph() - H.add_edge(3, 4, key=0) - H.add_edge(3, 4, key=1) - GH = nx.compose(G, H) - assert set(GH) == set(G) | set(H) - assert (set(GH.edges(keys=True)) == - set(G.edges(keys=True)) | set(H.edges(keys=True))) - H.add_edge(1, 2, key=2) - GH = nx.compose(G, H) - assert set(GH) == set(G) | set(H) - assert (set(GH.edges(keys=True)) == - set(G.edges(keys=True)) | set(H.edges(keys=True))) - - -def test_full_join_graph(): - # Simple Graphs - G = nx.Graph() - G.add_node(0) - G.add_edge(1, 2) - H = nx.Graph() - H.add_edge(3, 4) - - U = nx.full_join(G, H) - assert set(U) == set(G) | set(H) - assert len(U) == len(G) + len(H) - assert (len(U.edges()) == - len(G.edges()) + len(H.edges()) + len(G) * len(H)) - - # Rename - U = nx.full_join(G, H, rename=('g', 'h')) - assert set(U) == set(['g0', 'g1', 'g2', 'h3', 'h4']) - assert len(U) == len(G) + len(H) - assert (len(U.edges()) == - len(G.edges()) + len(H.edges()) + len(G) * len(H)) - - # Rename graphs with string-like nodes - G = nx.Graph() - G.add_node("a") - G.add_edge("b", "c") - H = nx.Graph() - H.add_edge("d", "e") - - U = nx.full_join(G, H, rename=('g', 'h')) - assert set(U) == set(['ga', 'gb', 'gc', 'hd', 'he']) - assert len(U) == len(G) + len(H) - assert (len(U.edges()) == - len(G.edges()) + len(H.edges()) + len(G) * len(H)) - - # DiGraphs - G = nx.DiGraph() - G.add_node(0) - G.add_edge(1, 2) - H = nx.DiGraph() - H.add_edge(3, 4) - - U = nx.full_join(G, H) - assert set(U) == set(G) | set(H) - assert len(U) == len(G) + len(H) - assert (len(U.edges()) == - len(G.edges()) + len(H.edges()) + len(G)*len(H) * 2) - - # DiGraphs Rename - U = nx.full_join(G, H, rename=('g', 'h')) - assert set(U) == set(['g0', 'g1', 'g2', 'h3', 'h4']) - assert len(U) == len(G) + len(H) - assert (len(U.edges()) == - len(G.edges()) + len(H.edges()) + len(G) * len(H) * 2) - - -def test_full_join_multigraph(): - # MultiGraphs - G = nx.MultiGraph() - G.add_node(0) - G.add_edge(1, 2) - H = nx.MultiGraph() - H.add_edge(3, 4) - - U = nx.full_join(G, H) - assert set(U) == set(G) | set(H) - assert len(U) == len(G) + len(H) - assert (len(U.edges()) == - len(G.edges()) + len(H.edges()) + len(G) * len(H)) - - # MultiGraphs rename - U = nx.full_join(G, H, rename=('g', 'h')) - assert set(U) == set(['g0', 'g1', 'g2', 'h3', 'h4']) - assert len(U) == len(G) + len(H) - assert (len(U.edges()) == - len(G.edges()) + len(H.edges()) + len(G) * len(H)) - - # MultiDiGraphs - G = nx.MultiDiGraph() - G.add_node(0) - G.add_edge(1, 2) - H = nx.MultiDiGraph() - H.add_edge(3, 4) - - U = nx.full_join(G, H) - assert set(U) == set(G) | set(H) - assert len(U) == len(G) + len(H) - assert (len(U.edges()) == - len(G.edges()) + len(H.edges()) + len(G) * len(H) * 2) - - # MultiDiGraphs rename - U = nx.full_join(G, H, rename=('g', 'h')) - assert set(U) == set(['g0', 'g1', 'g2', 'h3', 'h4']) - assert len(U) == len(G) + len(H) - assert (len(U.edges()) == - len(G.edges()) + len(H.edges()) + len(G) * len(H) * 2) - - -def test_mixed_type_union(): - G = nx.Graph() - H = nx.MultiGraph() - pytest.raises(nx.NetworkXError, nx.union, G, H) - pytest.raises(nx.NetworkXError, nx.disjoint_union, G, H) - pytest.raises(nx.NetworkXError, nx.intersection, G, H) - pytest.raises(nx.NetworkXError, nx.difference, G, H) - pytest.raises(nx.NetworkXError, nx.symmetric_difference, G, H) - pytest.raises(nx.NetworkXError, nx.compose, G, H) diff --git a/extensions/fablabchemnitz/networkx/algorithms/operators/tests/test_product.py b/extensions/fablabchemnitz/networkx/algorithms/operators/tests/test_product.py deleted file mode 100644 index b6649aa8..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/operators/tests/test_product.py +++ /dev/null @@ -1,392 +0,0 @@ -import pytest -import networkx as nx -from networkx.testing import assert_edges_equal - - -def test_tensor_product_raises(): - with pytest.raises(nx.NetworkXError): - P = nx.tensor_product(nx.DiGraph(), nx.Graph()) - - -def test_tensor_product_null(): - null = nx.null_graph() - empty10 = nx.empty_graph(10) - K3 = nx.complete_graph(3) - K10 = nx.complete_graph(10) - P3 = nx.path_graph(3) - P10 = nx.path_graph(10) - # null graph - G = nx.tensor_product(null, null) - assert nx.is_isomorphic(G, null) - # null_graph X anything = null_graph and v.v. - G = nx.tensor_product(null, empty10) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(null, K3) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(null, K10) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(null, P3) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(null, P10) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(empty10, null) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(K3, null) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(K10, null) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(P3, null) - assert nx.is_isomorphic(G, null) - G = nx.tensor_product(P10, null) - assert nx.is_isomorphic(G, null) - - -def test_tensor_product_size(): - P5 = nx.path_graph(5) - K3 = nx.complete_graph(3) - K5 = nx.complete_graph(5) - - G = nx.tensor_product(P5, K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.tensor_product(K3, K5) - assert nx.number_of_nodes(G) == 3 * 5 - - -def test_tensor_product_combinations(): - # basic smoke test, more realistic tests would be useful - P5 = nx.path_graph(5) - K3 = nx.complete_graph(3) - G = nx.tensor_product(P5, K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.tensor_product(P5, nx.MultiGraph(K3)) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.tensor_product(nx.MultiGraph(P5), K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.tensor_product(nx.MultiGraph(P5), nx.MultiGraph(K3)) - assert nx.number_of_nodes(G) == 5 * 3 - - G = nx.tensor_product(nx.DiGraph(P5), nx.DiGraph(K3)) - assert nx.number_of_nodes(G) == 5 * 3 - - -def test_tensor_product_classic_result(): - K2 = nx.complete_graph(2) - G = nx.petersen_graph() - G = nx.tensor_product(G, K2) - assert nx.is_isomorphic(G, nx.desargues_graph()) - - G = nx.cycle_graph(5) - G = nx.tensor_product(G, K2) - assert nx.is_isomorphic(G, nx.cycle_graph(10)) - - G = nx.tetrahedral_graph() - G = nx.tensor_product(G, K2) - assert nx.is_isomorphic(G, nx.cubical_graph()) - - -def test_tensor_product_random(): - G = nx.erdos_renyi_graph(10, 2 / 10.) - H = nx.erdos_renyi_graph(10, 2 / 10.) - GH = nx.tensor_product(G, H) - - for (u_G, u_H) in GH.nodes(): - for (v_G, v_H) in GH.nodes(): - if H.has_edge(u_H, v_H) and G.has_edge(u_G, v_G): - assert GH.has_edge((u_G, u_H), (v_G, v_H)) - else: - assert not GH.has_edge((u_G, u_H), (v_G, v_H)) - - -def test_cartesian_product_multigraph(): - G = nx.MultiGraph() - G.add_edge(1, 2, key=0) - G.add_edge(1, 2, key=1) - H = nx.MultiGraph() - H.add_edge(3, 4, key=0) - H.add_edge(3, 4, key=1) - GH = nx.cartesian_product(G, H) - assert set(GH) == {(1, 3), (2, 3), (2, 4), (1, 4)} - assert ({(frozenset([u, v]), k) for u, v, k in GH.edges(keys=True)} == - {(frozenset([u, v]), k) for u, v, k in - [((1, 3), (2, 3), 0), ((1, 3), (2, 3), 1), - ((1, 3), (1, 4), 0), ((1, 3), (1, 4), 1), - ((2, 3), (2, 4), 0), ((2, 3), (2, 4), 1), - ((2, 4), (1, 4), 0), ((2, 4), (1, 4), 1)]}) - - -def test_cartesian_product_raises(): - with pytest.raises(nx.NetworkXError): - P = nx.cartesian_product(nx.DiGraph(), nx.Graph()) - - -def test_cartesian_product_null(): - null = nx.null_graph() - empty10 = nx.empty_graph(10) - K3 = nx.complete_graph(3) - K10 = nx.complete_graph(10) - P3 = nx.path_graph(3) - P10 = nx.path_graph(10) - # null graph - G = nx.cartesian_product(null, null) - assert nx.is_isomorphic(G, null) - # null_graph X anything = null_graph and v.v. - G = nx.cartesian_product(null, empty10) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(null, K3) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(null, K10) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(null, P3) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(null, P10) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(empty10, null) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(K3, null) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(K10, null) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(P3, null) - assert nx.is_isomorphic(G, null) - G = nx.cartesian_product(P10, null) - assert nx.is_isomorphic(G, null) - - -def test_cartesian_product_size(): - # order(GXH)=order(G)*order(H) - K5 = nx.complete_graph(5) - P5 = nx.path_graph(5) - K3 = nx.complete_graph(3) - G = nx.cartesian_product(P5, K3) - assert nx.number_of_nodes(G) == 5 * 3 - assert (nx.number_of_edges(G) == - nx.number_of_edges(P5) * nx.number_of_nodes(K3) + - nx.number_of_edges(K3) * nx.number_of_nodes(P5)) - G = nx.cartesian_product(K3, K5) - assert nx.number_of_nodes(G) == 3 * 5 - assert (nx.number_of_edges(G) == - nx.number_of_edges(K5) * nx.number_of_nodes(K3) + - nx.number_of_edges(K3) * nx.number_of_nodes(K5)) - - -def test_cartesian_product_classic(): - # test some classic product graphs - P2 = nx.path_graph(2) - P3 = nx.path_graph(3) - # cube = 2-path X 2-path - G = nx.cartesian_product(P2, P2) - G = nx.cartesian_product(P2, G) - assert nx.is_isomorphic(G, nx.cubical_graph()) - - # 3x3 grid - G = nx.cartesian_product(P3, P3) - assert nx.is_isomorphic(G, nx.grid_2d_graph(3, 3)) - - -def test_cartesian_product_random(): - G = nx.erdos_renyi_graph(10, 2 / 10.) - H = nx.erdos_renyi_graph(10, 2 / 10.) - GH = nx.cartesian_product(G, H) - - for (u_G, u_H) in GH.nodes(): - for (v_G, v_H) in GH.nodes(): - if (u_G == v_G and H.has_edge(u_H, v_H)) or \ - (u_H == v_H and G.has_edge(u_G, v_G)): - assert GH.has_edge((u_G, u_H), (v_G, v_H)) - else: - assert not GH.has_edge((u_G, u_H), (v_G, v_H)) - - -def test_lexicographic_product_raises(): - with pytest.raises(nx.NetworkXError): - P = nx.lexicographic_product(nx.DiGraph(), nx.Graph()) - - -def test_lexicographic_product_null(): - null = nx.null_graph() - empty10 = nx.empty_graph(10) - K3 = nx.complete_graph(3) - K10 = nx.complete_graph(10) - P3 = nx.path_graph(3) - P10 = nx.path_graph(10) - # null graph - G = nx.lexicographic_product(null, null) - assert nx.is_isomorphic(G, null) - # null_graph X anything = null_graph and v.v. - G = nx.lexicographic_product(null, empty10) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(null, K3) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(null, K10) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(null, P3) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(null, P10) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(empty10, null) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(K3, null) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(K10, null) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(P3, null) - assert nx.is_isomorphic(G, null) - G = nx.lexicographic_product(P10, null) - assert nx.is_isomorphic(G, null) - - -def test_lexicographic_product_size(): - K5 = nx.complete_graph(5) - P5 = nx.path_graph(5) - K3 = nx.complete_graph(3) - G = nx.lexicographic_product(P5, K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.lexicographic_product(K3, K5) - assert nx.number_of_nodes(G) == 3 * 5 - - -def test_lexicographic_product_combinations(): - P5 = nx.path_graph(5) - K3 = nx.complete_graph(3) - G = nx.lexicographic_product(P5, K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.lexicographic_product(nx.MultiGraph(P5), K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.lexicographic_product(P5, nx.MultiGraph(K3)) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.lexicographic_product(nx.MultiGraph(P5), nx.MultiGraph(K3)) - assert nx.number_of_nodes(G) == 5 * 3 - - # No classic easily found classic results for lexicographic product - - -def test_lexicographic_product_random(): - G = nx.erdos_renyi_graph(10, 2 / 10.) - H = nx.erdos_renyi_graph(10, 2 / 10.) - GH = nx.lexicographic_product(G, H) - - for (u_G, u_H) in GH.nodes(): - for (v_G, v_H) in GH.nodes(): - if G.has_edge(u_G, v_G) or (u_G == v_G and H.has_edge(u_H, v_H)): - assert GH.has_edge((u_G, u_H), (v_G, v_H)) - else: - assert not GH.has_edge((u_G, u_H), (v_G, v_H)) - - -def test_strong_product_raises(): - with pytest.raises(nx.NetworkXError): - P = nx.strong_product(nx.DiGraph(), nx.Graph()) - - -def test_strong_product_null(): - null = nx.null_graph() - empty10 = nx.empty_graph(10) - K3 = nx.complete_graph(3) - K10 = nx.complete_graph(10) - P3 = nx.path_graph(3) - P10 = nx.path_graph(10) - # null graph - G = nx.strong_product(null, null) - assert nx.is_isomorphic(G, null) - # null_graph X anything = null_graph and v.v. - G = nx.strong_product(null, empty10) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(null, K3) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(null, K10) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(null, P3) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(null, P10) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(empty10, null) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(K3, null) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(K10, null) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(P3, null) - assert nx.is_isomorphic(G, null) - G = nx.strong_product(P10, null) - assert nx.is_isomorphic(G, null) - - -def test_strong_product_size(): - K5 = nx.complete_graph(5) - P5 = nx.path_graph(5) - K3 = nx.complete_graph(3) - G = nx.strong_product(P5, K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.strong_product(K3, K5) - assert nx.number_of_nodes(G) == 3 * 5 - - -def test_strong_product_combinations(): - P5 = nx.path_graph(5) - K3 = nx.complete_graph(3) - G = nx.strong_product(P5, K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.strong_product(nx.MultiGraph(P5), K3) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.strong_product(P5, nx.MultiGraph(K3)) - assert nx.number_of_nodes(G) == 5 * 3 - G = nx.strong_product(nx.MultiGraph(P5), nx.MultiGraph(K3)) - assert nx.number_of_nodes(G) == 5 * 3 - - # No classic easily found classic results for strong product - - -def test_strong_product_random(): - G = nx.erdos_renyi_graph(10, 2 / 10.) - H = nx.erdos_renyi_graph(10, 2 / 10.) - GH = nx.strong_product(G, H) - - for (u_G, u_H) in GH.nodes(): - for (v_G, v_H) in GH.nodes(): - if (u_G == v_G and H.has_edge(u_H, v_H)) or \ - (u_H == v_H and G.has_edge(u_G, v_G)) or \ - (G.has_edge(u_G, v_G) and H.has_edge(u_H, v_H)): - assert GH.has_edge((u_G, u_H), (v_G, v_H)) - else: - assert not GH.has_edge((u_G, u_H), (v_G, v_H)) - - -def test_graph_power_raises(): - with pytest.raises(nx.NetworkXNotImplemented): - nx.power(nx.MultiDiGraph(), 2) - - -def test_graph_power(): - # wikipedia example for graph power - G = nx.cycle_graph(7) - G.add_edge(6, 7) - G.add_edge(7, 8) - G.add_edge(8, 9) - G.add_edge(9, 2) - H = nx.power(G, 2) - - assert_edges_equal(list(H.edges()), - [(0, 1), (0, 2), (0, 5), (0, 6), (0, 7), (1, 9), - (1, 2), (1, 3), (1, 6), (2, 3), (2, 4), (2, 8), - (2, 9), (3, 4), (3, 5), (3, 9), (4, 5), (4, 6), - (5, 6), (5, 7), (6, 7), (6, 8), (7, 8), (7, 9), - (8, 9)]) - - -def test_graph_power_negative(): - with pytest.raises(ValueError): - nx.power(nx.Graph(), -1) - - -def test_rooted_product_raises(): - with pytest.raises(nx.NetworkXError): - nx.rooted_product(nx.Graph(), nx.path_graph(2), 10) - - -def test_rooted_product(): - G = nx.cycle_graph(5) - H = nx.Graph() - H.add_edges_from([('a', 'b'), ('b', 'c'), ('b', 'd')]) - R = nx.rooted_product(G, H, 'a') - assert len(R) == len(G) * len(H) - assert R.size() == G.size() + len(G) * H.size() diff --git a/extensions/fablabchemnitz/networkx/algorithms/operators/tests/test_unary.py b/extensions/fablabchemnitz/networkx/algorithms/operators/tests/test_unary.py deleted file mode 100644 index f954a081..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/operators/tests/test_unary.py +++ /dev/null @@ -1,47 +0,0 @@ -import pytest -import networkx as nx - - -def test_complement(): - null = nx.null_graph() - empty1 = nx.empty_graph(1) - empty10 = nx.empty_graph(10) - K3 = nx.complete_graph(3) - K5 = nx.complete_graph(5) - K10 = nx.complete_graph(10) - P2 = nx.path_graph(2) - P3 = nx.path_graph(3) - P5 = nx.path_graph(5) - P10 = nx.path_graph(10) - # complement of the complete graph is empty - - G = nx.complement(K3) - assert nx.is_isomorphic(G, nx.empty_graph(3)) - G = nx.complement(K5) - assert nx.is_isomorphic(G, nx.empty_graph(5)) - # for any G, G=complement(complement(G)) - P3cc = nx.complement(nx.complement(P3)) - assert nx.is_isomorphic(P3, P3cc) - nullcc = nx.complement(nx.complement(null)) - assert nx.is_isomorphic(null, nullcc) - b = nx.bull_graph() - bcc = nx.complement(nx.complement(b)) - assert nx.is_isomorphic(b, bcc) - - -def test_complement_2(): - G1 = nx.DiGraph() - G1.add_edge('A', 'B') - G1.add_edge('A', 'C') - G1.add_edge('A', 'D') - G1C = nx.complement(G1) - assert (sorted(G1C.edges()) == - [('B', 'A'), ('B', 'C'), - ('B', 'D'), ('C', 'A'), ('C', 'B'), - ('C', 'D'), ('D', 'A'), ('D', 'B'), ('D', 'C')]) - - -def test_reverse1(): - # Other tests for reverse are done by the DiGraph and MultiDigraph. - G1 = nx.Graph() - pytest.raises(nx.NetworkXError, nx.reverse, G1) diff --git a/extensions/fablabchemnitz/networkx/algorithms/operators/unary.py b/extensions/fablabchemnitz/networkx/algorithms/operators/unary.py deleted file mode 100644 index 45be75e7..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/operators/unary.py +++ /dev/null @@ -1,64 +0,0 @@ -"""Unary operations on graphs""" -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -import networkx as nx -from networkx.utils import not_implemented_for -__author__ = """\n""".join(['Aric Hagberg ', - 'Pieter Swart (swart@lanl.gov)', - 'Dan Schult(dschult@colgate.edu)']) -__all__ = ['complement', 'reverse'] - - -def complement(G): - """Returns the graph complement of G. - - Parameters - ---------- - G : graph - A NetworkX graph - - Returns - ------- - GC : A new graph. - - Notes - ------ - Note that complement() does not create self-loops and also - does not produce parallel edges for MultiGraphs. - - Graph, node, and edge data are not propagated to the new graph. - """ - R = G.__class__() - R.add_nodes_from(G) - R.add_edges_from(((n, n2) - for n, nbrs in G.adjacency() - for n2 in G if n2 not in nbrs - if n != n2)) - return R - - -def reverse(G, copy=True): - """Returns the reverse directed graph of G. - - Parameters - ---------- - G : directed graph - A NetworkX directed graph - copy : bool - If True, then a new graph is returned. If False, then the graph is - reversed in place. - - Returns - ------- - H : directed graph - The reversed G. - - """ - if not G.is_directed(): - raise nx.NetworkXError("Cannot reverse an undirected graph.") - else: - return G.reverse(copy=copy) diff --git a/extensions/fablabchemnitz/networkx/algorithms/planar_drawing.py b/extensions/fablabchemnitz/networkx/algorithms/planar_drawing.py deleted file mode 100644 index 4383cc02..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/planar_drawing.py +++ /dev/null @@ -1,465 +0,0 @@ -import networkx as nx -from collections import defaultdict - - -__all__ = ["combinatorial_embedding_to_pos"] - - -def combinatorial_embedding_to_pos(embedding, fully_triangulate=False): - """Assigns every node a (x, y) position based on the given embedding - - The algorithm iteratively inserts nodes of the input graph in a certain - order and rearranges previously inserted nodes so that the planar drawing - stays valid. This is done efficiently by only maintaining relative - positions during the node placements and calculating the absolute positions - at the end. For more information see [1]_. - - Parameters - ---------- - embedding : nx.PlanarEmbedding - This defines the order of the edges - - fully_triangulate : bool - If set to True the algorithm adds edges to a copy of the input - embedding and makes it chordal. - - Returns - ------- - pos : dict - Maps each node to a tuple that defines the (x, y) position - - References - ---------- - .. [1] M. Chrobak and T.H. Payne: - A Linear-time Algorithm for Drawing a Planar Graph on a Grid 1989 - http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.51.6677 - - """ - if len(embedding.nodes()) < 4: - # Position the node in any triangle - default_positions = [(0, 0), (2, 0), (1, 1)] - pos = {} - for i, v in enumerate(embedding.nodes()): - pos[v] = default_positions[i] - return pos - - embedding, outer_face = triangulate_embedding(embedding, fully_triangulate) - - # The following dicts map a node to another node - # If a node is not in the key set it means that the node is not yet in G_k - # If a node maps to None then the corresponding subtree does not exist - left_t_child = {} - right_t_child = {} - - # The following dicts map a node to an integer - delta_x = {} - y_coordinate = {} - - node_list = get_canonical_ordering(embedding, outer_face) - - # 1. Phase: Compute relative positions - - # Initialization - v1, v2, v3 = node_list[0][0], node_list[1][0], node_list[2][0] - - delta_x[v1] = 0 - y_coordinate[v1] = 0 - right_t_child[v1] = v3 - left_t_child[v1] = None - - delta_x[v2] = 1 - y_coordinate[v2] = 0 - right_t_child[v2] = None - left_t_child[v2] = None - - delta_x[v3] = 1 - y_coordinate[v3] = 1 - right_t_child[v3] = v2 - left_t_child[v3] = None - - for k in range(3, len(node_list)): - vk, contour_neighbors = node_list[k] - wp = contour_neighbors[0] - wp1 = contour_neighbors[1] - wq = contour_neighbors[-1] - wq1 = contour_neighbors[-2] - adds_mult_tri = len(contour_neighbors) > 2 - - # Stretch gaps: - delta_x[wp1] += 1 - delta_x[wq] += 1 - - delta_x_wp_wq = sum((delta_x[x] for x in contour_neighbors[1:])) - - # Adjust offsets - delta_x[vk] = (-y_coordinate[wp] + delta_x_wp_wq + y_coordinate[wq])//2 - y_coordinate[vk] = (y_coordinate[wp] + delta_x_wp_wq + - y_coordinate[wq]) // 2 - delta_x[wq] = delta_x_wp_wq - delta_x[vk] - if adds_mult_tri: - delta_x[wp1] -= delta_x[vk] - - # Install v_k: - right_t_child[wp] = vk - right_t_child[vk] = wq - if adds_mult_tri: - left_t_child[vk] = wp1 - right_t_child[wq1] = None - else: - left_t_child[vk] = None - - # 2. Phase: Set absolute positions - pos = dict() - pos[v1] = (0, y_coordinate[v1]) - remaining_nodes = [v1] - while remaining_nodes: - parent_node = remaining_nodes.pop() - - # Calculate position for left child - set_position(parent_node, left_t_child, - remaining_nodes, delta_x, y_coordinate, pos) - # Calculate position for right child - set_position(parent_node, right_t_child, - remaining_nodes, delta_x, y_coordinate, pos) - return pos - - -def set_position(parent, tree, remaining_nodes, delta_x, y_coordinate, pos): - """Helper method to calculate the absolute position of nodes.""" - child = tree[parent] - parent_node_x = pos[parent][0] - if child is not None: - # Calculate pos of child - child_x = parent_node_x + delta_x[child] - pos[child] = (child_x, y_coordinate[child]) - # Remember to calculate pos of its children - remaining_nodes.append(child) - - -def get_canonical_ordering(embedding, outer_face): - """Returns a canonical ordering of the nodes - - The canonical ordering of nodes (v1, ..., vn) must fulfill the following - conditions: - (See Lemma 1 in [2]_) - - - For the subgraph G_k of the input graph induced by v1, ..., vk it holds: - - 2-connected - - internally triangulated - - the edge (v1, v2) is part of the outer face - - For a node v(k+1) the following holds: - - The node v(k+1) is part of the outer face of G_k - - It has at least two neighbors in G_k - - All neighbors of v(k+1) in G_k lie consecutively on the outer face of - G_k (excluding the edge (v1, v2)). - - The algorithm used here starts with G_n (containing all nodes). It first - selects the nodes v1 and v2. And then tries to find the order of the other - nodes by checking which node can be removed in order to fulfill the - conditions mentioned above. This is done by calculating the number of - chords of nodes on the outer face. For more information see [1]_. - - Parameters - ---------- - embedding : nx.PlanarEmbedding - The embedding must be triangulated - outer_face : list - The nodes on the outer face of the graph - - Returns - ------- - ordering : list - A list of tuples `(vk, wp_wq)`. Here `vk` is the node at this position - in the canonical ordering. The element `wp_wq` is a list of nodes that - make up the outer face of G_k. - - References - ---------- - .. [1] Steven Chaplick. - Canonical Orders of Planar Graphs and (some of) Their Applications 2015 - https://wuecampus2.uni-wuerzburg.de/moodle/pluginfile.php/545727/mod_resource/content/0/vg-ss15-vl03-canonical-orders-druckversion.pdf - .. [2] M. Chrobak and T.H. Payne: - A Linear-time Algorithm for Drawing a Planar Graph on a Grid 1989 - http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.51.6677 - - """ - v1 = outer_face[0] - v2 = outer_face[1] - chords = defaultdict(int) # Maps nodes to the number of their chords - marked_nodes = set() - ready_to_pick = set(outer_face) - - # Initialize outer_face_ccw_nbr (do not include v1 -> v2) - outer_face_ccw_nbr = {} - prev_nbr = v2 - for idx in range(2, len(outer_face)): - outer_face_ccw_nbr[prev_nbr] = outer_face[idx] - prev_nbr = outer_face[idx] - outer_face_ccw_nbr[prev_nbr] = v1 - - # Initialize outer_face_cw_nbr (do not include v2 -> v1) - outer_face_cw_nbr = {} - prev_nbr = v1 - for idx in range(len(outer_face)-1, 0, -1): - outer_face_cw_nbr[prev_nbr] = outer_face[idx] - prev_nbr = outer_face[idx] - - def is_outer_face_nbr(x, y): - if x not in outer_face_ccw_nbr: - return outer_face_cw_nbr[x] == y - if x not in outer_face_cw_nbr: - return outer_face_ccw_nbr[x] == y - return outer_face_ccw_nbr[x] == y or outer_face_cw_nbr[x] == y - - def is_on_outer_face(x): - return x not in marked_nodes and (x in outer_face_ccw_nbr.keys() or - x == v1) - - # Initialize number of chords - for v in outer_face: - for nbr in embedding.neighbors_cw_order(v): - if is_on_outer_face(nbr) and not is_outer_face_nbr(v, nbr): - chords[v] += 1 - ready_to_pick.discard(v) - - # Initialize canonical_ordering - canonical_ordering = [None] * len(embedding.nodes()) # type: list - canonical_ordering[0] = (v1, []) - canonical_ordering[1] = (v2, []) - ready_to_pick.discard(v1) - ready_to_pick.discard(v2) - - for k in range(len(embedding.nodes())-1, 1, -1): - # 1. Pick v from ready_to_pick - v = ready_to_pick.pop() - marked_nodes.add(v) - - # v has exactly two neighbors on the outer face (wp and wq) - wp = None - wq = None - # Iterate over neighbors of v to find wp and wq - nbr_iterator = iter(embedding.neighbors_cw_order(v)) - while True: - nbr = next(nbr_iterator) - if nbr in marked_nodes: - # Only consider nodes that are not yet removed - continue - if is_on_outer_face(nbr): - # nbr is either wp or wq - if nbr == v1: - wp = v1 - elif nbr == v2: - wq = v2 - else: - if outer_face_cw_nbr[nbr] == v: - # nbr is wp - wp = nbr - else: - # nbr is wq - wq = nbr - if wp is not None and wq is not None: - # We don't need to iterate any further - break - - # Obtain new nodes on outer face (neighbors of v from wp to wq) - wp_wq = [wp] - nbr = wp - while nbr != wq: - # Get next next neighbor (clockwise on the outer face) - next_nbr = embedding[v][nbr]['ccw'] - wp_wq.append(next_nbr) - # Update outer face - outer_face_cw_nbr[nbr] = next_nbr - outer_face_ccw_nbr[next_nbr] = nbr - # Move to next neighbor of v - nbr = next_nbr - - if len(wp_wq) == 2: - # There was a chord between wp and wq, decrease number of chords - chords[wp] -= 1 - if chords[wp] == 0: - ready_to_pick.add(wp) - chords[wq] -= 1 - if chords[wq] == 0: - ready_to_pick.add(wq) - else: - # Update all chords involving w_(p+1) to w_(q-1) - new_face_nodes = set(wp_wq[1:-1]) - for w in new_face_nodes: - # If we do not find a chord for w later we can pick it next - ready_to_pick.add(w) - for nbr in embedding.neighbors_cw_order(w): - if is_on_outer_face(nbr) and not is_outer_face_nbr(w, nbr): - # There is a chord involving w - chords[w] += 1 - ready_to_pick.discard(w) - if nbr not in new_face_nodes: - # Also increase chord for the neighbor - # We only iterator over new_face_nodes - chords[nbr] += 1 - ready_to_pick.discard(nbr) - # Set the canonical ordering node and the list of contour neighbors - canonical_ordering[k] = (v, wp_wq) - - return canonical_ordering - - -def triangulate_face(embedding, v1, v2): - """Triangulates the face given by half edge (v, w) - - Parameters - ---------- - embedding : nx.PlanarEmbedding - v1 : node - The half-edge (v1, v2) belongs to the face that gets triangulated - v2 : node - """ - _, v3 = embedding.next_face_half_edge(v1, v2) - _, v4 = embedding.next_face_half_edge(v2, v3) - if v1 == v2 or v1 == v3: - # The component has less than 3 nodes - return - while v1 != v4: - # Add edge if not already present on other side - if embedding.has_edge(v1, v3): - # Cannot triangulate at this position - v1, v2, v3 = v2, v3, v4 - else: - # Add edge for triangulation - embedding.add_half_edge_cw(v1, v3, v2) - embedding.add_half_edge_ccw(v3, v1, v2) - v1, v2, v3 = v1, v3, v4 - # Get next node - _, v4 = embedding.next_face_half_edge(v2, v3) - - -def triangulate_embedding(embedding, fully_triangulate=True): - """Triangulates the embedding. - - Traverses faces of the embedding and adds edges to a copy of the - embedding to triangulate it. - The method also ensures that the resulting graph is 2-connected by adding - edges if the same vertex is contained twice on a path around a face. - - Parameters - ---------- - embedding : nx.PlanarEmbedding - The input graph must contain at least 3 nodes. - - fully_triangulate : bool - If set to False the face with the most nodes is chooses as outer face. - This outer face does not get triangulated. - - Returns - ------- - (embedding, outer_face) : (nx.PlanarEmbedding, list) tuple - The element `embedding` is a new embedding containing all edges from - the input embedding and the additional edges to triangulate the graph. - The element `outer_face` is a list of nodes that lie on the outer face. - If the graph is fully triangulated these are three arbitrary connected - nodes. - - """ - if len(embedding.nodes) <= 1: - return embedding, list(embedding.nodes) - embedding = nx.PlanarEmbedding(embedding) - - # Get a list with a node for each connected component - component_nodes = [next(iter(x)) for x in - nx.connected_components(embedding)] - - # 1. Make graph a single component (add edge between components) - for i in range(len(component_nodes)-1): - v1 = component_nodes[i] - v2 = component_nodes[i+1] - embedding.connect_components(v1, v2) - - # 2. Calculate faces, ensure 2-connectedness and determine outer face - outer_face = [] # A face with the most number of nodes - face_list = [] - edges_visited = set() # Used to keep track of already visited faces - for v in embedding.nodes(): - for w in embedding.neighbors_cw_order(v): - new_face = make_bi_connected(embedding, v, w, edges_visited) - if new_face: - # Found a new face - face_list.append(new_face) - if len(new_face) > len(outer_face): - # The face is a candidate to be the outer face - outer_face = new_face - - # 3. Triangulate (internal) faces - for face in face_list: - if face is not outer_face or fully_triangulate: - # Triangulate this face - triangulate_face(embedding, face[0], face[1]) - - if fully_triangulate: - v1 = outer_face[0] - v2 = outer_face[1] - v3 = embedding[v2][v1]['ccw'] - outer_face = [v1, v2, v3] - - return embedding, outer_face - - -def make_bi_connected(embedding, starting_node, outgoing_node, edges_counted): - """Triangulate a face and make it 2-connected - - This method also adds all edges on the face to `edges_counted`. - - Parameters - ---------- - embedding: nx.PlanarEmbedding - The embedding that defines the faces - starting_node : node - A node on the face - outgoing_node : node - A node such that the half edge (starting_node, outgoing_node) belongs - to the face - edges_counted: set - Set of all half-edges that belong to a face that have been visited - - Returns - ------- - face_nodes: list - A list of all nodes at the border of this face - """ - - # Check if the face has already been calculated - if (starting_node, outgoing_node) in edges_counted: - # This face was already counted - return [] - edges_counted.add((starting_node, outgoing_node)) - - # Add all edges to edges_counted which have this face to their left - v1 = starting_node - v2 = outgoing_node - face_list = [starting_node] # List of nodes around the face - face_set = set(face_list) # Set for faster queries - _, v3 = embedding.next_face_half_edge(v1, v2) - - # Move the nodes v1, v2, v3 around the face: - while v2 != starting_node or v3 != outgoing_node: - if v1 == v2: - raise nx.NetworkXException("Invalid half-edge") - # cycle is not completed yet - if v2 in face_set: - # v2 encountered twice: Add edge to ensure 2-connectedness - embedding.add_half_edge_cw(v1, v3, v2) - embedding.add_half_edge_ccw(v3, v1, v2) - edges_counted.add((v2, v3)) - edges_counted.add((v3, v1)) - v2 = v1 - else: - face_set.add(v2) - face_list.append(v2) - - # set next edge - v1 = v2 - v2, v3 = embedding.next_face_half_edge(v2, v3) - - # remember that this edge has been counted - edges_counted.add((v1, v2)) - - return face_list diff --git a/extensions/fablabchemnitz/networkx/algorithms/planarity.py b/extensions/fablabchemnitz/networkx/algorithms/planarity.py deleted file mode 100644 index 85c726dd..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/planarity.py +++ /dev/null @@ -1,1097 +0,0 @@ -from collections import defaultdict -import networkx as nx - -__all__ = ["check_planarity", "PlanarEmbedding"] - - -def check_planarity(G, counterexample=False): - """Check if a graph is planar and return a counterexample or an embedding. - - A graph is planar iff it can be drawn in a plane without - any edge intersections. - - Parameters - ---------- - G : NetworkX graph - counterexample : bool - A Kuratowski subgraph (to proof non planarity) is only returned if set - to true. - - Returns - ------- - (is_planar, certificate) : (bool, NetworkX graph) tuple - is_planar is true if the graph is planar. - If the graph is planar `certificate` is a PlanarEmbedding - otherwise it is a Kuratowski subgraph. - - Notes - ----- - A (combinatorial) embedding consists of cyclic orderings of the incident - edges at each vertex. Given such an embedding there are multiple approaches - discussed in literature to drawing the graph (subject to various - constraints, e.g. integer coordinates), see e.g. [2]. - - The planarity check algorithm and extraction of the combinatorial embedding - is based on the Left-Right Planarity Test [1]. - - A counterexample is only generated if the corresponding parameter is set, - because the complexity of the counterexample generation is higher. - - References - ---------- - .. [1] Ulrik Brandes: - The Left-Right Planarity Test - 2009 - http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.217.9208 - .. [2] Takao Nishizeki, Md Saidur Rahman: - Planar graph drawing - Lecture Notes Series on Computing: Volume 12 - 2004 - """ - - planarity_state = LRPlanarity(G) - embedding = planarity_state.lr_planarity() - if embedding is None: - # graph is not planar - if counterexample: - return False, get_counterexample(G) - else: - return False, None - else: - # graph is planar - return True, embedding - - -def check_planarity_recursive(G, counterexample=False): - """Recursive version of :meth:`check_planarity`.""" - planarity_state = LRPlanarity(G) - embedding = planarity_state.lr_planarity_recursive() - if embedding is None: - # graph is not planar - if counterexample: - return False, get_counterexample_recursive(G) - else: - return False, None - else: - # graph is planar - return True, embedding - - -def get_counterexample(G): - """Obtains a Kuratowski subgraph. - - Raises nx.NetworkXException if G is planar. - - The function removes edges such that the graph is still not planar. - At some point the removal of any edge would make the graph planar. - This subgraph must be a Kuratowski subgraph. - - Parameters - ---------- - G : NetworkX graph - - Returns - ------- - subgraph : NetworkX graph - A Kuratowski subgraph that proves that G is not planar. - - """ - # copy graph - G = nx.Graph(G) - - if check_planarity(G)[0]: - raise nx.NetworkXException("G is planar - no counter example.") - - # find Kuratowski subgraph - subgraph = nx.Graph() - for u in G: - nbrs = list(G[u]) - for v in nbrs: - G.remove_edge(u, v) - if check_planarity(G)[0]: - G.add_edge(u, v) - subgraph.add_edge(u, v) - - return subgraph - - -def get_counterexample_recursive(G): - """Recursive version of :meth:`get_counterexample`. - """ - - # copy graph - G = nx.Graph(G) - - if check_planarity_recursive(G)[0]: - raise nx.NetworkXException("G is planar - no counter example.") - - # find Kuratowski subgraph - subgraph = nx.Graph() - for u in G: - nbrs = list(G[u]) - for v in nbrs: - G.remove_edge(u, v) - if check_planarity_recursive(G)[0]: - G.add_edge(u, v) - subgraph.add_edge(u, v) - - return subgraph - - -class Interval(object): - """Represents a set of return edges. - - All return edges in an interval induce a same constraint on the contained - edges, which means that all edges must either have a left orientation or - all edges must have a right orientation. - """ - - def __init__(self, low=None, high=None): - self.low = low - self.high = high - - def empty(self): - """Check if the interval is empty""" - return self.low is None and self.high is None - - def copy(self): - """Returns a copy of this interval""" - return Interval(self.low, self.high) - - def conflicting(self, b, planarity_state): - """Returns True if interval I conflicts with edge b""" - return (not self.empty() and - planarity_state.lowpt[self.high] > planarity_state.lowpt[b]) - - -class ConflictPair(object): - """Represents a different constraint between two intervals. - - The edges in the left interval must have a different orientation than - the one in the right interval. - """ - - def __init__(self, left=Interval(), right=Interval()): - self.left = left - self.right = right - - def swap(self): - """Swap left and right intervals""" - temp = self.left - self.left = self.right - self.right = temp - - def lowest(self, planarity_state): - """Returns the lowest lowpoint of a conflict pair""" - if self.left.empty(): - return planarity_state.lowpt[self.right.low] - if self.right.empty(): - return planarity_state.lowpt[self.left.low] - return min(planarity_state.lowpt[self.left.low], - planarity_state.lowpt[self.right.low]) - - -def top_of_stack(l): - """Returns the element on top of the stack.""" - if not l: - return None - return l[-1] - - -class LRPlanarity(object): - """A class to maintain the state during planarity check.""" - __slots__ = [ - 'G', 'roots', 'height', 'lowpt', 'lowpt2', 'nesting_depth', - 'parent_edge', 'DG', 'adjs', 'ordered_adjs', 'ref', 'side', 'S', - 'stack_bottom', 'lowpt_edge', 'left_ref', 'right_ref', 'embedding' - ] - - def __init__(self, G): - # copy G without adding self-loops - self.G = nx.Graph() - self.G.add_nodes_from(G.nodes) - for e in G.edges: - if e[0] != e[1]: - self.G.add_edge(e[0], e[1]) - - self.roots = [] - - # distance from tree root - self.height = defaultdict(lambda: None) - - self.lowpt = {} # height of lowest return point of an edge - self.lowpt2 = {} # height of second lowest return point - self.nesting_depth = {} # for nesting order - - # None -> missing edge - self.parent_edge = defaultdict(lambda: None) - - # oriented DFS graph - self.DG = nx.DiGraph() - self.DG.add_nodes_from(G.nodes) - - self.adjs = {} - self.ordered_adjs = {} - - self.ref = defaultdict(lambda: None) - self.side = defaultdict(lambda: 1) - - # stack of conflict pairs - self.S = [] - self.stack_bottom = {} - self.lowpt_edge = {} - - self.left_ref = {} - self.right_ref = {} - - self.embedding = PlanarEmbedding() - - def lr_planarity(self): - """Execute the LR planarity test. - - Returns - ------- - embedding : dict - If the graph is planar an embedding is returned. Otherwise None. - """ - if self.G.order() > 2 and self.G.size() > 3 * self.G.order() - 6: - # graph is not planar - return None - - # make adjacency lists for dfs - for v in self.G: - self.adjs[v] = list(self.G[v]) - - # orientation of the graph by depth first search traversal - for v in self.G: - if self.height[v] is None: - self.height[v] = 0 - self.roots.append(v) - self.dfs_orientation(v) - - # Free no longer used variables - self.G = None - self.lowpt2 = None - self.adjs = None - - # testing - for v in self.DG: # sort the adjacency lists by nesting depth - # note: this sorting leads to non linear time - self.ordered_adjs[v] = sorted( - self.DG[v], key=lambda x: self.nesting_depth[(v, x)]) - for v in self.roots: - if not self.dfs_testing(v): - return None - - # Free no longer used variables - self.height = None - self.lowpt = None - self.S = None - self.stack_bottom = None - self.lowpt_edge = None - - for e in self.DG.edges: - self.nesting_depth[e] = self.sign(e) * self.nesting_depth[e] - - self.embedding.add_nodes_from(self.DG.nodes) - for v in self.DG: - # sort the adjacency lists again - self.ordered_adjs[v] = sorted( - self.DG[v], key=lambda x: self.nesting_depth[(v, x)]) - # initialize the embedding - previous_node = None - for w in self.ordered_adjs[v]: - self.embedding.add_half_edge_cw(v, w, previous_node) - previous_node = w - - # Free no longer used variables - self.DG = None - self.nesting_depth = None - self.ref = None - - # compute the complete embedding - for v in self.roots: - self.dfs_embedding(v) - - # Free no longer used variables - self.roots = None - self.parent_edge = None - self.ordered_adjs = None - self.left_ref = None - self.right_ref = None - self.side = None - - return self.embedding - - def lr_planarity_recursive(self): - """Recursive version of :meth:`lr_planarity`.""" - if self.G.order() > 2 and self.G.size() > 3 * self.G.order() - 6: - # graph is not planar - return None - - # orientation of the graph by depth first search traversal - for v in self.G: - if self.height[v] is None: - self.height[v] = 0 - self.roots.append(v) - self.dfs_orientation_recursive(v) - - # Free no longer used variable - self.G = None - - # testing - for v in self.DG: # sort the adjacency lists by nesting depth - # note: this sorting leads to non linear time - self.ordered_adjs[v] = sorted( - self.DG[v], key=lambda x: self.nesting_depth[(v, x)]) - for v in self.roots: - if not self.dfs_testing_recursive(v): - return None - - for e in self.DG.edges: - self.nesting_depth[e] = (self.sign_recursive(e) * - self.nesting_depth[e]) - - self.embedding.add_nodes_from(self.DG.nodes) - for v in self.DG: - # sort the adjacency lists again - self.ordered_adjs[v] = sorted( - self.DG[v], key=lambda x: self.nesting_depth[(v, x)]) - # initialize the embedding - previous_node = None - for w in self.ordered_adjs[v]: - self.embedding.add_half_edge_cw(v, w, previous_node) - previous_node = w - - # compute the complete embedding - for v in self.roots: - self.dfs_embedding_recursive(v) - - return self.embedding - - def dfs_orientation(self, v): - """Orient the graph by DFS, compute lowpoints and nesting order. - """ - # the recursion stack - dfs_stack = [v] - # index of next edge to handle in adjacency list of each node - ind = defaultdict(lambda: 0) - # boolean to indicate whether to skip the initial work for an edge - skip_init = defaultdict(lambda: False) - - while dfs_stack: - v = dfs_stack.pop() - e = self.parent_edge[v] - - for w in self.adjs[v][ind[v]:]: - vw = (v, w) - - if not skip_init[vw]: - if (v, w) in self.DG.edges or (w, v) in self.DG.edges: - ind[v] += 1 - continue # the edge was already oriented - - self.DG.add_edge(v, w) # orient the edge - - self.lowpt[vw] = self.height[v] - self.lowpt2[vw] = self.height[v] - if self.height[w] is None: # (v, w) is a tree edge - self.parent_edge[w] = vw - self.height[w] = self.height[v] + 1 - - dfs_stack.append(v) # revisit v after finishing w - dfs_stack.append(w) # visit w next - skip_init[vw] = True # don't redo this block - break # handle next node in dfs_stack (i.e. w) - else: # (v, w) is a back edge - self.lowpt[vw] = self.height[w] - - # determine nesting graph - self.nesting_depth[vw] = 2 * self.lowpt[vw] - if self.lowpt2[vw] < self.height[v]: # chordal - self.nesting_depth[vw] += 1 - - # update lowpoints of parent edge e - if e is not None: - if self.lowpt[vw] < self.lowpt[e]: - self.lowpt2[e] = min(self.lowpt[e], self.lowpt2[vw]) - self.lowpt[e] = self.lowpt[vw] - elif self.lowpt[vw] > self.lowpt[e]: - self.lowpt2[e] = min(self.lowpt2[e], self.lowpt[vw]) - else: - self.lowpt2[e] = min(self.lowpt2[e], self.lowpt2[vw]) - - ind[v] += 1 - - def dfs_orientation_recursive(self, v): - """Recursive version of :meth:`dfs_orientation`.""" - e = self.parent_edge[v] - for w in self.G[v]: - if (v, w) in self.DG.edges or (w, v) in self.DG.edges: - continue # the edge was already oriented - vw = (v, w) - self.DG.add_edge(v, w) # orient the edge - - self.lowpt[vw] = self.height[v] - self.lowpt2[vw] = self.height[v] - if self.height[w] is None: # (v, w) is a tree edge - self.parent_edge[w] = vw - self.height[w] = self.height[v] + 1 - self.dfs_orientation_recursive(w) - else: # (v, w) is a back edge - self.lowpt[vw] = self.height[w] - - # determine nesting graph - self.nesting_depth[vw] = 2 * self.lowpt[vw] - if self.lowpt2[vw] < self.height[v]: # chordal - self.nesting_depth[vw] += 1 - - # update lowpoints of parent edge e - if e is not None: - if self.lowpt[vw] < self.lowpt[e]: - self.lowpt2[e] = min(self.lowpt[e], self.lowpt2[vw]) - self.lowpt[e] = self.lowpt[vw] - elif self.lowpt[vw] > self.lowpt[e]: - self.lowpt2[e] = min(self.lowpt2[e], self.lowpt[vw]) - else: - self.lowpt2[e] = min(self.lowpt2[e], self.lowpt2[vw]) - - def dfs_testing(self, v): - """Test for LR partition.""" - # the recursion stack - dfs_stack = [v] - # index of next edge to handle in adjacency list of each node - ind = defaultdict(lambda: 0) - # boolean to indicate whether to skip the initial work for an edge - skip_init = defaultdict(lambda: False) - - while dfs_stack: - v = dfs_stack.pop() - e = self.parent_edge[v] - # to indicate whether to skip the final block after the for loop - skip_final = False - - for w in self.ordered_adjs[v][ind[v]:]: - ei = (v, w) - - if not skip_init[ei]: - self.stack_bottom[ei] = top_of_stack(self.S) - - if ei == self.parent_edge[w]: # tree edge - dfs_stack.append(v) # revisit v after finishing w - dfs_stack.append(w) # visit w next - skip_init[ei] = True # don't redo this block - skip_final = True # skip final work after breaking - break # handle next node in dfs_stack (i.e. w) - else: # back edge - self.lowpt_edge[ei] = ei - self.S.append(ConflictPair(right=Interval(ei, ei))) - - # integrate new return edges - if self.lowpt[ei] < self.height[v]: - if w == self.ordered_adjs[v][0]: # e_i has return edge - self.lowpt_edge[e] = self.lowpt_edge[ei] - else: # add constraints of e_i - if not self.add_constraints(ei, e): - # graph is not planar - return False - - ind[v] += 1 - - if not skip_final: - # remove back edges returning to parent - if e is not None: # v isn't root - self.remove_back_edges(e) - - return True - - def dfs_testing_recursive(self, v): - """Recursive version of :meth:`dfs_testing`.""" - e = self.parent_edge[v] - for w in self.ordered_adjs[v]: - ei = (v, w) - self.stack_bottom[ei] = top_of_stack(self.S) - if ei == self.parent_edge[w]: # tree edge - if not self.dfs_testing_recursive(w): - return False - else: # back edge - self.lowpt_edge[ei] = ei - self.S.append(ConflictPair(right=Interval(ei, ei))) - - # integrate new return edges - if self.lowpt[ei] < self.height[v]: - if w == self.ordered_adjs[v][0]: # e_i has return edge - self.lowpt_edge[e] = self.lowpt_edge[ei] - else: # add constraints of e_i - if not self.add_constraints(ei, e): - # graph is not planar - return False - - # remove back edges returning to parent - if e is not None: # v isn't root - self.remove_back_edges(e) - return True - - def add_constraints(self, ei, e): - P = ConflictPair() - # merge return edges of e_i into P.right - while True: - Q = self.S.pop() - if not Q.left.empty(): - Q.swap() - if not Q.left.empty(): # not planar - return False - if self.lowpt[Q.right.low] > self.lowpt[e]: - # merge intervals - if P.right.empty(): # topmost interval - P.right = Q.right.copy() - else: - self.ref[P.right.low] = Q.right.high - P.right.low = Q.right.low - else: # align - self.ref[Q.right.low] = self.lowpt_edge[e] - if top_of_stack(self.S) == self.stack_bottom[ei]: - break - # merge conflicting return edges of e_1,...,e_i-1 into P.L - while (top_of_stack(self.S).left.conflicting(ei, self) or - top_of_stack(self.S).right.conflicting(ei, self)): - Q = self.S.pop() - if Q.right.conflicting(ei, self): - Q.swap() - if Q.right.conflicting(ei, self): # not planar - return False - # merge interval below lowpt(e_i) into P.R - self.ref[P.right.low] = Q.right.high - if Q.right.low is not None: - P.right.low = Q.right.low - - if P.left.empty(): # topmost interval - P.left = Q.left.copy() - else: - self.ref[P.left.low] = Q.left.high - P.left.low = Q.left.low - - if not (P.left.empty() and P.right.empty()): - self.S.append(P) - return True - - def remove_back_edges(self, e): - u = e[0] - # trim back edges ending at parent u - # drop entire conflict pairs - while self.S and top_of_stack(self.S).lowest(self) == self.height[u]: - P = self.S.pop() - if P.left.low is not None: - self.side[P.left.low] = -1 - - if self.S: # one more conflict pair to consider - P = self.S.pop() - # trim left interval - while P.left.high is not None and P.left.high[1] == u: - P.left.high = self.ref[P.left.high] - if P.left.high is None and P.left.low is not None: - # just emptied - self.ref[P.left.low] = P.right.low - self.side[P.left.low] = -1 - P.left.low = None - # trim right interval - while P.right.high is not None and P.right.high[1] == u: - P.right.high = self.ref[P.right.high] - if P.right.high is None and P.right.low is not None: - # just emptied - self.ref[P.right.low] = P.left.low - self.side[P.right.low] = -1 - P.right.low = None - self.S.append(P) - - # side of e is side of a highest return edge - if self.lowpt[e] < self.height[u]: # e has return edge - hl = top_of_stack(self.S).left.high - hr = top_of_stack(self.S).right.high - - if hl is not None and ( - hr is None or self.lowpt[hl] > self.lowpt[hr]): - self.ref[e] = hl - else: - self.ref[e] = hr - - def dfs_embedding(self, v): - """Completes the embedding.""" - # the recursion stack - dfs_stack = [v] - # index of next edge to handle in adjacency list of each node - ind = defaultdict(lambda: 0) - - while dfs_stack: - v = dfs_stack.pop() - - for w in self.ordered_adjs[v][ind[v]:]: - ind[v] += 1 - ei = (v, w) - - if ei == self.parent_edge[w]: # tree edge - self.embedding.add_half_edge_first(w, v) - self.left_ref[v] = w - self.right_ref[v] = w - - dfs_stack.append(v) # revisit v after finishing w - dfs_stack.append(w) # visit w next - break # handle next node in dfs_stack (i.e. w) - else: # back edge - if self.side[ei] == 1: - self.embedding.add_half_edge_cw(w, v, - self.right_ref[w]) - else: - self.embedding.add_half_edge_ccw(w, v, - self.left_ref[w]) - self.left_ref[w] = v - - def dfs_embedding_recursive(self, v): - """Recursive version of :meth:`dfs_embedding`.""" - for w in self.ordered_adjs[v]: - ei = (v, w) - if ei == self.parent_edge[w]: # tree edge - self.embedding.add_half_edge_first(w, v) - self.left_ref[v] = w - self.right_ref[v] = w - self.dfs_embedding_recursive(w) - else: # back edge - if self.side[ei] == 1: - # place v directly after right_ref[w] in embed. list of w - self.embedding.add_half_edge_cw(w, v, self.right_ref[w]) - else: - # place v directly before left_ref[w] in embed. list of w - self.embedding.add_half_edge_ccw(w, v, self.left_ref[w]) - self.left_ref[w] = v - - def sign(self, e): - """Resolve the relative side of an edge to the absolute side.""" - # the recursion stack - dfs_stack = [e] - # dict to remember reference edges - old_ref = defaultdict(lambda: None) - - while dfs_stack: - e = dfs_stack.pop() - - if self.ref[e] is not None: - dfs_stack.append(e) # revisit e after finishing self.ref[e] - dfs_stack.append(self.ref[e]) # visit self.ref[e] next - old_ref[e] = self.ref[e] # remember value of self.ref[e] - self.ref[e] = None - else: - self.side[e] *= self.side[old_ref[e]] - - return self.side[e] - - def sign_recursive(self, e): - """Recursive version of :meth:`sign`.""" - if self.ref[e] is not None: - self.side[e] = self.side[e] * self.sign_recursive(self.ref[e]) - self.ref[e] = None - return self.side[e] - - -class PlanarEmbedding(nx.DiGraph): - """Represents a planar graph with its planar embedding. - - The planar embedding is given by a `combinatorial embedding - `_. - - **Neighbor ordering:** - - In comparison to a usual graph structure, the embedding also stores the - order of all neighbors for every vertex. - The order of the neighbors can be given in clockwise (cw) direction or - counterclockwise (ccw) direction. This order is stored as edge attributes - in the underlying directed graph. For the edge (u, v) the edge attribute - 'cw' is set to the neighbor of u that follows immediately after v in - clockwise direction. - - In order for a PlanarEmbedding to be valid it must fulfill multiple - conditions. It is possible to check if these conditions are fulfilled with - the method :meth:`check_structure`. - The conditions are: - - * Edges must go in both directions (because the edge attributes differ) - * Every edge must have a 'cw' and 'ccw' attribute which corresponds to a - correct planar embedding. - * A node with non zero degree must have a node attribute 'first_nbr'. - - As long as a PlanarEmbedding is invalid only the following methods should - be called: - - * :meth:`add_half_edge_ccw` - * :meth:`add_half_edge_cw` - * :meth:`connect_components` - * :meth:`add_half_edge_first` - - Even though the graph is a subclass of nx.DiGraph, it can still be used - for algorithms that require undirected graphs, because the method - :meth:`is_directed` is overridden. This is possible, because a valid - PlanarGraph must have edges in both directions. - - **Half edges:** - - In methods like `add_half_edge_ccw` the term "half-edge" is used, which is - a term that is used in `doubly connected edge lists - `_. It is used - to emphasize that the edge is only in one direction and there exists - another half-edge in the opposite direction. - While conventional edges always have two faces (including outer face) next - to them, it is possible to assign each half-edge *exactly one* face. - For a half-edge (u, v) that is orientated such that u is below v then the - face that belongs to (u, v) is to the right of this half-edge. - - Examples - -------- - - Create an embedding of a star graph (compare `nx.star_graph(3)`): - - >>> G = nx.PlanarEmbedding() - >>> G.add_half_edge_cw(0, 1, None) - >>> G.add_half_edge_cw(0, 2, 1) - >>> G.add_half_edge_cw(0, 3, 2) - >>> G.add_half_edge_cw(1, 0, None) - >>> G.add_half_edge_cw(2, 0, None) - >>> G.add_half_edge_cw(3, 0, None) - - Alternatively the same embedding can also be defined in counterclockwise - orientation. The following results in exactly the same PlanarEmbedding: - - >>> G = nx.PlanarEmbedding() - >>> G.add_half_edge_ccw(0, 1, None) - >>> G.add_half_edge_ccw(0, 3, 1) - >>> G.add_half_edge_ccw(0, 2, 3) - >>> G.add_half_edge_ccw(1, 0, None) - >>> G.add_half_edge_ccw(2, 0, None) - >>> G.add_half_edge_ccw(3, 0, None) - - After creating a graph, it is possible to validate that the PlanarEmbedding - object is correct: - - >>> G.check_structure() - - """ - - def get_data(self): - """Converts the adjacency structure into a better readable structure. - - Returns - ------- - embedding : dict - A dict mapping all nodes to a list of neighbors sorted in - clockwise order. - - See Also - -------- - set_data - - """ - embedding = dict() - for v in self: - embedding[v] = list(self.neighbors_cw_order(v)) - return embedding - - def set_data(self, data): - """Inserts edges according to given sorted neighbor list. - - The input format is the same as the output format of get_data(). - - Parameters - ---------- - data : dict - A dict mapping all nodes to a list of neighbors sorted in - clockwise order. - - See Also - -------- - get_data - - """ - for v in data: - for w in reversed(data[v]): - self.add_half_edge_first(v, w) - - def neighbors_cw_order(self, v): - """Generator for the neighbors of v in clockwise order. - - Parameters - ---------- - v : node - - Yields - ------ - node - - """ - if len(self[v]) == 0: - # v has no neighbors - return - start_node = self.nodes[v]['first_nbr'] - yield start_node - current_node = self[v][start_node]['cw'] - while start_node != current_node: - yield current_node - current_node = self[v][current_node]['cw'] - - def check_structure(self): - """Runs without exceptions if this object is valid. - - Checks that the following properties are fulfilled: - - * Edges go in both directions (because the edge attributes differ). - * Every edge has a 'cw' and 'ccw' attribute which corresponds to a - correct planar embedding. - * A node with a degree larger than 0 has a node attribute 'first_nbr'. - - Running this method verifies that the underlying Graph must be planar. - - Raises - ------ - nx.NetworkXException - This exception is raised with a short explanation if the - PlanarEmbedding is invalid. - """ - # Check fundamental structure - for v in self: - try: - sorted_nbrs = set(self.neighbors_cw_order(v)) - except KeyError: - msg = "Bad embedding. " \ - "Missing orientation for a neighbor of {}".format(v) - raise nx.NetworkXException(msg) - - unsorted_nbrs = set(self[v]) - if sorted_nbrs != unsorted_nbrs: - msg = "Bad embedding. Edge orientations not set correctly." - raise nx.NetworkXException(msg) - for w in self[v]: - # Check if opposite half-edge exists - if not self.has_edge(w, v): - msg = "Bad embedding. Opposite half-edge is missing." - raise nx.NetworkXException(msg) - - # Check planarity - counted_half_edges = set() - for component in nx.connected_components(self): - if len(component) == 1: - # Don't need to check single node component - continue - num_nodes = len(component) - num_half_edges = 0 - num_faces = 0 - for v in component: - for w in self.neighbors_cw_order(v): - num_half_edges += 1 - if (v, w) not in counted_half_edges: - # We encountered a new face - num_faces += 1 - # Mark all half-edges belonging to this face - self.traverse_face(v, w, counted_half_edges) - num_edges = num_half_edges // 2 # num_half_edges is even - if num_nodes - num_edges + num_faces != 2: - # The result does not match Euler's formula - msg = "Bad embedding. The graph does not match Euler's formula" - raise nx.NetworkXException(msg) - - def add_half_edge_ccw(self, start_node, end_node, reference_neighbor): - """Adds a half-edge from start_node to end_node. - - The half-edge is added counter clockwise next to the existing half-edge - (start_node, reference_neighbor). - - Parameters - ---------- - start_node : node - Start node of inserted edge. - end_node : node - End node of inserted edge. - reference_neighbor: node - End node of reference edge. - - Raises - ------ - nx.NetworkXException - If the reference_neighbor does not exist. - - See Also - -------- - add_half_edge_cw - connect_components - add_half_edge_first - - """ - if reference_neighbor is None: - # The start node has no neighbors - self.add_edge(start_node, end_node) # Add edge to graph - self[start_node][end_node]['cw'] = end_node - self[start_node][end_node]['ccw'] = end_node - self.nodes[start_node]['first_nbr'] = end_node - else: - ccw_reference = self[start_node][reference_neighbor]['ccw'] - self.add_half_edge_cw(start_node, end_node, ccw_reference) - - if reference_neighbor == self.nodes[start_node].get('first_nbr', - None): - # Update first neighbor - self.nodes[start_node]['first_nbr'] = end_node - - def add_half_edge_cw(self, start_node, end_node, reference_neighbor): - """Adds a half-edge from start_node to end_node. - - The half-edge is added clockwise next to the existing half-edge - (start_node, reference_neighbor). - - Parameters - ---------- - start_node : node - Start node of inserted edge. - end_node : node - End node of inserted edge. - reference_neighbor: node - End node of reference edge. - - Raises - ------ - nx.NetworkXException - If the reference_neighbor does not exist. - - See Also - -------- - add_half_edge_ccw - connect_components - add_half_edge_first - """ - self.add_edge(start_node, end_node) # Add edge to graph - - if reference_neighbor is None: - # The start node has no neighbors - self[start_node][end_node]['cw'] = end_node - self[start_node][end_node]['ccw'] = end_node - self.nodes[start_node]['first_nbr'] = end_node - return - - if reference_neighbor not in self[start_node]: - raise nx.NetworkXException( - "Cannot add edge. Reference neighbor does not exist") - - # Get half-edge at the other side - cw_reference = self[start_node][reference_neighbor]['cw'] - # Alter half-edge data structures - self[start_node][reference_neighbor]['cw'] = end_node - self[start_node][end_node]['cw'] = cw_reference - self[start_node][cw_reference]['ccw'] = end_node - self[start_node][end_node]['ccw'] = reference_neighbor - - def connect_components(self, v, w): - """Adds half-edges for (v, w) and (w, v) at some position. - - This method should only be called if v and w are in different - components, or it might break the embedding. - This especially means that if `connect_components(v, w)` - is called it is not allowed to call `connect_components(w, v)` - afterwards. The neighbor orientations in both directions are - all set correctly after the first call. - - Parameters - ---------- - v : node - w : node - - See Also - -------- - add_half_edge_ccw - add_half_edge_cw - add_half_edge_first - """ - self.add_half_edge_first(v, w) - self.add_half_edge_first(w, v) - - def add_half_edge_first(self, start_node, end_node): - """The added half-edge is inserted at the first position in the order. - - Parameters - ---------- - start_node : node - end_node : node - - See Also - -------- - add_half_edge_ccw - add_half_edge_cw - connect_components - """ - if start_node in self and 'first_nbr' in self.nodes[start_node]: - reference = self.nodes[start_node]['first_nbr'] - else: - reference = None - self.add_half_edge_ccw(start_node, end_node, reference) - - def next_face_half_edge(self, v, w): - """Returns the following half-edge left of a face. - - Parameters - ---------- - v : node - w : node - - Returns - ------- - half-edge : tuple - """ - new_node = self[w][v]['ccw'] - return w, new_node - - def traverse_face(self, v, w, mark_half_edges=None): - """Returns nodes on the face that belong to the half-edge (v, w). - - The face that is traversed lies to the right of the half-edge (in an - orientation where v is below w). - - Optionally it is possible to pass a set to which all encountered half - edges are added. Before calling this method, this set must not include - any half-edges that belong to the face. - - Parameters - ---------- - v : node - Start node of half-edge. - w : node - End node of half-edge. - mark_half_edges: set, optional - Set to which all encountered half-edges are added. - - Returns - ------- - face : list - A list of nodes that lie on this face. - """ - if mark_half_edges is None: - mark_half_edges = set() - - face_nodes = [v] - mark_half_edges.add((v, w)) - prev_node = v - cur_node = w - # Last half-edge is (incoming_node, v) - incoming_node = self[v][w]['cw'] - - while cur_node != v or prev_node != incoming_node: - face_nodes.append(cur_node) - prev_node, cur_node = self.next_face_half_edge(prev_node, cur_node) - if (prev_node, cur_node) in mark_half_edges: - raise nx.NetworkXException( - "Bad planar embedding. Impossible face.") - mark_half_edges.add((prev_node, cur_node)) - - return face_nodes - - def is_directed(self): - """A valid PlanarEmbedding is undirected. - - All reverse edges are contained, i.e. for every existing - half-edge (v, w) the half-edge in the opposite direction (w, v) is also - contained. - """ - return False diff --git a/extensions/fablabchemnitz/networkx/algorithms/reciprocity.py b/extensions/fablabchemnitz/networkx/algorithms/reciprocity.py deleted file mode 100644 index c0ed9d4f..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/reciprocity.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2015-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Haochen Wu (wuhaochen42@gmail.com) -"""Algorithms to calculate reciprocity in a directed graph.""" -from networkx import NetworkXError -from ..utils import not_implemented_for - -__all__ = ['reciprocity', 'overall_reciprocity'] - - -@not_implemented_for('undirected', 'multigraph') -def reciprocity(G, nodes=None): - r"""Compute the reciprocity in a directed graph. - - The reciprocity of a directed graph is defined as the ratio - of the number of edges pointing in both directions to the total - number of edges in the graph. - Formally, $r = |{(u,v) \in G|(v,u) \in G}| / |{(u,v) \in G}|$. - - The reciprocity of a single node u is defined similarly, - it is the ratio of the number of edges in both directions to - the total number of edges attached to node u. - - Parameters - ---------- - G : graph - A networkx directed graph - nodes : container of nodes, optional (default=whole graph) - Compute reciprocity for nodes in this container. - - Returns - ------- - out : dictionary - Reciprocity keyed by node label. - - Notes - ----- - The reciprocity is not defined for isolated nodes. - In such cases this function will return None. - - """ - # If `nodes` is not specified, calculate the reciprocity of the graph. - if nodes is None: - return overall_reciprocity(G) - - # If `nodes` represents a single node in the graph, return only its - # reciprocity. - if nodes in G: - reciprocity = next(_reciprocity_iter(G, nodes))[1] - if reciprocity is None: - raise NetworkXError('Not defined for isolated nodes.') - else: - return reciprocity - - # Otherwise, `nodes` represents an iterable of nodes, so return a - # dictionary mapping node to its reciprocity. - return dict(_reciprocity_iter(G, nodes)) - - -def _reciprocity_iter(G, nodes): - """ Return an iterator of (node, reciprocity). - """ - n = G.nbunch_iter(nodes) - for node in n: - pred = set(G.predecessors(node)) - succ = set(G.successors(node)) - overlap = pred & succ - n_total = len(pred) + len(succ) - - # Reciprocity is not defined for isolated nodes. - # Return None. - if n_total == 0: - yield (node, None) - else: - reciprocity = 2.0 * float(len(overlap)) / float(n_total) - yield (node, reciprocity) - - -@not_implemented_for('undirected', 'multigraph') -def overall_reciprocity(G): - """Compute the reciprocity for the whole graph. - - See the doc of reciprocity for the definition. - - Parameters - ---------- - G : graph - A networkx graph - - """ - n_all_edge = G.number_of_edges() - n_overlap_edge = (n_all_edge - G.to_undirected().number_of_edges()) * 2 - - if n_all_edge == 0: - raise NetworkXError("Not defined for empty graphs") - - return float(n_overlap_edge) / float(n_all_edge) diff --git a/extensions/fablabchemnitz/networkx/algorithms/richclub.py b/extensions/fablabchemnitz/networkx/algorithms/richclub.py deleted file mode 100644 index d6d35376..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/richclub.py +++ /dev/null @@ -1,129 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Ben Edwards (bedwards@cs.unm.edu) -# Aric Hagberg (hagberg@lanl.gov) -"""Functions for computing rich-club coefficients.""" - -import networkx as nx -from networkx.utils import accumulate -from networkx.utils import not_implemented_for - -__all__ = ['rich_club_coefficient'] - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def rich_club_coefficient(G, normalized=True, Q=100, seed=None): - r"""Returns the rich-club coefficient of the graph `G`. - - For each degree *k*, the *rich-club coefficient* is the ratio of the - number of actual to the number of potential edges for nodes with - degree greater than *k*: - - .. math:: - - \phi(k) = \frac{2 E_k}{N_k (N_k - 1)} - - where `N_k` is the number of nodes with degree larger than *k*, and - `E_k` is the number of edges among those nodes. - - Parameters - ---------- - G : NetworkX graph - Undirected graph with neither parallel edges nor self-loops. - normalized : bool (optional) - Normalize using randomized network as in [1]_ - Q : float (optional, default=100) - If `normalized` is True, perform `Q * m` double-edge - swaps, where `m` is the number of edges in `G`, to use as a - null-model for normalization. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - rc : dictionary - A dictionary, keyed by degree, with rich-club coefficient values. - - Examples - -------- - >>> G = nx.Graph([(0, 1), (0, 2), (1, 2), (1, 3), (1, 4), (4, 5)]) - >>> rc = nx.rich_club_coefficient(G, normalized=False) - >>> rc[0] # doctest: +SKIP - 0.4 - - Notes - ----- - The rich club definition and algorithm are found in [1]_. This - algorithm ignores any edge weights and is not defined for directed - graphs or graphs with parallel edges or self loops. - - Estimates for appropriate values of `Q` are found in [2]_. - - References - ---------- - .. [1] Julian J. McAuley, Luciano da Fontoura Costa, - and Tibério S. Caetano, - "The rich-club phenomenon across complex network hierarchies", - Applied Physics Letters Vol 91 Issue 8, August 2007. - https://arxiv.org/abs/physics/0701290 - .. [2] R. Milo, N. Kashtan, S. Itzkovitz, M. E. J. Newman, U. Alon, - "Uniform generation of random graphs with arbitrary degree - sequences", 2006. https://arxiv.org/abs/cond-mat/0312028 - """ - if nx.number_of_selfloops(G) > 0: - raise Exception('rich_club_coefficient is not implemented for ' - 'graphs with self loops.') - rc = _compute_rc(G) - if normalized: - # make R a copy of G, randomize with Q*|E| double edge swaps - # and use rich_club coefficient of R to normalize - R = G.copy() - E = R.number_of_edges() - nx.double_edge_swap(R, Q * E, max_tries=Q * E * 10, seed=seed) - rcran = _compute_rc(R) - rc = {k: v / rcran[k] for k, v in rc.items()} - return rc - - -def _compute_rc(G): - """Returns the rich-club coefficient for each degree in the graph - `G`. - - `G` is an undirected graph without multiedges. - - Returns a dictionary mapping degree to rich-club coefficient for - that degree. - - """ - deghist = nx.degree_histogram(G) - total = sum(deghist) - # Compute the number of nodes with degree greater than `k`, for each - # degree `k` (omitting the last entry, which is zero). - nks = (total - cs for cs in accumulate(deghist) if total - cs > 1) - # Create a sorted list of pairs of edge endpoint degrees. - # - # The list is sorted in reverse order so that we can pop from the - # right side of the list later, instead of popping from the left - # side of the list, which would have a linear time cost. - edge_degrees = sorted((sorted(map(G.degree, e)) for e in G.edges()), - reverse=True) - ek = G.number_of_edges() - k1, k2 = edge_degrees.pop() - rc = {} - for d, nk in enumerate(nks): - while k1 <= d: - if len(edge_degrees) == 0: - ek = 0 - break - k1, k2 = edge_degrees.pop() - ek -= 1 - rc[d] = 2 * ek / (nk * (nk - 1)) - return rc diff --git a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/__init__.py deleted file mode 100644 index eb0d91ce..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from networkx.algorithms.shortest_paths.generic import * -from networkx.algorithms.shortest_paths.unweighted import * -from networkx.algorithms.shortest_paths.weighted import * -from networkx.algorithms.shortest_paths.astar import * -from networkx.algorithms.shortest_paths.dense import * diff --git a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/astar.py b/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/astar.py deleted file mode 100644 index 232c5e20..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/astar.py +++ /dev/null @@ -1,176 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Salim Fadhley -# Matteo Dell'Amico -"""Shortest paths and path lengths using the A* ("A star") algorithm. -""" -from heapq import heappush, heappop -from itertools import count - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ['astar_path', 'astar_path_length'] - - -@not_implemented_for('multigraph') -def astar_path(G, source, target, heuristic=None, weight='weight'): - """Returns a list of nodes in a shortest path between source and target - using the A* ("A-star") algorithm. - - There may be more than one shortest path. This returns only one. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path - - target : node - Ending node for path - - heuristic : function - A function to evaluate the estimate of the distance - from the a node to the target. The function takes - two nodes arguments and must return a number. - - weight: string, optional (default='weight') - Edge data key corresponding to the edge weight. - - Raises - ------ - NetworkXNoPath - If no path exists between source and target. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> print(nx.astar_path(G, 0, 4)) - [0, 1, 2, 3, 4] - >>> G = nx.grid_graph(dim=[3, 3]) # nodes are two-tuples (x,y) - >>> nx.set_edge_attributes(G, {e: e[1][0]*2 for e in G.edges()}, 'cost') - >>> def dist(a, b): - ... (x1, y1) = a - ... (x2, y2) = b - ... return ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5 - >>> print(nx.astar_path(G, (0, 0), (2, 2), heuristic=dist, weight='cost')) - [(0, 0), (0, 1), (0, 2), (1, 2), (2, 2)] - - - See Also - -------- - shortest_path, dijkstra_path - - """ - if source not in G or target not in G: - msg = 'Either source {} or target {} is not in G' - raise nx.NodeNotFound(msg.format(source, target)) - - if heuristic is None: - # The default heuristic is h=0 - same as Dijkstra's algorithm - def heuristic(u, v): - return 0 - - push = heappush - pop = heappop - - # The queue stores priority, node, cost to reach, and parent. - # Uses Python heapq to keep in priority order. - # Add a counter to the queue to prevent the underlying heap from - # attempting to compare the nodes themselves. The hash breaks ties in the - # priority and is guaranteed unique for all nodes in the graph. - c = count() - queue = [(0, next(c), source, 0, None)] - - # Maps enqueued nodes to distance of discovered paths and the - # computed heuristics to target. We avoid computing the heuristics - # more than once and inserting the node into the queue too many times. - enqueued = {} - # Maps explored nodes to parent closest to the source. - explored = {} - - while queue: - # Pop the smallest item from queue. - _, __, curnode, dist, parent = pop(queue) - - if curnode == target: - path = [curnode] - node = parent - while node is not None: - path.append(node) - node = explored[node] - path.reverse() - return path - - if curnode in explored: - # Do not override the parent of starting node - if explored[curnode] is None: - continue - - # Skip bad paths that were enqueued before finding a better one - qcost, h = enqueued[curnode] - if qcost < dist: - continue - - explored[curnode] = parent - - for neighbor, w in G[curnode].items(): - ncost = dist + w.get(weight, 1) - if neighbor in enqueued: - qcost, h = enqueued[neighbor] - # if qcost <= ncost, a less costly path from the - # neighbor to the source was already determined. - # Therefore, we won't attempt to push this neighbor - # to the queue - if qcost <= ncost: - continue - else: - h = heuristic(neighbor, target) - enqueued[neighbor] = ncost, h - push(queue, (ncost + h, next(c), neighbor, ncost, curnode)) - - raise nx.NetworkXNoPath("Node %s not reachable from %s" % (target, source)) - - -def astar_path_length(G, source, target, heuristic=None, weight='weight'): - """Returns the length of the shortest path between source and target using - the A* ("A-star") algorithm. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path - - target : node - Ending node for path - - heuristic : function - A function to evaluate the estimate of the distance - from the a node to the target. The function takes - two nodes arguments and must return a number. - - Raises - ------ - NetworkXNoPath - If no path exists between source and target. - - See Also - -------- - astar_path - - """ - if source not in G or target not in G: - msg = 'Either source {} or target {} is not in G' - raise nx.NodeNotFound(msg.format(source, target)) - - path = astar_path(G, source, target, heuristic, weight) - return sum(G[u][v].get(weight, 1) for u, v in zip(path[:-1], path[1:])) diff --git a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/dense.py b/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/dense.py deleted file mode 100644 index 8f11c1f9..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/dense.py +++ /dev/null @@ -1,217 +0,0 @@ -# -*- coding: utf-8 -*- -"""Floyd-Warshall algorithm for shortest paths. -""" -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg -# Miguel Sozinho Ramalho -import networkx as nx - -__all__ = ['floyd_warshall', - 'floyd_warshall_predecessor_and_distance', - 'reconstruct_path', - 'floyd_warshall_numpy'] - - -def floyd_warshall_numpy(G, nodelist=None, weight='weight'): - """Find all-pairs shortest path lengths using Floyd's algorithm. - - Parameters - ---------- - G : NetworkX graph - - nodelist : list, optional - The rows and columns are ordered by the nodes in nodelist. - If nodelist is None then the ordering is produced by G.nodes(). - - weight: string, optional (default= 'weight') - Edge data key corresponding to the edge weight. - - Returns - ------- - distance : NumPy matrix - A matrix of shortest path distances between nodes. - If there is no path between to nodes the corresponding matrix entry - will be Inf. - - Notes - ------ - Floyd's algorithm is appropriate for finding shortest paths in - dense graphs or graphs with negative weights when Dijkstra's - algorithm fails. This algorithm can still fail if there are negative - cycles. It has running time $O(n^3)$ with running space of $O(n^2)$. - """ - try: - import numpy as np - except ImportError: - raise ImportError( - "to_numpy_matrix() requires numpy: http://scipy.org/ ") - - # To handle cases when an edge has weight=0, we must make sure that - # nonedges are not given the value 0 as well. - A = nx.to_numpy_matrix(G, nodelist=nodelist, multigraph_weight=min, - weight=weight, nonedge=np.inf) - n, m = A.shape - A[np.identity(n) == 1] = 0 # diagonal elements should be zero - for i in range(n): - A = np.minimum(A, A[i, :] + A[:, i]) - return A - - -def floyd_warshall_predecessor_and_distance(G, weight='weight'): - """Find all-pairs shortest path lengths using Floyd's algorithm. - - Parameters - ---------- - G : NetworkX graph - - weight: string, optional (default= 'weight') - Edge data key corresponding to the edge weight. - - Returns - ------- - predecessor,distance : dictionaries - Dictionaries, keyed by source and target, of predecessors and distances - in the shortest path. - - Examples - -------- - >>> G = nx.DiGraph() - >>> G.add_weighted_edges_from([('s', 'u', 10), ('s', 'x', 5), - ... ('u', 'v', 1), ('u', 'x', 2), ('v', 'y', 1), ('x', 'u', 3), - ... ('x', 'v', 5), ('x', 'y', 2), ('y', 's', 7), ('y', 'v', 6)]) - >>> predecessors, _ = nx.floyd_warshall_predecessor_and_distance(G) - >>> print(nx.reconstruct_path('s', 'v', predecessors)) - ['s', 'x', 'u', 'v'] - - Notes - ------ - Floyd's algorithm is appropriate for finding shortest paths - in dense graphs or graphs with negative weights when Dijkstra's algorithm - fails. This algorithm can still fail if there are negative cycles. - It has running time $O(n^3)$ with running space of $O(n^2)$. - - See Also - -------- - floyd_warshall - floyd_warshall_numpy - all_pairs_shortest_path - all_pairs_shortest_path_length - """ - from collections import defaultdict - # dictionary-of-dictionaries representation for dist and pred - # use some defaultdict magick here - # for dist the default is the floating point inf value - dist = defaultdict(lambda: defaultdict(lambda: float('inf'))) - for u in G: - dist[u][u] = 0 - pred = defaultdict(dict) - # initialize path distance dictionary to be the adjacency matrix - # also set the distance to self to 0 (zero diagonal) - undirected = not G.is_directed() - for u, v, d in G.edges(data=True): - e_weight = d.get(weight, 1.0) - dist[u][v] = min(e_weight, dist[u][v]) - pred[u][v] = u - if undirected: - dist[v][u] = min(e_weight, dist[v][u]) - pred[v][u] = v - for w in G: - dist_w = dist[w] # save recomputation - for u in G: - dist_u = dist[u] # save recomputation - for v in G: - d = dist_u[w] + dist_w[v] - if dist_u[v] > d: - dist_u[v] = d - pred[u][v] = pred[w][v] - return dict(pred), dict(dist) - - -def reconstruct_path(source, target, predecessors): - """Reconstruct a path from source to target using the predecessors - dict as returned by floyd_warshall_predecessor_and_distance - - Parameters - ---------- - source : node - Starting node for path - - target : node - Ending node for path - - predecessors: dictionary - Dictionary, keyed by source and target, of predecessors in the - shortest path, as returned by floyd_warshall_predecessor_and_distance - - Returns - ------- - path : list - A list of nodes containing the shortest path from source to target - - If source and target are the same, an empty list is returned - - Notes - ------ - This function is meant to give more applicability to the - floyd_warshall_predecessor_and_distance function - - See Also - -------- - floyd_warshall_predecessor_and_distance - """ - if source == target: - return [] - prev = predecessors[source] - curr = prev[target] - path = [target, curr] - while curr != source: - curr = prev[curr] - path.append(curr) - return list(reversed(path)) - - -def floyd_warshall(G, weight='weight'): - """Find all-pairs shortest path lengths using Floyd's algorithm. - - Parameters - ---------- - G : NetworkX graph - - weight: string, optional (default= 'weight') - Edge data key corresponding to the edge weight. - - - Returns - ------- - distance : dict - A dictionary, keyed by source and target, of shortest paths distances - between nodes. - - Notes - ------ - Floyd's algorithm is appropriate for finding shortest paths - in dense graphs or graphs with negative weights when Dijkstra's algorithm - fails. This algorithm can still fail if there are negative cycles. - It has running time $O(n^3)$ with running space of $O(n^2)$. - - See Also - -------- - floyd_warshall_predecessor_and_distance - floyd_warshall_numpy - all_pairs_shortest_path - all_pairs_shortest_path_length - """ - # could make this its own function to reduce memory costs - return floyd_warshall_predecessor_and_distance(G, weight=weight)[1] - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/generic.py b/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/generic.py deleted file mode 100644 index 8f8add15..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/generic.py +++ /dev/null @@ -1,515 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg -# Sérgio Nery Simões -""" -Compute the shortest paths and path lengths between nodes in the graph. - -These algorithms work with undirected and directed graphs. - -""" - -import networkx as nx -from networkx.algorithms.components import connected_components - -__all__ = ['shortest_path', 'all_shortest_paths', - 'shortest_path_length', 'average_shortest_path_length', - 'has_path'] - - -def has_path(G, source, target): - """Returns *True* if *G* has a path from *source* to *target*. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path - - target : node - Ending node for path - """ - try: - nx.shortest_path(G, source, target) - except nx.NetworkXNoPath: - return False - return True - - -def shortest_path(G, source=None, target=None, weight=None, method='dijkstra'): - """Compute shortest paths in the graph. - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Starting node for path. If not specified, compute shortest - paths for each possible starting node. - - target : node, optional - Ending node for path. If not specified, compute shortest - paths to all possible nodes. - - weight : None or string, optional (default = None) - If None, every edge has weight/distance/cost 1. - If a string, use this edge attribute as the edge weight. - Any edge attribute not present defaults to 1. - - method : string, optional (default = 'dijkstra') - The algorithm to use to compute the path. - Supported options: 'dijkstra', 'bellman-ford'. - Other inputs produce a ValueError. - If `weight` is None, unweighted graph methods are used, and this - suggestion is ignored. - - Returns - ------- - path: list or dictionary - All returned paths include both the source and target in the path. - - If the source and target are both specified, return a single list - of nodes in a shortest path from the source to the target. - - If only the source is specified, return a dictionary keyed by - targets with a list of nodes in a shortest path from the source - to one of the targets. - - If only the target is specified, return a dictionary keyed by - sources with a list of nodes in a shortest path from one of the - sources to the target. - - If neither the source nor target are specified return a dictionary - of dictionaries with path[source][target]=[list of nodes in path]. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - ValueError - If `method` is not among the supported options. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> print(nx.shortest_path(G, source=0, target=4)) - [0, 1, 2, 3, 4] - >>> p = nx.shortest_path(G, source=0) # target not specified - >>> p[4] - [0, 1, 2, 3, 4] - >>> p = nx.shortest_path(G, target=4) # source not specified - >>> p[0] - [0, 1, 2, 3, 4] - >>> p = nx.shortest_path(G) # source, target not specified - >>> p[0][4] - [0, 1, 2, 3, 4] - - Notes - ----- - There may be more than one shortest path between a source and target. - This returns only one of them. - - See Also - -------- - all_pairs_shortest_path() - all_pairs_dijkstra_path() - all_pairs_bellman_ford_path() - single_source_shortest_path() - single_source_dijkstra_path() - single_source_bellman_ford_path() - """ - if method not in ('dijkstra', 'bellman-ford'): - # so we don't need to check in each branch later - raise ValueError('method not supported: {}'.format(method)) - method = 'unweighted' if weight is None else method - if source is None: - if target is None: - # Find paths between all pairs. - if method == 'unweighted': - paths = dict(nx.all_pairs_shortest_path(G)) - elif method == 'dijkstra': - paths = dict(nx.all_pairs_dijkstra_path(G, weight=weight)) - else: # method == 'bellman-ford': - paths = dict(nx.all_pairs_bellman_ford_path(G, weight=weight)) - else: - # Find paths from all nodes co-accessible to the target. - with nx.utils.reversed(G): - if method == 'unweighted': - paths = nx.single_source_shortest_path(G, target) - elif method == 'dijkstra': - paths = nx.single_source_dijkstra_path(G, target, - weight=weight) - else: # method == 'bellman-ford': - paths = nx.single_source_bellman_ford_path(G, target, - weight=weight) - # Now flip the paths so they go from a source to the target. - for target in paths: - paths[target] = list(reversed(paths[target])) - else: - if target is None: - # Find paths to all nodes accessible from the source. - if method == 'unweighted': - paths = nx.single_source_shortest_path(G, source) - elif method == 'dijkstra': - paths = nx.single_source_dijkstra_path(G, source, - weight=weight) - else: # method == 'bellman-ford': - paths = nx.single_source_bellman_ford_path(G, source, - weight=weight) - else: - # Find shortest source-target path. - if method == 'unweighted': - paths = nx.bidirectional_shortest_path(G, source, target) - elif method == 'dijkstra': - paths = nx.dijkstra_path(G, source, target, weight) - else: # method == 'bellman-ford': - paths = nx.bellman_ford_path(G, source, target, weight) - return paths - - -def shortest_path_length(G, - source=None, - target=None, - weight=None, - method='dijkstra'): - """Compute shortest path lengths in the graph. - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Starting node for path. - If not specified, compute shortest path lengths using all nodes as - source nodes. - - target : node, optional - Ending node for path. - If not specified, compute shortest path lengths using all nodes as - target nodes. - - weight : None or string, optional (default = None) - If None, every edge has weight/distance/cost 1. - If a string, use this edge attribute as the edge weight. - Any edge attribute not present defaults to 1. - - method : string, optional (default = 'dijkstra') - The algorithm to use to compute the path length. - Supported options: 'dijkstra', 'bellman-ford'. - Other inputs produce a ValueError. - If `weight` is None, unweighted graph methods are used, and this - suggestion is ignored. - - Returns - ------- - length: int or iterator - If the source and target are both specified, return the length of - the shortest path from the source to the target. - - If only the source is specified, return a dict keyed by target - to the shortest path length from the source to that target. - - If only the target is specified, return a dict keyed by source - to the shortest path length from that source to the target. - - If neither the source nor target are specified, return an iterator - over (source, dictionary) where dictionary is keyed by target to - shortest path length from source to that target. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - NetworkXNoPath - If no path exists between source and target. - - ValueError - If `method` is not among the supported options. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> nx.shortest_path_length(G, source=0, target=4) - 4 - >>> p = nx.shortest_path_length(G, source=0) # target not specified - >>> p[4] - 4 - >>> p = nx.shortest_path_length(G, target=4) # source not specified - >>> p[0] - 4 - >>> p = dict(nx.shortest_path_length(G)) # source,target not specified - >>> p[0][4] - 4 - - Notes - ----- - The length of the path is always 1 less than the number of nodes involved - in the path since the length measures the number of edges followed. - - For digraphs this returns the shortest directed path length. To find path - lengths in the reverse direction use G.reverse(copy=False) first to flip - the edge orientation. - - See Also - -------- - all_pairs_shortest_path_length() - all_pairs_dijkstra_path_length() - all_pairs_bellman_ford_path_length() - single_source_shortest_path_length() - single_source_dijkstra_path_length() - single_source_bellman_ford_path_length() - """ - if method not in ('dijkstra', 'bellman-ford'): - # so we don't need to check in each branch later - raise ValueError('method not supported: {}'.format(method)) - method = 'unweighted' if weight is None else method - if source is None: - if target is None: - # Find paths between all pairs. - if method == 'unweighted': - paths = nx.all_pairs_shortest_path_length(G) - elif method == 'dijkstra': - paths = nx.all_pairs_dijkstra_path_length(G, weight=weight) - else: # method == 'bellman-ford': - paths = nx.all_pairs_bellman_ford_path_length(G, weight=weight) - else: - # Find paths from all nodes co-accessible to the target. - with nx.utils.reversed(G): - if method == 'unweighted': - # We need to exhaust the iterator as Graph needs - # to be reversed. - path_length = nx.single_source_shortest_path_length - paths = path_length(G, target) - elif method == 'dijkstra': - path_length = nx.single_source_dijkstra_path_length - paths = path_length(G, target, weight=weight) - else: # method == 'bellman-ford': - path_length = nx.single_source_bellman_ford_path_length - paths = path_length(G, target, weight=weight) - else: - if target is None: - # Find paths to all nodes accessible from the source. - if method == 'unweighted': - paths = nx.single_source_shortest_path_length(G, source) - elif method == 'dijkstra': - path_length = nx.single_source_dijkstra_path_length - paths = path_length(G, source, weight=weight) - else: # method == 'bellman-ford': - path_length = nx.single_source_bellman_ford_path_length - paths = path_length(G, source, weight=weight) - else: - # Find shortest source-target path. - if method == 'unweighted': - p = nx.bidirectional_shortest_path(G, source, target) - paths = len(p) - 1 - elif method == 'dijkstra': - paths = nx.dijkstra_path_length(G, source, target, weight) - else: # method == 'bellman-ford': - paths = nx.bellman_ford_path_length(G, source, target, weight) - return paths - - -def average_shortest_path_length(G, weight=None, method=None): - r"""Returns the average shortest path length. - - The average shortest path length is - - .. math:: - - a =\sum_{s,t \in V} \frac{d(s, t)}{n(n-1)} - - where `V` is the set of nodes in `G`, - `d(s, t)` is the shortest path from `s` to `t`, - and `n` is the number of nodes in `G`. - - Parameters - ---------- - G : NetworkX graph - - weight : None or string, optional (default = None) - If None, every edge has weight/distance/cost 1. - If a string, use this edge attribute as the edge weight. - Any edge attribute not present defaults to 1. - - method : string, optional (default = 'unweighted' or 'djikstra') - The algorithm to use to compute the path lengths. - Supported options are 'unweighted', 'dijkstra', 'bellman-ford', - 'floyd-warshall' and 'floyd-warshall-numpy'. - Other method values produce a ValueError. - The default method is 'unweighted' if `weight` is None, - otherwise the default method is 'dijkstra'. - - Raises - ------ - NetworkXPointlessConcept - If `G` is the null graph (that is, the graph on zero nodes). - - NetworkXError - If `G` is not connected (or not weakly connected, in the case - of a directed graph). - - ValueError - If `method` is not among the supported options. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> nx.average_shortest_path_length(G) - 2.0 - - For disconnected graphs, you can compute the average shortest path - length for each component - - >>> G = nx.Graph([(1, 2), (3, 4)]) - >>> for C in (G.subgraph(c).copy() for c in connected_components(G)): - ... print(nx.average_shortest_path_length(C)) - 1.0 - 1.0 - - """ - single_source_methods = ['unweighted', - 'dijkstra', - 'bellman-ford'] - all_pairs_methods = ['floyd-warshall', - 'floyd-warshall-numpy'] - supported_methods = single_source_methods + all_pairs_methods - - if method is None: - method = 'unweighted' if weight is None else 'dijkstra' - if method not in supported_methods: - raise ValueError('method not supported: {}'.format(method)) - - n = len(G) - # For the special case of the null graph, raise an exception, since - # there are no paths in the null graph. - if n == 0: - msg = ('the null graph has no paths, thus there is no average' - 'shortest path length') - raise nx.NetworkXPointlessConcept(msg) - # For the special case of the trivial graph, return zero immediately. - if n == 1: - return 0 - # Shortest path length is undefined if the graph is disconnected. - if G.is_directed() and not nx.is_weakly_connected(G): - raise nx.NetworkXError("Graph is not weakly connected.") - if not G.is_directed() and not nx.is_connected(G): - raise nx.NetworkXError("Graph is not connected.") - - # Compute all-pairs shortest paths. - def path_length(v): - if method == 'unweighted': - return nx.single_source_shortest_path_length(G, v) - elif method == 'dijkstra': - return nx.single_source_dijkstra_path_length(G, v, weight=weight) - elif method == 'bellman-ford': - return nx.single_source_bellman_ford_path_length(G, v, - weight=weight) - - if method in single_source_methods: - # Sum the distances for each (ordered) pair of source and target node. - s = sum(l for u in G for l in path_length(u).values()) - else: - if method == 'floyd-warshall': - all_pairs = nx.floyd_warshall(G, weight=weight) - s = sum([sum(t.values()) for t in all_pairs.values()]) - elif method == 'floyd-warshall-numpy': - s = nx.floyd_warshall_numpy(G, weight=weight).sum() - return s / (n * (n - 1)) - - -def all_shortest_paths(G, source, target, weight=None, method='dijkstra'): - """Compute all shortest paths in the graph. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path. - - target : node - Ending node for path. - - weight : None or string, optional (default = None) - If None, every edge has weight/distance/cost 1. - If a string, use this edge attribute as the edge weight. - Any edge attribute not present defaults to 1. - - method : string, optional (default = 'dijkstra') - The algorithm to use to compute the path lengths. - Supported options: 'dijkstra', 'bellman-ford'. - Other inputs produce a ValueError. - If `weight` is None, unweighted graph methods are used, and this - suggestion is ignored. - - Returns - ------- - paths : generator of lists - A generator of all paths between source and target. - - Raises - ------ - ValueError - If `method` is not among the supported options. - - NetworkXNoPath - If `target` cannot be reached from `source`. - - Examples - -------- - >>> G = nx.Graph() - >>> nx.add_path(G, [0, 1, 2]) - >>> nx.add_path(G, [0, 10, 2]) - >>> print([p for p in nx.all_shortest_paths(G, source=0, target=2)]) - [[0, 1, 2], [0, 10, 2]] - - Notes - ----- - There may be many shortest paths between the source and target. - - See Also - -------- - shortest_path() - single_source_shortest_path() - all_pairs_shortest_path() - """ - method = 'unweighted' if weight is None else method - if method == 'unweighted': - pred = nx.predecessor(G, source) - elif method == 'dijkstra': - pred, dist = nx.dijkstra_predecessor_and_distance(G, source, - weight=weight) - elif method == 'bellman-ford': - pred, dist = nx.bellman_ford_predecessor_and_distance(G, source, - weight=weight) - else: - raise ValueError('method not supported: {}'.format(method)) - - if target not in pred: - raise nx.NetworkXNoPath('Target {} cannot be reached' - 'from Source {}'.format(target, source)) - - stack = [[target, 0]] - top = 0 - while top >= 0: - node, i = stack[top] - if node == source: - yield [p for p, n in reversed(stack[:top + 1])] - if len(pred[node]) > i: - top += 1 - if top == len(stack): - stack.append([pred[node][i], 0]) - else: - stack[top] = [pred[node][i], 0] - else: - stack[top - 1][1] += 1 - top -= 1 diff --git a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_astar.py b/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_astar.py deleted file mode 100644 index 75e792f1..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_astar.py +++ /dev/null @@ -1,159 +0,0 @@ -import pytest - -from math import sqrt - -import networkx as nx -from networkx.utils import pairwise - - -def dist(a, b): - """Returns the Euclidean distance between points `a` and `b`.""" - return sqrt(sum((x1 - x2) ** 2 for x1, x2 in zip(a, b))) - - -class TestAStar: - - @classmethod - def setup_class(cls): - edges = [('s', 'u', 10), ('s', 'x', 5), ('u', 'v', 1), ('u', 'x', 2), - ('v', 'y', 1), ('x', 'u', 3), ('x', 'v', 5), ('x', 'y', 2), - ('y', 's', 7), ('y', 'v', 6)] - cls.XG = nx.DiGraph() - cls.XG.add_weighted_edges_from(edges) - - def test_multiple_optimal_paths(self): - """Tests that A* algorithm finds any of multiple optimal paths""" - heuristic_values = {"a": 1.35, "b": 1.18, "c": 0.67, "d": 0} - - def h(u, v): - return heuristic_values[u] - - graph = nx.Graph() - points = ["a", "b", "c", "d"] - edges = [("a", "b", 0.18), ("a", "c", 0.68), - ("b", "c", 0.50), ("c", "d", 0.67)] - - graph.add_nodes_from(points) - graph.add_weighted_edges_from(edges) - - path1 = ["a", "c", "d"] - path2 = ["a", "b", "c", "d"] - assert nx.astar_path(graph, "a", "d", h) in (path1, path2) - - def test_astar_directed(self): - assert nx.astar_path(self.XG, 's', 'v') == ['s', 'x', 'u', 'v'] - assert nx.astar_path_length(self.XG, 's', 'v') == 9 - - def test_astar_multigraph(self): - G = nx.MultiDiGraph(self.XG) - pytest.raises(nx.NetworkXNotImplemented, nx.astar_path, G, 's', 'v') - pytest.raises(nx.NetworkXNotImplemented, nx.astar_path_length, - G, 's', 'v') - - def test_astar_undirected(self): - GG = self.XG.to_undirected() - # make sure we get lower weight - # to_undirected might choose either edge with weight 2 or weight 3 - GG['u']['x']['weight'] = 2 - GG['y']['v']['weight'] = 2 - assert nx.astar_path(GG, 's', 'v') == ['s', 'x', 'u', 'v'] - assert nx.astar_path_length(GG, 's', 'v') == 8 - - def test_astar_directed2(self): - XG2 = nx.DiGraph() - edges = [(1, 4, 1), (4, 5, 1), (5, 6, 1), (6, 3, 1), (1, 3, 50), - (1, 2, 100), (2, 3, 100)] - XG2.add_weighted_edges_from(edges) - assert nx.astar_path(XG2, 1, 3) == [1, 4, 5, 6, 3] - - def test_astar_undirected2(self): - XG3 = nx.Graph() - edges = [(0, 1, 2), (1, 2, 12), (2, 3, 1), (3, 4, 5), (4, 5, 1), - (5, 0, 10)] - XG3.add_weighted_edges_from(edges) - assert nx.astar_path(XG3, 0, 3) == [0, 1, 2, 3] - assert nx.astar_path_length(XG3, 0, 3) == 15 - - def test_astar_undirected3(self): - XG4 = nx.Graph() - edges = [(0, 1, 2), (1, 2, 2), (2, 3, 1), (3, 4, 1), (4, 5, 1), - (5, 6, 1), (6, 7, 1), (7, 0, 1)] - XG4.add_weighted_edges_from(edges) - assert nx.astar_path(XG4, 0, 2) == [0, 1, 2] - assert nx.astar_path_length(XG4, 0, 2) == 4 - - """ Tests that A* finds correct path when multiple paths exist - and the best one is not expanded first (GH issue #3464) - """ - def test_astar_directed3(self): - heuristic_values = {"n5": 36, "n2": 4, "n1": 0, "n0": 0} - - def h(u, v): - return heuristic_values[u] - - edges = [("n5", "n1", 11), ("n5", "n2", 9), - ("n2", "n1", 1), ("n1", "n0", 32)] - graph = nx.DiGraph() - graph.add_weighted_edges_from(edges) - answer = ["n5", "n2", "n1", "n0"] - assert nx.astar_path(graph, "n5", "n0", h) == answer - - """ Tests that that parent is not wrongly overridden when a - node is re-explored multiple times. - """ - def test_astar_directed4(self): - edges = [("a", "b", 1), ("a", "c", 1), ("b", "d", 2), - ("c", "d", 1), ("d", "e", 1)] - graph = nx.DiGraph() - graph.add_weighted_edges_from(edges) - assert nx.astar_path(graph, "a", "e") == ["a", "c", "d", "e"] - -# >>> MXG4=NX.MultiGraph(XG4) -# >>> MXG4.add_edge(0,1,3) -# >>> NX.dijkstra_path(MXG4,0,2) -# [0, 1, 2] - - def test_astar_w1(self): - G = nx.DiGraph() - G.add_edges_from([('s', 'u'), ('s', 'x'), ('u', 'v'), ('u', 'x'), - ('v', 'y'), ('x', 'u'), ('x', 'w'), ('w', 'v'), - ('x', 'y'), ('y', 's'), ('y', 'v')]) - assert nx.astar_path(G, 's', 'v') == ['s', 'u', 'v'] - assert nx.astar_path_length(G, 's', 'v') == 2 - - def test_astar_nopath(self): - with pytest.raises(nx.NodeNotFound): - nx.astar_path(self.XG, 's', 'moon') - - def test_cycle(self): - C = nx.cycle_graph(7) - assert nx.astar_path(C, 0, 3) == [0, 1, 2, 3] - assert nx.dijkstra_path(C, 0, 4) == [0, 6, 5, 4] - - def test_unorderable_nodes(self): - """Tests that A* accommodates nodes that are not orderable. - - For more information, see issue #554. - - """ - # TODO In Python 3, instances of the `object` class are - # unorderable by default, so we wouldn't need to define our own - # class here, we could just instantiate an instance of the - # `object` class. However, we still support Python 2; when - # support for Python 2 is dropped, this test can be simplified - # by replacing `Unorderable()` by `object()`. - class Unorderable(object): - - def __le__(self): - raise NotImplemented - - def __ge__(self): - raise NotImplemented - - # Create the cycle graph on four nodes, with nodes represented - # as (unorderable) Python objects. - nodes = [Unorderable() for n in range(4)] - G = nx.Graph() - G.add_edges_from(pairwise(nodes, cyclic=True)) - path = nx.astar_path(G, nodes[0], nodes[2]) - assert len(path) == 3 diff --git a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_dense.py b/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_dense.py deleted file mode 100644 index b2446d01..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_dense.py +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/bin/env python -import pytest -import networkx as nx - - -class TestFloyd: - @classmethod - def setup_class(cls): - pass - - def test_floyd_warshall_predecessor_and_distance(self): - XG = nx.DiGraph() - XG.add_weighted_edges_from([('s', 'u', 10), ('s', 'x', 5), - ('u', 'v', 1), ('u', 'x', 2), - ('v', 'y', 1), ('x', 'u', 3), - ('x', 'v', 5), ('x', 'y', 2), - ('y', 's', 7), ('y', 'v', 6)]) - path, dist = nx.floyd_warshall_predecessor_and_distance(XG) - assert dist['s']['v'] == 9 - assert path['s']['v'] == 'u' - assert (dist == - {'y': {'y': 0, 'x': 12, 's': 7, 'u': 15, 'v': 6}, - 'x': {'y': 2, 'x': 0, 's': 9, 'u': 3, 'v': 4}, - 's': {'y': 7, 'x': 5, 's': 0, 'u': 8, 'v': 9}, - 'u': {'y': 2, 'x': 2, 's': 9, 'u': 0, 'v': 1}, - 'v': {'y': 1, 'x': 13, 's': 8, 'u': 16, 'v': 0}}) - - GG = XG.to_undirected() - # make sure we get lower weight - # to_undirected might choose either edge with weight 2 or weight 3 - GG['u']['x']['weight'] = 2 - path, dist = nx.floyd_warshall_predecessor_and_distance(GG) - assert dist['s']['v'] == 8 - # skip this test, could be alternate path s-u-v -# assert_equal(path['s']['v'],'y') - - G = nx.DiGraph() # no weights - G.add_edges_from([('s', 'u'), ('s', 'x'), - ('u', 'v'), ('u', 'x'), - ('v', 'y'), ('x', 'u'), - ('x', 'v'), ('x', 'y'), - ('y', 's'), ('y', 'v')]) - path, dist = nx.floyd_warshall_predecessor_and_distance(G) - assert dist['s']['v'] == 2 - # skip this test, could be alternate path s-u-v - # assert_equal(path['s']['v'],'x') - - # alternate interface - dist = nx.floyd_warshall(G) - assert dist['s']['v'] == 2 - - # floyd_warshall_predecessor_and_distance returns - # dicts-of-defautdicts - # make sure we don't get empty dictionary - XG = nx.DiGraph() - XG.add_weighted_edges_from([('v', 'x', 5.0), ('y', 'x', 5.0), - ('v', 'y', 6.0), ('x', 'u', 2.0)]) - path, dist = nx.floyd_warshall_predecessor_and_distance(XG) - inf = float("inf") - assert (dist == - {'v': {'v': 0, 'x': 5.0, 'y': 6.0, 'u': 7.0}, - 'x': {'x': 0, 'u': 2.0, 'v': inf, 'y': inf}, - 'y': {'y': 0, 'x': 5.0, 'v': inf, 'u': 7.0}, - 'u': {'u': 0, 'v': inf, 'x': inf, 'y': inf}}) - assert (path == - {'v': {'x': 'v', 'y': 'v', 'u': 'x'}, - 'x': {'u': 'x'}, - 'y': {'x': 'y', 'u': 'x'}}) - - def test_reconstruct_path(self): - with pytest.raises(KeyError): - XG = nx.DiGraph() - XG.add_weighted_edges_from([('s', 'u', 10), ('s', 'x', 5), - ('u', 'v', 1), ('u', 'x', 2), - ('v', 'y', 1), ('x', 'u', 3), - ('x', 'v', 5), ('x', 'y', 2), - ('y', 's', 7), ('y', 'v', 6)]) - predecessors, _ = nx.floyd_warshall_predecessor_and_distance(XG) - - path = nx.reconstruct_path('s', 'v', predecessors) - assert path == ['s', 'x', 'u', 'v'] - - path = nx.reconstruct_path('s', 's', predecessors) - assert path == [] - - # this part raises the keyError - nx.reconstruct_path('1', '2', predecessors) - - def test_cycle(self): - path, dist = nx.floyd_warshall_predecessor_and_distance( - nx.cycle_graph(7)) - assert dist[0][3] == 3 - assert path[0][3] == 2 - assert dist[0][4] == 3 - - def test_weighted(self): - XG3 = nx.Graph() - XG3.add_weighted_edges_from([[0, 1, 2], [1, 2, 12], [2, 3, 1], - [3, 4, 5], [4, 5, 1], [5, 0, 10]]) - path, dist = nx.floyd_warshall_predecessor_and_distance(XG3) - assert dist[0][3] == 15 - assert path[0][3] == 2 - - def test_weighted2(self): - XG4 = nx.Graph() - XG4.add_weighted_edges_from([[0, 1, 2], [1, 2, 2], [2, 3, 1], - [3, 4, 1], [4, 5, 1], [5, 6, 1], - [6, 7, 1], [7, 0, 1]]) - path, dist = nx.floyd_warshall_predecessor_and_distance(XG4) - assert dist[0][2] == 4 - assert path[0][2] == 1 - - def test_weight_parameter(self): - XG4 = nx.Graph() - XG4.add_edges_from([(0, 1, {'heavy': 2}), (1, 2, {'heavy': 2}), - (2, 3, {'heavy': 1}), (3, 4, {'heavy': 1}), - (4, 5, {'heavy': 1}), (5, 6, {'heavy': 1}), - (6, 7, {'heavy': 1}), (7, 0, {'heavy': 1})]) - path, dist = nx.floyd_warshall_predecessor_and_distance(XG4, - weight='heavy') - assert dist[0][2] == 4 - assert path[0][2] == 1 - - def test_zero_distance(self): - XG = nx.DiGraph() - XG.add_weighted_edges_from([('s', 'u', 10), ('s', 'x', 5), - ('u', 'v', 1), ('u', 'x', 2), - ('v', 'y', 1), ('x', 'u', 3), - ('x', 'v', 5), ('x', 'y', 2), - ('y', 's', 7), ('y', 'v', 6)]) - path, dist = nx.floyd_warshall_predecessor_and_distance(XG) - - for u in XG: - assert dist[u][u] == 0 - - GG = XG.to_undirected() - # make sure we get lower weight - # to_undirected might choose either edge with weight 2 or weight 3 - GG['u']['x']['weight'] = 2 - path, dist = nx.floyd_warshall_predecessor_and_distance(GG) - - for u in GG: - dist[u][u] = 0 - - def test_zero_weight(self): - G = nx.DiGraph() - edges = [(1, 2, -2), (2, 3, -4), (1, 5, 1), - (5, 4, 0), (4, 3, -5), (2, 5, -7)] - G.add_weighted_edges_from(edges) - dist = nx.floyd_warshall(G) - assert dist[1][3] == -14 - - G = nx.MultiDiGraph() - edges.append((2, 5, -7)) - G.add_weighted_edges_from(edges) - dist = nx.floyd_warshall(G) - assert dist[1][3] == -14 diff --git a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_dense_numpy.py b/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_dense_numpy.py deleted file mode 100644 index 49d907f3..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_dense_numpy.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python -import pytest -numpy = pytest.importorskip('numpy') -npt = pytest.importorskip('numpy.testing') - - -import networkx as nx - - -class TestFloydNumpy(object): - - def test_cycle_numpy(self): - dist = nx.floyd_warshall_numpy(nx.cycle_graph(7)) - assert dist[0, 3] == 3 - assert dist[0, 4] == 3 - - def test_weighted_numpy_three_edges(self): - XG3 = nx.Graph() - XG3.add_weighted_edges_from([[0, 1, 2], [1, 2, 12], [2, 3, 1], - [3, 4, 5], [4, 5, 1], [5, 0, 10]]) - dist = nx.floyd_warshall_numpy(XG3) - assert dist[0, 3] == 15 - - def test_weighted_numpy_two_edges(self): - XG4 = nx.Graph() - XG4.add_weighted_edges_from([[0, 1, 2], [1, 2, 2], [2, 3, 1], - [3, 4, 1], [4, 5, 1], [5, 6, 1], - [6, 7, 1], [7, 0, 1]]) - dist = nx.floyd_warshall_numpy(XG4) - assert dist[0, 2] == 4 - - def test_weight_parameter_numpy(self): - XG4 = nx.Graph() - XG4.add_edges_from([(0, 1, {'heavy': 2}), (1, 2, {'heavy': 2}), - (2, 3, {'heavy': 1}), (3, 4, {'heavy': 1}), - (4, 5, {'heavy': 1}), (5, 6, {'heavy': 1}), - (6, 7, {'heavy': 1}), (7, 0, {'heavy': 1})]) - dist = nx.floyd_warshall_numpy(XG4, weight='heavy') - assert dist[0, 2] == 4 - - def test_directed_cycle_numpy(self): - G = nx.DiGraph() - nx.add_cycle(G, [0, 1, 2, 3]) - pred, dist = nx.floyd_warshall_predecessor_and_distance(G) - D = nx.utils.dict_to_numpy_array(dist) - npt.assert_equal(nx.floyd_warshall_numpy(G), D) - - def test_zero_weight(self): - G = nx.DiGraph() - edges = [(1, 2, -2), (2, 3, -4), (1, 5, 1), (5, 4, 0), (4, 3, -5), (2, 5, -7)] - G.add_weighted_edges_from(edges) - dist = nx.floyd_warshall_numpy(G) - assert int(numpy.min(dist)) == -14 - - G = nx.MultiDiGraph() - edges.append((2, 5, -7)) - G.add_weighted_edges_from(edges) - dist = nx.floyd_warshall_numpy(G) - assert int(numpy.min(dist)) == -14 diff --git a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_generic.py b/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_generic.py deleted file mode 100644 index d4953263..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_generic.py +++ /dev/null @@ -1,370 +0,0 @@ -import pytest - - -import networkx as nx -from networkx.testing import almost_equal - -def validate_grid_path(r, c, s, t, p): - assert isinstance(p, list) - assert p[0] == s - assert p[-1] == t - s = ((s - 1) // c, (s - 1) % c) - t = ((t - 1) // c, (t - 1) % c) - assert len(p) == abs(t[0] - s[0]) + abs(t[1] - s[1]) + 1 - p = [((u - 1) // c, (u - 1) % c) for u in p] - for u in p: - assert 0 <= u[0] < r - assert 0 <= u[1] < c - for u, v in zip(p[:-1], p[1:]): - assert (abs(v[0] - u[0]), abs(v[1] - u[1])) in [(0, 1), (1, 0)] - - -class TestGenericPath: - - @classmethod - def setup_class(cls): - from networkx import convert_node_labels_to_integers as cnlti - cls.grid = cnlti(nx.grid_2d_graph(4, 4), first_label=1, - ordering="sorted") - cls.cycle = nx.cycle_graph(7) - cls.directed_cycle = nx.cycle_graph(7, create_using=nx.DiGraph()) - cls.neg_weights = nx.DiGraph() - cls.neg_weights.add_edge(0, 1, weight=1) - cls.neg_weights.add_edge(0, 2, weight=3) - cls.neg_weights.add_edge(1, 3, weight=1) - cls.neg_weights.add_edge(2, 3, weight=-2) - - def test_shortest_path(self): - assert nx.shortest_path(self.cycle, 0, 3) == [0, 1, 2, 3] - assert nx.shortest_path(self.cycle, 0, 4) == [0, 6, 5, 4] - validate_grid_path(4, 4, 1, 12, nx.shortest_path(self.grid, 1, 12)) - assert nx.shortest_path(self.directed_cycle, 0, 3) == [0, 1, 2, 3] - # now with weights - assert (nx.shortest_path(self.cycle, 0, 3, weight='weight') == - [0, 1, 2, 3]) - assert (nx.shortest_path(self.cycle, 0, 4, weight='weight') == - [0, 6, 5, 4]) - validate_grid_path(4, 4, 1, 12, nx.shortest_path(self.grid, 1, 12, - weight='weight')) - assert (nx.shortest_path(self.directed_cycle, 0, 3, - weight='weight') == - [0, 1, 2, 3]) - # weights and method specified - assert (nx.shortest_path(self.directed_cycle, 0, 3, - weight='weight', method='dijkstra') == - [0, 1, 2, 3]) - assert (nx.shortest_path(self.directed_cycle, 0, 3, - weight='weight', method='bellman-ford') == - [0, 1, 2, 3]) - # when Dijkstra's will probably (depending on precise implementation) - # incorrectly return [0, 1, 3] instead - assert (nx.shortest_path(self.neg_weights, 0, 3, weight='weight', - method='bellman-ford') == - [0, 2, 3]) - # confirm bad method rejection - pytest.raises(ValueError, nx.shortest_path, self.cycle, method='SPAM') - # confirm absent source rejection - pytest.raises(nx.NodeNotFound, nx.shortest_path, self.cycle, 8) - - def test_shortest_path_target(self): - answer = {0: [0, 1], 1: [1], 2: [2, 1]} - sp = nx.shortest_path(nx.path_graph(3), target=1) - assert sp == answer - # with weights - sp = nx.shortest_path(nx.path_graph(3), target=1, weight='weight') - assert sp == answer - # weights and method specified - sp = nx.shortest_path(nx.path_graph(3), target=1, weight='weight', - method='dijkstra') - assert sp == answer - sp = nx.shortest_path(nx.path_graph(3), target=1, weight='weight', - method='bellman-ford') - assert sp == answer - - def test_shortest_path_length(self): - assert nx.shortest_path_length(self.cycle, 0, 3) == 3 - assert nx.shortest_path_length(self.grid, 1, 12) == 5 - assert nx.shortest_path_length(self.directed_cycle, 0, 4) == 4 - # now with weights - assert (nx.shortest_path_length(self.cycle, 0, 3, - weight='weight') == - 3) - assert (nx.shortest_path_length(self.grid, 1, 12, - weight='weight') == - 5) - assert (nx.shortest_path_length(self.directed_cycle, 0, 4, - weight='weight') == - 4) - # weights and method specified - assert (nx.shortest_path_length(self.cycle, 0, 3, weight='weight', - method='dijkstra') == - 3) - assert (nx.shortest_path_length(self.cycle, 0, 3, weight='weight', - method='bellman-ford') == - 3) - # confirm bad method rejection - pytest.raises(ValueError, - nx.shortest_path_length, - self.cycle, - method='SPAM') - # confirm absent source rejection - pytest.raises(nx.NodeNotFound, nx.shortest_path_length, self.cycle, 8) - - def test_shortest_path_length_target(self): - answer = {0: 1, 1: 0, 2: 1} - sp = dict(nx.shortest_path_length(nx.path_graph(3), target=1)) - assert sp == answer - # with weights - sp = nx.shortest_path_length(nx.path_graph(3), target=1, - weight='weight') - assert sp == answer - # weights and method specified - sp = nx.shortest_path_length(nx.path_graph(3), target=1, - weight='weight', method='dijkstra') - assert sp == answer - sp = nx.shortest_path_length(nx.path_graph(3), target=1, - weight='weight', method='bellman-ford') - assert sp == answer - - def test_single_source_shortest_path(self): - p = nx.shortest_path(self.cycle, 0) - assert p[3] == [0, 1, 2, 3] - assert p == nx.single_source_shortest_path(self.cycle, 0) - p = nx.shortest_path(self.grid, 1) - validate_grid_path(4, 4, 1, 12, p[12]) - # now with weights - p = nx.shortest_path(self.cycle, 0, weight='weight') - assert p[3] == [0, 1, 2, 3] - assert p == nx.single_source_dijkstra_path(self.cycle, 0) - p = nx.shortest_path(self.grid, 1, weight='weight') - validate_grid_path(4, 4, 1, 12, p[12]) - # weights and method specified - p = nx.shortest_path(self.cycle, 0, method='dijkstra', weight='weight') - assert p[3] == [0, 1, 2, 3] - assert p == nx.single_source_shortest_path(self.cycle, 0) - p = nx.shortest_path(self.cycle, 0, method='bellman-ford', - weight='weight') - assert p[3] == [0, 1, 2, 3] - assert p == nx.single_source_shortest_path(self.cycle, 0) - - def test_single_source_shortest_path_length(self): - ans = dict(nx.shortest_path_length(self.cycle, 0)) - assert ans == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert (ans == - dict(nx.single_source_shortest_path_length(self.cycle, - 0))) - ans = dict(nx.shortest_path_length(self.grid, 1)) - assert ans[16] == 6 - # now with weights - ans = dict(nx.shortest_path_length(self.cycle, 0, weight='weight')) - assert ans == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert ans == dict(nx.single_source_dijkstra_path_length( - self.cycle, 0)) - ans = dict(nx.shortest_path_length(self.grid, 1, weight='weight')) - assert ans[16] == 6 - # weights and method specified - ans = dict(nx.shortest_path_length(self.cycle, 0, weight='weight', - method='dijkstra')) - assert ans == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert ans == dict(nx.single_source_dijkstra_path_length( - self.cycle, 0)) - ans = dict(nx.shortest_path_length(self.cycle, 0, weight='weight', - method='bellman-ford')) - assert ans == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert ans == dict(nx.single_source_bellman_ford_path_length( - self.cycle, 0)) - - def test_all_pairs_shortest_path(self): - p = nx.shortest_path(self.cycle) - assert p[0][3] == [0, 1, 2, 3] - assert p == dict(nx.all_pairs_shortest_path(self.cycle)) - p = nx.shortest_path(self.grid) - validate_grid_path(4, 4, 1, 12, p[1][12]) - # now with weights - p = nx.shortest_path(self.cycle, weight='weight') - assert p[0][3] == [0, 1, 2, 3] - assert p == dict(nx.all_pairs_dijkstra_path(self.cycle)) - p = nx.shortest_path(self.grid, weight='weight') - validate_grid_path(4, 4, 1, 12, p[1][12]) - # weights and method specified - p = nx.shortest_path(self.cycle, weight='weight', method='dijkstra') - assert p[0][3] == [0, 1, 2, 3] - assert p == dict(nx.all_pairs_dijkstra_path(self.cycle)) - p = nx.shortest_path(self.cycle, weight='weight', - method='bellman-ford') - assert p[0][3] == [0, 1, 2, 3] - assert p == dict(nx.all_pairs_bellman_ford_path(self.cycle)) - - def test_all_pairs_shortest_path_length(self): - ans = dict(nx.shortest_path_length(self.cycle)) - assert ans[0] == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert ans == dict(nx.all_pairs_shortest_path_length(self.cycle)) - ans = dict(nx.shortest_path_length(self.grid)) - assert ans[1][16] == 6 - # now with weights - ans = dict(nx.shortest_path_length(self.cycle, weight='weight')) - assert ans[0] == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert ans == dict(nx.all_pairs_dijkstra_path_length(self.cycle)) - ans = dict(nx.shortest_path_length(self.grid, weight='weight')) - assert ans[1][16] == 6 - # weights and method specified - ans = dict(nx.shortest_path_length(self.cycle, weight='weight', - method='dijkstra')) - assert ans[0] == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert ans == dict(nx.all_pairs_dijkstra_path_length(self.cycle)) - ans = dict(nx.shortest_path_length(self.cycle, weight='weight', - method='bellman-ford')) - assert ans[0] == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert (ans == - dict(nx.all_pairs_bellman_ford_path_length(self.cycle))) - - def test_has_path(self): - G = nx.Graph() - nx.add_path(G, range(3)) - nx.add_path(G, range(3, 5)) - assert nx.has_path(G, 0, 2) - assert not nx.has_path(G, 0, 4) - - def test_all_shortest_paths(self): - G = nx.Graph() - nx.add_path(G, [0, 1, 2, 3]) - nx.add_path(G, [0, 10, 20, 3]) - assert ([[0, 1, 2, 3], [0, 10, 20, 3]] == - sorted(nx.all_shortest_paths(G, 0, 3))) - # with weights - G = nx.Graph() - nx.add_path(G, [0, 1, 2, 3]) - nx.add_path(G, [0, 10, 20, 3]) - assert ([[0, 1, 2, 3], [0, 10, 20, 3]] == - sorted(nx.all_shortest_paths(G, 0, 3, weight='weight'))) - # weights and method specified - G = nx.Graph() - nx.add_path(G, [0, 1, 2, 3]) - nx.add_path(G, [0, 10, 20, 3]) - assert ([[0, 1, 2, 3], [0, 10, 20, 3]] == - sorted(nx.all_shortest_paths(G, 0, 3, weight='weight', - method='dijkstra'))) - G = nx.Graph() - nx.add_path(G, [0, 1, 2, 3]) - nx.add_path(G, [0, 10, 20, 3]) - assert ([[0, 1, 2, 3], [0, 10, 20, 3]] == - sorted(nx.all_shortest_paths(G, 0, 3, weight='weight', - method='bellman-ford'))) - - def test_all_shortest_paths_raise(self): - with pytest.raises(nx.NetworkXNoPath): - G = nx.path_graph(4) - G.add_node(4) - list(nx.all_shortest_paths(G, 0, 4)) - - def test_bad_method(self): - with pytest.raises(ValueError): - G = nx.path_graph(2) - list(nx.all_shortest_paths(G, 0, 1, weight='weight', method='SPAM')) - - -class TestAverageShortestPathLength(object): - - def test_cycle_graph(self): - ans = nx.average_shortest_path_length(nx.cycle_graph(7)) - assert almost_equal(ans, 2) - - def test_path_graph(self): - ans = nx.average_shortest_path_length(nx.path_graph(5)) - assert almost_equal(ans, 2) - - def test_weighted(self): - G = nx.Graph() - nx.add_cycle(G, range(7), weight=2) - ans = nx.average_shortest_path_length(G, weight='weight') - assert almost_equal(ans, 4) - G = nx.Graph() - nx.add_path(G, range(5), weight=2) - ans = nx.average_shortest_path_length(G, weight='weight') - assert almost_equal(ans, 4) - - def test_specified_methods(self): - G = nx.Graph() - nx.add_cycle(G, range(7), weight=2) - ans = nx.average_shortest_path_length(G, - weight='weight', - method='dijkstra') - assert almost_equal(ans, 4) - ans = nx.average_shortest_path_length(G, - weight='weight', - method='bellman-ford') - assert almost_equal(ans, 4) - ans = nx.average_shortest_path_length(G, - weight='weight', - method='floyd-warshall') - assert almost_equal(ans, 4) - - G = nx.Graph() - nx.add_path(G, range(5), weight=2) - ans = nx.average_shortest_path_length(G, - weight='weight', - method='dijkstra') - assert almost_equal(ans, 4) - ans = nx.average_shortest_path_length(G, - weight='weight', - method='bellman-ford') - assert almost_equal(ans, 4) - ans = nx.average_shortest_path_length(G, - weight='weight', - method='floyd-warshall') - assert almost_equal(ans, 4) - - def test_disconnected(self): - g = nx.Graph() - g.add_nodes_from(range(3)) - g.add_edge(0, 1) - pytest.raises(nx.NetworkXError, nx.average_shortest_path_length, g) - g = g.to_directed() - pytest.raises(nx.NetworkXError, nx.average_shortest_path_length, g) - - def test_trivial_graph(self): - """Tests that the trivial graph has average path length zero, - since there is exactly one path of length zero in the trivial - graph. - - For more information, see issue #1960. - - """ - G = nx.trivial_graph() - assert nx.average_shortest_path_length(G) == 0 - - def test_null_graph(self): - with pytest.raises(nx.NetworkXPointlessConcept): - nx.average_shortest_path_length(nx.null_graph()) - - def test_bad_method(self): - with pytest.raises(ValueError): - G = nx.path_graph(2) - nx.average_shortest_path_length(G, weight='weight', method='SPAM') - - -class TestAverageShortestPathLengthNumpy(object): - - @classmethod - def setup_class(cls): - global numpy - global npt - import pytest - numpy = pytest.importorskip('numpy') - npt = pytest.importorskip('numpy.testing') - - - def test_specified_methods_numpy(self): - G = nx.Graph() - nx.add_cycle(G, range(7), weight=2) - ans = nx.average_shortest_path_length(G, - weight='weight', - method='floyd-warshall-numpy') - npt.assert_almost_equal(ans, 4) - - G = nx.Graph() - nx.add_path(G, range(5), weight=2) - ans = nx.average_shortest_path_length(G, - weight='weight', - method='floyd-warshall-numpy') - npt.assert_almost_equal(ans, 4) diff --git a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_unweighted.py b/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_unweighted.py deleted file mode 100644 index 9cf63fbd..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_unweighted.py +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/env python -import networkx as nx - - -def validate_grid_path(r, c, s, t, p): - assert isinstance(p, list) - assert p[0] == s - assert p[-1] == t - s = ((s - 1) // c, (s - 1) % c) - t = ((t - 1) // c, (t - 1) % c) - assert len(p) == abs(t[0] - s[0]) + abs(t[1] - s[1]) + 1 - p = [((u - 1) // c, (u - 1) % c) for u in p] - for u in p: - assert 0 <= u[0] < r - assert 0 <= u[1] < c - for u, v in zip(p[:-1], p[1:]): - assert (abs(v[0] - u[0]), abs(v[1] - u[1])) in [(0, 1), (1, 0)] - - -class TestUnweightedPath: - - @classmethod - def setup_class(cls): - from networkx import convert_node_labels_to_integers as cnlti - cls.grid = cnlti(nx.grid_2d_graph(4, 4), first_label=1, ordering="sorted") - cls.cycle = nx.cycle_graph(7) - cls.directed_cycle = nx.cycle_graph(7, create_using=nx.DiGraph()) - - def test_bidirectional_shortest_path(self): - assert (nx.bidirectional_shortest_path(self.cycle, 0, 3) == - [0, 1, 2, 3]) - assert (nx.bidirectional_shortest_path(self.cycle, 0, 4) == - [0, 6, 5, 4]) - validate_grid_path(4, 4, 1, 12, nx.bidirectional_shortest_path(self.grid, 1, 12)) - assert (nx.bidirectional_shortest_path(self.directed_cycle, 0, 3) == - [0, 1, 2, 3]) - - def test_shortest_path_length(self): - assert nx.shortest_path_length(self.cycle, 0, 3) == 3 - assert nx.shortest_path_length(self.grid, 1, 12) == 5 - assert nx.shortest_path_length(self.directed_cycle, 0, 4) == 4 - # now with weights - assert nx.shortest_path_length(self.cycle, 0, 3, weight=True) == 3 - assert nx.shortest_path_length(self.grid, 1, 12, weight=True) == 5 - assert nx.shortest_path_length(self.directed_cycle, 0, 4, weight=True) == 4 - - def test_single_source_shortest_path(self): - p = nx.single_source_shortest_path(self.directed_cycle, 3) - assert p[0] == [3, 4, 5, 6, 0] - p = nx.single_source_shortest_path(self.cycle, 0) - assert p[3] == [0, 1, 2, 3] - p = nx.single_source_shortest_path(self.cycle, 0, cutoff=0) - assert p == {0: [0]} - - def test_single_source_shortest_path_length(self): - pl = nx.single_source_shortest_path_length - lengths = {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert dict(pl(self.cycle, 0)) == lengths - lengths = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6} - assert dict(pl(self.directed_cycle, 0)) == lengths - - def test_single_target_shortest_path(self): - p = nx.single_target_shortest_path(self.directed_cycle, 0) - assert p[3] == [3, 4, 5, 6, 0] - p = nx.single_target_shortest_path(self.cycle, 0) - assert p[3] == [3, 2, 1, 0] - p = nx.single_target_shortest_path(self.cycle, 0, cutoff=0) - assert p == {0: [0]} - - def test_single_target_shortest_path_length(self): - pl = nx.single_target_shortest_path_length - lengths = {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert dict(pl(self.cycle, 0)) == lengths - lengths = {0: 0, 1: 6, 2: 5, 3: 4, 4: 3, 5: 2, 6: 1} - assert dict(pl(self.directed_cycle, 0)) == lengths - - def test_all_pairs_shortest_path(self): - p = dict(nx.all_pairs_shortest_path(self.cycle)) - assert p[0][3] == [0, 1, 2, 3] - p = dict(nx.all_pairs_shortest_path(self.grid)) - validate_grid_path(4, 4, 1, 12, p[1][12]) - - def test_all_pairs_shortest_path_length(self): - l = dict(nx.all_pairs_shortest_path_length(self.cycle)) - assert l[0] == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - l = dict(nx.all_pairs_shortest_path_length(self.grid)) - assert l[1][16] == 6 - - def test_predecessor_path(self): - G = nx.path_graph(4) - assert nx.predecessor(G, 0) == {0: [], 1: [0], 2: [1], 3: [2]} - assert nx.predecessor(G, 0, 3) == [2] - - def test_predecessor_cycle(self): - G = nx.cycle_graph(4) - pred = nx.predecessor(G, 0) - assert pred[0] == [] - assert pred[1] == [0] - assert pred[2] in [[1, 3], [3, 1]] - assert pred[3] == [0] - - def test_predecessor_cutoff(self): - G = nx.path_graph(4) - p = nx.predecessor(G, 0, 3) - assert not 4 in p - - def test_predecessor_target(self): - G = nx.path_graph(4) - p = nx.predecessor(G, 0, 3) - assert p == [2] - p = nx.predecessor(G, 0, 3, cutoff=2) - assert p == [] - p, s = nx.predecessor(G, 0, 3, return_seen=True) - assert p == [2] - assert s == 3 - p, s = nx.predecessor(G, 0, 3, cutoff=2, return_seen=True) - assert p == [] - assert s == -1 diff --git a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_weighted.py b/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_weighted.py deleted file mode 100644 index 6d97787a..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/tests/test_weighted.py +++ /dev/null @@ -1,611 +0,0 @@ - -import pytest - -import networkx as nx -from networkx.utils import pairwise - - -def validate_path(G, s, t, soln_len, path): - assert path[0] == s - assert path[-1] == t - if not G.is_multigraph(): - computed = sum(G[u][v].get('weight', 1) for u, v in pairwise(path)) - assert soln_len == computed - else: - computed = sum(min(e.get('weight', 1) for e in G[u][v].values()) - for u, v in pairwise(path)) - assert soln_len == computed - - -def validate_length_path(G, s, t, soln_len, length, path): - assert soln_len == length - validate_path(G, s, t, length, path) - - -class WeightedTestBase(object): - """Base class for test classes that test functions for computing - shortest paths in weighted graphs. - - """ - - def setup(self): - """Creates some graphs for use in the unit tests.""" - cnlti = nx.convert_node_labels_to_integers - self.grid = cnlti(nx.grid_2d_graph(4, 4), first_label=1, - ordering="sorted") - self.cycle = nx.cycle_graph(7) - self.directed_cycle = nx.cycle_graph(7, create_using=nx.DiGraph()) - self.XG = nx.DiGraph() - self.XG.add_weighted_edges_from([('s', 'u', 10), ('s', 'x', 5), - ('u', 'v', 1), ('u', 'x', 2), - ('v', 'y', 1), ('x', 'u', 3), - ('x', 'v', 5), ('x', 'y', 2), - ('y', 's', 7), ('y', 'v', 6)]) - self.MXG = nx.MultiDiGraph(self.XG) - self.MXG.add_edge('s', 'u', weight=15) - self.XG2 = nx.DiGraph() - self.XG2.add_weighted_edges_from([[1, 4, 1], [4, 5, 1], - [5, 6, 1], [6, 3, 1], - [1, 3, 50], [1, 2, 100], - [2, 3, 100]]) - - self.XG3 = nx.Graph() - self.XG3.add_weighted_edges_from([[0, 1, 2], [1, 2, 12], - [2, 3, 1], [3, 4, 5], - [4, 5, 1], [5, 0, 10]]) - - self.XG4 = nx.Graph() - self.XG4.add_weighted_edges_from([[0, 1, 2], [1, 2, 2], - [2, 3, 1], [3, 4, 1], - [4, 5, 1], [5, 6, 1], - [6, 7, 1], [7, 0, 1]]) - self.MXG4 = nx.MultiGraph(self.XG4) - self.MXG4.add_edge(0, 1, weight=3) - self.G = nx.DiGraph() # no weights - self.G.add_edges_from([('s', 'u'), ('s', 'x'), - ('u', 'v'), ('u', 'x'), - ('v', 'y'), ('x', 'u'), - ('x', 'v'), ('x', 'y'), - ('y', 's'), ('y', 'v')]) - - -class TestWeightedPath(WeightedTestBase): - - def test_dijkstra(self): - (D, P) = nx.single_source_dijkstra(self.XG, 's') - validate_path(self.XG, 's', 'v', 9, P['v']) - assert D['v'] == 9 - - validate_path( - self.XG, 's', 'v', 9, nx.single_source_dijkstra_path(self.XG, 's')['v']) - assert dict( - nx.single_source_dijkstra_path_length(self.XG, 's'))['v'] == 9 - - validate_path( - self.XG, 's', 'v', 9, nx.single_source_dijkstra(self.XG, 's')[1]['v']) - validate_path( - self.MXG, 's', 'v', 9, nx.single_source_dijkstra_path(self.MXG, 's')['v']) - - GG = self.XG.to_undirected() - # make sure we get lower weight - # to_undirected might choose either edge with weight 2 or weight 3 - GG['u']['x']['weight'] = 2 - (D, P) = nx.single_source_dijkstra(GG, 's') - validate_path(GG, 's', 'v', 8, P['v']) - assert D['v'] == 8 # uses lower weight of 2 on u<->x edge - validate_path(GG, 's', 'v', 8, nx.dijkstra_path(GG, 's', 'v')) - assert nx.dijkstra_path_length(GG, 's', 'v') == 8 - - validate_path(self.XG2, 1, 3, 4, nx.dijkstra_path(self.XG2, 1, 3)) - validate_path(self.XG3, 0, 3, 15, nx.dijkstra_path(self.XG3, 0, 3)) - assert nx.dijkstra_path_length(self.XG3, 0, 3) == 15 - validate_path(self.XG4, 0, 2, 4, nx.dijkstra_path(self.XG4, 0, 2)) - assert nx.dijkstra_path_length(self.XG4, 0, 2) == 4 - validate_path(self.MXG4, 0, 2, 4, nx.dijkstra_path(self.MXG4, 0, 2)) - validate_path( - self.G, 's', 'v', 2, nx.single_source_dijkstra(self.G, 's', 'v')[1]) - validate_path( - self.G, 's', 'v', 2, nx.single_source_dijkstra(self.G, 's')[1]['v']) - - validate_path(self.G, 's', 'v', 2, nx.dijkstra_path(self.G, 's', 'v')) - assert nx.dijkstra_path_length(self.G, 's', 'v') == 2 - - # NetworkXError: node s not reachable from moon - pytest.raises(nx.NetworkXNoPath, nx.dijkstra_path, self.G, 's', 'moon') - pytest.raises( - nx.NetworkXNoPath, nx.dijkstra_path_length, self.G, 's', 'moon') - - validate_path(self.cycle, 0, 3, 3, nx.dijkstra_path(self.cycle, 0, 3)) - validate_path(self.cycle, 0, 4, 3, nx.dijkstra_path(self.cycle, 0, 4)) - - assert nx.single_source_dijkstra(self.cycle, 0, 0) == (0, [0]) - - def test_bidirectional_dijkstra(self): - validate_length_path( - self.XG, 's', 'v', 9, *nx.bidirectional_dijkstra(self.XG, 's', 'v')) - validate_length_path( - self.G, 's', 'v', 2, *nx.bidirectional_dijkstra(self.G, 's', 'v')) - validate_length_path( - self.cycle, 0, 3, 3, *nx.bidirectional_dijkstra(self.cycle, 0, 3)) - validate_length_path( - self.cycle, 0, 4, 3, *nx.bidirectional_dijkstra(self.cycle, 0, 4)) - validate_length_path( - self.XG3, 0, 3, 15, *nx.bidirectional_dijkstra(self.XG3, 0, 3)) - validate_length_path( - self.XG4, 0, 2, 4, *nx.bidirectional_dijkstra(self.XG4, 0, 2)) - - # need more tests here - P = nx.single_source_dijkstra_path(self.XG, 's')['v'] - validate_path(self.XG, 's', 'v', sum(self.XG[u][v]['weight'] for u, v in zip( - P[:-1], P[1:])), nx.dijkstra_path(self.XG, 's', 'v')) - - # check absent source - G = nx.path_graph(2) - pytest.raises(nx.NodeNotFound, nx.bidirectional_dijkstra, G, 3, 0) - - def test_bidirectional_dijkstra_no_path(self): - with pytest.raises(nx.NetworkXNoPath): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5, 6]) - path = nx.bidirectional_dijkstra(G, 1, 6) - - def test_absent_source(self): - # the check is in _dijkstra_multisource, but this will provide - # regression testing against later changes to any of the "client" - # Dijkstra or Bellman-Ford functions - G = nx.path_graph(2) - for fn in (nx.dijkstra_path, - nx.dijkstra_path_length, - nx.single_source_dijkstra_path, - nx.single_source_dijkstra_path_length, - nx.single_source_dijkstra, - nx.dijkstra_predecessor_and_distance,): - pytest.raises(nx.NodeNotFound, fn, G, 3, 0) - - def test_dijkstra_predecessor1(self): - G = nx.path_graph(4) - assert (nx.dijkstra_predecessor_and_distance(G, 0) == - ({0: [], 1: [0], 2: [1], 3: [2]}, {0: 0, 1: 1, 2: 2, 3: 3})) - - def test_dijkstra_predecessor2(self): - # 4-cycle - G = nx.Graph([(0, 1), (1, 2), (2, 3), (3, 0)]) - pred, dist = nx.dijkstra_predecessor_and_distance(G, (0)) - assert pred[0] == [] - assert pred[1] == [0] - assert pred[2] in [[1, 3], [3, 1]] - assert pred[3] == [0] - assert dist == {0: 0, 1: 1, 2: 2, 3: 1} - - def test_dijkstra_predecessor3(self): - XG = nx.DiGraph() - XG.add_weighted_edges_from([('s', 'u', 10), ('s', 'x', 5), - ('u', 'v', 1), ('u', 'x', 2), - ('v', 'y', 1), ('x', 'u', 3), - ('x', 'v', 5), ('x', 'y', 2), - ('y', 's', 7), ('y', 'v', 6)]) - (P, D) = nx.dijkstra_predecessor_and_distance(XG, 's') - assert P['v'] == ['u'] - assert D['v'] == 9 - (P, D) = nx.dijkstra_predecessor_and_distance(XG, 's', cutoff=8) - assert not 'v' in D - - def test_single_source_dijkstra_path_length(self): - pl = nx.single_source_dijkstra_path_length - assert dict(pl(self.MXG4, 0))[2] == 4 - spl = pl(self.MXG4, 0, cutoff=2) - assert not 2 in spl - - def test_bidirectional_dijkstra_multigraph(self): - G = nx.MultiGraph() - G.add_edge('a', 'b', weight=10) - G.add_edge('a', 'b', weight=100) - dp = nx.bidirectional_dijkstra(G, 'a', 'b') - assert dp == (10, ['a', 'b']) - - def test_dijkstra_pred_distance_multigraph(self): - G = nx.MultiGraph() - G.add_edge('a', 'b', key='short', foo=5, weight=100) - G.add_edge('a', 'b', key='long', bar=1, weight=110) - p, d = nx.dijkstra_predecessor_and_distance(G, 'a') - assert p == {'a': [], 'b': ['a']} - assert d == {'a': 0, 'b': 100} - - def test_negative_edge_cycle(self): - G = nx.cycle_graph(5, create_using=nx.DiGraph()) - assert nx.negative_edge_cycle(G) == False - G.add_edge(8, 9, weight=-7) - G.add_edge(9, 8, weight=3) - graph_size = len(G) - assert nx.negative_edge_cycle(G) == True - assert graph_size == len(G) - pytest.raises(ValueError, nx.single_source_dijkstra_path_length, G, 8) - pytest.raises(ValueError, nx.single_source_dijkstra, G, 8) - pytest.raises(ValueError, nx.dijkstra_predecessor_and_distance, G, 8) - G.add_edge(9, 10) - pytest.raises(ValueError, nx.bidirectional_dijkstra, G, 8, 10) - - def test_weight_function(self): - """Tests that a callable weight is interpreted as a weight - function instead of an edge attribute. - - """ - # Create a triangle in which the edge from node 0 to node 2 has - # a large weight and the other two edges have a small weight. - G = nx.complete_graph(3) - G.adj[0][2]['weight'] = 10 - G.adj[0][1]['weight'] = 1 - G.adj[1][2]['weight'] = 1 - # The weight function will take the multiplicative inverse of - # the weights on the edges. This way, weights that were large - # before now become small and vice versa. - - def weight(u, v, d): return 1 / d['weight'] - # The shortest path from 0 to 2 using the actual weights on the - # edges should be [0, 1, 2]. - distance, path = nx.single_source_dijkstra(G, 0, 2) - assert distance == 2 - assert path == [0, 1, 2] - # However, with the above weight function, the shortest path - # should be [0, 2], since that has a very small weight. - distance, path = nx.single_source_dijkstra(G, 0, 2, weight=weight) - assert distance == 1 / 10 - assert path == [0, 2] - - def test_all_pairs_dijkstra_path(self): - cycle = nx.cycle_graph(7) - p = dict(nx.all_pairs_dijkstra_path(cycle)) - assert p[0][3] == [0, 1, 2, 3] - - cycle[1][2]['weight'] = 10 - p = dict(nx.all_pairs_dijkstra_path(cycle)) - assert p[0][3] == [0, 6, 5, 4, 3] - - def test_all_pairs_dijkstra_path_length(self): - cycle = nx.cycle_graph(7) - pl = dict(nx.all_pairs_dijkstra_path_length(cycle)) - assert pl[0] == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - - cycle[1][2]['weight'] = 10 - pl = dict(nx.all_pairs_dijkstra_path_length(cycle)) - assert pl[0] == {0: 0, 1: 1, 2: 5, 3: 4, 4: 3, 5: 2, 6: 1} - - def test_all_pairs_dijkstra(self): - cycle = nx.cycle_graph(7) - out = dict(nx.all_pairs_dijkstra(cycle)) - assert out[0][0] == {0: 0, 1: 1, 2: 2, 3: 3, 4: 3, 5: 2, 6: 1} - assert out[0][1][3] == [0, 1, 2, 3] - - cycle[1][2]['weight'] = 10 - out = dict(nx.all_pairs_dijkstra(cycle)) - assert out[0][0] == {0: 0, 1: 1, 2: 5, 3: 4, 4: 3, 5: 2, 6: 1} - assert out[0][1][3] == [0, 6, 5, 4, 3] - - -class TestDijkstraPathLength(object): - """Unit tests for the :func:`networkx.dijkstra_path_length` - function. - - """ - - def test_weight_function(self): - """Tests for computing the length of the shortest path using - Dijkstra's algorithm with a user-defined weight function. - - """ - # Create a triangle in which the edge from node 0 to node 2 has - # a large weight and the other two edges have a small weight. - G = nx.complete_graph(3) - G.adj[0][2]['weight'] = 10 - G.adj[0][1]['weight'] = 1 - G.adj[1][2]['weight'] = 1 - # The weight function will take the multiplicative inverse of - # the weights on the edges. This way, weights that were large - # before now become small and vice versa. - - def weight(u, v, d): return 1 / d['weight'] - # The shortest path from 0 to 2 using the actual weights on the - # edges should be [0, 1, 2]. However, with the above weight - # function, the shortest path should be [0, 2], since that has a - # very small weight. - length = nx.dijkstra_path_length(G, 0, 2, weight=weight) - assert length == 1 / 10 - - -class TestMultiSourceDijkstra(object): - """Unit tests for the multi-source dialect of Dijkstra's shortest - path algorithms. - - """ - - def test_no_sources(self): - with pytest.raises(ValueError): - nx.multi_source_dijkstra(nx.Graph(), {}) - - def test_path_no_sources(self): - with pytest.raises(ValueError): - nx.multi_source_dijkstra_path(nx.Graph(), {}) - - def test_path_length_no_sources(self): - with pytest.raises(ValueError): - nx.multi_source_dijkstra_path_length(nx.Graph(), {}) - - def test_absent_source(self): - G = nx.path_graph(2) - for fn in (nx.multi_source_dijkstra_path, - nx.multi_source_dijkstra_path_length, - nx.multi_source_dijkstra,): - pytest.raises(nx.NodeNotFound, fn, G, [3], 0) - - def test_two_sources(self): - edges = [(0, 1, 1), (1, 2, 1), (2, 3, 10), (3, 4, 1)] - G = nx.Graph() - G.add_weighted_edges_from(edges) - sources = {0, 4} - distances, paths = nx.multi_source_dijkstra(G, sources) - expected_distances = {0: 0, 1: 1, 2: 2, 3: 1, 4: 0} - expected_paths = {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [4, 3], 4: [4]} - assert distances == expected_distances - assert paths == expected_paths - - def test_simple_paths(self): - G = nx.path_graph(4) - lengths = nx.multi_source_dijkstra_path_length(G, [0]) - assert lengths == {n: n for n in G} - paths = nx.multi_source_dijkstra_path(G, [0]) - assert paths == {n: list(range(n + 1)) for n in G} - - -class TestBellmanFordAndGoldbergRadzik(WeightedTestBase): - - def test_single_node_graph(self): - G = nx.DiGraph() - G.add_node(0) - assert nx.single_source_bellman_ford_path(G, 0) == {0: [0]} - assert nx.single_source_bellman_ford_path_length(G, 0) == {0: 0} - assert nx.single_source_bellman_ford(G, 0) == ({0: 0}, {0: [0]}) - assert nx.bellman_ford_predecessor_and_distance(G, 0) == ({0: []}, {0: 0}) - assert nx.goldberg_radzik(G, 0) == ({0: None}, {0: 0}) - - def test_absent_source_bellman_ford(self): - # the check is in _bellman_ford; this provides regression testing - # against later changes to "client" Bellman-Ford functions - G = nx.path_graph(2) - for fn in (nx.bellman_ford_predecessor_and_distance, - nx.bellman_ford_path, - nx.bellman_ford_path_length, - nx.single_source_bellman_ford_path, - nx.single_source_bellman_ford_path_length, - nx.single_source_bellman_ford,): - pytest.raises(nx.NodeNotFound, fn, G, 3, 0) - - def test_absent_source_goldberg_radzik(self): - with pytest.raises(nx.NodeNotFound): - G = nx.path_graph(2) - nx.goldberg_radzik(G, 3, 0) - - def test_negative_weight_cycle(self): - G = nx.cycle_graph(5, create_using=nx.DiGraph()) - G.add_edge(1, 2, weight=-7) - for i in range(5): - pytest.raises(nx.NetworkXUnbounded, nx.single_source_bellman_ford_path, G, i) - pytest.raises(nx.NetworkXUnbounded, nx.single_source_bellman_ford_path_length, G, i) - pytest.raises(nx.NetworkXUnbounded, nx.single_source_bellman_ford, G, i) - pytest.raises(nx.NetworkXUnbounded, nx.bellman_ford_predecessor_and_distance, G, i) - pytest.raises(nx.NetworkXUnbounded, nx.goldberg_radzik, G, i) - G = nx.cycle_graph(5) # undirected Graph - G.add_edge(1, 2, weight=-3) - for i in range(5): - pytest.raises(nx.NetworkXUnbounded, nx.single_source_bellman_ford_path, G, i) - pytest.raises(nx.NetworkXUnbounded, nx.single_source_bellman_ford_path_length, G, i) - pytest.raises(nx.NetworkXUnbounded, nx.single_source_bellman_ford, G, i) - pytest.raises(nx.NetworkXUnbounded, nx.bellman_ford_predecessor_and_distance, G, i) - pytest.raises(nx.NetworkXUnbounded, nx.goldberg_radzik, G, i) - G = nx.DiGraph([(1, 1, {'weight': -1})]) - pytest.raises(nx.NetworkXUnbounded, nx.single_source_bellman_ford_path, G, 1) - pytest.raises(nx.NetworkXUnbounded, nx.single_source_bellman_ford_path_length, G, 1) - pytest.raises(nx.NetworkXUnbounded, nx.single_source_bellman_ford, G, 1) - pytest.raises(nx.NetworkXUnbounded, nx.bellman_ford_predecessor_and_distance, G, 1) - pytest.raises(nx.NetworkXUnbounded, nx.goldberg_radzik, G, 1) - # no negative cycle but negative weight - G = nx.cycle_graph(5, create_using=nx.DiGraph()) - G.add_edge(1, 2, weight=-3) - assert (nx.single_source_bellman_ford_path(G, 0) == - {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 1, 2, 3], 4: [0, 1, 2, 3, 4]}) - assert (nx.single_source_bellman_ford_path_length(G, 0) == - {0: 0, 1: 1, 2: -2, 3: -1, 4: 0}) - assert (nx.single_source_bellman_ford(G, 0) == - ({0: 0, 1: 1, 2: -2, 3: -1, 4: 0}, - {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 1, 2, 3], 4: [0, 1, 2, 3, 4]})) - assert (nx.bellman_ford_predecessor_and_distance(G, 0) == - ({0: [], 1: [0], 2: [1], 3: [2], 4: [3]}, - {0: 0, 1: 1, 2: -2, 3: -1, 4: 0})) - assert (nx.goldberg_radzik(G, 0) == - ({0: None, 1: 0, 2: 1, 3: 2, 4: 3}, - {0: 0, 1: 1, 2: -2, 3: -1, 4: 0})) - - def test_not_connected(self): - G = nx.complete_graph(6) - G.add_edge(10, 11) - G.add_edge(10, 12) - assert (nx.single_source_bellman_ford_path(G, 0) == - {0: [0], 1: [0, 1], 2: [0, 2], 3: [0, 3], 4: [0, 4], 5: [0, 5]}) - assert (nx.single_source_bellman_ford_path_length(G, 0) == - {0: 0, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1}) - assert (nx.single_source_bellman_ford(G, 0) == - ({0: 0, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1}, - {0: [0], 1: [0, 1], 2: [0, 2], 3: [0, 3], 4: [0, 4], 5: [0, 5]})) - assert (nx.bellman_ford_predecessor_and_distance(G, 0) == - ({0: [], 1: [0], 2: [0], 3: [0], 4: [0], 5: [0]}, - {0: 0, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1})) - assert (nx.goldberg_radzik(G, 0) == - ({0: None, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0}, - {0: 0, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1})) - - # not connected, with a component not containing the source that - # contains a negative cost cycle. - G = nx.complete_graph(6) - G.add_edges_from([('A', 'B', {'load': 3}), - ('B', 'C', {'load': -10}), - ('C', 'A', {'load': 2})]) - assert (nx.single_source_bellman_ford_path(G, 0, weight='load') == - {0: [0], 1: [0, 1], 2: [0, 2], 3: [0, 3], 4: [0, 4], 5: [0, 5]}) - assert (nx.single_source_bellman_ford_path_length(G, 0, weight='load') == - {0: 0, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1}) - assert (nx.single_source_bellman_ford(G, 0, weight='load') == - ({0: 0, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1}, - {0: [0], 1: [0, 1], 2: [0, 2], 3: [0, 3], 4: [0, 4], 5: [0, 5]})) - assert (nx.bellman_ford_predecessor_and_distance(G, 0, weight='load') == - ({0: [], 1: [0], 2: [0], 3: [0], 4: [0], 5: [0]}, - {0: 0, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1})) - assert (nx.goldberg_radzik(G, 0, weight='load') == - ({0: None, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0}, - {0: 0, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1})) - - def test_multigraph(self): - assert nx.bellman_ford_path(self.MXG, 's', 'v') == ['s', 'x', 'u', 'v'] - assert nx.bellman_ford_path_length(self.MXG, 's', 'v') == 9 - assert nx.single_source_bellman_ford_path(self.MXG, 's')['v'] == ['s', 'x', 'u', 'v'] - assert nx.single_source_bellman_ford_path_length(self.MXG, 's')['v'] == 9 - D, P = nx.single_source_bellman_ford(self.MXG, 's', target='v') - assert D == 9 - assert P == ['s', 'x', 'u', 'v'] - P, D = nx.bellman_ford_predecessor_and_distance(self.MXG, 's') - assert P['v'] == ['u'] - assert D['v'] == 9 - P, D = nx.goldberg_radzik(self.MXG, 's') - assert P['v'] == 'u' - assert D['v'] == 9 - assert nx.bellman_ford_path(self.MXG4, 0, 2) == [0, 1, 2] - assert nx.bellman_ford_path_length(self.MXG4, 0, 2) == 4 - assert nx.single_source_bellman_ford_path(self.MXG4, 0)[2] == [0, 1, 2] - assert nx.single_source_bellman_ford_path_length(self.MXG4, 0)[2] == 4 - D, P = nx.single_source_bellman_ford(self.MXG4, 0, target=2) - assert D == 4 - assert P == [0, 1, 2] - P, D = nx.bellman_ford_predecessor_and_distance(self.MXG4, 0) - assert P[2] == [1] - assert D[2] == 4 - P, D = nx.goldberg_radzik(self.MXG4, 0) - assert P[2] == 1 - assert D[2] == 4 - - def test_others(self): - assert nx.bellman_ford_path(self.XG, 's', 'v') == ['s', 'x', 'u', 'v'] - assert nx.bellman_ford_path_length(self.XG, 's', 'v') == 9 - assert nx.single_source_bellman_ford_path(self.XG, 's')['v'] == ['s', 'x', 'u', 'v'] - assert nx.single_source_bellman_ford_path_length(self.XG, 's')['v'] == 9 - D, P = nx.single_source_bellman_ford(self.XG, 's', target='v') - assert D == 9 - assert P == ['s', 'x', 'u', 'v'] - (P, D) = nx.bellman_ford_predecessor_and_distance(self.XG, 's') - assert P['v'] == ['u'] - assert D['v'] == 9 - (P, D) = nx.goldberg_radzik(self.XG, 's') - assert P['v'] == 'u' - assert D['v'] == 9 - - def test_path_graph(self): - G = nx.path_graph(4) - assert (nx.single_source_bellman_ford_path(G, 0) == - {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 1, 2, 3]}) - assert (nx.single_source_bellman_ford_path_length(G, 0) == - {0: 0, 1: 1, 2: 2, 3: 3}) - assert (nx.single_source_bellman_ford(G, 0) == - ({0: 0, 1: 1, 2: 2, 3: 3}, {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 1, 2, 3]})) - assert (nx.bellman_ford_predecessor_and_distance(G, 0) == - ({0: [], 1: [0], 2: [1], 3: [2]}, {0: 0, 1: 1, 2: 2, 3: 3})) - assert (nx.goldberg_radzik(G, 0) == - ({0: None, 1: 0, 2: 1, 3: 2}, {0: 0, 1: 1, 2: 2, 3: 3})) - assert (nx.single_source_bellman_ford_path(G, 3) == - {0: [3, 2, 1, 0], 1: [3, 2, 1], 2: [3, 2], 3: [3]}) - assert (nx.single_source_bellman_ford_path_length(G, 3) == - {0: 3, 1: 2, 2: 1, 3: 0}) - assert (nx.single_source_bellman_ford(G, 3) == - ({0: 3, 1: 2, 2: 1, 3: 0}, {0: [3, 2, 1, 0], 1: [3, 2, 1], 2: [3, 2], 3: [3]})) - assert (nx.bellman_ford_predecessor_and_distance(G, 3) == - ({0: [1], 1: [2], 2: [3], 3: []}, {0: 3, 1: 2, 2: 1, 3: 0})) - assert (nx.goldberg_radzik(G, 3) == - ({0: 1, 1: 2, 2: 3, 3: None}, {0: 3, 1: 2, 2: 1, 3: 0})) - - def test_4_cycle(self): - # 4-cycle - G = nx.Graph([(0, 1), (1, 2), (2, 3), (3, 0)]) - dist, path = nx.single_source_bellman_ford(G, 0) - assert dist == {0: 0, 1: 1, 2: 2, 3: 1} - assert path[0] == [0] - assert path[1] == [0, 1] - assert path[2] in [[0, 1, 2], [0, 3, 2]] - assert path[3] == [0, 3] - - pred, dist = nx.bellman_ford_predecessor_and_distance(G, 0) - assert pred[0] == [] - assert pred[1] == [0] - assert pred[2] in [[1, 3], [3, 1]] - assert pred[3] == [0] - assert dist == {0: 0, 1: 1, 2: 2, 3: 1} - - pred, dist = nx.goldberg_radzik(G, 0) - assert pred[0] == None - assert pred[1] == 0 - assert pred[2] in [1, 3] - assert pred[3] == 0 - assert dist == {0: 0, 1: 1, 2: 2, 3: 1} - - def test_negative_weight(self): - G = nx.DiGraph() - G.add_nodes_from('abcd') - G.add_edge('a','d', weight = 0) - G.add_edge('a','b', weight = 1) - G.add_edge('b','c', weight = -3) - G.add_edge('c','d', weight = 1) - - assert nx.bellman_ford_path(G, 'a', 'd') == ['a', 'b', 'c', 'd'] - assert nx.bellman_ford_path_length(G, 'a', 'd') == -1 - - -class TestJohnsonAlgorithm(WeightedTestBase): - - def test_single_node_graph(self): - with pytest.raises(nx.NetworkXError): - G = nx.DiGraph() - G.add_node(0) - nx.johnson(G) - - def test_negative_cycle(self): - G = nx.DiGraph() - G.add_weighted_edges_from([('0', '3', 3), ('0', '1', -5), ('1', '0', -5), - ('0', '2', 2), ('1', '2', 4), - ('2', '3', 1)]) - pytest.raises(nx.NetworkXUnbounded, nx.johnson, G) - G = nx.Graph() - G.add_weighted_edges_from([('0', '3', 3), ('0', '1', -5), ('1', '0', -5), - ('0', '2', 2), ('1', '2', 4), - ('2', '3', 1)]) - pytest.raises(nx.NetworkXUnbounded, nx.johnson, G) - - def test_negative_weights(self): - G = nx.DiGraph() - G.add_weighted_edges_from([('0', '3', 3), ('0', '1', -5), - ('0', '2', 2), ('1', '2', 4), - ('2', '3', 1)]) - paths = nx.johnson(G) - assert paths == {'1': {'1': ['1'], '3': ['1', '2', '3'], - '2': ['1', '2']}, '0': {'1': ['0', '1'], - '0': ['0'], '3': ['0', '1', '2', '3'], - '2': ['0', '1', '2']}, '3': {'3': ['3']}, - '2': {'3': ['2', '3'], '2': ['2']}} - - def test_unweighted_graph(self): - with pytest.raises(nx.NetworkXError): - G = nx.path_graph(5) - nx.johnson(G) - - def test_graphs(self): - validate_path(self.XG, 's', 'v', 9, nx.johnson(self.XG)['s']['v']) - validate_path(self.MXG, 's', 'v', 9, nx.johnson(self.MXG)['s']['v']) - validate_path(self.XG2, 1, 3, 4, nx.johnson(self.XG2)[1][3]) - validate_path(self.XG3, 0, 3, 15, nx.johnson(self.XG3)[0][3]) - validate_path(self.XG4, 0, 2, 4, nx.johnson(self.XG4)[0][2]) - validate_path(self.MXG4, 0, 2, 4, nx.johnson(self.MXG4)[0][2]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/unweighted.py b/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/unweighted.py deleted file mode 100644 index c10666cb..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/unweighted.py +++ /dev/null @@ -1,530 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Author: Aric Hagberg -""" -Shortest path algorithms for unweighted graphs. -""" -import networkx as nx - -__all__ = ['bidirectional_shortest_path', - 'single_source_shortest_path', - 'single_source_shortest_path_length', - 'single_target_shortest_path', - 'single_target_shortest_path_length', - 'all_pairs_shortest_path', - 'all_pairs_shortest_path_length', - 'predecessor'] - - -def single_source_shortest_path_length(G, source, cutoff=None): - """Compute the shortest path lengths from source to all reachable nodes. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path - - cutoff : integer, optional - Depth to stop the search. Only paths of length <= cutoff are returned. - - Returns - ------- - lengths : dict - Dict keyed by node to shortest path length to source. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length = nx.single_source_shortest_path_length(G, 0) - >>> length[4] - 4 - >>> for node in length: - ... print('{}: {}'.format(node, length[node])) - 0: 0 - 1: 1 - 2: 2 - 3: 3 - 4: 4 - - See Also - -------- - shortest_path_length - """ - if source not in G: - raise nx.NodeNotFound('Source {} is not in G'.format(source)) - if cutoff is None: - cutoff = float('inf') - nextlevel = {source: 1} - return dict(_single_shortest_path_length(G.adj, nextlevel, cutoff)) - - -def _single_shortest_path_length(adj, firstlevel, cutoff): - """Yields (node, level) in a breadth first search - - Shortest Path Length helper function - Parameters - ---------- - adj : dict - Adjacency dict or view - firstlevel : dict - starting nodes, e.g. {source: 1} or {target: 1} - cutoff : int or float - level at which we stop the process - """ - seen = {} # level (number of hops) when seen in BFS - level = 0 # the current level - nextlevel = firstlevel # dict of nodes to check at next level - - while nextlevel and cutoff >= level: - thislevel = nextlevel # advance to next level - nextlevel = {} # and start a new list (fringe) - for v in thislevel: - if v not in seen: - seen[v] = level # set the level of vertex v - nextlevel.update(adj[v]) # add neighbors of v - yield (v, level) - level += 1 - del seen - - -def single_target_shortest_path_length(G, target, cutoff=None): - """Compute the shortest path lengths to target from all reachable nodes. - - Parameters - ---------- - G : NetworkX graph - - target : node - Target node for path - - cutoff : integer, optional - Depth to stop the search. Only paths of length <= cutoff are returned. - - Returns - ------- - lengths : iterator - (source, shortest path length) iterator - - Examples - -------- - >>> G = nx.path_graph(5, create_using=nx.DiGraph()) - >>> length = dict(nx.single_target_shortest_path_length(G, 4)) - >>> length[0] - 4 - >>> for node in range(5): - ... print('{}: {}'.format(node, length[node])) - 0: 4 - 1: 3 - 2: 2 - 3: 1 - 4: 0 - - See Also - -------- - single_source_shortest_path_length, shortest_path_length - """ - if target not in G: - raise nx.NodeNotFound('Target {} is not in G'.format(target)) - - if cutoff is None: - cutoff = float('inf') - # handle either directed or undirected - adj = G.pred if G.is_directed() else G.adj - nextlevel = {target: 1} - return _single_shortest_path_length(adj, nextlevel, cutoff) - - -def all_pairs_shortest_path_length(G, cutoff=None): - """Computes the shortest path lengths between all nodes in `G`. - - Parameters - ---------- - G : NetworkX graph - - cutoff : integer, optional - Depth at which to stop the search. Only paths of length at most - `cutoff` are returned. - - Returns - ------- - lengths : iterator - (source, dictionary) iterator with dictionary keyed by target and - shortest path length as the key value. - - Notes - ----- - The iterator returned only has reachable node pairs. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length = dict(nx.all_pairs_shortest_path_length(G)) - >>> for node in [0, 1, 2, 3, 4]: - ... print('1 - {}: {}'.format(node, length[1][node])) - 1 - 0: 1 - 1 - 1: 0 - 1 - 2: 1 - 1 - 3: 2 - 1 - 4: 3 - >>> length[3][2] - 1 - >>> length[2][2] - 0 - - """ - length = single_source_shortest_path_length - # TODO This can be trivially parallelized. - for n in G: - yield (n, length(G, n, cutoff=cutoff)) - - -def bidirectional_shortest_path(G, source, target): - """Returns a list of nodes in a shortest path between source and target. - - Parameters - ---------- - G : NetworkX graph - - source : node label - starting node for path - - target : node label - ending node for path - - Returns - ------- - path: list - List of nodes in a path from source to target. - - Raises - ------ - NetworkXNoPath - If no path exists between source and target. - - See Also - -------- - shortest_path - - Notes - ----- - This algorithm is used by shortest_path(G, source, target). - """ - - if source not in G or target not in G: - msg = 'Either source {} or target {} is not in G' - raise nx.NodeNotFound(msg.format(source, target)) - - # call helper to do the real work - results = _bidirectional_pred_succ(G, source, target) - pred, succ, w = results - - # build path from pred+w+succ - path = [] - # from source to w - while w is not None: - path.append(w) - w = pred[w] - path.reverse() - # from w to target - w = succ[path[-1]] - while w is not None: - path.append(w) - w = succ[w] - - return path - - -def _bidirectional_pred_succ(G, source, target): - """Bidirectional shortest path helper. - - Returns (pred, succ, w) where - pred is a dictionary of predecessors from w to the source, and - succ is a dictionary of successors from w to the target. - """ - # does BFS from both source and target and meets in the middle - if target == source: - return ({target: None}, {source: None}, source) - - # handle either directed or undirected - if G.is_directed(): - Gpred = G.pred - Gsucc = G.succ - else: - Gpred = G.adj - Gsucc = G.adj - - # predecesssor and successors in search - pred = {source: None} - succ = {target: None} - - # initialize fringes, start with forward - forward_fringe = [source] - reverse_fringe = [target] - - while forward_fringe and reverse_fringe: - if len(forward_fringe) <= len(reverse_fringe): - this_level = forward_fringe - forward_fringe = [] - for v in this_level: - for w in Gsucc[v]: - if w not in pred: - forward_fringe.append(w) - pred[w] = v - if w in succ: # path found - return pred, succ, w - else: - this_level = reverse_fringe - reverse_fringe = [] - for v in this_level: - for w in Gpred[v]: - if w not in succ: - succ[w] = v - reverse_fringe.append(w) - if w in pred: # found path - return pred, succ, w - - raise nx.NetworkXNoPath("No path between %s and %s." % (source, target)) - - -def single_source_shortest_path(G, source, cutoff=None): - """Compute shortest path between source - and all other nodes reachable from source. - - Parameters - ---------- - G : NetworkX graph - - source : node label - Starting node for path - - cutoff : integer, optional - Depth to stop the search. Only paths of length <= cutoff are returned. - - Returns - ------- - lengths : dictionary - Dictionary, keyed by target, of shortest paths. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> path = nx.single_source_shortest_path(G, 0) - >>> path[4] - [0, 1, 2, 3, 4] - - Notes - ----- - The shortest path is not necessarily unique. So there can be multiple - paths between the source and each target node, all of which have the - same 'shortest' length. For each target node, this function returns - only one of those paths. - - See Also - -------- - shortest_path - """ - if source not in G: - raise nx.NodeNotFound("Source {} not in G".format(source)) - - def join(p1, p2): - return p1 + p2 - if cutoff is None: - cutoff = float('inf') - nextlevel = {source: 1} # list of nodes to check at next level - paths = {source: [source]} # paths dictionary (paths to key from source) - return dict(_single_shortest_path(G.adj, nextlevel, paths, cutoff, join)) - - -def _single_shortest_path(adj, firstlevel, paths, cutoff, join): - """Returns shortest paths - - Shortest Path helper function - Parameters - ---------- - adj : dict - Adjacency dict or view - firstlevel : dict - starting nodes, e.g. {source: 1} or {target: 1} - paths : dict - paths for starting nodes, e.g. {source: [source]} - cutoff : int or float - level at which we stop the process - join : function - function to construct a path from two partial paths. Requires two - list inputs `p1` and `p2`, and returns a list. Usually returns - `p1 + p2` (forward from source) or `p2 + p1` (backward from target) - """ - level = 0 # the current level - nextlevel = firstlevel - while nextlevel and cutoff > level: - thislevel = nextlevel - nextlevel = {} - for v in thislevel: - for w in adj[v]: - if w not in paths: - paths[w] = join(paths[v], [w]) - nextlevel[w] = 1 - level += 1 - return paths - - -def single_target_shortest_path(G, target, cutoff=None): - """Compute shortest path to target from all nodes that reach target. - - Parameters - ---------- - G : NetworkX graph - - target : node label - Target node for path - - cutoff : integer, optional - Depth to stop the search. Only paths of length <= cutoff are returned. - - Returns - ------- - lengths : dictionary - Dictionary, keyed by target, of shortest paths. - - Examples - -------- - >>> G = nx.path_graph(5, create_using=nx.DiGraph()) - >>> path = nx.single_target_shortest_path(G, 4) - >>> path[0] - [0, 1, 2, 3, 4] - - Notes - ----- - The shortest path is not necessarily unique. So there can be multiple - paths between the source and each target node, all of which have the - same 'shortest' length. For each target node, this function returns - only one of those paths. - - See Also - -------- - shortest_path, single_source_shortest_path - """ - if target not in G: - raise nx.NodeNotFound("Target {} not in G".format(target)) - - def join(p1, p2): - return p2 + p1 - # handle undirected graphs - adj = G.pred if G.is_directed() else G.adj - if cutoff is None: - cutoff = float('inf') - nextlevel = {target: 1} # list of nodes to check at next level - paths = {target: [target]} # paths dictionary (paths to key from source) - return dict(_single_shortest_path(adj, nextlevel, paths, cutoff, join)) - - -def all_pairs_shortest_path(G, cutoff=None): - """Compute shortest paths between all nodes. - - Parameters - ---------- - G : NetworkX graph - - cutoff : integer, optional - Depth at which to stop the search. Only paths of length at most - `cutoff` are returned. - - Returns - ------- - lengths : dictionary - Dictionary, keyed by source and target, of shortest paths. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> path = dict(nx.all_pairs_shortest_path(G)) - >>> print(path[0][4]) - [0, 1, 2, 3, 4] - - See Also - -------- - floyd_warshall() - - """ - # TODO This can be trivially parallelized. - for n in G: - yield (n, single_source_shortest_path(G, n, cutoff=cutoff)) - - -def predecessor(G, source, target=None, cutoff=None, return_seen=None): - """Returns dict of predecessors for the path from source to all nodes in G - - - Parameters - ---------- - G : NetworkX graph - - source : node label - Starting node for path - - target : node label, optional - Ending node for path. If provided only predecessors between - source and target are returned - - cutoff : integer, optional - Depth to stop the search. Only paths of length <= cutoff are returned. - - - Returns - ------- - pred : dictionary - Dictionary, keyed by node, of predecessors in the shortest path. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> list(G) - [0, 1, 2, 3] - >>> nx.predecessor(G, 0) - {0: [], 1: [0], 2: [1], 3: [2]} - - """ - if source not in G: - raise nx.NodeNotFound("Source {} not in G".format(source)) - - level = 0 # the current level - nextlevel = [source] # list of nodes to check at next level - seen = {source: level} # level (number of hops) when seen in BFS - pred = {source: []} # predecessor dictionary - while nextlevel: - level = level + 1 - thislevel = nextlevel - nextlevel = [] - for v in thislevel: - for w in G[v]: - if w not in seen: - pred[w] = [v] - seen[w] = level - nextlevel.append(w) - elif (seen[w] == level): # add v to predecessor list if it - pred[w].append(v) # is at the correct level - if (cutoff and cutoff <= level): - break - - if target is not None: - if return_seen: - if target not in pred: - return ([], -1) # No predecessor - return (pred[target], seen[target]) - else: - if target not in pred: - return [] # No predecessor - return pred[target] - else: - if return_seen: - return (pred, seen) - else: - return pred diff --git a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/weighted.py b/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/weighted.py deleted file mode 100644 index 994557f0..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/shortest_paths/weighted.py +++ /dev/null @@ -1,2173 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg -# Loïc Séguin-C. -# Dan Schult -# Niels van Adrichem -""" -Shortest path algorithms for weighed graphs. -""" - -from collections import deque -from heapq import heappush, heappop -from itertools import count -import networkx as nx -from networkx.utils import generate_unique_node - - -__all__ = ['dijkstra_path', - 'dijkstra_path_length', - 'bidirectional_dijkstra', - 'single_source_dijkstra', - 'single_source_dijkstra_path', - 'single_source_dijkstra_path_length', - 'multi_source_dijkstra', - 'multi_source_dijkstra_path', - 'multi_source_dijkstra_path_length', - 'all_pairs_dijkstra', - 'all_pairs_dijkstra_path', - 'all_pairs_dijkstra_path_length', - 'dijkstra_predecessor_and_distance', - 'bellman_ford_path', - 'bellman_ford_path_length', - 'single_source_bellman_ford', - 'single_source_bellman_ford_path', - 'single_source_bellman_ford_path_length', - 'all_pairs_bellman_ford_path', - 'all_pairs_bellman_ford_path_length', - 'bellman_ford_predecessor_and_distance', - 'negative_edge_cycle', - 'goldberg_radzik', - 'johnson'] - - -def _weight_function(G, weight): - """Returns a function that returns the weight of an edge. - - The returned function is specifically suitable for input to - functions :func:`_dijkstra` and :func:`_bellman_ford_relaxation`. - - Parameters - ---------- - G : NetworkX graph. - - weight : string or function - If it is callable, `weight` itself is returned. If it is a string, - it is assumed to be the name of the edge attribute that represents - the weight of an edge. In that case, a function is returned that - gets the edge weight according to the specified edge attribute. - - Returns - ------- - function - This function returns a callable that accepts exactly three inputs: - a node, an node adjacent to the first one, and the edge attribute - dictionary for the eedge joining those nodes. That function returns - a number representing the weight of an edge. - - If `G` is a multigraph, and `weight` is not callable, the - minimum edge weight over all parallel edges is returned. If any edge - does not have an attribute with key `weight`, it is assumed to - have weight one. - - """ - if callable(weight): - return weight - # If the weight keyword argument is not callable, we assume it is a - # string representing the edge attribute containing the weight of - # the edge. - if G.is_multigraph(): - return lambda u, v, d: min(attr.get(weight, 1) for attr in d.values()) - return lambda u, v, data: data.get(weight, 1) - - -def dijkstra_path(G, source, target, weight='weight'): - """Returns the shortest weighted path from source to target in G. - - Uses Dijkstra's Method to compute the shortest weighted path - between two nodes in a graph. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node - - target : node - Ending node - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - path : list - List of nodes in a shortest path. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - NetworkXNoPath - If no path exists between source and target. - - Examples - -------- - >>> G=nx.path_graph(5) - >>> print(nx.dijkstra_path(G,0,4)) - [0, 1, 2, 3, 4] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - The weight function can be used to include node weights. - - >>> def func(u, v, d): - ... node_u_wt = G.nodes[u].get('node_weight', 1) - ... node_v_wt = G.nodes[v].get('node_weight', 1) - ... edge_wt = d.get('weight', 1) - ... return node_u_wt/2 + node_v_wt/2 + edge_wt - - In this example we take the average of start and end node - weights of an edge and add it to the weight of the edge. - - The function :func:`single_source_dijkstra` computes both - path and length-of-path if you need both, use that. - - See Also - -------- - bidirectional_dijkstra(), bellman_ford_path() - single_source_dijkstra() - """ - (length, path) = single_source_dijkstra(G, source, target=target, - weight=weight) - return path - - -def dijkstra_path_length(G, source, target, weight='weight'): - """Returns the shortest weighted path length in G from source to target. - - Uses Dijkstra's Method to compute the shortest weighted path length - between two nodes in a graph. - - Parameters - ---------- - G : NetworkX graph - - source : node label - starting node for path - - target : node label - ending node for path - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - length : number - Shortest path length. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - NetworkXNoPath - If no path exists between source and target. - - Examples - -------- - >>> G=nx.path_graph(5) - >>> print(nx.dijkstra_path_length(G,0,4)) - 4 - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - The function :func:`single_source_dijkstra` computes both - path and length-of-path if you need both, use that. - - See Also - -------- - bidirectional_dijkstra(), bellman_ford_path_length() - single_source_dijkstra() - - """ - if source == target: - return 0 - weight = _weight_function(G, weight) - length = _dijkstra(G, source, weight, target=target) - try: - return length[target] - except KeyError: - raise nx.NetworkXNoPath( - "Node %s not reachable from %s" % (target, source)) - - -def single_source_dijkstra_path(G, source, cutoff=None, weight='weight'): - """Find shortest weighted paths in G from a source node. - - Compute shortest path between source and all other reachable - nodes for a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path. - - cutoff : integer or float, optional - Depth to stop the search. Only return paths with length <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - paths : dictionary - Dictionary of shortest path lengths keyed by target. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - Examples - -------- - >>> G=nx.path_graph(5) - >>> path=nx.single_source_dijkstra_path(G,0) - >>> path[4] - [0, 1, 2, 3, 4] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - See Also - -------- - single_source_dijkstra(), single_source_bellman_ford() - - """ - return multi_source_dijkstra_path(G, {source}, cutoff=cutoff, - weight=weight) - - -def single_source_dijkstra_path_length(G, source, cutoff=None, - weight='weight'): - """Find shortest weighted path lengths in G from a source node. - - Compute the shortest path length between source and all other - reachable nodes for a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - source : node label - Starting node for path - - cutoff : integer or float, optional - Depth to stop the search. Only return paths with length <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - length : dict - Dict keyed by node to shortest path length from source. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length = nx.single_source_dijkstra_path_length(G, 0) - >>> length[4] - 4 - >>> for node in [0, 1, 2, 3, 4]: - ... print('{}: {}'.format(node, length[node])) - 0: 0 - 1: 1 - 2: 2 - 3: 3 - 4: 4 - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - See Also - -------- - single_source_dijkstra(), single_source_bellman_ford_path_length() - - """ - return multi_source_dijkstra_path_length(G, {source}, cutoff=cutoff, - weight=weight) - - -def single_source_dijkstra(G, source, target=None, cutoff=None, - weight='weight'): - """Find shortest weighted paths and lengths from a source node. - - Compute the shortest path length between source and all other - reachable nodes for a weighted graph. - - Uses Dijkstra's algorithm to compute shortest paths and lengths - between a source and all other reachable nodes in a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - source : node label - Starting node for path - - target : node label, optional - Ending node for path - - cutoff : integer or float, optional - Depth to stop the search. Only return paths with length <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - distance, path : pair of dictionaries, or numeric and list. - If target is None, paths and lengths to all nodes are computed. - The return value is a tuple of two dictionaries keyed by target nodes. - The first dictionary stores distance to each target node. - The second stores the path to each target node. - If target is not None, returns a tuple (distance, path), where - distance is the distance from source to target and path is a list - representing the path from source to target. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length, path = nx.single_source_dijkstra(G, 0) - >>> print(length[4]) - 4 - >>> for node in [0, 1, 2, 3, 4]: - ... print('{}: {}'.format(node, length[node])) - 0: 0 - 1: 1 - 2: 2 - 3: 3 - 4: 4 - >>> path[4] - [0, 1, 2, 3, 4] - >>> length, path = nx.single_source_dijkstra(G, 0, 1) - >>> length - 1 - >>> path - [0, 1] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - Based on the Python cookbook recipe (119466) at - http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/119466 - - This algorithm is not guaranteed to work if edge weights - are negative or are floating point numbers - (overflows and roundoff errors can cause problems). - - See Also - -------- - single_source_dijkstra_path() - single_source_dijkstra_path_length() - single_source_bellman_ford() - """ - return multi_source_dijkstra(G, {source}, cutoff=cutoff, target=target, - weight=weight) - - -def multi_source_dijkstra_path(G, sources, cutoff=None, weight='weight'): - """Find shortest weighted paths in G from a given set of source - nodes. - - Compute shortest path between any of the source nodes and all other - reachable nodes for a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - sources : non-empty set of nodes - Starting nodes for paths. If this is just a set containing a - single node, then all paths computed by this function will start - from that node. If there are two or more nodes in the set, the - computed paths may begin from any one of the start nodes. - - cutoff : integer or float, optional - Depth to stop the search. Only return paths with length <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - paths : dictionary - Dictionary of shortest paths keyed by target. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> path = nx.multi_source_dijkstra_path(G, {0, 4}) - >>> path[1] - [0, 1] - >>> path[3] - [4, 3] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - Raises - ------ - ValueError - If `sources` is empty. - NodeNotFound - If any of `sources` is not in `G`. - - See Also - -------- - multi_source_dijkstra(), multi_source_bellman_ford() - - """ - length, path = multi_source_dijkstra(G, sources, cutoff=cutoff, - weight=weight) - return path - - -def multi_source_dijkstra_path_length(G, sources, cutoff=None, - weight='weight'): - """Find shortest weighted path lengths in G from a given set of - source nodes. - - Compute the shortest path length between any of the source nodes and - all other reachable nodes for a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - sources : non-empty set of nodes - Starting nodes for paths. If this is just a set containing a - single node, then all paths computed by this function will start - from that node. If there are two or more nodes in the set, the - computed paths may begin from any one of the start nodes. - - cutoff : integer or float, optional - Depth to stop the search. Only return paths with length <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - length : dict - Dict keyed by node to shortest path length to nearest source. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length = nx.multi_source_dijkstra_path_length(G, {0, 4}) - >>> for node in [0, 1, 2, 3, 4]: - ... print('{}: {}'.format(node, length[node])) - 0: 0 - 1: 1 - 2: 2 - 3: 1 - 4: 0 - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - Raises - ------ - ValueError - If `sources` is empty. - NodeNotFound - If any of `sources` is not in `G`. - - See Also - -------- - multi_source_dijkstra() - - """ - if not sources: - raise ValueError('sources must not be empty') - weight = _weight_function(G, weight) - return _dijkstra_multisource(G, sources, weight, cutoff=cutoff) - - -def multi_source_dijkstra(G, sources, target=None, cutoff=None, - weight='weight'): - """Find shortest weighted paths and lengths from a given set of - source nodes. - - Uses Dijkstra's algorithm to compute the shortest paths and lengths - between one of the source nodes and the given `target`, or all other - reachable nodes if not specified, for a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - sources : non-empty set of nodes - Starting nodes for paths. If this is just a set containing a - single node, then all paths computed by this function will start - from that node. If there are two or more nodes in the set, the - computed paths may begin from any one of the start nodes. - - target : node label, optional - Ending node for path - - cutoff : integer or float, optional - Depth to stop the search. Only return paths with length <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - distance, path : pair of dictionaries, or numeric and list - If target is None, returns a tuple of two dictionaries keyed by node. - The first dictionary stores distance from one of the source nodes. - The second stores the path from one of the sources to that node. - If target is not None, returns a tuple of (distance, path) where - distance is the distance from source to target and path is a list - representing the path from source to target. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length, path = nx.multi_source_dijkstra(G, {0, 4}) - >>> for node in [0, 1, 2, 3, 4]: - ... print('{}: {}'.format(node, length[node])) - 0: 0 - 1: 1 - 2: 2 - 3: 1 - 4: 0 - >>> path[1] - [0, 1] - >>> path[3] - [4, 3] - - >>> length, path = nx.multi_source_dijkstra(G, {0, 4}, 1) - >>> length - 1 - >>> path - [0, 1] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The weight function can be used to hide edges by returning None. - So ``weight = lambda u, v, d: 1 if d['color']=="red" else None`` - will find the shortest red path. - - Based on the Python cookbook recipe (119466) at - http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/119466 - - This algorithm is not guaranteed to work if edge weights - are negative or are floating point numbers - (overflows and roundoff errors can cause problems). - - Raises - ------ - ValueError - If `sources` is empty. - NodeNotFound - If any of `sources` is not in `G`. - - See Also - -------- - multi_source_dijkstra_path() - multi_source_dijkstra_path_length() - - """ - if not sources: - raise ValueError('sources must not be empty') - if target in sources: - return (0, [target]) - weight = _weight_function(G, weight) - paths = {source: [source] for source in sources} # dictionary of paths - dist = _dijkstra_multisource(G, sources, weight, paths=paths, - cutoff=cutoff, target=target) - if target is None: - return (dist, paths) - try: - return (dist[target], paths[target]) - except KeyError: - raise nx.NetworkXNoPath("No path to {}.".format(target)) - - -def _dijkstra(G, source, weight, pred=None, paths=None, cutoff=None, - target=None): - """Uses Dijkstra's algorithm to find shortest weighted paths from a - single source. - - This is a convenience function for :func:`_dijkstra_multisource` - with all the arguments the same, except the keyword argument - `sources` set to ``[source]``. - - """ - return _dijkstra_multisource(G, [source], weight, pred=pred, paths=paths, - cutoff=cutoff, target=target) - - -def _dijkstra_multisource(G, sources, weight, pred=None, paths=None, - cutoff=None, target=None): - """Uses Dijkstra's algorithm to find shortest weighted paths - - Parameters - ---------- - G : NetworkX graph - - sources : non-empty iterable of nodes - Starting nodes for paths. If this is just an iterable containing - a single node, then all paths computed by this function will - start from that node. If there are two or more nodes in this - iterable, the computed paths may begin from any one of the start - nodes. - - weight: function - Function with (u, v, data) input that returns that edges weight - - pred: dict of lists, optional(default=None) - dict to store a list of predecessors keyed by that node - If None, predecessors are not stored. - - paths: dict, optional (default=None) - dict to store the path list from source to each node, keyed by node. - If None, paths are not stored. - - target : node label, optional - Ending node for path. Search is halted when target is found. - - cutoff : integer or float, optional - Depth to stop the search. Only return paths with length <= cutoff. - - Returns - ------- - distance : dictionary - A mapping from node to shortest distance to that node from one - of the source nodes. - - Raises - ------ - NodeNotFound - If any of `sources` is not in `G`. - - Notes - ----- - The optional predecessor and path dictionaries can be accessed by - the caller through the original pred and paths objects passed - as arguments. No need to explicitly return pred or paths. - - """ - G_succ = G._succ if G.is_directed() else G._adj - - push = heappush - pop = heappop - dist = {} # dictionary of final distances - seen = {} - # fringe is heapq with 3-tuples (distance,c,node) - # use the count c to avoid comparing nodes (may not be able to) - c = count() - fringe = [] - for source in sources: - if source not in G: - raise nx.NodeNotFound("Source {} not in G".format(source)) - seen[source] = 0 - push(fringe, (0, next(c), source)) - while fringe: - (d, _, v) = pop(fringe) - if v in dist: - continue # already searched this node. - dist[v] = d - if v == target: - break - for u, e in G_succ[v].items(): - cost = weight(v, u, e) - if cost is None: - continue - vu_dist = dist[v] + cost - if cutoff is not None: - if vu_dist > cutoff: - continue - if u in dist: - if vu_dist < dist[u]: - raise ValueError('Contradictory paths found:', - 'negative weights?') - elif u not in seen or vu_dist < seen[u]: - seen[u] = vu_dist - push(fringe, (vu_dist, next(c), u)) - if paths is not None: - paths[u] = paths[v] + [u] - if pred is not None: - pred[u] = [v] - elif vu_dist == seen[u]: - if pred is not None: - pred[u].append(v) - - # The optional predecessor and path dictionaries can be accessed - # by the caller via the pred and paths objects passed as arguments. - return dist - - -def dijkstra_predecessor_and_distance(G, source, cutoff=None, weight='weight'): - """Compute weighted shortest path length and predecessors. - - Uses Dijkstra's Method to obtain the shortest weighted paths - and return dictionaries of predecessors for each node and - distance for each node from the `source`. - - Parameters - ---------- - G : NetworkX graph - - source : node label - Starting node for path - - cutoff : integer or float, optional - Depth to stop the search. Only return paths with length <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - pred, distance : dictionaries - Returns two dictionaries representing a list of predecessors - of a node and the distance to each node. - Warning: If target is specified, the dicts are incomplete as they - only contain information for the nodes along a path to target. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The list of predecessors contains more than one element only when - there are more than one shortest paths to the key node. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.path_graph(5, create_using = nx.DiGraph()) - >>> pred, dist = nx.dijkstra_predecessor_and_distance(G, 0) - >>> sorted(pred.items()) - [(0, []), (1, [0]), (2, [1]), (3, [2]), (4, [3])] - >>> sorted(dist.items()) - [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)] - - >>> pred, dist = nx.dijkstra_predecessor_and_distance(G, 0, 1) - >>> sorted(pred.items()) - [(0, []), (1, [0])] - >>> sorted(dist.items()) - [(0, 0), (1, 1)] - """ - - weight = _weight_function(G, weight) - pred = {source: []} # dictionary of predecessors - return (pred, _dijkstra(G, source, weight, pred=pred, cutoff=cutoff)) - - -def all_pairs_dijkstra(G, cutoff=None, weight='weight'): - """Find shortest weighted paths and lengths between all nodes. - - Parameters - ---------- - G : NetworkX graph - - cutoff : integer or float, optional - Depth to stop the search. Only return paths with length <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edge[u][v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Yields - ------ - (node, (distance, path)) : (node obj, (dict, dict)) - Each source node has two associated dicts. The first holds distance - keyed by target and the second holds paths keyed by target. - (See single_source_dijkstra for the source/target node terminology.) - If desired you can apply `dict()` to this function to create a dict - keyed by source node to the two dicts. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> len_path = dict(nx.all_pairs_dijkstra(G)) - >>> print(len_path[3][0][1]) - 2 - >>> for node in [0, 1, 2, 3, 4]: - ... print('3 - {}: {}'.format(node, len_path[3][0][node])) - 3 - 0: 3 - 3 - 1: 2 - 3 - 2: 1 - 3 - 3: 0 - 3 - 4: 1 - >>> len_path[3][1][1] - [3, 2, 1] - >>> for n, (dist, path) in nx.all_pairs_dijkstra(G): - ... print(path[1]) - [0, 1] - [1] - [2, 1] - [3, 2, 1] - [4, 3, 2, 1] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The yielded dicts only have keys for reachable nodes. - """ - for n in G: - dist, path = single_source_dijkstra(G, n, cutoff=cutoff, weight=weight) - yield (n, (dist, path)) - - -def all_pairs_dijkstra_path_length(G, cutoff=None, weight='weight'): - """Compute shortest path lengths between all nodes in a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - cutoff : integer or float, optional - Depth to stop the search. Only return paths with length <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - distance : iterator - (source, dictionary) iterator with dictionary keyed by target and - shortest path length as the key value. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length = dict(nx.all_pairs_dijkstra_path_length(G)) - >>> for node in [0, 1, 2, 3, 4]: - ... print('1 - {}: {}'.format(node, length[1][node])) - 1 - 0: 1 - 1 - 1: 0 - 1 - 2: 1 - 1 - 3: 2 - 1 - 4: 3 - >>> length[3][2] - 1 - >>> length[2][2] - 0 - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The dictionary returned only has keys for reachable node pairs. - """ - length = single_source_dijkstra_path_length - for n in G: - yield (n, length(G, n, cutoff=cutoff, weight=weight)) - - -def all_pairs_dijkstra_path(G, cutoff=None, weight='weight'): - """Compute shortest paths between all nodes in a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - cutoff : integer or float, optional - Depth to stop the search. Only return paths with length <= cutoff. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - distance : dictionary - Dictionary, keyed by source and target, of shortest paths. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> path = dict(nx.all_pairs_dijkstra_path(G)) - >>> print(path[0][4]) - [0, 1, 2, 3, 4] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - See Also - -------- - floyd_warshall(), all_pairs_bellman_ford_path() - - """ - path = single_source_dijkstra_path - # TODO This can be trivially parallelized. - for n in G: - yield (n, path(G, n, cutoff=cutoff, weight=weight)) - - -def bellman_ford_predecessor_and_distance(G, source, target=None, - weight='weight'): - """Compute shortest path lengths and predecessors on shortest paths - in weighted graphs. - - The algorithm has a running time of $O(mn)$ where $n$ is the number of - nodes and $m$ is the number of edges. It is slower than Dijkstra but - can handle negative edge weights. - - Parameters - ---------- - G : NetworkX graph - The algorithm works for all types of graphs, including directed - graphs and multigraphs. - - source: node label - Starting node for path - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - pred, dist : dictionaries - Returns two dictionaries keyed by node to predecessor in the - path and to the distance from the source respectively. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - NetworkXUnbounded - If the (di)graph contains a negative cost (di)cycle, the - algorithm raises an exception to indicate the presence of the - negative cost (di)cycle. Note: any negative weight edge in an - undirected graph is a negative cost cycle. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.path_graph(5, create_using = nx.DiGraph()) - >>> pred, dist = nx.bellman_ford_predecessor_and_distance(G, 0) - >>> sorted(pred.items()) - [(0, []), (1, [0]), (2, [1]), (3, [2]), (4, [3])] - >>> sorted(dist.items()) - [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)] - - >>> pred, dist = nx.bellman_ford_predecessor_and_distance(G, 0, 1) - >>> sorted(pred.items()) - [(0, []), (1, [0]), (2, [1]), (3, [2]), (4, [3])] - >>> sorted(dist.items()) - [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)] - - >>> import pytest - >>> G = nx.cycle_graph(5, create_using = nx.DiGraph()) - >>> G[1][2]['weight'] = -7 - >>> pytest.raises(nx.NetworkXUnbounded, \ - nx.bellman_ford_predecessor_and_distance, G, 0) - - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The dictionaries returned only have keys for nodes reachable from - the source. - - In the case where the (di)graph is not connected, if a component - not containing the source contains a negative cost (di)cycle, it - will not be detected. - - In NetworkX v2.1 and prior, the source node had predecessor `[None]`. - In NetworkX v2.2 this changed to the source node having predecessor `[]` - """ - if source not in G: - raise nx.NodeNotFound("Node %s is not found in the graph" % source) - weight = _weight_function(G, weight) - if any(weight(u, v, d) < 0 for u, v, d in nx.selfloop_edges(G, data=True)): - raise nx.NetworkXUnbounded("Negative cost cycle detected.") - - dist = {source: 0} - pred = {source: []} - - if len(G) == 1: - return pred, dist - - weight = _weight_function(G, weight) - - dist = _bellman_ford(G, [source], weight, pred=pred, dist=dist, - target=target) - return (pred, dist) - - -def _bellman_ford(G, source, weight, pred=None, paths=None, dist=None, - target=None): - """Relaxation loop for Bellman–Ford algorithm. - - This is an implementation of the SPFA variant. - See https://en.wikipedia.org/wiki/Shortest_Path_Faster_Algorithm - - Parameters - ---------- - G : NetworkX graph - - source: list - List of source nodes. The shortest path from any of the source - nodes will be found if multiple sources are provided. - - weight : function - The weight of an edge is the value returned by the function. The - function must accept exactly three positional arguments: the two - endpoints of an edge and the dictionary of edge attributes for - that edge. The function must return a number. - - pred: dict of lists, optional (default=None) - dict to store a list of predecessors keyed by that node - If None, predecessors are not stored - - paths: dict, optional (default=None) - dict to store the path list from source to each node, keyed by node - If None, paths are not stored - - dist: dict, optional (default=None) - dict to store distance from source to the keyed node - If None, returned dist dict contents default to 0 for every node in the - source list - - target: node label, optional - Ending node for path. Path lengths to other destinations may (and - probably will) be incorrect. - - Returns - ------- - Returns a dict keyed by node to the distance from the source. - Dicts for paths and pred are in the mutated input dicts by those names. - - Raises - ------ - NodeNotFound - If any of `source` is not in `G`. - - NetworkXUnbounded - If the (di)graph contains a negative cost (di)cycle, the - algorithm raises an exception to indicate the presence of the - negative cost (di)cycle. Note: any negative weight edge in an - undirected graph is a negative cost cycle - """ - for s in source: - if s not in G: - raise nx.NodeNotFound("Source {} not in G".format(s)) - - if pred is None: - pred = {v: [] for v in source} - - if dist is None: - dist = {v: 0 for v in source} - - G_succ = G.succ if G.is_directed() else G.adj - inf = float('inf') - n = len(G) - - count = {} - q = deque(source) - in_q = set(source) - while q: - u = q.popleft() - in_q.remove(u) - - # Skip relaxations if any of the predecessors of u is in the queue. - if all(pred_u not in in_q for pred_u in pred[u]): - dist_u = dist[u] - for v, e in G_succ[u].items(): - dist_v = dist_u + weight(v, u, e) - - if dist_v < dist.get(v, inf): - if v not in in_q: - q.append(v) - in_q.add(v) - count_v = count.get(v, 0) + 1 - if count_v == n: - raise nx.NetworkXUnbounded( - "Negative cost cycle detected.") - count[v] = count_v - dist[v] = dist_v - pred[v] = [u] - - elif dist.get(v) is not None and dist_v == dist.get(v): - pred[v].append(u) - - if paths is not None: - dsts = [target] if target is not None else pred - for dst in dsts: - - path = [dst] - cur = dst - - while pred[cur]: - cur = pred[cur][0] - path.append(cur) - - path.reverse() - paths[dst] = path - - return dist - - -def bellman_ford_path(G, source, target, weight='weight'): - """Returns the shortest path from source to target in a weighted graph G. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node - - target : node - Ending node - - weight: string, optional (default='weight') - Edge data key corresponding to the edge weight - - Returns - ------- - path : list - List of nodes in a shortest path. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - NetworkXNoPath - If no path exists between source and target. - - Examples - -------- - >>> G=nx.path_graph(5) - >>> print(nx.bellman_ford_path(G, 0, 4)) - [0, 1, 2, 3, 4] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - See Also - -------- - dijkstra_path(), bellman_ford_path_length() - """ - length, path = single_source_bellman_ford(G, source, - target=target, weight=weight) - return path - - -def bellman_ford_path_length(G, source, target, weight='weight'): - """Returns the shortest path length from source to target - in a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - source : node label - starting node for path - - target : node label - ending node for path - - weight: string, optional (default='weight') - Edge data key corresponding to the edge weight - - Returns - ------- - length : number - Shortest path length. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - NetworkXNoPath - If no path exists between source and target. - - Examples - -------- - >>> G=nx.path_graph(5) - >>> print(nx.bellman_ford_path_length(G,0,4)) - 4 - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - See Also - -------- - dijkstra_path_length(), bellman_ford_path() - """ - if source == target: - return 0 - - weight = _weight_function(G, weight) - - length = _bellman_ford(G, [source], weight, target=target) - - try: - return length[target] - except KeyError: - raise nx.NetworkXNoPath( - "node %s not reachable from %s" % (target, source)) - - -def single_source_bellman_ford_path(G, source, weight='weight'): - """Compute shortest path between source and all other reachable - nodes for a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path. - - weight: string, optional (default='weight') - Edge data key corresponding to the edge weight - - Returns - ------- - paths : dictionary - Dictionary of shortest path lengths keyed by target. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - Examples - -------- - >>> G=nx.path_graph(5) - >>> path=nx.single_source_bellman_ford_path(G,0) - >>> path[4] - [0, 1, 2, 3, 4] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - See Also - -------- - single_source_dijkstra(), single_source_bellman_ford() - - """ - (length, path) = single_source_bellman_ford( - G, source, weight=weight) - return path - - -def single_source_bellman_ford_path_length(G, source, weight='weight'): - """Compute the shortest path length between source and all other - reachable nodes for a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - source : node label - Starting node for path - - weight: string, optional (default='weight') - Edge data key corresponding to the edge weight. - - Returns - ------- - length : iterator - (target, shortest path length) iterator - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length = dict(nx.single_source_bellman_ford_path_length(G, 0)) - >>> length[4] - 4 - >>> for node in [0, 1, 2, 3, 4]: - ... print('{}: {}'.format(node, length[node])) - 0: 0 - 1: 1 - 2: 2 - 3: 3 - 4: 4 - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - See Also - -------- - single_source_dijkstra(), single_source_bellman_ford() - - """ - weight = _weight_function(G, weight) - return _bellman_ford(G, [source], weight) - - -def single_source_bellman_ford(G, source, target=None, weight='weight'): - """Compute shortest paths and lengths in a weighted graph G. - - Uses Bellman-Ford algorithm for shortest paths. - - Parameters - ---------- - G : NetworkX graph - - source : node label - Starting node for path - - target : node label, optional - Ending node for path - - Returns - ------- - distance, path : pair of dictionaries, or numeric and list - If target is None, returns a tuple of two dictionaries keyed by node. - The first dictionary stores distance from one of the source nodes. - The second stores the path from one of the sources to that node. - If target is not None, returns a tuple of (distance, path) where - distance is the distance from source to target and path is a list - representing the path from source to target. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length, path = nx.single_source_bellman_ford(G, 0) - >>> print(length[4]) - 4 - >>> for node in [0, 1, 2, 3, 4]: - ... print('{}: {}'.format(node, length[node])) - 0: 0 - 1: 1 - 2: 2 - 3: 3 - 4: 4 - >>> path[4] - [0, 1, 2, 3, 4] - >>> length, path = nx.single_source_bellman_ford(G, 0, 1) - >>> length - 1 - >>> path - [0, 1] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - See Also - -------- - single_source_dijkstra() - single_source_bellman_ford_path() - single_source_bellman_ford_path_length() - """ - if source == target: - return (0, [source]) - - weight = _weight_function(G, weight) - - paths = {source: [source]} # dictionary of paths - dist = _bellman_ford(G, [source], weight, paths=paths, target=target) - if target is None: - return (dist, paths) - try: - return (dist[target], paths[target]) - except KeyError: - msg = "Node %s not reachable from %s" % (target, source) - raise nx.NetworkXNoPath(msg) - - -def all_pairs_bellman_ford_path_length(G, weight='weight'): - """ Compute shortest path lengths between all nodes in a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - weight: string, optional (default='weight') - Edge data key corresponding to the edge weight - - Returns - ------- - distance : iterator - (source, dictionary) iterator with dictionary keyed by target and - shortest path length as the key value. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length = dict(nx.all_pairs_bellman_ford_path_length(G)) - >>> for node in [0, 1, 2, 3, 4]: - ... print('1 - {}: {}'.format(node, length[1][node])) - 1 - 0: 1 - 1 - 1: 0 - 1 - 2: 1 - 1 - 3: 2 - 1 - 4: 3 - >>> length[3][2] - 1 - >>> length[2][2] - 0 - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The dictionary returned only has keys for reachable node pairs. - """ - length = single_source_bellman_ford_path_length - for n in G: - yield (n, dict(length(G, n, weight=weight))) - - -def all_pairs_bellman_ford_path(G, weight='weight'): - """ Compute shortest paths between all nodes in a weighted graph. - - Parameters - ---------- - G : NetworkX graph - - weight: string, optional (default='weight') - Edge data key corresponding to the edge weight - - Returns - ------- - distance : dictionary - Dictionary, keyed by source and target, of shortest paths. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> path = dict(nx.all_pairs_bellman_ford_path(G)) - >>> print(path[0][4]) - [0, 1, 2, 3, 4] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - See Also - -------- - floyd_warshall(), all_pairs_dijkstra_path() - - """ - path = single_source_bellman_ford_path - # TODO This can be trivially parallelized. - for n in G: - yield (n, path(G, n, weight=weight)) - - -def goldberg_radzik(G, source, weight='weight'): - """Compute shortest path lengths and predecessors on shortest paths - in weighted graphs. - - The algorithm has a running time of $O(mn)$ where $n$ is the number of - nodes and $m$ is the number of edges. It is slower than Dijkstra but - can handle negative edge weights. - - Parameters - ---------- - G : NetworkX graph - The algorithm works for all types of graphs, including directed - graphs and multigraphs. - - source: node label - Starting node for path - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - pred, dist : dictionaries - Returns two dictionaries keyed by node to predecessor in the - path and to the distance from the source respectively. - - Raises - ------ - NodeNotFound - If `source` is not in `G`. - - NetworkXUnbounded - If the (di)graph contains a negative cost (di)cycle, the - algorithm raises an exception to indicate the presence of the - negative cost (di)cycle. Note: any negative weight edge in an - undirected graph is a negative cost cycle. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.path_graph(5, create_using = nx.DiGraph()) - >>> pred, dist = nx.goldberg_radzik(G, 0) - >>> sorted(pred.items()) - [(0, None), (1, 0), (2, 1), (3, 2), (4, 3)] - >>> sorted(dist.items()) - [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)] - - >>> import pytest - >>> G = nx.cycle_graph(5, create_using = nx.DiGraph()) - >>> G[1][2]['weight'] = -7 - >>> pytest.raises(nx.NetworkXUnbounded, nx.goldberg_radzik, G, 0) - - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - The dictionaries returned only have keys for nodes reachable from - the source. - - In the case where the (di)graph is not connected, if a component - not containing the source contains a negative cost (di)cycle, it - will not be detected. - - """ - if source not in G: - raise nx.NodeNotFound("Node %s is not found in the graph" % source) - weight = _weight_function(G, weight) - if any(weight(u, v, d) < 0 for u, v, d in nx.selfloop_edges(G, data=True)): - raise nx.NetworkXUnbounded("Negative cost cycle detected.") - - if len(G) == 1: - return {source: None}, {source: 0} - - if G.is_directed(): - G_succ = G.succ - else: - G_succ = G.adj - - inf = float('inf') - d = {u: inf for u in G} - d[source] = 0 - pred = {source: None} - - def topo_sort(relabeled): - """Topologically sort nodes relabeled in the previous round and detect - negative cycles. - """ - # List of nodes to scan in this round. Denoted by A in Goldberg and - # Radzik's paper. - to_scan = [] - # In the DFS in the loop below, neg_count records for each node the - # number of edges of negative reduced costs on the path from a DFS root - # to the node in the DFS forest. The reduced cost of an edge (u, v) is - # defined as d[u] + weight[u][v] - d[v]. - # - # neg_count also doubles as the DFS visit marker array. - neg_count = {} - for u in relabeled: - # Skip visited nodes. - if u in neg_count: - continue - d_u = d[u] - # Skip nodes without out-edges of negative reduced costs. - if all(d_u + weight(u, v, e) >= d[v] - for v, e in G_succ[u].items()): - continue - # Nonrecursive DFS that inserts nodes reachable from u via edges of - # nonpositive reduced costs into to_scan in (reverse) topological - # order. - stack = [(u, iter(G_succ[u].items()))] - in_stack = set([u]) - neg_count[u] = 0 - while stack: - u, it = stack[-1] - try: - v, e = next(it) - except StopIteration: - to_scan.append(u) - stack.pop() - in_stack.remove(u) - continue - t = d[u] + weight(u, v, e) - d_v = d[v] - if t <= d_v: - is_neg = t < d_v - d[v] = t - pred[v] = u - if v not in neg_count: - neg_count[v] = neg_count[u] + int(is_neg) - stack.append((v, iter(G_succ[v].items()))) - in_stack.add(v) - elif (v in in_stack and - neg_count[u] + int(is_neg) > neg_count[v]): - # (u, v) is a back edge, and the cycle formed by the - # path v to u and (u, v) contains at least one edge of - # negative reduced cost. The cycle must be of negative - # cost. - raise nx.NetworkXUnbounded( - 'Negative cost cycle detected.') - to_scan.reverse() - return to_scan - - def relax(to_scan): - """Relax out-edges of relabeled nodes. - """ - relabeled = set() - # Scan nodes in to_scan in topological order and relax incident - # out-edges. Add the relabled nodes to labeled. - for u in to_scan: - d_u = d[u] - for v, e in G_succ[u].items(): - w_e = weight(u, v, e) - if d_u + w_e < d[v]: - d[v] = d_u + w_e - pred[v] = u - relabeled.add(v) - return relabeled - - # Set of nodes relabled in the last round of scan operations. Denoted by B - # in Goldberg and Radzik's paper. - relabeled = set([source]) - - while relabeled: - to_scan = topo_sort(relabeled) - relabeled = relax(to_scan) - - d = {u: d[u] for u in pred} - return pred, d - - -def negative_edge_cycle(G, weight='weight'): - """Returns True if there exists a negative edge cycle anywhere in G. - - Parameters - ---------- - G : NetworkX graph - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - negative_cycle : bool - True if a negative edge cycle exists, otherwise False. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.cycle_graph(5, create_using = nx.DiGraph()) - >>> print(nx.negative_edge_cycle(G)) - False - >>> G[1][2]['weight'] = -7 - >>> print(nx.negative_edge_cycle(G)) - True - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - This algorithm uses bellman_ford_predecessor_and_distance() but finds - negative cycles on any component by first adding a new node connected to - every node, and starting bellman_ford_predecessor_and_distance on that - node. It then removes that extra node. - """ - newnode = generate_unique_node() - G.add_edges_from([(newnode, n) for n in G]) - - try: - bellman_ford_predecessor_and_distance(G, newnode, weight) - except nx.NetworkXUnbounded: - return True - finally: - G.remove_node(newnode) - return False - - -def bidirectional_dijkstra(G, source, target, weight='weight'): - r"""Dijkstra's algorithm for shortest paths using bidirectional search. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node. - - target : node - Ending node. - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - length, path : number and list - length is the distance from source to target. - path is a list of nodes on a path from source to target. - - Raises - ------ - NodeNotFound - If either `source` or `target` is not in `G`. - - NetworkXNoPath - If no path exists between source and target. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> length, path = nx.bidirectional_dijkstra(G, 0, 4) - >>> print(length) - 4 - >>> print(path) - [0, 1, 2, 3, 4] - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - In practice bidirectional Dijkstra is much more than twice as fast as - ordinary Dijkstra. - - Ordinary Dijkstra expands nodes in a sphere-like manner from the - source. The radius of this sphere will eventually be the length - of the shortest path. Bidirectional Dijkstra will expand nodes - from both the source and the target, making two spheres of half - this radius. Volume of the first sphere is `\pi*r*r` while the - others are `2*\pi*r/2*r/2`, making up half the volume. - - This algorithm is not guaranteed to work if edge weights - are negative or are floating point numbers - (overflows and roundoff errors can cause problems). - - See Also - -------- - shortest_path - shortest_path_length - """ - if source not in G or target not in G: - msg = 'Either source {} or target {} is not in G' - raise nx.NodeNotFound(msg.format(source, target)) - - if source == target: - return (0, [source]) - push = heappush - pop = heappop - # Init: [Forward, Backward] - dists = [{}, {}] # dictionary of final distances - paths = [{source: [source]}, {target: [target]}] # dictionary of paths - fringe = [[], []] # heap of (distance, node) for choosing node to expand - seen = [{source: 0}, {target: 0}] # dict of distances to seen nodes - c = count() - # initialize fringe heap - push(fringe[0], (0, next(c), source)) - push(fringe[1], (0, next(c), target)) - # neighs for extracting correct neighbor information - if G.is_directed(): - neighs = [G.successors, G.predecessors] - else: - neighs = [G.neighbors, G.neighbors] - # variables to hold shortest discovered path - # finaldist = 1e30000 - finalpath = [] - dir = 1 - while fringe[0] and fringe[1]: - # choose direction - # dir == 0 is forward direction and dir == 1 is back - dir = 1 - dir - # extract closest to expand - (dist, _, v) = pop(fringe[dir]) - if v in dists[dir]: - # Shortest path to v has already been found - continue - # update distance - dists[dir][v] = dist # equal to seen[dir][v] - if v in dists[1 - dir]: - # if we have scanned v in both directions we are done - # we have now discovered the shortest path - return (finaldist, finalpath) - - for w in neighs[dir](v): - if(dir == 0): # forward - if G.is_multigraph(): - minweight = min((dd.get(weight, 1) - for k, dd in G[v][w].items())) - else: - minweight = G[v][w].get(weight, 1) - vwLength = dists[dir][v] + minweight # G[v][w].get(weight,1) - else: # back, must remember to change v,w->w,v - if G.is_multigraph(): - minweight = min((dd.get(weight, 1) - for k, dd in G[w][v].items())) - else: - minweight = G[w][v].get(weight, 1) - vwLength = dists[dir][v] + minweight # G[w][v].get(weight,1) - - if w in dists[dir]: - if vwLength < dists[dir][w]: - raise ValueError( - "Contradictory paths found: negative weights?") - elif w not in seen[dir] or vwLength < seen[dir][w]: - # relaxing - seen[dir][w] = vwLength - push(fringe[dir], (vwLength, next(c), w)) - paths[dir][w] = paths[dir][v] + [w] - if w in seen[0] and w in seen[1]: - # see if this path is better than than the already - # discovered shortest path - totaldist = seen[0][w] + seen[1][w] - if finalpath == [] or finaldist > totaldist: - finaldist = totaldist - revpath = paths[1][w][:] - revpath.reverse() - finalpath = paths[0][w] + revpath[1:] - raise nx.NetworkXNoPath("No path between %s and %s." % (source, target)) - - -def johnson(G, weight='weight'): - r"""Uses Johnson's Algorithm to compute shortest paths. - - Johnson's Algorithm finds a shortest path between each pair of - nodes in a weighted graph even if negative weights are present. - - Parameters - ---------- - G : NetworkX graph - - weight : string or function - If this is a string, then edge weights will be accessed via the - edge attribute with this key (that is, the weight of the edge - joining `u` to `v` will be ``G.edges[u, v][weight]``). If no - such edge attribute exists, the weight of the edge is assumed to - be one. - - If this is a function, the weight of an edge is the value - returned by the function. The function must accept exactly three - positional arguments: the two endpoints of an edge and the - dictionary of edge attributes for that edge. The function must - return a number. - - Returns - ------- - distance : dictionary - Dictionary, keyed by source and target, of shortest paths. - - Raises - ------ - NetworkXError - If given graph is not weighted. - - Examples - -------- - >>> import networkx as nx - >>> graph = nx.DiGraph() - >>> graph.add_weighted_edges_from([('0', '3', 3), ('0', '1', -5), - ... ('0', '2', 2), ('1', '2', 4), ('2', '3', 1)]) - >>> paths = nx.johnson(graph, weight='weight') - >>> paths['0']['2'] - ['0', '1', '2'] - - Notes - ----- - Johnson's algorithm is suitable even for graphs with negative weights. It - works by using the Bellman–Ford algorithm to compute a transformation of - the input graph that removes all negative weights, allowing Dijkstra's - algorithm to be used on the transformed graph. - - The time complexity of this algorithm is $O(n^2 \log n + n m)$, - where $n$ is the number of nodes and $m$ the number of edges in the - graph. For dense graphs, this may be faster than the Floyd–Warshall - algorithm. - - See Also - -------- - floyd_warshall_predecessor_and_distance - floyd_warshall_numpy - all_pairs_shortest_path - all_pairs_shortest_path_length - all_pairs_dijkstra_path - bellman_ford_predecessor_and_distance - all_pairs_bellman_ford_path - all_pairs_bellman_ford_path_length - - """ - if not nx.is_weighted(G, weight=weight): - raise nx.NetworkXError('Graph is not weighted.') - - dist = {v: 0 for v in G} - pred = {v: [] for v in G} - weight = _weight_function(G, weight) - - # Calculate distance of shortest paths - dist_bellman = _bellman_ford(G, list(G), weight, pred=pred, dist=dist) - - # Update the weight function to take into account the Bellman--Ford - # relaxation distances. - def new_weight(u, v, d): - return weight(u, v, d) + dist_bellman[u] - dist_bellman[v] - - def dist_path(v): - paths = {v: [v]} - _dijkstra(G, v, new_weight, paths=paths) - return paths - - return {v: dist_path(v) for v in G} diff --git a/extensions/fablabchemnitz/networkx/algorithms/similarity.py b/extensions/fablabchemnitz/networkx/algorithms/similarity.py deleted file mode 100644 index 48fe552c..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/similarity.py +++ /dev/null @@ -1,1256 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2010 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Author: Andrey Paramonov -""" Functions measuring similarity using graph edit distance. - -The graph edit distance is the number of edge/node changes needed -to make two graphs isomorphic. - -The default algorithm/implementation is sub-optimal for some graphs. -The problem of finding the exact Graph Edit Distance (GED) is NP-hard -so it is often slow. If the simple interface `graph_edit_distance` -takes too long for your graph, try `optimize_graph_edit_distance` -and/or `optimize_edit_paths`. - -At the same time, I encourage capable people to investigate -alternative GED algorithms, in order to improve the choices available. -""" -from itertools import product -import math -import networkx as nx -from operator import * -import sys - -__author__ = 'Andrey Paramonov ' - -__all__ = [ - 'graph_edit_distance', - 'optimal_edit_paths', - 'optimize_graph_edit_distance', - 'optimize_edit_paths', - 'simrank_similarity', - 'simrank_similarity_numpy', -] - - -def debug_print(*args, **kwargs): - print(*args, **kwargs) - - -def graph_edit_distance(G1, G2, node_match=None, edge_match=None, - node_subst_cost=None, node_del_cost=None, - node_ins_cost=None, - edge_subst_cost=None, edge_del_cost=None, - edge_ins_cost=None, - upper_bound=None): - """Returns GED (graph edit distance) between graphs G1 and G2. - - Graph edit distance is a graph similarity measure analogous to - Levenshtein distance for strings. It is defined as minimum cost - of edit path (sequence of node and edge edit operations) - transforming graph G1 to graph isomorphic to G2. - - Parameters - ---------- - G1, G2: graphs - The two graphs G1 and G2 must be of the same type. - - node_match : callable - A function that returns True if node n1 in G1 and n2 in G2 - should be considered equal during matching. - - The function will be called like - - node_match(G1.nodes[n1], G2.nodes[n2]). - - That is, the function will receive the node attribute - dictionaries for n1 and n2 as inputs. - - Ignored if node_subst_cost is specified. If neither - node_match nor node_subst_cost are specified then node - attributes are not considered. - - edge_match : callable - A function that returns True if the edge attribute dictionaries - for the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should - be considered equal during matching. - - The function will be called like - - edge_match(G1[u1][v1], G2[u2][v2]). - - That is, the function will receive the edge attribute - dictionaries of the edges under consideration. - - Ignored if edge_subst_cost is specified. If neither - edge_match nor edge_subst_cost are specified then edge - attributes are not considered. - - node_subst_cost, node_del_cost, node_ins_cost : callable - Functions that return the costs of node substitution, node - deletion, and node insertion, respectively. - - The functions will be called like - - node_subst_cost(G1.nodes[n1], G2.nodes[n2]), - node_del_cost(G1.nodes[n1]), - node_ins_cost(G2.nodes[n2]). - - That is, the functions will receive the node attribute - dictionaries as inputs. The functions are expected to return - positive numeric values. - - Function node_subst_cost overrides node_match if specified. - If neither node_match nor node_subst_cost are specified then - default node substitution cost of 0 is used (node attributes - are not considered during matching). - - If node_del_cost is not specified then default node deletion - cost of 1 is used. If node_ins_cost is not specified then - default node insertion cost of 1 is used. - - edge_subst_cost, edge_del_cost, edge_ins_cost : callable - Functions that return the costs of edge substitution, edge - deletion, and edge insertion, respectively. - - The functions will be called like - - edge_subst_cost(G1[u1][v1], G2[u2][v2]), - edge_del_cost(G1[u1][v1]), - edge_ins_cost(G2[u2][v2]). - - That is, the functions will receive the edge attribute - dictionaries as inputs. The functions are expected to return - positive numeric values. - - Function edge_subst_cost overrides edge_match if specified. - If neither edge_match nor edge_subst_cost are specified then - default edge substitution cost of 0 is used (edge attributes - are not considered during matching). - - If edge_del_cost is not specified then default edge deletion - cost of 1 is used. If edge_ins_cost is not specified then - default edge insertion cost of 1 is used. - - upper_bound : numeric - Maximum edit distance to consider. Return None if no edit - distance under or equal to upper_bound exists. - - Examples - -------- - >>> G1 = nx.cycle_graph(6) - >>> G2 = nx.wheel_graph(7) - >>> nx.graph_edit_distance(G1, G2) - 7.0 - - See Also - -------- - optimal_edit_paths, optimize_graph_edit_distance, - - is_isomorphic (test for graph edit distance of 0) - - References - ---------- - .. [1] Zeina Abu-Aisheh, Romain Raveaux, Jean-Yves Ramel, Patrick - Martineau. An Exact Graph Edit Distance Algorithm for Solving - Pattern Recognition Problems. 4th International Conference on - Pattern Recognition Applications and Methods 2015, Jan 2015, - Lisbon, Portugal. 2015, - <10.5220/0005209202710278>. - https://hal.archives-ouvertes.fr/hal-01168816 - - """ - bestcost = None - for vertex_path, edge_path, cost in \ - optimize_edit_paths(G1, G2, node_match, edge_match, - node_subst_cost, node_del_cost, node_ins_cost, - edge_subst_cost, edge_del_cost, edge_ins_cost, - upper_bound, True): - #assert bestcost is None or cost < bestcost - bestcost = cost - return bestcost - - -def optimal_edit_paths(G1, G2, node_match=None, edge_match=None, - node_subst_cost=None, node_del_cost=None, - node_ins_cost=None, - edge_subst_cost=None, edge_del_cost=None, - edge_ins_cost=None, - upper_bound=None): - """Returns all minimum-cost edit paths transforming G1 to G2. - - Graph edit path is a sequence of node and edge edit operations - transforming graph G1 to graph isomorphic to G2. Edit operations - include substitutions, deletions, and insertions. - - Parameters - ---------- - G1, G2: graphs - The two graphs G1 and G2 must be of the same type. - - node_match : callable - A function that returns True if node n1 in G1 and n2 in G2 - should be considered equal during matching. - - The function will be called like - - node_match(G1.nodes[n1], G2.nodes[n2]). - - That is, the function will receive the node attribute - dictionaries for n1 and n2 as inputs. - - Ignored if node_subst_cost is specified. If neither - node_match nor node_subst_cost are specified then node - attributes are not considered. - - edge_match : callable - A function that returns True if the edge attribute dictionaries - for the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should - be considered equal during matching. - - The function will be called like - - edge_match(G1[u1][v1], G2[u2][v2]). - - That is, the function will receive the edge attribute - dictionaries of the edges under consideration. - - Ignored if edge_subst_cost is specified. If neither - edge_match nor edge_subst_cost are specified then edge - attributes are not considered. - - node_subst_cost, node_del_cost, node_ins_cost : callable - Functions that return the costs of node substitution, node - deletion, and node insertion, respectively. - - The functions will be called like - - node_subst_cost(G1.nodes[n1], G2.nodes[n2]), - node_del_cost(G1.nodes[n1]), - node_ins_cost(G2.nodes[n2]). - - That is, the functions will receive the node attribute - dictionaries as inputs. The functions are expected to return - positive numeric values. - - Function node_subst_cost overrides node_match if specified. - If neither node_match nor node_subst_cost are specified then - default node substitution cost of 0 is used (node attributes - are not considered during matching). - - If node_del_cost is not specified then default node deletion - cost of 1 is used. If node_ins_cost is not specified then - default node insertion cost of 1 is used. - - edge_subst_cost, edge_del_cost, edge_ins_cost : callable - Functions that return the costs of edge substitution, edge - deletion, and edge insertion, respectively. - - The functions will be called like - - edge_subst_cost(G1[u1][v1], G2[u2][v2]), - edge_del_cost(G1[u1][v1]), - edge_ins_cost(G2[u2][v2]). - - That is, the functions will receive the edge attribute - dictionaries as inputs. The functions are expected to return - positive numeric values. - - Function edge_subst_cost overrides edge_match if specified. - If neither edge_match nor edge_subst_cost are specified then - default edge substitution cost of 0 is used (edge attributes - are not considered during matching). - - If edge_del_cost is not specified then default edge deletion - cost of 1 is used. If edge_ins_cost is not specified then - default edge insertion cost of 1 is used. - - upper_bound : numeric - Maximum edit distance to consider. - - Returns - ------- - edit_paths : list of tuples (node_edit_path, edge_edit_path) - node_edit_path : list of tuples (u, v) - edge_edit_path : list of tuples ((u1, v1), (u2, v2)) - - cost : numeric - Optimal edit path cost (graph edit distance). - - Examples - -------- - >>> G1 = nx.cycle_graph(6) - >>> G2 = nx.wheel_graph(7) - >>> paths, cost = nx.optimal_edit_paths(G1, G2) - >>> len(paths) - 84 - >>> cost - 7.0 - - See Also - -------- - graph_edit_distance, optimize_edit_paths - - References - ---------- - .. [1] Zeina Abu-Aisheh, Romain Raveaux, Jean-Yves Ramel, Patrick - Martineau. An Exact Graph Edit Distance Algorithm for Solving - Pattern Recognition Problems. 4th International Conference on - Pattern Recognition Applications and Methods 2015, Jan 2015, - Lisbon, Portugal. 2015, - <10.5220/0005209202710278>. - https://hal.archives-ouvertes.fr/hal-01168816 - - """ - paths = list() - bestcost = None - for vertex_path, edge_path, cost in \ - optimize_edit_paths(G1, G2, node_match, edge_match, - node_subst_cost, node_del_cost, node_ins_cost, - edge_subst_cost, edge_del_cost, edge_ins_cost, - upper_bound, False): - #assert bestcost is None or cost <= bestcost - if bestcost is not None and cost < bestcost: - paths = list() - paths.append((vertex_path, edge_path)) - bestcost = cost - return paths, bestcost - - -def optimize_graph_edit_distance(G1, G2, node_match=None, edge_match=None, - node_subst_cost=None, node_del_cost=None, - node_ins_cost=None, - edge_subst_cost=None, edge_del_cost=None, - edge_ins_cost=None, - upper_bound=None): - """Returns consecutive approximations of GED (graph edit distance) - between graphs G1 and G2. - - Graph edit distance is a graph similarity measure analogous to - Levenshtein distance for strings. It is defined as minimum cost - of edit path (sequence of node and edge edit operations) - transforming graph G1 to graph isomorphic to G2. - - Parameters - ---------- - G1, G2: graphs - The two graphs G1 and G2 must be of the same type. - - node_match : callable - A function that returns True if node n1 in G1 and n2 in G2 - should be considered equal during matching. - - The function will be called like - - node_match(G1.nodes[n1], G2.nodes[n2]). - - That is, the function will receive the node attribute - dictionaries for n1 and n2 as inputs. - - Ignored if node_subst_cost is specified. If neither - node_match nor node_subst_cost are specified then node - attributes are not considered. - - edge_match : callable - A function that returns True if the edge attribute dictionaries - for the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should - be considered equal during matching. - - The function will be called like - - edge_match(G1[u1][v1], G2[u2][v2]). - - That is, the function will receive the edge attribute - dictionaries of the edges under consideration. - - Ignored if edge_subst_cost is specified. If neither - edge_match nor edge_subst_cost are specified then edge - attributes are not considered. - - node_subst_cost, node_del_cost, node_ins_cost : callable - Functions that return the costs of node substitution, node - deletion, and node insertion, respectively. - - The functions will be called like - - node_subst_cost(G1.nodes[n1], G2.nodes[n2]), - node_del_cost(G1.nodes[n1]), - node_ins_cost(G2.nodes[n2]). - - That is, the functions will receive the node attribute - dictionaries as inputs. The functions are expected to return - positive numeric values. - - Function node_subst_cost overrides node_match if specified. - If neither node_match nor node_subst_cost are specified then - default node substitution cost of 0 is used (node attributes - are not considered during matching). - - If node_del_cost is not specified then default node deletion - cost of 1 is used. If node_ins_cost is not specified then - default node insertion cost of 1 is used. - - edge_subst_cost, edge_del_cost, edge_ins_cost : callable - Functions that return the costs of edge substitution, edge - deletion, and edge insertion, respectively. - - The functions will be called like - - edge_subst_cost(G1[u1][v1], G2[u2][v2]), - edge_del_cost(G1[u1][v1]), - edge_ins_cost(G2[u2][v2]). - - That is, the functions will receive the edge attribute - dictionaries as inputs. The functions are expected to return - positive numeric values. - - Function edge_subst_cost overrides edge_match if specified. - If neither edge_match nor edge_subst_cost are specified then - default edge substitution cost of 0 is used (edge attributes - are not considered during matching). - - If edge_del_cost is not specified then default edge deletion - cost of 1 is used. If edge_ins_cost is not specified then - default edge insertion cost of 1 is used. - - upper_bound : numeric - Maximum edit distance to consider. - - Returns - ------- - Generator of consecutive approximations of graph edit distance. - - Examples - -------- - >>> G1 = nx.cycle_graph(6) - >>> G2 = nx.wheel_graph(7) - >>> for v in nx.optimize_graph_edit_distance(G1, G2): - ... minv = v - >>> minv - 7.0 - - See Also - -------- - graph_edit_distance, optimize_edit_paths - - References - ---------- - .. [1] Zeina Abu-Aisheh, Romain Raveaux, Jean-Yves Ramel, Patrick - Martineau. An Exact Graph Edit Distance Algorithm for Solving - Pattern Recognition Problems. 4th International Conference on - Pattern Recognition Applications and Methods 2015, Jan 2015, - Lisbon, Portugal. 2015, - <10.5220/0005209202710278>. - https://hal.archives-ouvertes.fr/hal-01168816 - """ - for vertex_path, edge_path, cost in \ - optimize_edit_paths(G1, G2, node_match, edge_match, - node_subst_cost, node_del_cost, node_ins_cost, - edge_subst_cost, edge_del_cost, edge_ins_cost, - upper_bound, True): - yield cost - - -def optimize_edit_paths(G1, G2, node_match=None, edge_match=None, - node_subst_cost=None, node_del_cost=None, - node_ins_cost=None, - edge_subst_cost=None, edge_del_cost=None, - edge_ins_cost=None, - upper_bound=None, strictly_decreasing=True): - """GED (graph edit distance) calculation: advanced interface. - - Graph edit path is a sequence of node and edge edit operations - transforming graph G1 to graph isomorphic to G2. Edit operations - include substitutions, deletions, and insertions. - - Graph edit distance is defined as minimum cost of edit path. - - Parameters - ---------- - G1, G2: graphs - The two graphs G1 and G2 must be of the same type. - - node_match : callable - A function that returns True if node n1 in G1 and n2 in G2 - should be considered equal during matching. - - The function will be called like - - node_match(G1.nodes[n1], G2.nodes[n2]). - - That is, the function will receive the node attribute - dictionaries for n1 and n2 as inputs. - - Ignored if node_subst_cost is specified. If neither - node_match nor node_subst_cost are specified then node - attributes are not considered. - - edge_match : callable - A function that returns True if the edge attribute dictionaries - for the pair of nodes (u1, v1) in G1 and (u2, v2) in G2 should - be considered equal during matching. - - The function will be called like - - edge_match(G1[u1][v1], G2[u2][v2]). - - That is, the function will receive the edge attribute - dictionaries of the edges under consideration. - - Ignored if edge_subst_cost is specified. If neither - edge_match nor edge_subst_cost are specified then edge - attributes are not considered. - - node_subst_cost, node_del_cost, node_ins_cost : callable - Functions that return the costs of node substitution, node - deletion, and node insertion, respectively. - - The functions will be called like - - node_subst_cost(G1.nodes[n1], G2.nodes[n2]), - node_del_cost(G1.nodes[n1]), - node_ins_cost(G2.nodes[n2]). - - That is, the functions will receive the node attribute - dictionaries as inputs. The functions are expected to return - positive numeric values. - - Function node_subst_cost overrides node_match if specified. - If neither node_match nor node_subst_cost are specified then - default node substitution cost of 0 is used (node attributes - are not considered during matching). - - If node_del_cost is not specified then default node deletion - cost of 1 is used. If node_ins_cost is not specified then - default node insertion cost of 1 is used. - - edge_subst_cost, edge_del_cost, edge_ins_cost : callable - Functions that return the costs of edge substitution, edge - deletion, and edge insertion, respectively. - - The functions will be called like - - edge_subst_cost(G1[u1][v1], G2[u2][v2]), - edge_del_cost(G1[u1][v1]), - edge_ins_cost(G2[u2][v2]). - - That is, the functions will receive the edge attribute - dictionaries as inputs. The functions are expected to return - positive numeric values. - - Function edge_subst_cost overrides edge_match if specified. - If neither edge_match nor edge_subst_cost are specified then - default edge substitution cost of 0 is used (edge attributes - are not considered during matching). - - If edge_del_cost is not specified then default edge deletion - cost of 1 is used. If edge_ins_cost is not specified then - default edge insertion cost of 1 is used. - - upper_bound : numeric - Maximum edit distance to consider. - - strictly_decreasing : bool - If True, return consecutive approximations of strictly - decreasing cost. Otherwise, return all edit paths of cost - less than or equal to the previous minimum cost. - - Returns - ------- - Generator of tuples (node_edit_path, edge_edit_path, cost) - node_edit_path : list of tuples (u, v) - edge_edit_path : list of tuples ((u1, v1), (u2, v2)) - cost : numeric - - See Also - -------- - graph_edit_distance, optimize_graph_edit_distance, optimal_edit_paths - - References - ---------- - .. [1] Zeina Abu-Aisheh, Romain Raveaux, Jean-Yves Ramel, Patrick - Martineau. An Exact Graph Edit Distance Algorithm for Solving - Pattern Recognition Problems. 4th International Conference on - Pattern Recognition Applications and Methods 2015, Jan 2015, - Lisbon, Portugal. 2015, - <10.5220/0005209202710278>. - https://hal.archives-ouvertes.fr/hal-01168816 - - """ - # TODO: support DiGraph - - import numpy as np - from scipy.optimize import linear_sum_assignment - - class CostMatrix: - def __init__(self, C, lsa_row_ind, lsa_col_ind, ls): - #assert C.shape[0] == len(lsa_row_ind) - #assert C.shape[1] == len(lsa_col_ind) - #assert len(lsa_row_ind) == len(lsa_col_ind) - #assert set(lsa_row_ind) == set(range(len(lsa_row_ind))) - #assert set(lsa_col_ind) == set(range(len(lsa_col_ind))) - #assert ls == C[lsa_row_ind, lsa_col_ind].sum() - self.C = C - self.lsa_row_ind = lsa_row_ind - self.lsa_col_ind = lsa_col_ind - self.ls = ls - - def make_CostMatrix(C, m, n): - #assert(C.shape == (m + n, m + n)) - lsa_row_ind, lsa_col_ind = linear_sum_assignment(C) - - # Fixup dummy assignments: - # each substitution i<->j should have dummy assignment m+j<->n+i - # NOTE: fast reduce of Cv relies on it - #assert len(lsa_row_ind) == len(lsa_col_ind) - indexes = zip(range(len(lsa_row_ind)), lsa_row_ind, lsa_col_ind) - subst_ind = list(k for k, i, j in indexes if i < m and j < n) - indexes = zip(range(len(lsa_row_ind)), lsa_row_ind, lsa_col_ind) - dummy_ind = list(k for k, i, j in indexes if i >= m and j >= n) - #assert len(subst_ind) == len(dummy_ind) - lsa_row_ind[dummy_ind] = lsa_col_ind[subst_ind] + m - lsa_col_ind[dummy_ind] = lsa_row_ind[subst_ind] + n - - return CostMatrix(C, lsa_row_ind, lsa_col_ind, - C[lsa_row_ind, lsa_col_ind].sum()) - - def extract_C(C, i, j, m, n): - #assert(C.shape == (m + n, m + n)) - row_ind = [k in i or k - m in j for k in range(m + n)] - col_ind = [k in j or k - n in i for k in range(m + n)] - return C[row_ind, :][:, col_ind] - - def reduce_C(C, i, j, m, n): - #assert(C.shape == (m + n, m + n)) - row_ind = [k not in i and k - m not in j for k in range(m + n)] - col_ind = [k not in j and k - n not in i for k in range(m + n)] - return C[row_ind, :][:, col_ind] - - def reduce_ind(ind, i): - #assert set(ind) == set(range(len(ind))) - rind = ind[[k not in i for k in ind]] - for k in set(i): - rind[rind >= k] -= 1 - return rind - - def match_edges(u, v, pending_g, pending_h, Ce, matched_uv=[]): - """ - Parameters: - u, v: matched vertices, u=None or v=None for - deletion/insertion - pending_g, pending_h: lists of edges not yet mapped - Ce: CostMatrix of pending edge mappings - matched_uv: partial vertex edit path - list of tuples (u, v) of previously matched vertex - mappings u<->v, u=None or v=None for - deletion/insertion - - Returns: - list of (i, j): indices of edge mappings g<->h - localCe: local CostMatrix of edge mappings - (basically submatrix of Ce at cross of rows i, cols j) - """ - M = len(pending_g) - N = len(pending_h) - #assert Ce.C.shape == (M + N, M + N) - - g_ind = [i for i in range(M) if pending_g[i][:2] == (u, u) or - any(pending_g[i][:2] in ((p, u), (u, p)) - for p, q in matched_uv)] - h_ind = [j for j in range(N) if pending_h[j][:2] == (v, v) or - any(pending_h[j][:2] in ((q, v), (v, q)) - for p, q in matched_uv)] - m = len(g_ind) - n = len(h_ind) - - if m or n: - C = extract_C(Ce.C, g_ind, h_ind, M, N) - #assert C.shape == (m + n, m + n) - - # Forbid structurally invalid matches - # NOTE: inf remembered from Ce construction - for k, i in zip(range(m), g_ind): - g = pending_g[i][:2] - for l, j in zip(range(n), h_ind): - h = pending_h[j][:2] - if nx.is_directed(G1) or nx.is_directed(G2): - if any(g == (p, u) and h == (q, v) or - g == (u, p) and h == (v, q) - for p, q in matched_uv): - continue - else: - if any(g in ((p, u), (u, p)) and h in ((q, v), (v, q)) - for p, q in matched_uv): - continue - if g == (u, u): - continue - if h == (v, v): - continue - C[k, l] = inf - - localCe = make_CostMatrix(C, m, n) - ij = list((g_ind[k] if k < m else M + h_ind[l], - h_ind[l] if l < n else N + g_ind[k]) - for k, l in zip(localCe.lsa_row_ind, localCe.lsa_col_ind) - if k < m or l < n) - - else: - ij = [] - localCe = CostMatrix(np.empty((0, 0)), [], [], 0) - - return ij, localCe - - def reduce_Ce(Ce, ij, m, n): - if len(ij): - i, j = zip(*ij) - m_i = m - sum(1 for t in i if t < m) - n_j = n - sum(1 for t in j if t < n) - return make_CostMatrix(reduce_C(Ce.C, i, j, m, n), m_i, n_j) - else: - return Ce - - def get_edit_ops(matched_uv, pending_u, pending_v, Cv, - pending_g, pending_h, Ce, matched_cost): - """ - Parameters: - matched_uv: partial vertex edit path - list of tuples (u, v) of vertex mappings u<->v, - u=None or v=None for deletion/insertion - pending_u, pending_v: lists of vertices not yet mapped - Cv: CostMatrix of pending vertex mappings - pending_g, pending_h: lists of edges not yet mapped - Ce: CostMatrix of pending edge mappings - matched_cost: cost of partial edit path - - Returns: - sequence of - (i, j): indices of vertex mapping u<->v - Cv_ij: reduced CostMatrix of pending vertex mappings - (basically Cv with row i, col j removed) - list of (x, y): indices of edge mappings g<->h - Ce_xy: reduced CostMatrix of pending edge mappings - (basically Ce with rows x, cols y removed) - cost: total cost of edit operation - NOTE: most promising ops first - """ - m = len(pending_u) - n = len(pending_v) - #assert Cv.C.shape == (m + n, m + n) - - # 1) a vertex mapping from optimal linear sum assignment - i, j = min((k, l) for k, l in zip(Cv.lsa_row_ind, Cv.lsa_col_ind) - if k < m or l < n) - xy, localCe = match_edges(pending_u[i] if i < m else None, - pending_v[j] if j < n else None, - pending_g, pending_h, Ce, matched_uv) - Ce_xy = reduce_Ce(Ce, xy, len(pending_g), len(pending_h)) - #assert Ce.ls <= localCe.ls + Ce_xy.ls - if prune(matched_cost + Cv.ls + localCe.ls + Ce_xy.ls): - pass - else: - # get reduced Cv efficiently - Cv_ij = CostMatrix(reduce_C(Cv.C, (i,), (j,), m, n), - reduce_ind(Cv.lsa_row_ind, (i, m + j)), - reduce_ind(Cv.lsa_col_ind, (j, n + i)), - Cv.ls - Cv.C[i, j]) - yield (i, j), Cv_ij, xy, Ce_xy, Cv.C[i, j] + localCe.ls - - # 2) other candidates, sorted by lower-bound cost estimate - other = list() - fixed_i, fixed_j = i, j - if m <= n: - candidates = ((t, fixed_j) for t in range(m + n) - if t != fixed_i and (t < m or t == m + fixed_j)) - else: - candidates = ((fixed_i, t) for t in range(m + n) - if t != fixed_j and (t < n or t == n + fixed_i)) - for i, j in candidates: - if prune(matched_cost + Cv.C[i, j] + Ce.ls): - continue - Cv_ij = make_CostMatrix(reduce_C(Cv.C, (i,), (j,), m, n), - m - 1 if i < m else m, - n - 1 if j < n else n) - #assert Cv.ls <= Cv.C[i, j] + Cv_ij.ls - if prune(matched_cost + Cv.C[i, j] + Cv_ij.ls + Ce.ls): - continue - xy, localCe = match_edges(pending_u[i] if i < m else None, - pending_v[j] if j < n else None, - pending_g, pending_h, Ce, matched_uv) - if prune(matched_cost + Cv.C[i, j] + Cv_ij.ls + localCe.ls): - continue - Ce_xy = reduce_Ce(Ce, xy, len(pending_g), len(pending_h)) - #assert Ce.ls <= localCe.ls + Ce_xy.ls - if prune(matched_cost + Cv.C[i, j] + Cv_ij.ls + localCe.ls + - Ce_xy.ls): - continue - other.append(((i, j), Cv_ij, xy, Ce_xy, Cv.C[i, j] + localCe.ls)) - - # yield from - for t in sorted(other, key=lambda t: t[4] + t[1].ls + t[3].ls): - yield t - - def get_edit_paths(matched_uv, pending_u, pending_v, Cv, - matched_gh, pending_g, pending_h, Ce, matched_cost): - """ - Parameters: - matched_uv: partial vertex edit path - list of tuples (u, v) of vertex mappings u<->v, - u=None or v=None for deletion/insertion - pending_u, pending_v: lists of vertices not yet mapped - Cv: CostMatrix of pending vertex mappings - matched_gh: partial edge edit path - list of tuples (g, h) of edge mappings g<->h, - g=None or h=None for deletion/insertion - pending_g, pending_h: lists of edges not yet mapped - Ce: CostMatrix of pending edge mappings - matched_cost: cost of partial edit path - - Returns: - sequence of (vertex_path, edge_path, cost) - vertex_path: complete vertex edit path - list of tuples (u, v) of vertex mappings u<->v, - u=None or v=None for deletion/insertion - edge_path: complete edge edit path - list of tuples (g, h) of edge mappings g<->h, - g=None or h=None for deletion/insertion - cost: total cost of edit path - NOTE: path costs are non-increasing - """ - #debug_print('matched-uv:', matched_uv) - #debug_print('matched-gh:', matched_gh) - #debug_print('matched-cost:', matched_cost) - #debug_print('pending-u:', pending_u) - #debug_print('pending-v:', pending_v) - #debug_print(Cv.C) - #assert list(sorted(G1.nodes)) == list(sorted(list(u for u, v in matched_uv if u is not None) + pending_u)) - #assert list(sorted(G2.nodes)) == list(sorted(list(v for u, v in matched_uv if v is not None) + pending_v)) - #debug_print('pending-g:', pending_g) - #debug_print('pending-h:', pending_h) - #debug_print(Ce.C) - #assert list(sorted(G1.edges)) == list(sorted(list(g for g, h in matched_gh if g is not None) + pending_g)) - #assert list(sorted(G2.edges)) == list(sorted(list(h for g, h in matched_gh if h is not None) + pending_h)) - #debug_print() - - if prune(matched_cost + Cv.ls + Ce.ls): - return - - if not max(len(pending_u), len(pending_v)): - #assert not len(pending_g) - #assert not len(pending_h) - # path completed! - #assert matched_cost <= maxcost.value - maxcost.value = min(maxcost.value, matched_cost) - yield matched_uv, matched_gh, matched_cost - - else: - edit_ops = get_edit_ops(matched_uv, pending_u, pending_v, Cv, - pending_g, pending_h, Ce, matched_cost) - for ij, Cv_ij, xy, Ce_xy, edit_cost in edit_ops: - i, j = ij - #assert Cv.C[i, j] + sum(Ce.C[t] for t in xy) == edit_cost - if prune(matched_cost + edit_cost + Cv_ij.ls + Ce_xy.ls): - continue - - # dive deeper - u = pending_u.pop(i) if i < len(pending_u) else None - v = pending_v.pop(j) if j < len(pending_v) else None - matched_uv.append((u, v)) - for x, y in xy: - len_g = len(pending_g) - len_h = len(pending_h) - matched_gh.append((pending_g[x] if x < len_g else None, - pending_h[y] if y < len_h else None)) - sortedx = list(sorted(x for x, y in xy)) - sortedy = list(sorted(y for x, y in xy)) - G = list((pending_g.pop(x) if x < len(pending_g) else None) - for x in reversed(sortedx)) - H = list((pending_h.pop(y) if y < len(pending_h) else None) - for y in reversed(sortedy)) - - # yield from - for t in get_edit_paths(matched_uv, pending_u, pending_v, - Cv_ij, - matched_gh, pending_g, pending_h, - Ce_xy, - matched_cost + edit_cost): - yield t - - # backtrack - if u is not None: - pending_u.insert(i, u) - if v is not None: - pending_v.insert(j, v) - matched_uv.pop() - for x, g in zip(sortedx, reversed(G)): - if g is not None: - pending_g.insert(x, g) - for y, h in zip(sortedy, reversed(H)): - if h is not None: - pending_h.insert(y, h) - for t in xy: - matched_gh.pop() - - # Initialization - - pending_u = list(G1.nodes) - pending_v = list(G2.nodes) - - # cost matrix of vertex mappings - m = len(pending_u) - n = len(pending_v) - C = np.zeros((m + n, m + n)) - if node_subst_cost: - C[0:m, 0:n] = np.array([node_subst_cost(G1.nodes[u], G2.nodes[v]) - for u in pending_u for v in pending_v] - ).reshape(m, n) - elif node_match: - C[0:m, 0:n] = np.array([1 - int(node_match(G1.nodes[u], G2.nodes[v])) - for u in pending_u for v in pending_v] - ).reshape(m, n) - else: - # all zeroes - pass - #assert not min(m, n) or C[0:m, 0:n].min() >= 0 - if node_del_cost: - del_costs = [node_del_cost(G1.nodes[u]) for u in pending_u] - else: - del_costs = [1] * len(pending_u) - #assert not m or min(del_costs) >= 0 - if node_ins_cost: - ins_costs = [node_ins_cost(G2.nodes[v]) for v in pending_v] - else: - ins_costs = [1] * len(pending_v) - #assert not n or min(ins_costs) >= 0 - inf = C[0:m, 0:n].sum() + sum(del_costs) + sum(ins_costs) + 1 - C[0:m, n:n + m] = np.array([del_costs[i] if i == j else inf - for i in range(m) for j in range(m)] - ).reshape(m, m) - C[m:m + n, 0:n] = np.array([ins_costs[i] if i == j else inf - for i in range(n) for j in range(n)] - ).reshape(n, n) - Cv = make_CostMatrix(C, m, n) - #debug_print('Cv: {} x {}'.format(m, n)) - #debug_print(Cv.C) - - pending_g = list(G1.edges) - pending_h = list(G2.edges) - - # cost matrix of edge mappings - m = len(pending_g) - n = len(pending_h) - C = np.zeros((m + n, m + n)) - if edge_subst_cost: - C[0:m, 0:n] = np.array([edge_subst_cost(G1.edges[g], G2.edges[h]) - for g in pending_g for h in pending_h] - ).reshape(m, n) - elif edge_match: - C[0:m, 0:n] = np.array([1 - int(edge_match(G1.edges[g], G2.edges[h])) - for g in pending_g for h in pending_h] - ).reshape(m, n) - else: - # all zeroes - pass - #assert not min(m, n) or C[0:m, 0:n].min() >= 0 - if edge_del_cost: - del_costs = [edge_del_cost(G1.edges[g]) for g in pending_g] - else: - del_costs = [1] * len(pending_g) - #assert not m or min(del_costs) >= 0 - if edge_ins_cost: - ins_costs = [edge_ins_cost(G2.edges[h]) for h in pending_h] - else: - ins_costs = [1] * len(pending_h) - #assert not n or min(ins_costs) >= 0 - inf = C[0:m, 0:n].sum() + sum(del_costs) + sum(ins_costs) + 1 - C[0:m, n:n + m] = np.array([del_costs[i] if i == j else inf - for i in range(m) for j in range(m)] - ).reshape(m, m) - C[m:m + n, 0:n] = np.array([ins_costs[i] if i == j else inf - for i in range(n) for j in range(n)] - ).reshape(n, n) - Ce = make_CostMatrix(C, m, n) - #debug_print('Ce: {} x {}'.format(m, n)) - #debug_print(Ce.C) - #debug_print() - - class MaxCost: - def __init__(self): - # initial upper-bound estimate - # NOTE: should work for empty graph - self.value = Cv.C.sum() + Ce.C.sum() + 1 - maxcost = MaxCost() - - def prune(cost): - if upper_bound is not None: - if cost > upper_bound: - return True - if cost > maxcost.value: - return True - elif strictly_decreasing and cost >= maxcost.value: - return True - - # Now go! - - for vertex_path, edge_path, cost in \ - get_edit_paths([], pending_u, pending_v, Cv, - [], pending_g, pending_h, Ce, 0): - #assert sorted(G1.nodes) == sorted(u for u, v in vertex_path if u is not None) - #assert sorted(G2.nodes) == sorted(v for u, v in vertex_path if v is not None) - #assert sorted(G1.edges) == sorted(g for g, h in edge_path if g is not None) - #assert sorted(G2.edges) == sorted(h for g, h in edge_path if h is not None) - #print(vertex_path, edge_path, cost, file = sys.stderr) - #assert cost == maxcost.value - yield list(vertex_path), list(edge_path), cost - - -def _is_close(d1, d2, atolerance=0, rtolerance=0): - """Determines whether two adjacency matrices are within - a provided tolerance. - - Parameters - ---------- - d1 : dict - Adjacency dictionary - - d2 : dict - Adjacency dictionary - - atolerance : float - Some scalar tolerance value to determine closeness - - rtolerance : float - A scalar tolerance value that will be some proportion - of ``d2``'s value - - Returns - ------- - closeness : bool - If all of the nodes within ``d1`` and ``d2`` are within - a predefined tolerance, they are considered "close" and - this method will return True. Otherwise, this method will - return False. - - """ - # Pre-condition: d1 and d2 have the same keys at each level if they - # are dictionaries. - if not isinstance(d1, dict) and not isinstance(d2, dict): - return abs(d1 - d2) <= atolerance + rtolerance * abs(d2) - return all(all(_is_close(d1[u][v], d2[u][v]) for v in d1[u]) for u in d1) - - -def simrank_similarity(G, source=None, target=None, importance_factor=0.9, - max_iterations=100, tolerance=1e-4): - """Returns the SimRank similarity of nodes in the graph ``G``. - - SimRank is a similarity metric that says "two objects are considered - to be similar if they are referenced by similar objects." [1]_. - - The pseudo-code definition from the paper is:: - - def simrank(G, u, v): - in_neighbors_u = G.predecessors(u) - in_neighbors_v = G.predecessors(v) - scale = C / (len(in_neighbors_u) * len(in_neighbors_v)) - return scale * sum(simrank(G, w, x) - for w, x in product(in_neighbors_u, - in_neighbors_v)) - - where ``G`` is the graph, ``u`` is the source, ``v`` is the target, - and ``C`` is a float decay or importance factor between 0 and 1. - - The SimRank algorithm for determining node similarity is defined in - [2]_. - - Parameters - ---------- - G : NetworkX graph - A NetworkX graph - - source : node - If this is specified, the returned dictionary maps each node - ``v`` in the graph to the similarity between ``source`` and - ``v``. - - target : node - If both ``source`` and ``target`` are specified, the similarity - value between ``source`` and ``target`` is returned. If - ``target`` is specified but ``source`` is not, this argument is - ignored. - - importance_factor : float - The relative importance of indirect neighbors with respect to - direct neighbors. - - max_iterations : integer - Maximum number of iterations. - - tolerance : float - Error tolerance used to check convergence. When an iteration of - the algorithm finds that no similarity value changes more than - this amount, the algorithm halts. - - Returns - ------- - similarity : dictionary or float - If ``source`` and ``target`` are both ``None``, this returns a - dictionary of dictionaries, where keys are node pairs and value - are similarity of the pair of nodes. - - If ``source`` is not ``None`` but ``target`` is, this returns a - dictionary mapping node to the similarity of ``source`` and that - node. - - If neither ``source`` nor ``target`` is ``None``, this returns - the similarity value for the given pair of nodes. - - Examples - -------- - If the nodes of the graph are numbered from zero to *n - 1*, where *n* - is the number of nodes in the graph, you can create a SimRank matrix - from the return value of this function where the node numbers are - the row and column indices of the matrix:: - - >>> import networkx as nx - >>> from numpy import array - >>> G = nx.cycle_graph(4) - >>> sim = nx.simrank_similarity(G) - >>> lol = [[sim[u][v] for v in sorted(sim[u])] for u in sorted(sim)] - >>> sim_array = array(lol) - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/SimRank - .. [2] G. Jeh and J. Widom. - "SimRank: a measure of structural-context similarity", - In KDD'02: Proceedings of the Eighth ACM SIGKDD - International Conference on Knowledge Discovery and Data Mining, - pp. 538--543. ACM Press, 2002. - """ - prevsim = None - - # build up our similarity adjacency dictionary output - newsim = {u: {v: 1 if u == v else 0 for v in G} for u in G} - - # These functions compute the update to the similarity value of the nodes - # `u` and `v` with respect to the previous similarity values. - avg_sim = lambda s: sum(newsim[w][x] for (w, x) in s) / len(s) if s else 0.0 - sim = lambda u, v: importance_factor * avg_sim(list(product(G[u], G[v]))) - - for _ in range(max_iterations): - if prevsim and _is_close(prevsim, newsim, tolerance): - break - prevsim = newsim - newsim = {u: {v: sim(u, v) if u is not v else 1 - for v in newsim[u]} for u in newsim} - - if source is not None and target is not None: - return newsim[source][target] - if source is not None: - return newsim[source] - return newsim - - -def simrank_similarity_numpy(G, source=None, target=None, importance_factor=0.9, - max_iterations=100, tolerance=1e-4): - """Calculate SimRank of nodes in ``G`` using matrices with ``numpy``. - - The SimRank algorithm for determining node similarity is defined in - [1]_. - - Parameters - ---------- - G : NetworkX graph - A NetworkX graph - - source : node - If this is specified, the returned dictionary maps each node - ``v`` in the graph to the similarity between ``source`` and - ``v``. - - target : node - If both ``source`` and ``target`` are specified, the similarity - value between ``source`` and ``target`` is returned. If - ``target`` is specified but ``source`` is not, this argument is - ignored. - - importance_factor : float - The relative importance of indirect neighbors with respect to - direct neighbors. - - max_iterations : integer - Maximum number of iterations. - - tolerance : float - Error tolerance used to check convergence. When an iteration of - the algorithm finds that no similarity value changes more than - this amount, the algorithm halts. - - Returns - ------- - similarity : dictionary or float - If ``source`` and ``target`` are both ``None``, this returns a - dictionary of dictionaries, where keys are node pairs and value - are similarity of the pair of nodes. - - If ``source`` is not ``None`` but ``target`` is, this returns a - dictionary mapping node to the similarity of ``source`` and that - node. - - If neither ``source`` nor ``target`` is ``None``, this returns - the similarity value for the given pair of nodes. - - Examples - -------- - >>> import networkx as nx - >>> from numpy import array - >>> G = nx.cycle_graph(4) - >>> sim = nx.simrank_similarity_numpy(G) - - References - ---------- - .. [1] G. Jeh and J. Widom. - "SimRank: a measure of structural-context similarity", - In KDD'02: Proceedings of the Eighth ACM SIGKDD - International Conference on Knowledge Discovery and Data Mining, - pp. 538--543. ACM Press, 2002. - """ - # This algorithm follows roughly - # - # S = max{C * (A.T * S * A), I} - # - # where C is the importance factor, A is the column normalized - # adjacency matrix, and I is the identity matrix. - import numpy as np - adjacency_matrix = nx.to_numpy_array(G) - - # column-normalize the ``adjacency_matrix`` - adjacency_matrix /= adjacency_matrix.sum(axis=0) - - newsim = np.eye(adjacency_matrix.shape[0], dtype=np.float64) - for _ in range(max_iterations): - prevsim = np.copy(newsim) - newsim = importance_factor * np.matmul( - np.matmul(adjacency_matrix.T, prevsim), adjacency_matrix) - np.fill_diagonal(newsim, 1.0) - - if np.allclose(prevsim, newsim, atol=tolerance): - break - - if source is not None and target is not None: - return newsim[source, target] - if source is not None: - return newsim[source] - return newsim - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/algorithms/simple_paths.py b/extensions/fablabchemnitz/networkx/algorithms/simple_paths.py deleted file mode 100644 index d0785351..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/simple_paths.py +++ /dev/null @@ -1,813 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2012 by -# Sergio Nery Simoes -# All rights reserved. -# BSD license. -import collections -from heapq import heappush, heappop -from itertools import count - -import networkx as nx -from networkx.utils import not_implemented_for -from networkx.utils import pairwise - -__author__ = """\n""".join(['Sérgio Nery Simões ', - 'Aric Hagberg ', - 'Andrey Paramonov', - 'Jordi Torrents ']) - -__all__ = [ - 'all_simple_paths', - 'is_simple_path', - 'shortest_simple_paths', -] - - -def is_simple_path(G, nodes): - """Returns True if and only if the given nodes form a simple path in - `G`. - - A *simple path* in a graph is a nonempty sequence of nodes in which - no node appears more than once in the sequence, and each adjacent - pair of nodes in the sequence is adjacent in the graph. - - Parameters - ---------- - nodes : list - A list of one or more nodes in the graph `G`. - - Returns - ------- - bool - Whether the given list of nodes represents a simple path in - `G`. - - Notes - ----- - A list of zero nodes is not a path and a list of one node is a - path. Here's an explanation why. - - This function operates on *node paths*. One could also consider - *edge paths*. There is a bijection between node paths and edge - paths. - - The *length of a path* is the number of edges in the path, so a list - of nodes of length *n* corresponds to a path of length *n* - 1. - Thus the smallest edge path would be a list of zero edges, the empty - path. This corresponds to a list of one node. - - To convert between a node path and an edge path, you can use code - like the following:: - - >>> from networkx.utils import pairwise - >>> nodes = [0, 1, 2, 3] - >>> edges = list(pairwise(nodes)) - >>> edges - [(0, 1), (1, 2), (2, 3)] - >>> nodes = [edges[0][0]] + [v for u, v in edges] - >>> nodes - [0, 1, 2, 3] - - Examples - -------- - >>> G = nx.cycle_graph(4) - >>> nx.is_simple_path(G, [2, 3, 0]) - True - >>> nx.is_simple_path(G, [0, 2]) - False - - """ - # The empty list is not a valid path. Could also return - # NetworkXPointlessConcept here. - if len(nodes) == 0: - return False - # If the list is a single node, just check that the node is actually - # in the graph. - if len(nodes) == 1: - return nodes[0] in G - # Test that no node appears more than once, and that each - # adjacent pair of nodes is adjacent. - return (len(set(nodes)) == len(nodes) and - all(v in G[u] for u, v in pairwise(nodes))) - - -def all_simple_paths(G, source, target, cutoff=None): - """Generate all simple paths in the graph G from source to target. - - A simple path is a path with no repeated nodes. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path - - target : nodes - Single node or iterable of nodes at which to end path - - cutoff : integer, optional - Depth to stop the search. Only paths of length <= cutoff are returned. - - Returns - ------- - path_generator: generator - A generator that produces lists of simple paths. If there are no paths - between the source and target within the given cutoff the generator - produces no output. - - Examples - -------- - This iterator generates lists of nodes:: - - >>> G = nx.complete_graph(4) - >>> for path in nx.all_simple_paths(G, source=0, target=3): - ... print(path) - ... - [0, 1, 2, 3] - [0, 1, 3] - [0, 2, 1, 3] - [0, 2, 3] - [0, 3] - - You can generate only those paths that are shorter than a certain - length by using the `cutoff` keyword argument:: - - >>> paths = nx.all_simple_paths(G, source=0, target=3, cutoff=2) - >>> print(list(paths)) - [[0, 1, 3], [0, 2, 3], [0, 3]] - - To get each path as the corresponding list of edges, you can use the - :func:`networkx.utils.pairwise` helper function:: - - >>> paths = nx.all_simple_paths(G, source=0, target=3) - >>> for path in map(nx.utils.pairwise, paths): - ... print(list(path)) - [(0, 1), (1, 2), (2, 3)] - [(0, 1), (1, 3)] - [(0, 2), (2, 1), (1, 3)] - [(0, 2), (2, 3)] - [(0, 3)] - - Pass an iterable of nodes as target to generate all paths ending in any of several nodes:: - - >>> G = nx.complete_graph(4) - >>> for path in nx.all_simple_paths(G, source=0, target=[3, 2]): - ... print(path) - ... - [0, 1, 2] - [0, 1, 2, 3] - [0, 1, 3] - [0, 1, 3, 2] - [0, 2] - [0, 2, 1, 3] - [0, 2, 3] - [0, 3] - [0, 3, 1, 2] - [0, 3, 2] - - Iterate over each path from the root nodes to the leaf nodes in a - directed acyclic graph using a functional programming approach:: - - >>> from itertools import chain - >>> from itertools import product - >>> from itertools import starmap - >>> from functools import partial - >>> - >>> chaini = chain.from_iterable - >>> - >>> G = nx.DiGraph([(0, 1), (1, 2), (0, 3), (3, 2)]) - >>> roots = (v for v, d in G.in_degree() if d == 0) - >>> leaves = (v for v, d in G.out_degree() if d == 0) - >>> all_paths = partial(nx.all_simple_paths, G) - >>> list(chaini(starmap(all_paths, product(roots, leaves)))) - [[0, 1, 2], [0, 3, 2]] - - The same list computed using an iterative approach:: - - >>> G = nx.DiGraph([(0, 1), (1, 2), (0, 3), (3, 2)]) - >>> roots = (v for v, d in G.in_degree() if d == 0) - >>> leaves = (v for v, d in G.out_degree() if d == 0) - >>> all_paths = [] - >>> for root in roots: - ... for leaf in leaves: - ... paths = nx.all_simple_paths(G, root, leaf) - ... all_paths.extend(paths) - >>> all_paths - [[0, 1, 2], [0, 3, 2]] - - Iterate over each path from the root nodes to the leaf nodes in a - directed acyclic graph passing all leaves together to avoid unnecessary - compute:: - - >>> G = nx.DiGraph([(0, 1), (2, 1), (1, 3), (1, 4)]) - >>> roots = (v for v, d in G.in_degree() if d == 0) - >>> leaves = [v for v, d in G.out_degree() if d == 0] - >>> all_paths = [] - >>> for root in roots: - ... paths = nx.all_simple_paths(G, root, leaves) - ... all_paths.extend(paths) - >>> all_paths - [[0, 1, 3], [0, 1, 4], [2, 1, 3], [2, 1, 4]] - - Notes - ----- - This algorithm uses a modified depth-first search to generate the - paths [1]_. A single path can be found in $O(V+E)$ time but the - number of simple paths in a graph can be very large, e.g. $O(n!)$ in - the complete graph of order $n$. - - References - ---------- - .. [1] R. Sedgewick, "Algorithms in C, Part 5: Graph Algorithms", - Addison Wesley Professional, 3rd ed., 2001. - - See Also - -------- - all_shortest_paths, shortest_path - - """ - if source not in G: - raise nx.NodeNotFound('source node %s not in graph' % source) - if target in G: - targets = {target} - else: - try: - targets = set(target) - except TypeError: - raise nx.NodeNotFound('target node %s not in graph' % target) - if source in targets: - return [] - if cutoff is None: - cutoff = len(G) - 1 - if cutoff < 1: - return [] - if G.is_multigraph(): - return _all_simple_paths_multigraph(G, source, targets, cutoff) - else: - return _all_simple_paths_graph(G, source, targets, cutoff) - - -def _all_simple_paths_graph(G, source, targets, cutoff): - visited = collections.OrderedDict.fromkeys([source]) - stack = [iter(G[source])] - while stack: - children = stack[-1] - child = next(children, None) - if child is None: - stack.pop() - visited.popitem() - elif len(visited) < cutoff: - if child in visited: - continue - if child in targets: - yield list(visited) + [child] - visited[child] = None - if targets - set(visited.keys()): # expand stack until find all targets - stack.append(iter(G[child])) - else: - visited.popitem() # maybe other ways to child - else: # len(visited) == cutoff: - for target in (targets & (set(children) | {child})) - set(visited.keys()): - yield list(visited) + [target] - stack.pop() - visited.popitem() - - -def _all_simple_paths_multigraph(G, source, targets, cutoff): - visited = collections.OrderedDict.fromkeys([source]) - stack = [(v for u, v in G.edges(source))] - while stack: - children = stack[-1] - child = next(children, None) - if child is None: - stack.pop() - visited.popitem() - elif len(visited) < cutoff: - if child in visited: - continue - if child in targets: - yield list(visited) + [child] - visited[child] = None - if targets - set(visited.keys()): - stack.append((v for u, v in G.edges(child))) - else: - visited.popitem() - else: # len(visited) == cutoff: - for target in targets - set(visited.keys()): - count = ([child] + list(children)).count(target) - for i in range(count): - yield list(visited) + [target] - stack.pop() - visited.popitem() - - -@not_implemented_for('multigraph') -def shortest_simple_paths(G, source, target, weight=None): - """Generate all simple paths in the graph G from source to target, - starting from shortest ones. - - A simple path is a path with no repeated nodes. - - If a weighted shortest path search is to be used, no negative weights - are allowed. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for path - - target : node - Ending node for path - - weight : string - Name of the edge attribute to be used as a weight. If None all - edges are considered to have unit weight. Default value None. - - Returns - ------- - path_generator: generator - A generator that produces lists of simple paths, in order from - shortest to longest. - - Raises - ------ - NetworkXNoPath - If no path exists between source and target. - - NetworkXError - If source or target nodes are not in the input graph. - - NetworkXNotImplemented - If the input graph is a Multi[Di]Graph. - - Examples - -------- - - >>> G = nx.cycle_graph(7) - >>> paths = list(nx.shortest_simple_paths(G, 0, 3)) - >>> print(paths) - [[0, 1, 2, 3], [0, 6, 5, 4, 3]] - - You can use this function to efficiently compute the k shortest/best - paths between two nodes. - - >>> from itertools import islice - >>> def k_shortest_paths(G, source, target, k, weight=None): - ... return list(islice(nx.shortest_simple_paths(G, source, target, weight=weight), k)) - >>> for path in k_shortest_paths(G, 0, 3, 2): - ... print(path) - [0, 1, 2, 3] - [0, 6, 5, 4, 3] - - Notes - ----- - This procedure is based on algorithm by Jin Y. Yen [1]_. Finding - the first $K$ paths requires $O(KN^3)$ operations. - - See Also - -------- - all_shortest_paths - shortest_path - all_simple_paths - - References - ---------- - .. [1] Jin Y. Yen, "Finding the K Shortest Loopless Paths in a - Network", Management Science, Vol. 17, No. 11, Theory Series - (Jul., 1971), pp. 712-716. - - """ - if source not in G: - raise nx.NodeNotFound('source node %s not in graph' % source) - - if target not in G: - raise nx.NodeNotFound('target node %s not in graph' % target) - - if weight is None: - length_func = len - shortest_path_func = _bidirectional_shortest_path - else: - def length_func(path): - return sum(G.adj[u][v][weight] for (u, v) in zip(path, path[1:])) - shortest_path_func = _bidirectional_dijkstra - - listA = list() - listB = PathBuffer() - prev_path = None - while True: - if not prev_path: - length, path = shortest_path_func(G, source, target, weight=weight) - listB.push(length, path) - else: - ignore_nodes = set() - ignore_edges = set() - for i in range(1, len(prev_path)): - root = prev_path[:i] - root_length = length_func(root) - for path in listA: - if path[:i] == root: - ignore_edges.add((path[i - 1], path[i])) - try: - length, spur = shortest_path_func(G, root[-1], target, - ignore_nodes=ignore_nodes, - ignore_edges=ignore_edges, - weight=weight) - path = root[:-1] + spur - listB.push(root_length + length, path) - except nx.NetworkXNoPath: - pass - ignore_nodes.add(root[-1]) - - if listB: - path = listB.pop() - yield path - listA.append(path) - prev_path = path - else: - break - - -class PathBuffer(object): - - def __init__(self): - self.paths = set() - self.sortedpaths = list() - self.counter = count() - - def __len__(self): - return len(self.sortedpaths) - - def push(self, cost, path): - hashable_path = tuple(path) - if hashable_path not in self.paths: - heappush(self.sortedpaths, (cost, next(self.counter), path)) - self.paths.add(hashable_path) - - def pop(self): - (cost, num, path) = heappop(self.sortedpaths) - hashable_path = tuple(path) - self.paths.remove(hashable_path) - return path - - -def _bidirectional_shortest_path(G, source, target, - ignore_nodes=None, - ignore_edges=None, - weight=None): - """Returns the shortest path between source and target ignoring - nodes and edges in the containers ignore_nodes and ignore_edges. - - This is a custom modification of the standard bidirectional shortest - path implementation at networkx.algorithms.unweighted - - Parameters - ---------- - G : NetworkX graph - - source : node - starting node for path - - target : node - ending node for path - - ignore_nodes : container of nodes - nodes to ignore, optional - - ignore_edges : container of edges - edges to ignore, optional - - weight : None - This function accepts a weight argument for convenience of - shortest_simple_paths function. It will be ignored. - - Returns - ------- - path: list - List of nodes in a path from source to target. - - Raises - ------ - NetworkXNoPath - If no path exists between source and target. - - See Also - -------- - shortest_path - - """ - # call helper to do the real work - results = _bidirectional_pred_succ(G, source, target, ignore_nodes, ignore_edges) - pred, succ, w = results - - # build path from pred+w+succ - path = [] - # from w to target - while w is not None: - path.append(w) - w = succ[w] - # from source to w - w = pred[path[0]] - while w is not None: - path.insert(0, w) - w = pred[w] - - return len(path), path - - -def _bidirectional_pred_succ(G, source, target, ignore_nodes=None, ignore_edges=None): - """Bidirectional shortest path helper. - Returns (pred,succ,w) where - pred is a dictionary of predecessors from w to the source, and - succ is a dictionary of successors from w to the target. - """ - # does BFS from both source and target and meets in the middle - if ignore_nodes and (source in ignore_nodes or target in ignore_nodes): - raise nx.NetworkXNoPath("No path between %s and %s." % (source, target)) - if target == source: - return ({target: None}, {source: None}, source) - - # handle either directed or undirected - if G.is_directed(): - Gpred = G.predecessors - Gsucc = G.successors - else: - Gpred = G.neighbors - Gsucc = G.neighbors - - # support optional nodes filter - if ignore_nodes: - def filter_iter(nodes): - def iterate(v): - for w in nodes(v): - if w not in ignore_nodes: - yield w - return iterate - - Gpred = filter_iter(Gpred) - Gsucc = filter_iter(Gsucc) - - # support optional edges filter - if ignore_edges: - if G.is_directed(): - def filter_pred_iter(pred_iter): - def iterate(v): - for w in pred_iter(v): - if (w, v) not in ignore_edges: - yield w - return iterate - - def filter_succ_iter(succ_iter): - def iterate(v): - for w in succ_iter(v): - if (v, w) not in ignore_edges: - yield w - return iterate - - Gpred = filter_pred_iter(Gpred) - Gsucc = filter_succ_iter(Gsucc) - - else: - def filter_iter(nodes): - def iterate(v): - for w in nodes(v): - if (v, w) not in ignore_edges \ - and (w, v) not in ignore_edges: - yield w - return iterate - - Gpred = filter_iter(Gpred) - Gsucc = filter_iter(Gsucc) - - # predecesssor and successors in search - pred = {source: None} - succ = {target: None} - - # initialize fringes, start with forward - forward_fringe = [source] - reverse_fringe = [target] - - while forward_fringe and reverse_fringe: - if len(forward_fringe) <= len(reverse_fringe): - this_level = forward_fringe - forward_fringe = [] - for v in this_level: - for w in Gsucc(v): - if w not in pred: - forward_fringe.append(w) - pred[w] = v - if w in succ: - # found path - return pred, succ, w - else: - this_level = reverse_fringe - reverse_fringe = [] - for v in this_level: - for w in Gpred(v): - if w not in succ: - succ[w] = v - reverse_fringe.append(w) - if w in pred: - # found path - return pred, succ, w - - raise nx.NetworkXNoPath("No path between %s and %s." % (source, target)) - - -def _bidirectional_dijkstra(G, source, target, weight='weight', - ignore_nodes=None, ignore_edges=None): - """Dijkstra's algorithm for shortest paths using bidirectional search. - - This function returns the shortest path between source and target - ignoring nodes and edges in the containers ignore_nodes and - ignore_edges. - - This is a custom modification of the standard Dijkstra bidirectional - shortest path implementation at networkx.algorithms.weighted - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node. - - target : node - Ending node. - - weight: string, optional (default='weight') - Edge data key corresponding to the edge weight - - ignore_nodes : container of nodes - nodes to ignore, optional - - ignore_edges : container of edges - edges to ignore, optional - - Returns - ------- - length : number - Shortest path length. - - Returns a tuple of two dictionaries keyed by node. - The first dictionary stores distance from the source. - The second stores the path from the source to that node. - - Raises - ------ - NetworkXNoPath - If no path exists between source and target. - - Notes - ----- - Edge weight attributes must be numerical. - Distances are calculated as sums of weighted edges traversed. - - In practice bidirectional Dijkstra is much more than twice as fast as - ordinary Dijkstra. - - Ordinary Dijkstra expands nodes in a sphere-like manner from the - source. The radius of this sphere will eventually be the length - of the shortest path. Bidirectional Dijkstra will expand nodes - from both the source and the target, making two spheres of half - this radius. Volume of the first sphere is pi*r*r while the - others are 2*pi*r/2*r/2, making up half the volume. - - This algorithm is not guaranteed to work if edge weights - are negative or are floating point numbers - (overflows and roundoff errors can cause problems). - - See Also - -------- - shortest_path - shortest_path_length - """ - if ignore_nodes and (source in ignore_nodes or target in ignore_nodes): - raise nx.NetworkXNoPath("No path between %s and %s." % (source, target)) - if source == target: - return (0, [source]) - - # handle either directed or undirected - if G.is_directed(): - Gpred = G.predecessors - Gsucc = G.successors - else: - Gpred = G.neighbors - Gsucc = G.neighbors - - # support optional nodes filter - if ignore_nodes: - def filter_iter(nodes): - def iterate(v): - for w in nodes(v): - if w not in ignore_nodes: - yield w - return iterate - - Gpred = filter_iter(Gpred) - Gsucc = filter_iter(Gsucc) - - # support optional edges filter - if ignore_edges: - if G.is_directed(): - def filter_pred_iter(pred_iter): - def iterate(v): - for w in pred_iter(v): - if (w, v) not in ignore_edges: - yield w - return iterate - - def filter_succ_iter(succ_iter): - def iterate(v): - for w in succ_iter(v): - if (v, w) not in ignore_edges: - yield w - return iterate - - Gpred = filter_pred_iter(Gpred) - Gsucc = filter_succ_iter(Gsucc) - - else: - def filter_iter(nodes): - def iterate(v): - for w in nodes(v): - if (v, w) not in ignore_edges \ - and (w, v) not in ignore_edges: - yield w - return iterate - - Gpred = filter_iter(Gpred) - Gsucc = filter_iter(Gsucc) - - push = heappush - pop = heappop - # Init: Forward Backward - dists = [{}, {}] # dictionary of final distances - paths = [{source: [source]}, {target: [target]}] # dictionary of paths - fringe = [[], []] # heap of (distance, node) tuples for - # extracting next node to expand - seen = [{source: 0}, {target: 0}] # dictionary of distances to - # nodes seen - c = count() - # initialize fringe heap - push(fringe[0], (0, next(c), source)) - push(fringe[1], (0, next(c), target)) - # neighs for extracting correct neighbor information - neighs = [Gsucc, Gpred] - # variables to hold shortest discovered path - #finaldist = 1e30000 - finalpath = [] - dir = 1 - while fringe[0] and fringe[1]: - # choose direction - # dir == 0 is forward direction and dir == 1 is back - dir = 1 - dir - # extract closest to expand - (dist, _, v) = pop(fringe[dir]) - if v in dists[dir]: - # Shortest path to v has already been found - continue - # update distance - dists[dir][v] = dist # equal to seen[dir][v] - if v in dists[1 - dir]: - # if we have scanned v in both directions we are done - # we have now discovered the shortest path - return (finaldist, finalpath) - - for w in neighs[dir](v): - if(dir == 0): # forward - if G.is_multigraph(): - minweight = min((dd.get(weight, 1) - for k, dd in G[v][w].items())) - else: - minweight = G[v][w].get(weight, 1) - vwLength = dists[dir][v] + minweight # G[v][w].get(weight,1) - else: # back, must remember to change v,w->w,v - if G.is_multigraph(): - minweight = min((dd.get(weight, 1) - for k, dd in G[w][v].items())) - else: - minweight = G[w][v].get(weight, 1) - vwLength = dists[dir][v] + minweight # G[w][v].get(weight,1) - - if w in dists[dir]: - if vwLength < dists[dir][w]: - raise ValueError( - "Contradictory paths found: negative weights?") - elif w not in seen[dir] or vwLength < seen[dir][w]: - # relaxing - seen[dir][w] = vwLength - push(fringe[dir], (vwLength, next(c), w)) - paths[dir][w] = paths[dir][v] + [w] - if w in seen[0] and w in seen[1]: - # see if this path is better than than the already - # discovered shortest path - totaldist = seen[0][w] + seen[1][w] - if finalpath == [] or finaldist > totaldist: - finaldist = totaldist - revpath = paths[1][w][:] - revpath.reverse() - finalpath = paths[0][w] + revpath[1:] - raise nx.NetworkXNoPath("No path between %s and %s." % (source, target)) diff --git a/extensions/fablabchemnitz/networkx/algorithms/smallworld.py b/extensions/fablabchemnitz/networkx/algorithms/smallworld.py deleted file mode 100644 index 28fa347f..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/smallworld.py +++ /dev/null @@ -1,382 +0,0 @@ -# Copyright (C) 2017 by -# Romain Fontugne -# All rights reserved. -# BSD license. -# -# Author: Romain Fontugne (romain@iij.ad.jp) -"""Functions for estimating the small-world-ness of graphs. - -A small world network is characterized by a small average shortest path length, -and a large clustering coefficient. - -Small-worldness is commonly measured with the coefficient sigma or omega. - -Both coefficients compare the average clustering coefficient and shortest path -length of a given graph against the same quantities for an equivalent random -or lattice graph. - -For more information, see the Wikipedia article on small-world network [1]_. - -.. [1] Small-world network:: https://en.wikipedia.org/wiki/Small-world_network - -""" -import networkx as nx -from networkx.utils import not_implemented_for -from networkx.utils import py_random_state - -__all__ = ['random_reference', 'lattice_reference', 'sigma', 'omega'] - - -@py_random_state(3) -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def random_reference(G, niter=1, connectivity=True, seed=None): - """Compute a random graph by swapping edges of a given graph. - - Parameters - ---------- - G : graph - An undirected graph with 4 or more nodes. - - niter : integer (optional, default=1) - An edge is rewired approximately `niter` times. - - connectivity : boolean (optional, default=True) - When True, ensure connectivity for the randomized graph. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : graph - The randomized graph. - - Notes - ----- - The implementation is adapted from the algorithm by Maslov and Sneppen - (2002) [1]_. - - References - ---------- - .. [1] Maslov, Sergei, and Kim Sneppen. - "Specificity and stability in topology of protein networks." - Science 296.5569 (2002): 910-913. - """ - if G.is_directed(): - msg = "random_reference() not defined for directed graphs." - raise nx.NetworkXError(msg) - if len(G) < 4: - raise nx.NetworkXError("Graph has less than four nodes.") - - from networkx.utils import cumulative_distribution, discrete_sequence - local_conn = nx.connectivity.local_edge_connectivity - - G = G.copy() - keys, degrees = zip(*G.degree()) # keys, degree - cdf = nx.utils.cumulative_distribution(degrees) # cdf of degree - nnodes = len(G) - nedges = nx.number_of_edges(G) - niter = niter*nedges - ntries = int(nnodes*nedges/(nnodes*(nnodes-1)/2)) - swapcount = 0 - - for i in range(niter): - n = 0 - while n < ntries: - # pick two random edges without creating edge list - # choose source node indices from discrete distribution - (ai, ci) = discrete_sequence(2, cdistribution=cdf, seed=seed) - if ai == ci: - continue # same source, skip - a = keys[ai] # convert index to label - c = keys[ci] - # choose target uniformly from neighbors - b = seed.choice(list(G.neighbors(a))) - d = seed.choice(list(G.neighbors(c))) - bi = keys.index(b) - di = keys.index(d) - if b in [a, c, d] or d in [a, b, c]: - continue # all vertices should be different - - # don't create parallel edges - if (d not in G[a]) and (b not in G[c]): - G.add_edge(a, d) - G.add_edge(c, b) - G.remove_edge(a, b) - G.remove_edge(c, d) - - # Check if the graph is still connected - if connectivity and local_conn(G, a, b) == 0: - # Not connected, revert the swap - G.remove_edge(a, d) - G.remove_edge(c, b) - G.add_edge(a, b) - G.add_edge(c, d) - else: - swapcount += 1 - break - n += 1 - return G - - -@py_random_state(4) -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def lattice_reference(G, niter=1, D=None, connectivity=True, seed=None): - """Latticize the given graph by swapping edges. - - Parameters - ---------- - G : graph - An undirected graph with 4 or more nodes. - - niter : integer (optional, default=1) - An edge is rewired approximatively niter times. - - D : numpy.array (optional, default=None) - Distance to the diagonal matrix. - - connectivity : boolean (optional, default=True) - Ensure connectivity for the latticized graph when set to True. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : graph - The latticized graph. - - Notes - ----- - The implementation is adapted from the algorithm by Sporns et al. [1]_. - which is inspired from the original work by Maslov and Sneppen(2002) [2]_. - - References - ---------- - .. [1] Sporns, Olaf, and Jonathan D. Zwi. - "The small world of the cerebral cortex." - Neuroinformatics 2.2 (2004): 145-162. - .. [2] Maslov, Sergei, and Kim Sneppen. - "Specificity and stability in topology of protein networks." - Science 296.5569 (2002): 910-913. - """ - import numpy as np - from networkx.utils import cumulative_distribution, discrete_sequence - local_conn = nx.connectivity.local_edge_connectivity - - if G.is_directed(): - msg = "lattice_reference() not defined for directed graphs." - raise nx.NetworkXError(msg) - if len(G) < 4: - raise nx.NetworkXError("Graph has less than four nodes.") - # Instead of choosing uniformly at random from a generated edge list, - # this algorithm chooses nonuniformly from the set of nodes with - # probability weighted by degree. - G = G.copy() - keys, degrees = zip(*G.degree()) # keys, degree - cdf = cumulative_distribution(degrees) # cdf of degree - - nnodes = len(G) - nedges = nx.number_of_edges(G) - if D is None: - D = np.zeros((nnodes, nnodes)) - un = np.arange(1, nnodes) - um = np.arange(nnodes - 1, 0, -1) - u = np.append((0,), np.where(un < um, un, um)) - - for v in range(int(np.ceil(nnodes / 2))): - D[nnodes - v - 1, :] = np.append(u[v + 1:], u[:v + 1]) - D[v, :] = D[nnodes - v - 1, :][::-1] - - niter = niter*nedges - ntries = int(nnodes * nedges / (nnodes * (nnodes - 1) / 2)) - swapcount = 0 - - for i in range(niter): - n = 0 - while n < ntries: - # pick two random edges without creating edge list - # choose source node indices from discrete distribution - (ai, ci) = discrete_sequence(2, cdistribution=cdf, seed=seed) - if ai == ci: - continue # same source, skip - a = keys[ai] # convert index to label - c = keys[ci] - # choose target uniformly from neighbors - b = seed.choice(list(G.neighbors(a))) - d = seed.choice(list(G.neighbors(c))) - bi = keys.index(b) - di = keys.index(d) - - if b in [a, c, d] or d in [a, b, c]: - continue # all vertices should be different - - # don't create parallel edges - if (d not in G[a]) and (b not in G[c]): - if D[ai, bi] + D[ci, di] >= D[ai, ci] + D[bi, di]: - # only swap if we get closer to the diagonal - G.add_edge(a, d) - G.add_edge(c, b) - G.remove_edge(a, b) - G.remove_edge(c, d) - - # Check if the graph is still connected - if connectivity and local_conn(G, a, b) == 0: - # Not connected, revert the swap - G.remove_edge(a, d) - G.remove_edge(c, b) - G.add_edge(a, b) - G.add_edge(c, d) - else: - swapcount += 1 - break - n += 1 - - return G - - -@py_random_state(3) -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def sigma(G, niter=100, nrand=10, seed=None): - """Returns the small-world coefficient (sigma) of the given graph. - - The small-world coefficient is defined as: - sigma = C/Cr / L/Lr - where C and L are respectively the average clustering coefficient and - average shortest path length of G. Cr and Lr are respectively the average - clustering coefficient and average shortest path length of an equivalent - random graph. - - A graph is commonly classified as small-world if sigma>1. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - niter : integer (optional, default=100) - Approximate number of rewiring per edge to compute the equivalent - random graph. - nrand : integer (optional, default=10) - Number of random graphs generated to compute the average clustering - coefficient (Cr) and average shortest path length (Lr). - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - sigma : float - The small-world coefficient of G. - - Notes - ----- - The implementation is adapted from Humphries et al. [1]_ [2]_. - - References - ---------- - .. [1] The brainstem reticular formation is a small-world, not scale-free, - network M. D. Humphries, K. Gurney and T. J. Prescott, - Proc. Roy. Soc. B 2006 273, 503-511, doi:10.1098/rspb.2005.3354. - .. [2] Humphries and Gurney (2008). - "Network 'Small-World-Ness': A Quantitative Method for Determining - Canonical Network Equivalence". - PLoS One. 3 (4). PMID 18446219. doi:10.1371/journal.pone.0002051. - """ - import numpy as np - - # Compute the mean clustering coefficient and average shortest path length - # for an equivalent random graph - randMetrics = {"C": [], "L": []} - for i in range(nrand): - Gr = random_reference(G, niter=niter, seed=seed) - randMetrics["C"].append(nx.transitivity(Gr)) - randMetrics["L"].append(nx.average_shortest_path_length(Gr)) - - C = nx.transitivity(G) - L = nx.average_shortest_path_length(G) - Cr = np.mean(randMetrics["C"]) - Lr = np.mean(randMetrics["L"]) - - sigma = (C / Cr) / (L / Lr) - - return sigma - - -@py_random_state(3) -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def omega(G, niter=100, nrand=10, seed=None): - """Returns the small-world coefficient (omega) of a graph - - The small-world coefficient of a graph G is: - - omega = Lr/L - C/Cl - - where C and L are respectively the average clustering coefficient and - average shortest path length of G. Lr is the average shortest path length - of an equivalent random graph and Cl is the average clustering coefficient - of an equivalent lattice graph. - - The small-world coefficient (omega) ranges between -1 and 1. Values close - to 0 means the G features small-world characteristics. Values close to -1 - means G has a lattice shape whereas values close to 1 means G is a random - graph. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - niter: integer (optional, default=100) - Approximate number of rewiring per edge to compute the equivalent - random graph. - - nrand: integer (optional, default=10) - Number of random graphs generated to compute the average clustering - coefficient (Cr) and average shortest path length (Lr). - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - - Returns - ------- - omega : float - The small-work coefficient (omega) - - Notes - ----- - The implementation is adapted from the algorithm by Telesford et al. [1]_. - - References - ---------- - .. [1] Telesford, Joyce, Hayasaka, Burdette, and Laurienti (2011). - "The Ubiquity of Small-World Networks". - Brain Connectivity. 1 (0038): 367-75. PMC 3604768. PMID 22432451. - doi:10.1089/brain.2011.0038. - """ - import numpy as np - - # Compute the mean clustering coefficient and average shortest path length - # for an equivalent random graph - randMetrics = {"C": [], "L": []} - for i in range(nrand): - Gr = random_reference(G, niter=niter, seed=seed) - Gl = lattice_reference(G, niter=niter, seed=seed) - randMetrics["C"].append(nx.transitivity(Gl)) - randMetrics["L"].append(nx.average_shortest_path_length(Gr)) - - C = nx.transitivity(G) - L = nx.average_shortest_path_length(G) - Cl = np.mean(randMetrics["C"]) - Lr = np.mean(randMetrics["L"]) - - omega = (Lr / L) - (C / Cl) - - return omega diff --git a/extensions/fablabchemnitz/networkx/algorithms/smetric.py b/extensions/fablabchemnitz/networkx/algorithms/smetric.py deleted file mode 100644 index a2d05881..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/smetric.py +++ /dev/null @@ -1,37 +0,0 @@ -import networkx as nx -#from networkx.generators.smax import li_smax_graph - - -def s_metric(G, normalized=True): - """Returns the s-metric of graph. - - The s-metric is defined as the sum of the products deg(u)*deg(v) - for every edge (u,v) in G. If norm is provided construct the - s-max graph and compute it's s_metric, and return the normalized - s value - - Parameters - ---------- - G : graph - The graph used to compute the s-metric. - normalized : bool (optional) - Normalize the value. - - Returns - ------- - s : float - The s-metric of the graph. - - References - ---------- - .. [1] Lun Li, David Alderson, John C. Doyle, and Walter Willinger, - Towards a Theory of Scale-Free Graphs: - Definition, Properties, and Implications (Extended Version), 2005. - https://arxiv.org/abs/cond-mat/0501169 - """ - if normalized: - raise nx.NetworkXError("Normalization not implemented") -# Gmax = li_smax_graph(list(G.degree().values())) -# return s_metric(G,normalized=False)/s_metric(Gmax,normalized=False) -# else: - return float(sum([G.degree(u) * G.degree(v) for (u, v) in G.edges()])) diff --git a/extensions/fablabchemnitz/networkx/algorithms/sparsifiers.py b/extensions/fablabchemnitz/networkx/algorithms/sparsifiers.py deleted file mode 100644 index 453979e8..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/sparsifiers.py +++ /dev/null @@ -1,291 +0,0 @@ -# Copyright (C) 2018 -# Robert Gmyr -# All rights reserved. -# BSD license. -"""Functions for computing sparsifiers of graphs.""" -import math -import networkx as nx -from networkx.utils import not_implemented_for, py_random_state - -__all__ = ['spanner'] - - -@py_random_state(3) -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def spanner(G, stretch, weight=None, seed=None): - """Returns a spanner of the given graph with the given stretch. - - A spanner of a graph G = (V, E) with stretch t is a subgraph - H = (V, E_S) such that E_S is a subset of E and the distance between - any pair of nodes in H is at most t times the distance between the - nodes in G. - - Parameters - ---------- - G : NetworkX graph - An undirected simple graph. - - stretch : float - The stretch of the spanner. - - weight : object - The edge attribute to use as distance. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - NetworkX graph - A spanner of the given graph with the given stretch. - - Raises - ------ - ValueError - If a stretch less than 1 is given. - - Notes - ----- - This function implements the spanner algorithm by Baswana and Sen, - see [1]. - - This algorithm is a randomized las vegas algorithm: The expected - running time is O(km) where k = (stretch + 1) // 2 and m is the - number of edges in G. The returned graph is always a spanner of the - given graph with the specified stretch. For weighted graphs the - number of edges in the spanner is O(k * n^(1 + 1 / k)) where k is - defined as above and n is the number of nodes in G. For unweighted - graphs the number of edges is O(n^(1 + 1 / k) + kn). - - References - ---------- - [1] S. Baswana, S. Sen. A Simple and Linear Time Randomized - Algorithm for Computing Sparse Spanners in Weighted Graphs. - Random Struct. Algorithms 30(4): 532-563 (2007). - """ - if stretch < 1: - raise ValueError('stretch must be at least 1') - - k = (stretch + 1) // 2 - - # initialize spanner H with empty edge set - H = nx.empty_graph() - H.add_nodes_from(G.nodes) - - # phase 1: forming the clusters - # the residual graph has V' from the paper as its node set - # and E' from the paper as its edge set - residual_graph = _setup_residual_graph(G, weight) - # clustering is a dictionary that maps nodes in a cluster to the - # cluster center - clustering = {v: v for v in G.nodes} - sample_prob = math.pow(G.number_of_nodes(), - 1 / k) - size_limit = 2 * math.pow(G.number_of_nodes(), 1 + 1 / k) - - i = 0 - while i < k - 1: - # step 1: sample centers - sampled_centers = set() - for center in set(clustering.values()): - if seed.random() < sample_prob: - sampled_centers.add(center) - - # combined loop for steps 2 and 3 - edges_to_add = set() - edges_to_remove = set() - new_clustering = {} - for v in residual_graph.nodes: - if clustering[v] in sampled_centers: - continue - - # step 2: find neighboring (sampled) clusters and - # lightest edges to them - lightest_edge_neighbor, lightest_edge_weight =\ - _lightest_edge_dicts(residual_graph, clustering, v) - neighboring_sampled_centers =\ - set(lightest_edge_weight.keys()) & sampled_centers - - # step 3: add edges to spanner - if not neighboring_sampled_centers: - # connect to each neighboring center via lightest edge - for neighbor in lightest_edge_neighbor.values(): - edges_to_add.add((v, neighbor)) - # remove all incident edges - for neighbor in residual_graph.adj[v]: - edges_to_remove.add((v, neighbor)) - - else: # there is a neighboring sampled center - closest_center = min(neighboring_sampled_centers, - key=lightest_edge_weight.get) - closest_center_weight = lightest_edge_weight[closest_center] - closest_center_neighbor =\ - lightest_edge_neighbor[closest_center] - - edges_to_add.add((v, closest_center_neighbor)) - new_clustering[v] = closest_center - - # connect to centers with edge weight less than - # closest_center_weight - for center, edge_weight in lightest_edge_weight.items(): - if edge_weight < closest_center_weight: - neighbor = lightest_edge_neighbor[center] - edges_to_add.add((v, neighbor)) - - # remove edges to centers with edge weight less than - # closest_center_weight - for neighbor in residual_graph.adj[v]: - neighbor_cluster = clustering[neighbor] - neighbor_weight = lightest_edge_weight[neighbor_cluster] - if neighbor_cluster == closest_center or neighbor_weight < closest_center_weight: - edges_to_remove.add((v, neighbor)) - - # check whether iteration added too many edges to spanner, - # if so repeat - if len(edges_to_add) > size_limit: - # an iteration is repeated O(1) times on expectation - continue - - # iteration succeeded - i = i + 1 - - # actually add edges to spanner - for u, v in edges_to_add: - _add_edge_to_spanner(H, residual_graph, u, v, weight) - - # actually delete edges from residual graph - residual_graph.remove_edges_from(edges_to_remove) - - # copy old clustering data to new_clustering - for node, center in clustering.items(): - if center in sampled_centers: - new_clustering[node] = center - clustering = new_clustering - - # step 4: remove intra-cluster edges - for u in residual_graph.nodes: - for v in list(residual_graph.adj[u]): - if clustering[u] == clustering[v]: - residual_graph.remove_edge(u, v) - - # update residual graph node set - for v in list(residual_graph.nodes): - if v not in clustering: - residual_graph.remove_node(v) - - # phase 2: vertex-cluster joining - for v in residual_graph.nodes: - lightest_edge_neighbor, _ =\ - _lightest_edge_dicts(residual_graph, clustering, v) - for neighbor in lightest_edge_neighbor.values(): - _add_edge_to_spanner(H, residual_graph, v, neighbor, weight) - - return H - - -def _setup_residual_graph(G, weight): - """Setup residual graph as a copy of G with unique edges weights. - - The node set of the residual graph corresponds to the set V' from - the Baswana-Sen paper and the edge set corresponds to the set E' - from the paper. - - This function associates distinct weights to the edges of the - residual graph (even for unweighted input graphs), as required by - the algorithm. - - Parameters - ---------- - G : NetworkX graph - An undirected simple graph. - - weight : object - The edge attribute to use as distance. - - Returns - ------- - NetworkX graph - The residual graph used for the Baswana-Sen algorithm. - """ - residual_graph = G.copy() - - # establish unique edge weights, even for unweighted graphs - for u, v in G.edges(): - if not weight: - residual_graph[u][v]['weight'] = (id(u), id(v)) - else: - residual_graph[u][v]['weight'] = (G[u][v][weight], id(u), id(v)) - - return residual_graph - - -def _lightest_edge_dicts(residual_graph, clustering, node): - """Find the lightest edge to each cluster. - - Searches for the minimum-weight edge to each cluster adjacent to - the given node. - - Parameters - ---------- - residual_graph : NetworkX graph - The residual graph used by the Baswana-Sen algorithm. - - clustering : dictionary - The current clustering of the nodes. - - node : node - The node from which the search originates. - - Returns - ------- - lightest_edge_neighbor, lightest_edge_weight : dictionary, dictionary - lightest_edge_neighbor is a dictionary that maps a center C to - a node v in the corresponding cluster such that the edge from - the given node to v is the lightest edge from the given node to - any node in cluster. lightest_edge_weight maps a center C to the - weight of the aforementioned edge. - - Notes - ----- - If a cluster has no node that is adjacent to the given node in the - residual graph then the center of the cluster is not a key in the - returned dictionaries. - """ - lightest_edge_neighbor = {} - lightest_edge_weight = {} - for neighbor in residual_graph.adj[node]: - neighbor_center = clustering[neighbor] - weight = residual_graph[node][neighbor]['weight'] - if neighbor_center not in lightest_edge_weight or\ - weight < lightest_edge_weight[neighbor_center]: - lightest_edge_neighbor[neighbor_center] = neighbor - lightest_edge_weight[neighbor_center] = weight - return lightest_edge_neighbor, lightest_edge_weight - - -def _add_edge_to_spanner(H, residual_graph, u, v, weight): - """Add the edge {u, v} to the spanner H and take weight from - the residual graph. - - Parameters - ---------- - H : NetworkX graph - The spanner under construction. - - residual_graph : NetworkX graph - The residual graph used by the Baswana-Sen algorithm. The weight - for the edge is taken from this graph. - - u : node - One endpoint of the edge. - - v : node - The other endpoint of the edge. - - weight : object - The edge attribute to use as distance. - """ - H.add_edge(u, v) - if weight: - H[u][v][weight] = residual_graph[u][v]['weight'][0] diff --git a/extensions/fablabchemnitz/networkx/algorithms/structuralholes.py b/extensions/fablabchemnitz/networkx/algorithms/structuralholes.py deleted file mode 100644 index 0d8fdf1b..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/structuralholes.py +++ /dev/null @@ -1,279 +0,0 @@ -# -*- encoding: utf-8 -*- -# -# Copyright 2008-2019 NetworkX developers. -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -"""Functions for computing measures of structural holes.""" - -import networkx as nx - -__all__ = ['constraint', 'local_constraint', 'effective_size'] - - -def mutual_weight(G, u, v, weight=None): - """Returns the sum of the weights of the edge from `u` to `v` and - the edge from `v` to `u` in `G`. - - `weight` is the edge data key that represents the edge weight. If - the specified key is `None` or is not in the edge data for an edge, - that edge is assumed to have weight 1. - - Pre-conditions: `u` and `v` must both be in `G`. - - """ - try: - a_uv = G[u][v].get(weight, 1) - except KeyError: - a_uv = 0 - try: - a_vu = G[v][u].get(weight, 1) - except KeyError: - a_vu = 0 - return a_uv + a_vu - - -def normalized_mutual_weight(G, u, v, norm=sum, weight=None): - """Returns normalized mutual weight of the edges from `u` to `v` - with respect to the mutual weights of the neighbors of `u` in `G`. - - `norm` specifies how the normalization factor is computed. It must - be a function that takes a single argument and returns a number. - The argument will be an iterable of mutual weights - of pairs ``(u, w)``, where ``w`` ranges over each (in- and - out-)neighbor of ``u``. Commons values for `normalization` are - ``sum`` and ``max``. - - `weight` can be ``None`` or a string, if None, all edge weights - are considered equal. Otherwise holds the name of the edge - attribute used as weight. - - """ - scale = norm(mutual_weight(G, u, w, weight) - for w in set(nx.all_neighbors(G, u))) - return 0 if scale == 0 else mutual_weight(G, u, v, weight) / scale - - -def effective_size(G, nodes=None, weight=None): - r"""Returns the effective size of all nodes in the graph ``G``. - - The *effective size* of a node's ego network is based on the concept - of redundancy. A person's ego network has redundancy to the extent - that her contacts are connected to each other as well. The - nonredundant part of a person's relationships it's the effective - size of her ego network [1]_. Formally, the effective size of a - node $u$, denoted $e(u)$, is defined by - - .. math:: - - e(u) = \sum_{v \in N(u) \setminus \{u\}} - \left(1 - \sum_{w \in N(v)} p_{uw} m_{vw}\right) - - where $N(u)$ is the set of neighbors of $u$ and $p_{uw}$ is the - normalized mutual weight of the (directed or undirected) edges - joining $u$ and $v$, for each vertex $u$ and $v$ [1]_. And $m_{vw}$ - is the mutual weight of $v$ and $w$ divided by $v$ highest mutual - weight with any of its neighbors. The *mutual weight* of $u$ and $v$ - is the sum of the weights of edges joining them (edge weights are - assumed to be one if the graph is unweighted). - - For the case of unweighted and undirected graphs, Borgatti proposed - a simplified formula to compute effective size [2]_ - - .. math:: - - e(u) = n - \frac{2t}{n} - - where `t` is the number of ties in the ego network (not including - ties to ego) and `n` is the number of nodes (excluding ego). - - Parameters - ---------- - G : NetworkX graph - The graph containing ``v``. Directed graphs are treated like - undirected graphs when computing neighbors of ``v``. - - nodes : container, optional - Container of nodes in the graph ``G`` to compute the effective size. - If None, the effective size of every node is computed. - - weight : None or string, optional - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - - Returns - ------- - dict - Dictionary with nodes as keys and the constraint on the node as values. - - Notes - ----- - Burt also defined the related concept of *efficiency* of a node's ego - network, which is its effective size divided by the degree of that - node [1]_. So you can easily compute efficiency: - - >>> G = nx.DiGraph() - >>> G.add_edges_from([(0, 1), (0, 2), (1, 0), (2, 1)]) - >>> esize = nx.effective_size(G) - >>> efficiency = {n: v / G.degree(n) for n, v in esize.items()} - - See also - -------- - constraint - - References - ---------- - .. [1] Burt, Ronald S. - *Structural Holes: The Social Structure of Competition.* - Cambridge: Harvard University Press, 1995. - - .. [2] Borgatti, S. - "Structural Holes: Unpacking Burt's Redundancy Measures" - CONNECTIONS 20(1):35-38. - http://www.analytictech.com/connections/v20(1)/holes.htm - - """ - def redundancy(G, u, v, weight=None): - nmw = normalized_mutual_weight - r = sum(nmw(G, u, w, weight=weight) * nmw(G, v, w, norm=max, weight=weight) - for w in set(nx.all_neighbors(G, u))) - return 1 - r - effective_size = {} - if nodes is None: - nodes = G - # Use Borgatti's simplified formula for unweighted and undirected graphs - if not G.is_directed() and weight is None: - for v in nodes: - # Effective size is not defined for isolated nodes - if len(G[v]) == 0: - effective_size[v] = float('nan') - continue - E = nx.ego_graph(G, v, center=False, undirected=True) - effective_size[v] = len(E) - (2 * E.size()) / len(E) - else: - for v in nodes: - # Effective size is not defined for isolated nodes - if len(G[v]) == 0: - effective_size[v] = float('nan') - continue - effective_size[v] = sum(redundancy(G, v, u, weight) - for u in set(nx.all_neighbors(G, v))) - return effective_size - - -def constraint(G, nodes=None, weight=None): - r"""Returns the constraint on all nodes in the graph ``G``. - - The *constraint* is a measure of the extent to which a node *v* is - invested in those nodes that are themselves invested in the - neighbors of *v*. Formally, the *constraint on v*, denoted `c(v)`, - is defined by - - .. math:: - - c(v) = \sum_{w \in N(v) \setminus \{v\}} \ell(v, w) - - where `N(v)` is the subset of the neighbors of `v` that are either - predecessors or successors of `v` and `\ell(v, w)` is the local - constraint on `v` with respect to `w` [1]_. For the definition of local - constraint, see :func:`local_constraint`. - - Parameters - ---------- - G : NetworkX graph - The graph containing ``v``. This can be either directed or undirected. - - nodes : container, optional - Container of nodes in the graph ``G`` to compute the constraint. If - None, the constraint of every node is computed. - - weight : None or string, optional - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - - Returns - ------- - dict - Dictionary with nodes as keys and the constraint on the node as values. - - See also - -------- - local_constraint - - References - ---------- - .. [1] Burt, Ronald S. - "Structural holes and good ideas". - American Journal of Sociology (110): 349–399. - - """ - if nodes is None: - nodes = G - constraint = {} - for v in nodes: - # Constraint is not defined for isolated nodes - if len(G[v]) == 0: - constraint[v] = float('nan') - continue - constraint[v] = sum(local_constraint(G, v, n, weight) - for n in set(nx.all_neighbors(G, v))) - return constraint - - -def local_constraint(G, u, v, weight=None): - r"""Returns the local constraint on the node ``u`` with respect to - the node ``v`` in the graph ``G``. - - Formally, the *local constraint on u with respect to v*, denoted - $\ell(v)$, is defined by - - .. math:: - - \ell(u, v) = \left(p_{uv} + \sum_{w \in N(v)} p_{uw} p{wv}\right)^2, - - where $N(v)$ is the set of neighbors of $v$ and $p_{uv}$ is the - normalized mutual weight of the (directed or undirected) edges - joining $u$ and $v$, for each vertex $u$ and $v$ [1]_. The *mutual - weight* of $u$ and $v$ is the sum of the weights of edges joining - them (edge weights are assumed to be one if the graph is - unweighted). - - Parameters - ---------- - G : NetworkX graph - The graph containing ``u`` and ``v``. This can be either - directed or undirected. - - u : node - A node in the graph ``G``. - - v : node - A node in the graph ``G``. - - weight : None or string, optional - If None, all edge weights are considered equal. - Otherwise holds the name of the edge attribute used as weight. - - Returns - ------- - float - The constraint of the node ``v`` in the graph ``G``. - - See also - -------- - constraint - - References - ---------- - .. [1] Burt, Ronald S. - "Structural holes and good ideas". - American Journal of Sociology (110): 349–399. - - """ - nmw = normalized_mutual_weight - direct = nmw(G, u, v, weight=weight) - indirect = sum(nmw(G, u, w, weight=weight) * nmw(G, w, v, weight=weight) - for w in set(nx.all_neighbors(G, u))) - return (direct + indirect) ** 2 diff --git a/extensions/fablabchemnitz/networkx/algorithms/swap.py b/extensions/fablabchemnitz/networkx/algorithms/swap.py deleted file mode 100644 index 868e864e..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/swap.py +++ /dev/null @@ -1,282 +0,0 @@ -# -*- coding: utf-8 -*- -"""Swap edges in a graph. -""" -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. - -import math -from networkx.utils import py_random_state - -import networkx as nx - -__author__ = "\n".join(['Aric Hagberg (hagberg@lanl.gov)', - 'Pieter Swart (swart@lanl.gov)', - 'Dan Schult (dschult@colgate.edu)', - 'Joel Miller (joel.c.miller.research@gmail.com)', - 'Ben Edwards']) - -__all__ = ['double_edge_swap', - 'connected_double_edge_swap'] - - -@py_random_state(3) -def double_edge_swap(G, nswap=1, max_tries=100, seed=None): - """Swap two edges in the graph while keeping the node degrees fixed. - - A double-edge swap removes two randomly chosen edges u-v and x-y - and creates the new edges u-x and v-y:: - - u--v u v - becomes | | - x--y x y - - If either the edge u-x or v-y already exist no swap is performed - and another attempt is made to find a suitable edge pair. - - Parameters - ---------- - G : graph - An undirected graph - - nswap : integer (optional, default=1) - Number of double-edge swaps to perform - - max_tries : integer (optional) - Maximum number of attempts to swap edges - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : graph - The graph after double edge swaps. - - Notes - ----- - Does not enforce any connectivity constraints. - - The graph G is modified in place. - """ - if G.is_directed(): - raise nx.NetworkXError( - "double_edge_swap() not defined for directed graphs.") - if nswap > max_tries: - raise nx.NetworkXError("Number of swaps > number of tries allowed.") - if len(G) < 4: - raise nx.NetworkXError("Graph has less than four nodes.") - # Instead of choosing uniformly at random from a generated edge list, - # this algorithm chooses nonuniformly from the set of nodes with - # probability weighted by degree. - n = 0 - swapcount = 0 - keys, degrees = zip(*G.degree()) # keys, degree - cdf = nx.utils.cumulative_distribution(degrees) # cdf of degree - discrete_sequence = nx.utils.discrete_sequence - while swapcount < nswap: - # if random.random() < 0.5: continue # trick to avoid periodicities? - # pick two random edges without creating edge list - # choose source node indices from discrete distribution - (ui, xi) = discrete_sequence(2, cdistribution=cdf, seed=seed) - if ui == xi: - continue # same source, skip - u = keys[ui] # convert index to label - x = keys[xi] - # choose target uniformly from neighbors - v = seed.choice(list(G[u])) - y = seed.choice(list(G[x])) - if v == y: - continue # same target, skip - if (x not in G[u]) and (y not in G[v]): # don't create parallel edges - G.add_edge(u, x) - G.add_edge(v, y) - G.remove_edge(u, v) - G.remove_edge(x, y) - swapcount += 1 - if n >= max_tries: - e = ('Maximum number of swap attempts (%s) exceeded ' % n + - 'before desired swaps achieved (%s).' % nswap) - raise nx.NetworkXAlgorithmError(e) - n += 1 - return G - - -@py_random_state(3) -def connected_double_edge_swap(G, nswap=1, _window_threshold=3, seed=None): - """Attempts the specified number of double-edge swaps in the graph `G`. - - A double-edge swap removes two randomly chosen edges `(u, v)` and `(x, - y)` and creates the new edges `(u, x)` and `(v, y)`:: - - u--v u v - becomes | | - x--y x y - - If either `(u, x)` or `(v, y)` already exist, then no swap is performed - so the actual number of swapped edges is always *at most* `nswap`. - - Parameters - ---------- - G : graph - An undirected graph - - nswap : integer (optional, default=1) - Number of double-edge swaps to perform - - _window_threshold : integer - - The window size below which connectedness of the graph will be checked - after each swap. - - The "window" in this function is a dynamically updated integer that - represents the number of swap attempts to make before checking if the - graph remains connected. It is an optimization used to decrease the - running time of the algorithm in exchange for increased complexity of - implementation. - - If the window size is below this threshold, then the algorithm checks - after each swap if the graph remains connected by checking if there is a - path joining the two nodes whose edge was just removed. If the window - size is above this threshold, then the algorithm performs do all the - swaps in the window and only then check if the graph is still connected. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - int - The number of successful swaps - - Raises - ------ - - NetworkXError - - If the input graph is not connected, or if the graph has fewer than four - nodes. - - Notes - ----- - - The initial graph `G` must be connected, and the resulting graph is - connected. The graph `G` is modified in place. - - References - ---------- - .. [1] C. Gkantsidis and M. Mihail and E. Zegura, - The Markov chain simulation method for generating connected - power law random graphs, 2003. - http://citeseer.ist.psu.edu/gkantsidis03markov.html - """ - if not nx.is_connected(G): - raise nx.NetworkXError("Graph not connected") - if len(G) < 4: - raise nx.NetworkXError("Graph has less than four nodes.") - n = 0 - swapcount = 0 - deg = G.degree() - # Label key for nodes - dk = list(n for n, d in G.degree()) - cdf = nx.utils.cumulative_distribution(list(d for n, d in G.degree())) - discrete_sequence = nx.utils.discrete_sequence - window = 1 - while n < nswap: - wcount = 0 - swapped = [] - # If the window is small, we just check each time whether the graph is - # connected by checking if the nodes that were just separated are still - # connected. - if window < _window_threshold: - # This Boolean keeps track of whether there was a failure or not. - fail = False - while wcount < window and n < nswap: - # Pick two random edges without creating the edge list. Choose - # source nodes from the discrete degree distribution. - (ui, xi) = discrete_sequence(2, cdistribution=cdf, seed=seed) - # If the source nodes are the same, skip this pair. - if ui == xi: - continue - # Convert an index to a node label. - u = dk[ui] - x = dk[xi] - # Choose targets uniformly from neighbors. - v = seed.choice(list(G.neighbors(u))) - y = seed.choice(list(G.neighbors(x))) - # If the target nodes are the same, skip this pair. - if v == y: - continue - if x not in G[u] and y not in G[v]: - G.remove_edge(u, v) - G.remove_edge(x, y) - G.add_edge(u, x) - G.add_edge(v, y) - swapped.append((u, v, x, y)) - swapcount += 1 - n += 1 - # If G remains connected... - if nx.has_path(G, u, v): - wcount += 1 - # Otherwise, undo the changes. - else: - G.add_edge(u, v) - G.add_edge(x, y) - G.remove_edge(u, x) - G.remove_edge(v, y) - swapcount -= 1 - fail = True - # If one of the swaps failed, reduce the window size. - if fail: - window = int(math.ceil(window / 2)) - else: - window += 1 - # If the window is large, then there is a good chance that a bunch of - # swaps will work. It's quicker to do all those swaps first and then - # check if the graph remains connected. - else: - while wcount < window and n < nswap: - # Pick two random edges without creating the edge list. Choose - # source nodes from the discrete degree distribution. - (ui, xi) = nx.utils.discrete_sequence(2, cdistribution=cdf) - # If the source nodes are the same, skip this pair. - if ui == xi: - continue - # Convert an index to a node label. - u = dk[ui] - x = dk[xi] - # Choose targets uniformly from neighbors. - v = seed.choice(list(G.neighbors(u))) - y = seed.choice(list(G.neighbors(x))) - # If the target nodes are the same, skip this pair. - if v == y: - continue - if x not in G[u] and y not in G[v]: - G.remove_edge(u, v) - G.remove_edge(x, y) - G.add_edge(u, x) - G.add_edge(v, y) - swapped.append((u, v, x, y)) - swapcount += 1 - n += 1 - wcount += 1 - # If the graph remains connected, increase the window size. - if nx.is_connected(G): - window += 1 - # Otherwise, undo the changes from the previous window and decrease - # the window size. - else: - while swapped: - (u, v, x, y) = swapped.pop() - G.add_edge(u, v) - G.add_edge(x, y) - G.remove_edge(u, x) - G.remove_edge(v, y) - swapcount -= 1 - window = int(math.ceil(window / 2)) - return swapcount diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_asteroidal.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_asteroidal.py deleted file mode 100644 index b0487aff..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_asteroidal.py +++ /dev/null @@ -1,24 +0,0 @@ -import networkx as nx - - -def test_is_at_free(): - - is_at_free = nx.asteroidal.is_at_free - - cycle = nx.cycle_graph(6) - assert not is_at_free(cycle) - - path = nx.path_graph(6) - assert is_at_free(path) - - small_graph = nx.complete_graph(2) - assert is_at_free(small_graph) - - petersen = nx.petersen_graph() - assert not is_at_free(petersen) - - clique = nx.complete_graph(6) - assert is_at_free(clique) - - line_clique = nx.line_graph(clique) - assert not is_at_free(line_clique) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_boundary.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_boundary.py deleted file mode 100644 index ce64ae0b..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_boundary.py +++ /dev/null @@ -1,159 +0,0 @@ -# test_boundary.py - unit tests for the boundary module -# -# Copyright 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.boundary` module.""" - -from itertools import combinations - -import networkx as nx -from networkx.testing import almost_equal, assert_edges_equal -from networkx import convert_node_labels_to_integers as cnlti - - -class TestNodeBoundary(object): - """Unit tests for the :func:`~networkx.node_boundary` function.""" - - def test_null_graph(self): - """Tests that the null graph has empty node boundaries.""" - null = nx.null_graph() - assert nx.node_boundary(null, []) == set() - assert nx.node_boundary(null, [], []) == set() - assert nx.node_boundary(null, [1, 2, 3]) == set() - assert nx.node_boundary(null, [1, 2, 3], [4, 5, 6]) == set() - assert nx.node_boundary(null, [1, 2, 3], [3, 4, 5]) == set() - - def test_path_graph(self): - P10 = cnlti(nx.path_graph(10), first_label=1) - assert nx.node_boundary(P10, []) == set() - assert nx.node_boundary(P10, [], []) == set() - assert nx.node_boundary(P10, [1, 2, 3]) == {4} - assert nx.node_boundary(P10, [4, 5, 6]) == {3, 7} - assert nx.node_boundary(P10, [3, 4, 5, 6, 7]) == {2, 8} - assert nx.node_boundary(P10, [8, 9, 10]) == {7} - assert nx.node_boundary(P10, [4, 5, 6], [9, 10]) == set() - - def test_complete_graph(self): - K10 = cnlti(nx.complete_graph(10), first_label=1) - assert nx.node_boundary(K10, []) == set() - assert nx.node_boundary(K10, [], []) == set() - assert nx.node_boundary(K10, [1, 2, 3]) == {4, 5, 6, 7, 8, 9, 10} - assert nx.node_boundary(K10, [4, 5, 6]) == {1, 2, 3, 7, 8, 9, 10} - assert nx.node_boundary(K10, [3, 4, 5, 6, 7]) == {1, 2, 8, 9, 10} - assert nx.node_boundary(K10, [4, 5, 6], []) == set() - assert nx.node_boundary(K10, K10) == set() - assert nx.node_boundary(K10, [1, 2, 3], [3, 4, 5]) == {4, 5} - - def test_petersen(self): - """Check boundaries in the petersen graph - - cheeger(G,k)=min(|bdy(S)|/|S| for |S|=k, 0>> list(cycles('abc')) - [('a', 'b', 'c'), ('b', 'c', 'a'), ('c', 'a', 'b')] - - """ - n = len(seq) - cycled_seq = cycle(seq) - for x in seq: - yield tuple(islice(cycled_seq, n)) - next(cycled_seq) - - -def cyclic_equals(seq1, seq2): - """Decide whether two sequences are equal up to cyclic permutations. - - For example:: - - >>> cyclic_equals('xyz', 'zxy') - True - >>> cyclic_equals('xyz', 'zyx') - False - - """ - # Cast seq2 to a tuple since `cycles()` yields tuples. - seq2 = tuple(seq2) - return any(x == tuple(seq2) for x in cycles(seq1)) - - -class TestChainDecomposition(TestCase): - """Unit tests for the chain decomposition function.""" - - def assertContainsChain(self, chain, expected): - # A cycle could be expressed in two different orientations, one - # forward and one backward, so we need to check for cyclic - # equality in both orientations. - reversed_chain = list(reversed([tuple(reversed(e)) for e in chain])) - for candidate in expected: - if cyclic_equals(chain, candidate): - break - if cyclic_equals(reversed_chain, candidate): - break - else: - self.fail('chain not found') - - def test_decomposition(self): - edges = [ - # DFS tree edges. - (1, 2), (2, 3), (3, 4), (3, 5), (5, 6), (6, 7), (7, 8), (5, 9), - (9, 10), - # Nontree edges. - (1, 3), (1, 4), (2, 5), (5, 10), (6, 8) - ] - G = nx.Graph(edges) - expected = [ - [(1, 3), (3, 2), (2, 1)], - [(1, 4), (4, 3)], - [(2, 5), (5, 3)], - [(5, 10), (10, 9), (9, 5)], - [(6, 8), (8, 7), (7, 6)], - ] - chains = list(nx.chain_decomposition(G, root=1)) - self.assertEqual(len(chains), len(expected)) -# This chain decomposition isn't unique -# for chain in chains: -# print(chain) -# self.assertContainsChain(chain, expected) - - def test_barbell_graph(self): - # The (3, 0) barbell graph has two triangles joined by a single edge. - G = nx.barbell_graph(3, 0) - chains = list(nx.chain_decomposition(G, root=0)) - expected = [ - [(0, 1), (1, 2), (2, 0)], - [(3, 4), (4, 5), (5, 3)], - ] - self.assertEqual(len(chains), len(expected)) - for chain in chains: - self.assertContainsChain(chain, expected) - - def test_disconnected_graph(self): - """Test for a graph with multiple connected components.""" - G = nx.barbell_graph(3, 0) - H = nx.barbell_graph(3, 0) - mapping = dict(zip(range(6), 'abcdef')) - nx.relabel_nodes(H, mapping, copy=False) - G = nx.union(G, H) - chains = list(nx.chain_decomposition(G)) - expected = [ - [(0, 1), (1, 2), (2, 0)], - [(3, 4), (4, 5), (5, 3)], - [('a', 'b'), ('b', 'c'), ('c', 'a')], - [('d', 'e'), ('e', 'f'), ('f', 'd')], - ] - self.assertEqual(len(chains), len(expected)) - for chain in chains: - self.assertContainsChain(chain, expected) - - def test_disconnected_graph_root_node(self): - """Test for a single component of a disconnected graph.""" - G = nx.barbell_graph(3, 0) - H = nx.barbell_graph(3, 0) - mapping = dict(zip(range(6), 'abcdef')) - nx.relabel_nodes(H, mapping, copy=False) - G = nx.union(G, H) - chains = list(nx.chain_decomposition(G, root='a')) - expected = [ - [('a', 'b'), ('b', 'c'), ('c', 'a')], - [('d', 'e'), ('e', 'f'), ('f', 'd')], - ] - self.assertEqual(len(chains), len(expected)) - for chain in chains: - self.assertContainsChain(chain, expected) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_chordal.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_chordal.py deleted file mode 100644 index e7719275..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_chordal.py +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env python -import pytest -import networkx as nx - - -class TestMCS: - - @classmethod - def setup_class(cls): - # simple graph - connected_chordal_G = nx.Graph() - connected_chordal_G.add_edges_from([(1, 2), (1, 3), (2, 3), (2, 4), - (3, 4), (3, 5), (3, 6), (4, 5), - (4, 6), (5, 6)]) - cls.connected_chordal_G = connected_chordal_G - - chordal_G = nx.Graph() - chordal_G.add_edges_from([(1, 2), (1, 3), (2, 3), (2, 4), (3, 4), - (3, 5), (3, 6), (4, 5), (4, 6), (5, 6), - (7, 8)]) - chordal_G.add_node(9) - cls.chordal_G = chordal_G - - non_chordal_G = nx.Graph() - non_chordal_G.add_edges_from([(1, 2), (1, 3), (2, 4), (2, 5), - (3, 4), (3, 5)]) - cls.non_chordal_G = non_chordal_G - - def test_is_chordal(self): - assert not nx.is_chordal(self.non_chordal_G) - assert nx.is_chordal(self.chordal_G) - assert nx.is_chordal(self.connected_chordal_G) - assert nx.is_chordal(nx.complete_graph(3)) - assert nx.is_chordal(nx.cycle_graph(3)) - assert not nx.is_chordal(nx.cycle_graph(5)) - - def test_induced_nodes(self): - G = nx.generators.classic.path_graph(10) - Induced_nodes = nx.find_induced_nodes(G, 1, 9, 2) - assert Induced_nodes == set([1, 2, 3, 4, 5, 6, 7, 8, 9]) - pytest.raises(nx.NetworkXTreewidthBoundExceeded, - nx.find_induced_nodes, G, 1, 9, 1) - Induced_nodes = nx.find_induced_nodes(self.chordal_G, 1, 6) - assert Induced_nodes == set([1, 2, 4, 6]) - pytest.raises(nx.NetworkXError, - nx.find_induced_nodes, self.non_chordal_G, 1, 5) - - def test_chordal_find_cliques(self): - cliques = set([frozenset([9]), frozenset([7, 8]), frozenset([1, 2, 3]), - frozenset([2, 3, 4]), frozenset([3, 4, 5, 6])]) - assert nx.chordal_graph_cliques(self.chordal_G) == cliques - - def test_chordal_find_cliques_path(self): - G = nx.path_graph(10) - cliqueset = nx.chordal_graph_cliques(G) - for (u, v) in G.edges(): - assert (frozenset([u, v]) in cliqueset - or frozenset([v, u]) in cliqueset) - - def test_chordal_find_cliquesCC(self): - cliques = set([frozenset([1, 2, 3]), frozenset([2, 3, 4]), - frozenset([3, 4, 5, 6])]) - cgc = nx.chordal_graph_cliques - assert cgc(self.connected_chordal_G) == cliques - - def test_complete_to_chordal_graph(self): - fgrg = nx.fast_gnp_random_graph - test_graphs = [nx.barbell_graph(6, 2), nx.cycle_graph(15), - nx.wheel_graph(20), nx.grid_graph([10, 4]), - nx.ladder_graph(15), nx.star_graph(5), - nx.bull_graph(), fgrg(20, 0.3, seed=1)] - for G in test_graphs: - H, a = nx.complete_to_chordal_graph(G) - assert nx.is_chordal(H) - assert len(a) == H.number_of_nodes() - if nx.is_chordal(G): - assert G.number_of_edges() == H.number_of_edges() - assert set(a.values()) == {0} - else: - assert len(set(a.values())) == H.number_of_nodes() diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_clique.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_clique.py deleted file mode 100644 index 595015a9..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_clique.py +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/env python -import pytest -import networkx as nx -from networkx import convert_node_labels_to_integers as cnlti - - -class TestCliques: - - def setup_method(self): - z = [3, 4, 3, 4, 2, 4, 2, 1, 1, 1, 1] - self.G = cnlti(nx.generators.havel_hakimi_graph(z), first_label=1) - self.cl = list(nx.find_cliques(self.G)) - H = nx.complete_graph(6) - H = nx.relabel_nodes(H, dict([(i, i + 1) for i in range(6)])) - H.remove_edges_from([(2, 6), (2, 5), (2, 4), (1, 3), (5, 3)]) - self.H = H - - def test_find_cliques1(self): - cl = list(nx.find_cliques(self.G)) - rcl = nx.find_cliques_recursive(self.G) - expected = [[2, 6, 1, 3], [2, 6, 4], [5, 4, 7], [8, 9], [10, 11]] - assert sorted(map(sorted, cl)) == sorted(map(sorted, rcl)) - assert sorted(map(sorted, cl)) == sorted(map(sorted, expected)) - - def test_selfloops(self): - self.G.add_edge(1, 1) - cl = list(nx.find_cliques(self.G)) - rcl = list(nx.find_cliques_recursive(self.G)) - assert set(map(frozenset, cl)) == set(map(frozenset, rcl)) - answer = [{2, 6, 1, 3}, {2, 6, 4}, {5, 4, 7}, {8, 9}, {10, 11}] - assert len(answer) == len(cl) - assert all(set(c) in answer for c in cl) - - def test_find_cliques2(self): - hcl = list(nx.find_cliques(self.H)) - assert (sorted(map(sorted, hcl)) == - [[1, 2], [1, 4, 5, 6], [2, 3], [3, 4, 6]]) - - def test_clique_number(self): - G = self.G - assert nx.graph_clique_number(G) == 4 - assert nx.graph_clique_number(G, cliques=self.cl) == 4 - - def test_clique_number2(self): - G = nx.Graph() - G.add_nodes_from([1, 2, 3]) - assert nx.graph_clique_number(G) == 1 - - def test_clique_number3(self): - G = nx.Graph() - assert nx.graph_clique_number(G) == 0 - - def test_number_of_cliques(self): - G = self.G - assert nx.graph_number_of_cliques(G) == 5 - assert nx.graph_number_of_cliques(G, cliques=self.cl) == 5 - assert nx.number_of_cliques(G, 1) == 1 - assert list(nx.number_of_cliques(G, [1]).values()) == [1] - assert list(nx.number_of_cliques(G, [1, 2]).values()) == [1, 2] - assert nx.number_of_cliques(G, [1, 2]) == {1: 1, 2: 2} - assert nx.number_of_cliques(G, 2) == 2 - assert (nx.number_of_cliques(G) == - {1: 1, 2: 2, 3: 1, 4: 2, 5: 1, - 6: 2, 7: 1, 8: 1, 9: 1, 10: 1, 11: 1}) - assert (nx.number_of_cliques(G, nodes=list(G)) == - {1: 1, 2: 2, 3: 1, 4: 2, 5: 1, - 6: 2, 7: 1, 8: 1, 9: 1, 10: 1, 11: 1}) - assert (nx.number_of_cliques(G, nodes=[2, 3, 4]) == - {2: 2, 3: 1, 4: 2}) - assert (nx.number_of_cliques(G, cliques=self.cl) == - {1: 1, 2: 2, 3: 1, 4: 2, 5: 1, - 6: 2, 7: 1, 8: 1, 9: 1, 10: 1, 11: 1}) - assert (nx.number_of_cliques(G, list(G), cliques=self.cl) == - {1: 1, 2: 2, 3: 1, 4: 2, 5: 1, - 6: 2, 7: 1, 8: 1, 9: 1, 10: 1, 11: 1}) - - def test_node_clique_number(self): - G = self.G - assert nx.node_clique_number(G, 1) == 4 - assert list(nx.node_clique_number(G, [1]).values()) == [4] - assert list(nx.node_clique_number(G, [1, 2]).values()) == [4, 4] - assert nx.node_clique_number(G, [1, 2]) == {1: 4, 2: 4} - assert nx.node_clique_number(G, 1) == 4 - assert (nx.node_clique_number(G) == - {1: 4, 2: 4, 3: 4, 4: 3, 5: 3, 6: 4, - 7: 3, 8: 2, 9: 2, 10: 2, 11: 2}) - assert (nx.node_clique_number(G, cliques=self.cl) == - {1: 4, 2: 4, 3: 4, 4: 3, 5: 3, 6: 4, - 7: 3, 8: 2, 9: 2, 10: 2, 11: 2}) - - def test_cliques_containing_node(self): - G = self.G - assert (nx.cliques_containing_node(G, 1) == - [[2, 6, 1, 3]]) - assert (list(nx.cliques_containing_node(G, [1]).values()) == - [[[2, 6, 1, 3]]]) - assert ([sorted(c) for c in list(nx.cliques_containing_node(G, [1, 2]).values())] == - [[[2, 6, 1, 3]], [[2, 6, 1, 3], [2, 6, 4]]]) - result = nx.cliques_containing_node(G, [1, 2]) - for k, v in result.items(): - result[k] = sorted(v) - assert (result == - {1: [[2, 6, 1, 3]], 2: [[2, 6, 1, 3], [2, 6, 4]]}) - assert (nx.cliques_containing_node(G, 1) == - [[2, 6, 1, 3]]) - expected = [{2, 6, 1, 3}, {2, 6, 4}] - answer = [set(c) for c in nx.cliques_containing_node(G, 2)] - assert answer in (expected, list(reversed(expected))) - - answer = [set(c) for c in nx.cliques_containing_node(G, 2, cliques=self.cl)] - assert answer in (expected, list(reversed(expected))) - assert len(nx.cliques_containing_node(G)) == 11 - - def test_make_clique_bipartite(self): - G = self.G - B = nx.make_clique_bipartite(G) - assert (sorted(B) == - [-5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) - # Project onto the nodes of the original graph. - H = nx.project(B, range(1, 12)) - assert H.adj == G.adj - # Project onto the nodes representing the cliques. - H1 = nx.project(B, range(-5, 0)) - # Relabel the negative numbers as positive ones. - H1 = nx.relabel_nodes(H1, {-v: v for v in range(1, 6)}) - assert sorted(H1) == [1, 2, 3, 4, 5] - - def test_make_max_clique_graph(self): - """Tests that the maximal clique graph is the same as the bipartite - clique graph after being projected onto the nodes representing the - cliques. - - """ - G = self.G - B = nx.make_clique_bipartite(G) - # Project onto the nodes representing the cliques. - H1 = nx.project(B, range(-5, 0)) - # Relabel the negative numbers as nonnegative ones, starting at - # 0. - H1 = nx.relabel_nodes(H1, {-v: v - 1 for v in range(1, 6)}) - H2 = nx.make_max_clique_graph(G) - assert H1.adj == H2.adj - - def test_directed(self): - with pytest.raises(nx.NetworkXNotImplemented): - cliques = nx.find_cliques(nx.DiGraph()) - - -class TestEnumerateAllCliques: - - def test_paper_figure_4(self): - # Same graph as given in Fig. 4 of paper enumerate_all_cliques is - # based on. - # http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=1559964&isnumber=33129 - G = nx.Graph() - edges_fig_4 = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('a', 'e'), - ('b', 'c'), ('b', 'd'), ('b', 'e'), - ('c', 'd'), ('c', 'e'), - ('d', 'e'), - ('f', 'b'), ('f', 'c'), ('f', 'g'), - ('g', 'f'), ('g', 'c'), ('g', 'd'), ('g', 'e')] - G.add_edges_from(edges_fig_4) - - cliques = list(nx.enumerate_all_cliques(G)) - clique_sizes = list(map(len, cliques)) - assert sorted(clique_sizes) == clique_sizes - - expected_cliques = [['a'], - ['b'], - ['c'], - ['d'], - ['e'], - ['f'], - ['g'], - ['a', 'b'], - ['a', 'b', 'd'], - ['a', 'b', 'd', 'e'], - ['a', 'b', 'e'], - ['a', 'c'], - ['a', 'c', 'd'], - ['a', 'c', 'd', 'e'], - ['a', 'c', 'e'], - ['a', 'd'], - ['a', 'd', 'e'], - ['a', 'e'], - ['b', 'c'], - ['b', 'c', 'd'], - ['b', 'c', 'd', 'e'], - ['b', 'c', 'e'], - ['b', 'c', 'f'], - ['b', 'd'], - ['b', 'd', 'e'], - ['b', 'e'], - ['b', 'f'], - ['c', 'd'], - ['c', 'd', 'e'], - ['c', 'd', 'e', 'g'], - ['c', 'd', 'g'], - ['c', 'e'], - ['c', 'e', 'g'], - ['c', 'f'], - ['c', 'f', 'g'], - ['c', 'g'], - ['d', 'e'], - ['d', 'e', 'g'], - ['d', 'g'], - ['e', 'g'], - ['f', 'g'], - ['a', 'b', 'c'], - ['a', 'b', 'c', 'd'], - ['a', 'b', 'c', 'd', 'e'], - ['a', 'b', 'c', 'e']] - - assert (sorted(map(sorted, cliques)) == - sorted(map(sorted, expected_cliques))) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_cluster.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_cluster.py deleted file mode 100644 index 2e76114c..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_cluster.py +++ /dev/null @@ -1,273 +0,0 @@ -#!/usr/bin/env python -import networkx as nx - - -class TestTriangles: - - def test_empty(self): - G = nx.Graph() - assert list(nx.triangles(G).values()) == [] - - def test_path(self): - G = nx.path_graph(10) - assert (list(nx.triangles(G).values()) == - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) - assert (nx.triangles(G) == - {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, - 5: 0, 6: 0, 7: 0, 8: 0, 9: 0}) - - def test_cubical(self): - G = nx.cubical_graph() - assert (list(nx.triangles(G).values()) == - [0, 0, 0, 0, 0, 0, 0, 0]) - assert nx.triangles(G, 1) == 0 - assert list(nx.triangles(G, [1, 2]).values()) == [0, 0] - assert nx.triangles(G, 1) == 0 - assert nx.triangles(G, [1, 2]) == {1: 0, 2: 0} - - def test_k5(self): - G = nx.complete_graph(5) - assert list(nx.triangles(G).values()) == [6, 6, 6, 6, 6] - assert sum(nx.triangles(G).values()) / 3.0 == 10 - assert nx.triangles(G, 1) == 6 - G.remove_edge(1, 2) - assert list(nx.triangles(G).values()) == [5, 3, 3, 5, 5] - assert nx.triangles(G, 1) == 3 - - -class TestDirectedClustering: - - def test_clustering(self): - G = nx.DiGraph() - assert list(nx.clustering(G).values()) == [] - assert nx.clustering(G) == {} - - def test_path(self): - G = nx.path_graph(10, create_using=nx.DiGraph()) - assert (list(nx.clustering(G).values()) == - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) - assert (nx.clustering(G) == - {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0, - 5: 0.0, 6: 0.0, 7: 0.0, 8: 0.0, 9: 0.0}) - - def test_k5(self): - G = nx.complete_graph(5, create_using=nx.DiGraph()) - assert list(nx.clustering(G).values()) == [1, 1, 1, 1, 1] - assert nx.average_clustering(G) == 1 - G.remove_edge(1, 2) - assert (list(nx.clustering(G).values()) == - [11. / 12., 1.0, 1.0, 11. / 12., 11. / 12.]) - assert nx.clustering(G, [1, 4]) == {1: 1.0, 4: 11. /12.} - G.remove_edge(2, 1) - assert (list(nx.clustering(G).values()) == - [5. / 6., 1.0, 1.0, 5. / 6., 5. / 6.]) - assert nx.clustering(G, [1, 4]) == {1: 1.0, 4: 0.83333333333333337} - - def test_triangle_and_edge(self): - G = nx.cycle_graph(3, create_using=nx.DiGraph()) - G.add_edge(0, 4) - assert nx.clustering(G)[0] == 1.0 / 6.0 - - -class TestDirectedWeightedClustering: - - def test_clustering(self): - G = nx.DiGraph() - assert list(nx.clustering(G, weight='weight').values()) == [] - assert nx.clustering(G) == {} - - def test_path(self): - G = nx.path_graph(10, create_using=nx.DiGraph()) - assert (list(nx.clustering(G, weight='weight').values()) == - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) - assert (nx.clustering(G, weight='weight') == - {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0, - 5: 0.0, 6: 0.0, 7: 0.0, 8: 0.0, 9: 0.0}) - - def test_k5(self): - G = nx.complete_graph(5, create_using=nx.DiGraph()) - assert list(nx.clustering(G, weight='weight').values()) == [1, 1, 1, 1, 1] - assert nx.average_clustering(G, weight='weight') == 1 - G.remove_edge(1, 2) - assert (list(nx.clustering(G, weight='weight').values()) == - [11. / 12., 1.0, 1.0, 11. / 12., 11. / 12.]) - assert nx.clustering(G, [1, 4], weight='weight') == {1: 1.0, 4: 11. /12.} - G.remove_edge(2, 1) - assert (list(nx.clustering(G, weight='weight').values()) == - [5. / 6., 1.0, 1.0, 5. / 6., 5. / 6.]) - assert nx.clustering(G, [1, 4], weight='weight') == {1: 1.0, 4: 0.83333333333333337} - - def test_triangle_and_edge(self): - G = nx.cycle_graph(3, create_using=nx.DiGraph()) - G.add_edge(0, 4, weight=2) - assert nx.clustering(G)[0] == 1.0 / 6.0 - assert nx.clustering(G, weight='weight')[0] == 1.0 / 12.0 - - -class TestWeightedClustering: - - def test_clustering(self): - G = nx.Graph() - assert list(nx.clustering(G, weight='weight').values()) == [] - assert nx.clustering(G) == {} - - def test_path(self): - G = nx.path_graph(10) - assert (list(nx.clustering(G, weight='weight').values()) == - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) - assert (nx.clustering(G, weight='weight') == - {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0, - 5: 0.0, 6: 0.0, 7: 0.0, 8: 0.0, 9: 0.0}) - - def test_cubical(self): - G = nx.cubical_graph() - assert (list(nx.clustering(G, weight='weight').values()) == - [0, 0, 0, 0, 0, 0, 0, 0]) - assert nx.clustering(G, 1) == 0 - assert list(nx.clustering(G, [1, 2], weight='weight').values()) == [0, 0] - assert nx.clustering(G, 1, weight='weight') == 0 - assert nx.clustering(G, [1, 2], weight='weight') == {1: 0, 2: 0} - - def test_k5(self): - G = nx.complete_graph(5) - assert list(nx.clustering(G, weight='weight').values()) == [1, 1, 1, 1, 1] - assert nx.average_clustering(G, weight='weight') == 1 - G.remove_edge(1, 2) - assert (list(nx.clustering(G, weight='weight').values()) == - [5. / 6., 1.0, 1.0, 5. / 6., 5. / 6.]) - assert nx.clustering(G, [1, 4], weight='weight') == {1: 1.0, 4: 0.83333333333333337} - - def test_triangle_and_edge(self): - G = nx.cycle_graph(3) - G.add_edge(0, 4, weight=2) - assert nx.clustering(G)[0] == 1.0 / 3.0 - assert nx.clustering(G, weight='weight')[0] == 1.0 / 6.0 - - -class TestClustering: - - def test_clustering(self): - G = nx.Graph() - assert list(nx.clustering(G).values()) == [] - assert nx.clustering(G) == {} - - def test_path(self): - G = nx.path_graph(10) - assert (list(nx.clustering(G).values()) == - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) - assert (nx.clustering(G) == - {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0, - 5: 0.0, 6: 0.0, 7: 0.0, 8: 0.0, 9: 0.0}) - - def test_cubical(self): - G = nx.cubical_graph() - assert (list(nx.clustering(G).values()) == - [0, 0, 0, 0, 0, 0, 0, 0]) - assert nx.clustering(G, 1) == 0 - assert list(nx.clustering(G, [1, 2]).values()) == [0, 0] - assert nx.clustering(G, 1) == 0 - assert nx.clustering(G, [1, 2]) == {1: 0, 2: 0} - - def test_k5(self): - G = nx.complete_graph(5) - assert list(nx.clustering(G).values()) == [1, 1, 1, 1, 1] - assert nx.average_clustering(G) == 1 - G.remove_edge(1, 2) - assert (list(nx.clustering(G).values()) == - [5. / 6., 1.0, 1.0, 5. / 6., 5. / 6.]) - assert nx.clustering(G, [1, 4]) == {1: 1.0, 4: 0.83333333333333337} - - -class TestTransitivity: - - def test_transitivity(self): - G = nx.Graph() - assert nx.transitivity(G) == 0.0 - - def test_path(self): - G = nx.path_graph(10) - assert nx.transitivity(G) == 0.0 - - def test_cubical(self): - G = nx.cubical_graph() - assert nx.transitivity(G) == 0.0 - - def test_k5(self): - G = nx.complete_graph(5) - assert nx.transitivity(G) == 1.0 - G.remove_edge(1, 2) - assert nx.transitivity(G) == 0.875 - - -class TestSquareClustering: - - def test_clustering(self): - G = nx.Graph() - assert list(nx.square_clustering(G).values()) == [] - assert nx.square_clustering(G) == {} - - def test_path(self): - G = nx.path_graph(10) - assert (list(nx.square_clustering(G).values()) == - [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) - assert (nx.square_clustering(G) == - {0: 0.0, 1: 0.0, 2: 0.0, 3: 0.0, 4: 0.0, - 5: 0.0, 6: 0.0, 7: 0.0, 8: 0.0, 9: 0.0}) - - def test_cubical(self): - G = nx.cubical_graph() - assert (list(nx.square_clustering(G).values()) == - [0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]) - assert list(nx.square_clustering(G, [1, 2]).values()) == [0.5, 0.5] - assert nx.square_clustering(G, [1])[1] == 0.5 - assert nx.square_clustering(G, [1, 2]) == {1: 0.5, 2: 0.5} - - def test_k5(self): - G = nx.complete_graph(5) - assert list(nx.square_clustering(G).values()) == [1, 1, 1, 1, 1] - - def test_bipartite_k5(self): - G = nx.complete_bipartite_graph(5, 5) - assert (list(nx.square_clustering(G).values()) == - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) - - def test_lind_square_clustering(self): - """Test C4 for figure 1 Lind et al (2005)""" - G = nx.Graph([(1, 2), (1, 3), (1, 6), (1, 7), (2, 4), (2, 5), - (3, 4), (3, 5), (6, 7), (7, 8), (6, 8), (7, 9), - (7, 10), (6, 11), (6, 12), (2, 13), (2, 14), (3, 15), (3, 16)]) - G1 = G.subgraph([1, 2, 3, 4, 5, 13, 14, 15, 16]) - G2 = G.subgraph([1, 6, 7, 8, 9, 10, 11, 12]) - assert nx.square_clustering(G, [1])[1] == 3 / 75.0 - assert nx.square_clustering(G1, [1])[1] == 2 / 6.0 - assert nx.square_clustering(G2, [1])[1] == 1 / 5.0 - - -def test_average_clustering(): - G = nx.cycle_graph(3) - G.add_edge(2, 3) - assert nx.average_clustering(G) == (1 + 1 + 1 / 3.0) / 4.0 - assert nx.average_clustering(G, count_zeros=True) == (1 + 1 + 1 / 3.0) / 4.0 - assert nx.average_clustering(G, count_zeros=False) == (1 + 1 + 1 / 3.0) / 3.0 - - -class TestGeneralizedDegree: - - def test_generalized_degree(self): - G = nx.Graph() - assert nx.generalized_degree(G) == {} - - def test_path(self): - G = nx.path_graph(5) - assert nx.generalized_degree(G, 0) == {0: 1} - assert nx.generalized_degree(G, 1) == {0: 2} - - def test_cubical(self): - G = nx.cubical_graph() - assert nx.generalized_degree(G, 0) == {0: 3} - - def test_k5(self): - G = nx.complete_graph(5) - assert nx.generalized_degree(G, 0) == {3: 4} - G.remove_edge(0, 1) - assert nx.generalized_degree(G, 0) == {2: 3} diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_communicability.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_communicability.py deleted file mode 100644 index ad858b54..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_communicability.py +++ /dev/null @@ -1,75 +0,0 @@ -from collections import defaultdict - -import pytest -numpy = pytest.importorskip('numpy') -scipy = pytest.importorskip('scipy') - -import networkx as nx -from networkx.testing import almost_equal -from networkx.algorithms.communicability_alg import * - - -class TestCommunicability: - - def test_communicability(self): - answer = {0: {0: 1.5430806348152435, - 1: 1.1752011936438012 - }, - 1: {0: 1.1752011936438012, - 1: 1.5430806348152435 - } - } -# answer={(0, 0): 1.5430806348152435, -# (0, 1): 1.1752011936438012, -# (1, 0): 1.1752011936438012, -# (1, 1): 1.5430806348152435} - - result = communicability(nx.path_graph(2)) - for k1, val in result.items(): - for k2 in val: - assert almost_equal(answer[k1][k2], result[k1][k2], places=7) - - def test_communicability2(self): - - answer_orig = {('1', '1'): 1.6445956054135658, - ('1', 'Albert'): 0.7430186221096251, - ('1', 'Aric'): 0.7430186221096251, - ('1', 'Dan'): 1.6208126320442937, - ('1', 'Franck'): 0.42639707170035257, - ('Albert', '1'): 0.7430186221096251, - ('Albert', 'Albert'): 2.4368257358712189, - ('Albert', 'Aric'): 1.4368257358712191, - ('Albert', 'Dan'): 2.0472097037446453, - ('Albert', 'Franck'): 1.8340111678944691, - ('Aric', '1'): 0.7430186221096251, - ('Aric', 'Albert'): 1.4368257358712191, - ('Aric', 'Aric'): 2.4368257358712193, - ('Aric', 'Dan'): 2.0472097037446457, - ('Aric', 'Franck'): 1.8340111678944691, - ('Dan', '1'): 1.6208126320442937, - ('Dan', 'Albert'): 2.0472097037446453, - ('Dan', 'Aric'): 2.0472097037446457, - ('Dan', 'Dan'): 3.1306328496328168, - ('Dan', 'Franck'): 1.4860372442192515, - ('Franck', '1'): 0.42639707170035257, - ('Franck', 'Albert'): 1.8340111678944691, - ('Franck', 'Aric'): 1.8340111678944691, - ('Franck', 'Dan'): 1.4860372442192515, - ('Franck', 'Franck'): 2.3876142275231915} - - answer = defaultdict(dict) - for (k1, k2), v in answer_orig.items(): - answer[k1][k2] = v - - G1 = nx.Graph([('Franck', 'Aric'), ('Aric', 'Dan'), ('Dan', 'Albert'), - ('Albert', 'Franck'), ('Dan', '1'), ('Franck', 'Albert')]) - - result = communicability(G1) - for k1, val in result.items(): - for k2 in val: - assert almost_equal(answer[k1][k2], result[k1][k2], places=7) - - result = communicability_exp(G1) - for k1, val in result.items(): - for k2 in val: - assert almost_equal(answer[k1][k2], result[k1][k2], places=7) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_core.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_core.py deleted file mode 100644 index 585ca6b2..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_core.py +++ /dev/null @@ -1,154 +0,0 @@ -#!/usr/bin/env python -import networkx as nx -from networkx.testing.utils import * - - -class TestCore: - @classmethod - def setup_class(cls): - # G is the example graph in Figure 1 from Batagelj and - # Zaversnik's paper titled An O(m) Algorithm for Cores - # Decomposition of Networks, 2003, - # http://arXiv.org/abs/cs/0310049. With nodes labeled as - # shown, the 3-core is given by nodes 1-8, the 2-core by nodes - # 9-16, the 1-core by nodes 17-20 and node 21 is in the - # 0-core. - t1 = nx.convert_node_labels_to_integers(nx.tetrahedral_graph(), 1) - t2 = nx.convert_node_labels_to_integers(t1, 5) - G = nx.union(t1, t2) - G.add_edges_from([(3, 7), (2, 11), (11, 5), (11, 12), (5, 12), - (12, 19), (12, 18), (3, 9), (7, 9), (7, 10), - (9, 10), (9, 20), (17, 13), (13, 14), (14, 15), - (15, 16), (16, 13)]) - G.add_node(21) - cls.G = G - - # Create the graph H resulting from the degree sequence - # [0, 1, 2, 2, 2, 2, 3] when using the Havel-Hakimi algorithm. - - degseq = [0, 1, 2, 2, 2, 2, 3] - H = nx.havel_hakimi_graph(degseq) - mapping = {6: 0, 0: 1, 4: 3, 5: 6, 3: 4, 1: 2, 2: 5} - cls.H = nx.relabel_nodes(H, mapping) - - def test_trivial(self): - """Empty graph""" - G = nx.Graph() - assert nx.find_cores(G) == {} - - def test_find_cores(self): - core = nx.find_cores(self.G) - nodes_by_core = [sorted([n for n in core if core[n] == val]) - for val in range(4)] - assert_nodes_equal(nodes_by_core[0], [21]) - assert_nodes_equal(nodes_by_core[1], [17, 18, 19, 20]) - assert_nodes_equal(nodes_by_core[2], [9, 10, 11, 12, 13, 14, 15, 16]) - assert_nodes_equal(nodes_by_core[3], [1, 2, 3, 4, 5, 6, 7, 8]) - - def test_core_number(self): - # smoke test real name - cores = nx.core_number(self.G) - - def test_find_cores2(self): - core = nx.find_cores(self.H) - nodes_by_core = [sorted([n for n in core if core[n] == val]) - for val in range(3)] - assert_nodes_equal(nodes_by_core[0], [0]) - assert_nodes_equal(nodes_by_core[1], [1, 3]) - assert_nodes_equal(nodes_by_core[2], [2, 4, 5, 6]) - - def test_directed_find_cores(self): - '''core number had a bug for directed graphs found in issue #1959''' - # small example where too timid edge removal can make cn[2] = 3 - G = nx.DiGraph() - edges = [(1, 2), (2, 1), (2, 3), (2, 4), (3, 4), (4, 3)] - G.add_edges_from(edges) - assert nx.core_number(G) == {1: 2, 2: 2, 3: 2, 4: 2} - # small example where too aggressive edge removal can make cn[2] = 2 - more_edges = [(1, 5), (3, 5), (4, 5), (3, 6), (4, 6), (5, 6)] - G.add_edges_from(more_edges) - assert nx.core_number(G) == {1: 3, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3} - - def test_main_core(self): - main_core_subgraph = nx.k_core(self.H) - assert sorted(main_core_subgraph.nodes()) == [2, 4, 5, 6] - - def test_k_core(self): - # k=0 - k_core_subgraph = nx.k_core(self.H, k=0) - assert sorted(k_core_subgraph.nodes()) == sorted(self.H.nodes()) - # k=1 - k_core_subgraph = nx.k_core(self.H, k=1) - assert sorted(k_core_subgraph.nodes()) == [1, 2, 3, 4, 5, 6] - # k = 2 - k_core_subgraph = nx.k_core(self.H, k=2) - assert sorted(k_core_subgraph.nodes()) == [2, 4, 5, 6] - - def test_main_crust(self): - main_crust_subgraph = nx.k_crust(self.H) - assert sorted(main_crust_subgraph.nodes()) == [0, 1, 3] - - def test_k_crust(self): - # k = 0 - k_crust_subgraph = nx.k_crust(self.H, k=2) - assert sorted(k_crust_subgraph.nodes()) == sorted(self.H.nodes()) - # k=1 - k_crust_subgraph = nx.k_crust(self.H, k=1) - assert sorted(k_crust_subgraph.nodes()) == [0, 1, 3] - # k=2 - k_crust_subgraph = nx.k_crust(self.H, k=0) - assert sorted(k_crust_subgraph.nodes()) == [0] - - def test_main_shell(self): - main_shell_subgraph = nx.k_shell(self.H) - assert sorted(main_shell_subgraph.nodes()) == [2, 4, 5, 6] - - def test_k_shell(self): - # k=0 - k_shell_subgraph = nx.k_shell(self.H, k=2) - assert sorted(k_shell_subgraph.nodes()) == [2, 4, 5, 6] - # k=1 - k_shell_subgraph = nx.k_shell(self.H, k=1) - assert sorted(k_shell_subgraph.nodes()) == [1, 3] - # k=2 - k_shell_subgraph = nx.k_shell(self.H, k=0) - assert sorted(k_shell_subgraph.nodes()) == [0] - - def test_k_corona(self): - # k=0 - k_corona_subgraph = nx.k_corona(self.H, k=2) - assert sorted(k_corona_subgraph.nodes()) == [2, 4, 5, 6] - # k=1 - k_corona_subgraph = nx.k_corona(self.H, k=1) - assert sorted(k_corona_subgraph.nodes()) == [1] - # k=2 - k_corona_subgraph = nx.k_corona(self.H, k=0) - assert sorted(k_corona_subgraph.nodes()) == [0] - - def test_k_truss(self): - # k=-1 - k_truss_subgraph = nx.k_truss(self.G, -1) - assert sorted(k_truss_subgraph.nodes()) == list(range(1,21)) - # k=0 - k_truss_subgraph = nx.k_truss(self.G, 0) - assert sorted(k_truss_subgraph.nodes()) == list(range(1,21)) - # k=1 - k_truss_subgraph = nx.k_truss(self.G, 1) - assert sorted(k_truss_subgraph.nodes()) == list(range(1,13)) - # k=2 - k_truss_subgraph = nx.k_truss(self.G, 2) - assert sorted(k_truss_subgraph.nodes()) == list(range(1,9)) - # k=3 - k_truss_subgraph = nx.k_truss(self.G, 3) - assert sorted(k_truss_subgraph.nodes()) == [] - - def test_onion_layers(self): - layers = nx.onion_layers(self.G) - nodes_by_layer = [sorted([n for n in layers if layers[n] == val]) - for val in range(1, 7)] - assert_nodes_equal(nodes_by_layer[0], [21]) - assert_nodes_equal(nodes_by_layer[1], [17, 18, 19, 20]) - assert_nodes_equal(nodes_by_layer[2], [10, 12, 13, 14, 15, 16]) - assert_nodes_equal(nodes_by_layer[3], [9, 11]) - assert_nodes_equal(nodes_by_layer[4], [1, 2, 4, 5, 6, 8]) - assert_nodes_equal(nodes_by_layer[5], [3, 7]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_covering.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_covering.py deleted file mode 100644 index 06109b19..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_covering.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2016-2019 NetworkX developers. -# Copyright (C) 2016 by -# Nishant Nikhil -# All rights reserved. -# BSD license. - -import networkx as nx - - -class TestMinEdgeCover: - """Tests for :func:`networkx.algorithms.min_edge_cover`""" - - def test_empty_graph(self): - G = nx.Graph() - assert nx.min_edge_cover(G) == set() - - def test_graph_with_loop(self): - G = nx.Graph() - G.add_edge(0, 0) - assert nx.min_edge_cover(G) == {(0, 0)} - - def test_graph_single_edge(self): - G = nx.Graph() - G.add_edge(0, 1) - assert nx.min_edge_cover(G) in ({(0, 1)}, {(1, 0)}) - - def test_bipartite_explicit(self): - G = nx.Graph() - G.add_nodes_from([1, 2, 3, 4], bipartite=0) - G.add_nodes_from(['a', 'b', 'c'], bipartite=1) - G.add_edges_from([(1, 'a'), (1, 'b'), (2, 'b'), - (2, 'c'), (3, 'c'), (4, 'a')]) - min_cover = nx.min_edge_cover(G, nx.algorithms.bipartite.matching. - eppstein_matching) - min_cover2 = nx.min_edge_cover(G) - assert nx.is_edge_cover(G, min_cover) - assert len(min_cover) == 8 - - def test_complete_graph(self): - G = nx.complete_graph(10) - min_cover = nx.min_edge_cover(G) - assert nx.is_edge_cover(G, min_cover) - assert len(min_cover) == 5 - - -class TestIsEdgeCover: - """Tests for :func:`networkx.algorithms.is_edge_cover`""" - - def test_empty_graph(self): - G = nx.Graph() - assert nx.is_edge_cover(G, set()) - - def test_graph_with_loop(self): - G = nx.Graph() - G.add_edge(1, 1) - assert nx.is_edge_cover(G, {(1, 1)}) - - def test_graph_single_edge(self): - G = nx.Graph() - G.add_edge(0, 1) - assert nx.is_edge_cover(G, {(0, 0), (1, 1)}) - assert nx.is_edge_cover(G, {(0, 1), (1, 0)}) - assert nx.is_edge_cover(G, {(0, 1)}) - assert not nx.is_edge_cover(G, {(0, 0)}) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_cuts.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_cuts.py deleted file mode 100644 index 0befb7c2..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_cuts.py +++ /dev/null @@ -1,173 +0,0 @@ -# test_cuts.py - unit tests for the cuts module -# -# Copyright 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.cuts` module.""" - - -import networkx as nx - - -class TestCutSize(object): - """Unit tests for the :func:`~networkx.cut_size` function.""" - - def test_symmetric(self): - """Tests that the cut size is symmetric.""" - G = nx.barbell_graph(3, 0) - S = {0, 1, 4} - T = {2, 3, 5} - assert nx.cut_size(G, S, T) == 4 - assert nx.cut_size(G, T, S) == 4 - - def test_single_edge(self): - """Tests for a cut of a single edge.""" - G = nx.barbell_graph(3, 0) - S = {0, 1, 2} - T = {3, 4, 5} - assert nx.cut_size(G, S, T) == 1 - assert nx.cut_size(G, T, S) == 1 - - def test_directed(self): - """Tests that each directed edge is counted once in the cut.""" - G = nx.barbell_graph(3, 0).to_directed() - S = {0, 1, 2} - T = {3, 4, 5} - assert nx.cut_size(G, S, T) == 2 - assert nx.cut_size(G, T, S) == 2 - - def test_directed_symmetric(self): - """Tests that a cut in a directed graph is symmetric.""" - G = nx.barbell_graph(3, 0).to_directed() - S = {0, 1, 4} - T = {2, 3, 5} - assert nx.cut_size(G, S, T) == 8 - assert nx.cut_size(G, T, S) == 8 - - def test_multigraph(self): - """Tests that parallel edges are each counted for a cut.""" - G = nx.MultiGraph(['ab', 'ab']) - assert nx.cut_size(G, {'a'}, {'b'}) == 2 - - -class TestVolume(object): - """Unit tests for the :func:`~networkx.volume` function.""" - - def test_graph(self): - G = nx.cycle_graph(4) - assert nx.volume(G, {0, 1}) == 4 - - def test_digraph(self): - G = nx.DiGraph([(0, 1), (1, 2), (2, 3), (3, 0)]) - assert nx.volume(G, {0, 1}) == 2 - - def test_multigraph(self): - edges = list(nx.cycle_graph(4).edges()) - G = nx.MultiGraph(edges * 2) - assert nx.volume(G, {0, 1}) == 8 - - def test_multidigraph(self): - edges = [(0, 1), (1, 2), (2, 3), (3, 0)] - G = nx.MultiDiGraph(edges * 2) - assert nx.volume(G, {0, 1}) == 4 - - -class TestNormalizedCutSize(object): - """Unit tests for the :func:`~networkx.normalized_cut_size` - function. - - """ - - def test_graph(self): - G = nx.path_graph(4) - S = {1, 2} - T = set(G) - S - size = nx.normalized_cut_size(G, S, T) - # The cut looks like this: o-{-o--o-}-o - expected = 2 * ((1 / 4) + (1 / 2)) - assert expected == size - - def test_directed(self): - G = nx.DiGraph([(0, 1), (1, 2), (2, 3)]) - S = {1, 2} - T = set(G) - S - size = nx.normalized_cut_size(G, S, T) - # The cut looks like this: o-{->o-->o-}->o - expected = 2 * ((1 / 2) + (1 / 1)) - assert expected == size - - -class TestConductance(object): - """Unit tests for the :func:`~networkx.conductance` function.""" - - def test_graph(self): - G = nx.barbell_graph(5, 0) - # Consider the singleton sets containing the "bridge" nodes. - # There is only one cut edge, and each set has volume five. - S = {4} - T = {5} - conductance = nx.conductance(G, S, T) - expected = 1 / 5 - assert expected == conductance - - -class TestEdgeExpansion(object): - """Unit tests for the :func:`~networkx.edge_expansion` function.""" - - def test_graph(self): - G = nx.barbell_graph(5, 0) - S = set(range(5)) - T = set(G) - S - expansion = nx.edge_expansion(G, S, T) - expected = 1 / 5 - assert expected == expansion - - -class TestNodeExpansion(object): - """Unit tests for the :func:`~networkx.node_expansion` function. - - """ - - def test_graph(self): - G = nx.path_graph(8) - S = {3, 4, 5} - expansion = nx.node_expansion(G, S) - # The neighborhood of S has cardinality five, and S has - # cardinality three. - expected = 5 / 3 - assert expected == expansion - - -class TestBoundaryExpansion(object): - """Unit tests for the :func:`~networkx.boundary_expansion` function. - - """ - - def test_graph(self): - G = nx.complete_graph(10) - S = set(range(4)) - expansion = nx.boundary_expansion(G, S) - # The node boundary of S has cardinality six, and S has - # cardinality three. - expected = 6 / 4 - assert expected == expansion - - -class TestMixingExpansion(object): - """Unit tests for the :func:`~networkx.mixing_expansion` function. - - """ - - def test_graph(self): - G = nx.barbell_graph(5, 0) - S = set(range(5)) - T = set(G) - S - expansion = nx.mixing_expansion(G, S, T) - # There is one cut edge, and the total number of edges in the - # graph is twice the total number of edges in a clique of size - # five, plus one more for the bridge. - expected = 1 / (2 * (5 * 4 + 1)) - assert expected == expansion diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_cycles.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_cycles.py deleted file mode 100644 index 003f660a..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_cycles.py +++ /dev/null @@ -1,331 +0,0 @@ -#!/usr/bin/env python -import pytest -import networkx -import networkx as nx - -from networkx.algorithms import find_cycle -from networkx.algorithms import minimum_cycle_basis - -FORWARD = nx.algorithms.edgedfs.FORWARD -REVERSE = nx.algorithms.edgedfs.REVERSE - - -class TestCycles: - @classmethod - def setup_class(cls): - G = networkx.Graph() - nx.add_cycle(G, [0, 1, 2, 3]) - nx.add_cycle(G, [0, 3, 4, 5]) - nx.add_cycle(G, [0, 1, 6, 7, 8]) - G.add_edge(8, 9) - cls.G = G - - def is_cyclic_permutation(self, a, b): - n = len(a) - if len(b) != n: - return False - l = a + a - return any(l[i:i + n] == b for i in range(n)) - - def test_cycle_basis(self): - G = self.G - cy = networkx.cycle_basis(G, 0) - sort_cy = sorted(sorted(c) for c in cy) - assert sort_cy == [[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5]] - cy = networkx.cycle_basis(G, 1) - sort_cy = sorted(sorted(c) for c in cy) - assert sort_cy == [[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5]] - cy = networkx.cycle_basis(G, 9) - sort_cy = sorted(sorted(c) for c in cy) - assert sort_cy == [[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5]] - # test disconnected graphs - nx.add_cycle(G, "ABC") - cy = networkx.cycle_basis(G, 9) - sort_cy = sorted(sorted(c) for c in cy[:-1]) + [sorted(cy[-1])] - assert sort_cy == [[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5], - ['A', 'B', 'C']] - - def test_cycle_basis(self): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.DiGraph() - cy = networkx.cycle_basis(G, 0) - - def test_cycle_basis(self): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.MultiGraph() - cy = networkx.cycle_basis(G, 0) - - def test_simple_cycles(self): - edges = [(0, 0), (0, 1), (0, 2), (1, 2), (2, 0), (2, 1), (2, 2)] - G = nx.DiGraph(edges) - cc = sorted(nx.simple_cycles(G)) - ca = [[0], [0, 1, 2], [0, 2], [1, 2], [2]] - assert len(cc) == len(ca) - for c in cc: - assert any(self.is_cyclic_permutation(c, rc) for rc in ca) - - def test_simple_cycles_graph(self): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.Graph() - c = sorted(nx.simple_cycles(G)) - - def test_unsortable(self): - # TODO What does this test do? das 6/2013 - G = nx.DiGraph() - nx.add_cycle(G, ['a', 1]) - c = list(nx.simple_cycles(G)) - - def test_simple_cycles_small(self): - G = nx.DiGraph() - nx.add_cycle(G, [1, 2, 3]) - c = sorted(nx.simple_cycles(G)) - assert len(c) == 1 - assert self.is_cyclic_permutation(c[0], [1, 2, 3]) - nx.add_cycle(G, [10, 20, 30]) - cc = sorted(nx.simple_cycles(G)) - assert len(cc) == 2 - ca = [[1, 2, 3], [10, 20, 30]] - for c in cc: - assert any(self.is_cyclic_permutation(c, rc) for rc in ca) - - def test_simple_cycles_empty(self): - G = nx.DiGraph() - assert list(nx.simple_cycles(G)) == [] - - def test_complete_directed_graph(self): - # see table 2 in Johnson's paper - ncircuits = [1, 5, 20, 84, 409, 2365, 16064] - for n, c in zip(range(2, 9), ncircuits): - G = nx.DiGraph(nx.complete_graph(n)) - assert len(list(nx.simple_cycles(G))) == c - - def worst_case_graph(self, k): - # see figure 1 in Johnson's paper - # this graph has exactly 3k simple cycles - G = nx.DiGraph() - for n in range(2, k + 2): - G.add_edge(1, n) - G.add_edge(n, k + 2) - G.add_edge(2 * k + 1, 1) - for n in range(k + 2, 2 * k + 2): - G.add_edge(n, 2 * k + 2) - G.add_edge(n, n + 1) - G.add_edge(2 * k + 3, k + 2) - for n in range(2 * k + 3, 3 * k + 3): - G.add_edge(2 * k + 2, n) - G.add_edge(n, 3 * k + 3) - G.add_edge(3 * k + 3, 2 * k + 2) - return G - - def test_worst_case_graph(self): - # see figure 1 in Johnson's paper - for k in range(3, 10): - G = self.worst_case_graph(k) - l = len(list(nx.simple_cycles(G))) - assert l == 3 * k - - def test_recursive_simple_and_not(self): - for k in range(2, 10): - G = self.worst_case_graph(k) - cc = sorted(nx.simple_cycles(G)) - rcc = sorted(nx.recursive_simple_cycles(G)) - assert len(cc) == len(rcc) - for c in cc: - assert any(self.is_cyclic_permutation(c, r) for r in rcc) - for rc in rcc: - assert any(self.is_cyclic_permutation(rc, c) for c in cc) - - def test_simple_graph_with_reported_bug(self): - G = nx.DiGraph() - edges = [(0, 2), (0, 3), (1, 0), (1, 3), (2, 1), (2, 4), - (3, 2), (3, 4), (4, 0), (4, 1), (4, 5), (5, 0), - (5, 1), (5, 2), (5, 3)] - G.add_edges_from(edges) - cc = sorted(nx.simple_cycles(G)) - assert len(cc) == 26 - rcc = sorted(nx.recursive_simple_cycles(G)) - assert len(cc) == len(rcc) - for c in cc: - assert any(self.is_cyclic_permutation(c, rc) for rc in rcc) - for rc in rcc: - assert any(self.is_cyclic_permutation(rc, c) for c in cc) - -# These tests might fail with hash randomization since they depend on -# edge_dfs. For more information, see the comments in: -# networkx/algorithms/traversal/tests/test_edgedfs.py - - -class TestFindCycle(object): - @classmethod - def setup_class(cls): - cls.nodes = [0, 1, 2, 3] - cls.edges = [(-1, 0), (0, 1), (1, 0), (1, 0), (2, 1), (3, 1)] - - def test_graph_nocycle(self): - G = nx.Graph(self.edges) - pytest.raises(nx.exception.NetworkXNoCycle, find_cycle, G, self.nodes) - - def test_graph_cycle(self): - G = nx.Graph(self.edges) - G.add_edge(2, 0) - x = list(find_cycle(G, self.nodes)) - x_ = [(0, 1), (1, 2), (2, 0)] - assert x == x_ - - def test_graph_orientation_none(self): - G = nx.Graph(self.edges) - G.add_edge(2, 0) - x = list(find_cycle(G, self.nodes, orientation=None)) - x_ = [(0, 1), (1, 2), (2, 0)] - assert x == x_ - - def test_graph_orientation_original(self): - G = nx.Graph(self.edges) - G.add_edge(2, 0) - x = list(find_cycle(G, self.nodes, orientation='original')) - x_ = [(0, 1, FORWARD), (1, 2, FORWARD), (2, 0, FORWARD)] - assert x == x_ - - def test_digraph(self): - G = nx.DiGraph(self.edges) - x = list(find_cycle(G, self.nodes)) - x_ = [(0, 1), (1, 0)] - assert x == x_ - - def test_digraph_orientation_none(self): - G = nx.DiGraph(self.edges) - x = list(find_cycle(G, self.nodes, orientation=None)) - x_ = [(0, 1), (1, 0)] - assert x == x_ - - def test_digraph_orientation_original(self): - G = nx.DiGraph(self.edges) - x = list(find_cycle(G, self.nodes, orientation='original')) - x_ = [(0, 1, FORWARD), (1, 0, FORWARD)] - assert x == x_ - - def test_multigraph(self): - G = nx.MultiGraph(self.edges) - x = list(find_cycle(G, self.nodes)) - x_ = [(0, 1, 0), (1, 0, 1)] # or (1, 0, 2) - # Hash randomization...could be any edge. - assert x[0] == x_[0] - assert x[1][:2] == x_[1][:2] - - def test_multidigraph(self): - G = nx.MultiDiGraph(self.edges) - x = list(find_cycle(G, self.nodes)) - x_ = [(0, 1, 0), (1, 0, 0)] # (1, 0, 1) - assert x[0] == x_[0] - assert x[1][:2] == x_[1][:2] - - def test_digraph_ignore(self): - G = nx.DiGraph(self.edges) - x = list(find_cycle(G, self.nodes, orientation='ignore')) - x_ = [(0, 1, FORWARD), (1, 0, FORWARD)] - assert x == x_ - - def test_digraph_reverse(self): - G = nx.DiGraph(self.edges) - x = list(find_cycle(G, self.nodes, orientation='reverse')) - x_ = [(1, 0, REVERSE), (0, 1, REVERSE)] - assert x == x_ - - def test_multidigraph_ignore(self): - G = nx.MultiDiGraph(self.edges) - x = list(find_cycle(G, self.nodes, orientation='ignore')) - x_ = [(0, 1, 0, FORWARD), (1, 0, 0, FORWARD)] # or (1, 0, 1, 1) - assert x[0] == x_[0] - assert x[1][:2] == x_[1][:2] - assert x[1][3] == x_[1][3] - - def test_multidigraph_ignore2(self): - # Loop traversed an edge while ignoring its orientation. - G = nx.MultiDiGraph([(0, 1), (1, 2), (1, 2)]) - x = list(find_cycle(G, [0, 1, 2], orientation='ignore')) - x_ = [(1, 2, 0, FORWARD), (1, 2, 1, REVERSE)] - assert x == x_ - - def test_multidigraph_original(self): - # Node 2 doesn't need to be searched again from visited from 4. - # The goal here is to cover the case when 2 to be researched from 4, - # when 4 is visited from the first time (so we must make sure that 4 - # is not visited from 2, and hence, we respect the edge orientation). - G = nx.MultiDiGraph([(0, 1), (1, 2), (2, 3), (4, 2)]) - pytest.raises(nx.exception.NetworkXNoCycle, - find_cycle, G, [0, 1, 2, 3, 4], orientation='original') - - def test_dag(self): - G = nx.DiGraph([(0, 1), (0, 2), (1, 2)]) - pytest.raises(nx.exception.NetworkXNoCycle, - find_cycle, G, orientation='original') - x = list(find_cycle(G, orientation='ignore')) - assert x == [(0, 1, FORWARD), (1, 2, FORWARD), (0, 2, REVERSE)] - - def test_prev_explored(self): - # https://github.com/networkx/networkx/issues/2323 - - G = nx.DiGraph() - G.add_edges_from([(1, 0), (2, 0), (1, 2), (2, 1)]) - pytest.raises(nx.NetworkXNoCycle, find_cycle, G, source=0) - x = list(nx.find_cycle(G, 1)) - x_ = [(1, 2), (2, 1)] - assert x == x_ - - x = list(nx.find_cycle(G, 2)) - x_ = [(2, 1), (1, 2)] - assert x == x_ - - x = list(nx.find_cycle(G)) - x_ = [(1, 2), (2, 1)] - assert x == x_ - - def test_no_cycle(self): - # https://github.com/networkx/networkx/issues/2439 - - G = nx.DiGraph() - G.add_edges_from([(1, 2), (2, 0), (3, 1), (3, 2)]) - pytest.raises(nx.NetworkXNoCycle, find_cycle, G, source=0) - pytest.raises(nx.NetworkXNoCycle, find_cycle, G) - - -def assert_basis_equal(a, b): - assert sorted(a) == sorted(b) - - -class TestMinimumCycles(object): - @classmethod - def setup_class(cls): - T = nx.Graph() - nx.add_cycle(T, [1, 2, 3, 4], weight=1) - T.add_edge(2, 4, weight=5) - cls.diamond_graph = T - - def test_unweighted_diamond(self): - mcb = minimum_cycle_basis(self.diamond_graph) - assert_basis_equal([sorted(c) for c in mcb], [[1, 2, 4], [2, 3, 4]]) - - def test_weighted_diamond(self): - mcb = minimum_cycle_basis(self.diamond_graph, weight='weight') - assert_basis_equal([sorted(c) for c in mcb], [[1, 2, 4], [1, 2, 3, 4]]) - - def test_dimensionality(self): - # checks |MCB|=|E|-|V|+|NC| - ntrial = 10 - for _ in range(ntrial): - rg = nx.erdos_renyi_graph(10, 0.3) - nnodes = rg.number_of_nodes() - nedges = rg.number_of_edges() - ncomp = nx.number_connected_components(rg) - - dim_mcb = len(minimum_cycle_basis(rg)) - assert dim_mcb == nedges - nnodes + ncomp - - def test_complete_graph(self): - cg = nx.complete_graph(5) - mcb = minimum_cycle_basis(cg) - assert all([len(cycle) == 3 for cycle in mcb]) - - def test_tree_graph(self): - tg = nx.balanced_tree(3, 3) - assert not minimum_cycle_basis(tg) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_dag.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_dag.py deleted file mode 100644 index 2e0590c0..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_dag.py +++ /dev/null @@ -1,606 +0,0 @@ -from itertools import combinations, permutations - -import pytest - -import networkx as nx -from networkx.testing.utils import assert_edges_equal -from networkx.utils import consume -from networkx.utils import pairwise - - -class TestDagLongestPath(object): - """Unit tests computing the longest path in a directed acyclic graph.""" - - def test_empty(self): - G = nx.DiGraph() - assert nx.dag_longest_path(G) == [] - - def test_unweighted1(self): - edges = [(1, 2), (2, 3), (2, 4), (3, 5), (5, 6), (3, 7)] - G = nx.DiGraph(edges) - assert nx.dag_longest_path(G) == [1, 2, 3, 5, 6] - - def test_unweighted2(self): - edges = [(1, 2), (2, 3), (3, 4), (4, 5), (1, 3), (1, 5), (3, 5)] - G = nx.DiGraph(edges) - assert nx.dag_longest_path(G) == [1, 2, 3, 4, 5] - - def test_weighted(self): - G = nx.DiGraph() - edges = [(1, 2, -5), (2, 3, 1), (3, 4, 1), (4, 5, 0), (3, 5, 4), - (1, 6, 2)] - G.add_weighted_edges_from(edges) - assert nx.dag_longest_path(G) == [2, 3, 5] - - def test_undirected_not_implemented(self): - G = nx.Graph() - pytest.raises(nx.NetworkXNotImplemented, nx.dag_longest_path, G) - - def test_unorderable_nodes(self): - """Tests that computing the longest path does not depend on - nodes being orderable. - - For more information, see issue #1989. - - """ - # TODO In Python 3, instances of the `object` class are - # unorderable by default, so we wouldn't need to define our own - # class here, we could just instantiate an instance of the - # `object` class. However, we still support Python 2; when - # support for Python 2 is dropped, this test can be simplified - # by replacing `Unorderable()` by `object()`. - class Unorderable(object): - def __lt__(self, other): - error_msg = "< not supported between instances of {} and {}" - types = (type(self).__name__, type(other).__name__) - raise TypeError(error_msg.format(types)) - - # Create the directed path graph on four nodes in a diamond shape, - # with nodes represented as (unorderable) Python objects. - nodes = [Unorderable() for n in range(4)] - G = nx.DiGraph() - G.add_edge(nodes[0], nodes[1]) - G.add_edge(nodes[0], nodes[2]) - G.add_edge(nodes[2], nodes[3]) - G.add_edge(nodes[1], nodes[3]) - - # this will raise NotImplementedError when nodes need to be ordered - nx.dag_longest_path(G) - - -class TestDagLongestPathLength(object): - """Unit tests for computing the length of a longest path in a - directed acyclic graph. - - """ - - def test_unweighted(self): - edges = [(1, 2), (2, 3), (2, 4), (3, 5), (5, 6), (5, 7)] - G = nx.DiGraph(edges) - assert nx.dag_longest_path_length(G) == 4 - - edges = [(1, 2), (2, 3), (3, 4), (4, 5), (1, 3), (1, 5), (3, 5)] - G = nx.DiGraph(edges) - assert nx.dag_longest_path_length(G) == 4 - - # test degenerate graphs - G = nx.DiGraph() - G.add_node(1) - assert nx.dag_longest_path_length(G) == 0 - - def test_undirected_not_implemented(self): - G = nx.Graph() - pytest.raises(nx.NetworkXNotImplemented, nx.dag_longest_path_length, G) - - def test_weighted(self): - edges = [(1, 2, -5), (2, 3, 1), (3, 4, 1), (4, 5, 0), (3, 5, 4), - (1, 6, 2)] - G = nx.DiGraph() - G.add_weighted_edges_from(edges) - assert nx.dag_longest_path_length(G) == 5 - - -class TestDAG: - - @classmethod - def setup_class(cls): - pass - - def test_topological_sort1(self): - DG = nx.DiGraph([(1, 2), (1, 3), (2, 3)]) - - for algorithm in [nx.topological_sort, - nx.lexicographical_topological_sort]: - assert tuple(algorithm(DG)) == (1, 2, 3) - - DG.add_edge(3, 2) - - for algorithm in [nx.topological_sort, - nx.lexicographical_topological_sort]: - pytest.raises(nx.NetworkXUnfeasible, consume, algorithm(DG)) - - DG.remove_edge(2, 3) - - for algorithm in [nx.topological_sort, - nx.lexicographical_topological_sort]: - assert tuple(algorithm(DG)) == (1, 3, 2) - - DG.remove_edge(3, 2) - - assert tuple(nx.topological_sort(DG)) in {(1, 2, 3), (1, 3, 2)} - assert tuple(nx.lexicographical_topological_sort(DG)) == (1, 2, 3) - - def test_is_directed_acyclic_graph(self): - G = nx.generators.complete_graph(2) - assert not nx.is_directed_acyclic_graph(G) - assert not nx.is_directed_acyclic_graph(G.to_directed()) - assert not nx.is_directed_acyclic_graph(nx.Graph([(3, 4), (4, 5)])) - assert nx.is_directed_acyclic_graph(nx.DiGraph([(3, 4), (4, 5)])) - - def test_topological_sort2(self): - DG = nx.DiGraph({1: [2], 2: [3], 3: [4], - 4: [5], 5: [1], 11: [12], - 12: [13], 13: [14], 14: [15]}) - pytest.raises(nx.NetworkXUnfeasible, consume, nx.topological_sort(DG)) - - assert not nx.is_directed_acyclic_graph(DG) - - DG.remove_edge(1, 2) - consume(nx.topological_sort(DG)) - assert nx.is_directed_acyclic_graph(DG) - - def test_topological_sort3(self): - DG = nx.DiGraph() - DG.add_edges_from([(1, i) for i in range(2, 5)]) - DG.add_edges_from([(2, i) for i in range(5, 9)]) - DG.add_edges_from([(6, i) for i in range(9, 12)]) - DG.add_edges_from([(4, i) for i in range(12, 15)]) - - def validate(order): - assert isinstance(order, list) - assert set(order) == set(DG) - for u, v in combinations(order, 2): - assert not nx.has_path(DG, v, u) - validate(list(nx.topological_sort(DG))) - - DG.add_edge(14, 1) - pytest.raises(nx.NetworkXUnfeasible, consume, nx.topological_sort(DG)) - - def test_topological_sort4(self): - G = nx.Graph() - G.add_edge(1, 2) - # Only directed graphs can be topologically sorted. - pytest.raises(nx.NetworkXError, consume, nx.topological_sort(G)) - - def test_topological_sort5(self): - G = nx.DiGraph() - G.add_edge(0, 1) - assert list(nx.topological_sort(G)) == [0, 1] - - def test_topological_sort6(self): - for algorithm in [nx.topological_sort, - nx.lexicographical_topological_sort]: - def runtime_error(): - DG = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - first = True - for x in algorithm(DG): - if first: - first = False - DG.add_edge(5 - x, 5) - - def unfeasible_error(): - DG = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - first = True - for x in algorithm(DG): - if first: - first = False - DG.remove_node(4) - - def runtime_error2(): - DG = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - first = True - for x in algorithm(DG): - if first: - first = False - DG.remove_node(2) - - pytest.raises(RuntimeError, runtime_error) - pytest.raises(RuntimeError, runtime_error2) - pytest.raises(nx.NetworkXUnfeasible, unfeasible_error) - - def test_all_topological_sorts_1(self): - DG = nx.DiGraph([(1, 2), (2, 3), (3, 4), (4, 5)]) - assert list(nx.all_topological_sorts(DG)) == [[1, 2, 3, 4, 5]] - - def test_all_topological_sorts_2(self): - DG = nx.DiGraph([(1, 3), (2, 1), (2, 4), (4, 3), (4, 5)]) - assert (sorted(nx.all_topological_sorts(DG)) == - [[2, 1, 4, 3, 5], - [2, 1, 4, 5, 3], - [2, 4, 1, 3, 5], - [2, 4, 1, 5, 3], - [2, 4, 5, 1, 3]]) - - def test_all_topological_sorts_3(self): - def unfeasible(): - DG = nx.DiGraph([(1, 2), (2, 3), (3, 4), (4, 2), (4, 5)]) - # convert to list to execute generator - list(nx.all_topological_sorts(DG)) - - def not_implemented(): - G = nx.Graph([(1, 2), (2, 3)]) - # convert to list to execute generator - list(nx.all_topological_sorts(G)) - - def not_implemted_2(): - G = nx.MultiGraph([(1, 2), (1, 2), (2, 3)]) - list(nx.all_topological_sorts(G)) - pytest.raises(nx.NetworkXUnfeasible, unfeasible) - pytest.raises(nx.NetworkXNotImplemented, not_implemented) - pytest.raises(nx.NetworkXNotImplemented, not_implemted_2) - - def test_all_topological_sorts_4(self): - DG = nx.DiGraph() - for i in range(7): - DG.add_node(i) - assert (sorted(map(list, permutations(DG.nodes))) == - sorted(nx.all_topological_sorts(DG))) - - def test_all_topological_sorts_multigraph_1(self): - DG = nx.MultiDiGraph([(1, 2), (1, 2), (2, 3), - (3, 4), (3, 5), (3, 5), (3, 5)]) - assert (sorted(nx.all_topological_sorts(DG)) == - sorted([[1, 2, 3, 4, 5], - [1, 2, 3, 5, 4]])) - - def test_all_topological_sorts_multigraph_2(self): - N = 9 - edges = [] - for i in range(1, N): - edges.extend([(i, i+1)] * i) - DG = nx.MultiDiGraph(edges) - assert (list(nx.all_topological_sorts(DG)) == - [list(range(1, N+1))]) - - def test_ancestors(self): - G = nx.DiGraph() - ancestors = nx.algorithms.dag.ancestors - G.add_edges_from([ - (1, 2), (1, 3), (4, 2), (4, 3), (4, 5), (2, 6), (5, 6)]) - assert ancestors(G, 6) == set([1, 2, 4, 5]) - assert ancestors(G, 3) == set([1, 4]) - assert ancestors(G, 1) == set() - pytest.raises(nx.NetworkXError, ancestors, G, 8) - - def test_descendants(self): - G = nx.DiGraph() - descendants = nx.algorithms.dag.descendants - G.add_edges_from([ - (1, 2), (1, 3), (4, 2), (4, 3), (4, 5), (2, 6), (5, 6)]) - assert descendants(G, 1) == set([2, 3, 6]) - assert descendants(G, 4) == set([2, 3, 5, 6]) - assert descendants(G, 3) == set() - pytest.raises(nx.NetworkXError, descendants, G, 8) - - def test_transitive_closure(self): - G = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - assert_edges_equal(nx.transitive_closure(G).edges(), solution) - G = nx.DiGraph([(1, 2), (2, 3), (2, 4)]) - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4)] - assert_edges_equal(nx.transitive_closure(G).edges(), solution) - G = nx.DiGraph([(1, 2), (2, 3), (3, 1)]) - solution = [(1, 2), (2, 1), (2, 3), (3, 2), (1, 3), (3, 1)] - soln = sorted(solution + [(n, n) for n in G]) - assert_edges_equal(sorted(nx.transitive_closure(G).edges()), soln) - G = nx.Graph([(1, 2), (2, 3), (3, 4)]) - pytest.raises(nx.NetworkXNotImplemented, nx.transitive_closure, G) - - # test if edge data is copied - G = nx.DiGraph([(1, 2, {"a": 3}), (2, 3, {"b": 0}), (3, 4)]) - H = nx.transitive_closure(G) - for u, v in G.edges(): - assert G.get_edge_data(u, v) == H.get_edge_data(u, v) - - k = 10 - G = nx.DiGraph((i, i + 1, {"f": "b", "weight": i}) for i in range(k)) - H = nx.transitive_closure(G) - for u, v in G.edges(): - assert G.get_edge_data(u, v) == H.get_edge_data(u, v) - - def test_reflexive_transitive_closure(self): - G = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - soln = sorted(solution + [(n, n) for n in G]) - assert_edges_equal(nx.transitive_closure(G).edges(), solution) - assert_edges_equal(nx.transitive_closure(G, False).edges(), solution) - assert_edges_equal(nx.transitive_closure(G, True).edges(), soln) - assert_edges_equal(nx.transitive_closure(G, None).edges(), solution) - - G = nx.DiGraph([(1, 2), (2, 3), (2, 4)]) - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4)] - soln = sorted(solution + [(n, n) for n in G]) - assert_edges_equal(nx.transitive_closure(G).edges(), solution) - assert_edges_equal(nx.transitive_closure(G, False).edges(), solution) - assert_edges_equal(nx.transitive_closure(G, True).edges(), soln) - assert_edges_equal(nx.transitive_closure(G, None).edges(), solution) - - G = nx.DiGraph([(1, 2), (2, 3), (3, 1)]) - solution = sorted([(1, 2), (2, 1), (2, 3), (3, 2), (1, 3), (3, 1)]) - soln = sorted(solution + [(n, n) for n in G]) - assert_edges_equal(sorted(nx.transitive_closure(G).edges()), soln) - assert_edges_equal(sorted(nx.transitive_closure(G, False).edges()), soln) - assert_edges_equal(sorted(nx.transitive_closure(G, None).edges()), solution) - assert_edges_equal(sorted(nx.transitive_closure(G, True).edges()), soln) - - def test_transitive_closure_dag(self): - G = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - transitive_closure = nx.algorithms.dag.transitive_closure_dag - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - assert_edges_equal(transitive_closure(G).edges(), solution) - G = nx.DiGraph([(1, 2), (2, 3), (2, 4)]) - solution = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4)] - assert_edges_equal(transitive_closure(G).edges(), solution) - G = nx.Graph([(1, 2), (2, 3), (3, 4)]) - pytest.raises(nx.NetworkXNotImplemented, transitive_closure, G) - - # test if edge data is copied - G = nx.DiGraph([(1, 2, {"a": 3}), (2, 3, {"b": 0}), (3, 4)]) - H = transitive_closure(G) - for u, v in G.edges(): - assert G.get_edge_data(u, v) == H.get_edge_data(u, v) - - k = 10 - G = nx.DiGraph((i, i + 1, {"foo": "bar", "weight": i}) for i in range(k)) - H = transitive_closure(G) - for u, v in G.edges(): - assert G.get_edge_data(u, v) == H.get_edge_data(u, v) - - def test_transitive_reduction(self): - G = nx.DiGraph([(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]) - transitive_reduction = nx.algorithms.dag.transitive_reduction - solution = [(1, 2), (2, 3), (3, 4)] - assert_edges_equal(transitive_reduction(G).edges(), solution) - G = nx.DiGraph([(1, 2), (1, 3), (1, 4), (2, 3), (2, 4)]) - transitive_reduction = nx.algorithms.dag.transitive_reduction - solution = [(1, 2), (2, 3), (2, 4)] - assert_edges_equal(transitive_reduction(G).edges(), solution) - G = nx.Graph([(1, 2), (2, 3), (3, 4)]) - pytest.raises(nx.NetworkXNotImplemented, transitive_reduction, G) - - def _check_antichains(self, solution, result): - sol = [frozenset(a) for a in solution] - res = [frozenset(a) for a in result] - assert set(sol) == set(res) - - def test_antichains(self): - antichains = nx.algorithms.dag.antichains - G = nx.DiGraph([(1, 2), (2, 3), (3, 4)]) - solution = [[], [4], [3], [2], [1]] - self._check_antichains(list(antichains(G)), solution) - G = nx.DiGraph([(1, 2), (2, 3), (2, 4), (3, 5), (5, 6), (5, 7)]) - solution = [[], [4], [7], [7, 4], [6], [6, 4], [6, 7], [6, 7, 4], - [5], [5, 4], [3], [3, 4], [2], [1]] - self._check_antichains(list(antichains(G)), solution) - G = nx.DiGraph([(1, 2), (1, 3), (3, 4), (3, 5), (5, 6)]) - solution = [[], [6], [5], [4], [4, 6], [4, 5], [3], [2], [2, 6], - [2, 5], [2, 4], [2, 4, 6], [2, 4, 5], [2, 3], [1]] - self._check_antichains(list(antichains(G)), solution) - G = nx.DiGraph({0: [1, 2], 1: [4], 2: [3], 3: [4]}) - solution = [[], [4], [3], [2], [1], [1, 3], [1, 2], [0]] - self._check_antichains(list(antichains(G)), solution) - G = nx.DiGraph() - self._check_antichains(list(antichains(G)), [[]]) - G = nx.DiGraph() - G.add_nodes_from([0, 1, 2]) - solution = [[], [0], [1], [1, 0], [2], [2, 0], [2, 1], [2, 1, 0]] - self._check_antichains(list(antichains(G)), solution) - - def f(x): return list(antichains(x)) - G = nx.Graph([(1, 2), (2, 3), (3, 4)]) - pytest.raises(nx.NetworkXNotImplemented, f, G) - G = nx.DiGraph([(1, 2), (2, 3), (3, 1)]) - pytest.raises(nx.NetworkXUnfeasible, f, G) - - def test_lexicographical_topological_sort(self): - G = nx.DiGraph([(1, 2), (2, 3), (1, 4), (1, 5), (2, 6)]) - assert (list(nx.lexicographical_topological_sort(G)) == - [1, 2, 3, 4, 5, 6]) - assert (list(nx.lexicographical_topological_sort( - G, key=lambda x: x)) == - [1, 2, 3, 4, 5, 6]) - assert (list(nx.lexicographical_topological_sort( - G, key=lambda x: -x)) == - [1, 5, 4, 2, 6, 3]) - - def test_lexicographical_topological_sort2(self): - ''' - Check the case of two or more nodes with same key value. - Want to avoid exception raised due to comparing nodes directly. - See Issue #3493 - ''' - class Test_Node: - def __init__(self, n): - self.label = n - self.priority = 1 - - def __repr__(self): - return 'Node({})'.format(self.label) - - def sorting_key(node): - return node.priority - - test_nodes = [Test_Node(n) for n in range(4)] - G = nx.DiGraph() - edges = [(0, 1), (0, 2), (0, 3), (2, 3)] - G.add_edges_from((test_nodes[a], test_nodes[b]) for a, b in edges) - - sorting = list(nx.lexicographical_topological_sort(G, key=sorting_key)) - # order reported does depend on order of list(G) in python 3.5 - # and that is not deterministic due to dicts not being ordered until v3.6 - # after dropping NX support for 3.5 this can become: - # assert_equal(sorting, test_nodes) - assert set(sorting) == set(test_nodes) - - -def test_is_aperiodic_cycle(): - G = nx.DiGraph() - nx.add_cycle(G, [1, 2, 3, 4]) - assert not nx.is_aperiodic(G) - - -def test_is_aperiodic_cycle2(): - G = nx.DiGraph() - nx.add_cycle(G, [1, 2, 3, 4]) - nx.add_cycle(G, [3, 4, 5, 6, 7]) - assert nx.is_aperiodic(G) - - -def test_is_aperiodic_cycle3(): - G = nx.DiGraph() - nx.add_cycle(G, [1, 2, 3, 4]) - nx.add_cycle(G, [3, 4, 5, 6]) - assert not nx.is_aperiodic(G) - - -def test_is_aperiodic_cycle4(): - G = nx.DiGraph() - nx.add_cycle(G, [1, 2, 3, 4]) - G.add_edge(1, 3) - assert nx.is_aperiodic(G) - - -def test_is_aperiodic_selfloop(): - G = nx.DiGraph() - nx.add_cycle(G, [1, 2, 3, 4]) - G.add_edge(1, 1) - assert nx.is_aperiodic(G) - - -def test_is_aperiodic_raise(): - G = nx.Graph() - pytest.raises(nx.NetworkXError, - nx.is_aperiodic, - G) - - -def test_is_aperiodic_bipartite(): - # Bipartite graph - G = nx.DiGraph(nx.davis_southern_women_graph()) - assert not nx.is_aperiodic(G) - - -def test_is_aperiodic_rary_tree(): - G = nx.full_rary_tree(3, 27, create_using=nx.DiGraph()) - assert not nx.is_aperiodic(G) - - -def test_is_aperiodic_disconnected(): - # disconnected graph - G = nx.DiGraph() - nx.add_cycle(G, [1, 2, 3, 4]) - nx.add_cycle(G, [5, 6, 7, 8]) - assert not nx.is_aperiodic(G) - G.add_edge(1, 3) - G.add_edge(5, 7) - assert nx.is_aperiodic(G) - - -def test_is_aperiodic_disconnected2(): - G = nx.DiGraph() - nx.add_cycle(G, [0, 1, 2]) - G.add_edge(3, 3) - assert not nx.is_aperiodic(G) - - -class TestDagToBranching(object): - """Unit tests for the :func:`networkx.dag_to_branching` function.""" - - def test_single_root(self): - """Tests that a directed acyclic graph with a single degree - zero node produces an arborescence. - - """ - G = nx.DiGraph([(0, 1), (0, 2), (1, 3), (2, 3)]) - B = nx.dag_to_branching(G) - expected = nx.DiGraph([(0, 1), (1, 3), (0, 2), (2, 4)]) - assert nx.is_arborescence(B) - assert nx.is_isomorphic(B, expected) - - def test_multiple_roots(self): - """Tests that a directed acyclic graph with multiple degree zero - nodes creates an arborescence with multiple (weakly) connected - components. - - """ - G = nx.DiGraph([(0, 1), (0, 2), (1, 3), (2, 3), (5, 2)]) - B = nx.dag_to_branching(G) - expected = nx.DiGraph([(0, 1), (1, 3), (0, 2), (2, 4), (5, 6), (6, 7)]) - assert nx.is_branching(B) - assert not nx.is_arborescence(B) - assert nx.is_isomorphic(B, expected) - - # # Attributes are not copied by this function. If they were, this would - # # be a good test to uncomment. - # def test_copy_attributes(self): - # """Tests that node attributes are copied in the branching.""" - # G = nx.DiGraph([(0, 1), (0, 2), (1, 3), (2, 3)]) - # for v in G: - # G.node[v]['label'] = str(v) - # B = nx.dag_to_branching(G) - # # Determine the root node of the branching. - # root = next(v for v, d in B.in_degree() if d == 0) - # assert_equal(B.node[root]['label'], '0') - # children = B[root] - # # Get the left and right children, nodes 1 and 2, respectively. - # left, right = sorted(children, key=lambda v: B.node[v]['label']) - # assert_equal(B.node[left]['label'], '1') - # assert_equal(B.node[right]['label'], '2') - # # Get the left grandchild. - # children = B[left] - # assert_equal(len(children), 1) - # left_grandchild = arbitrary_element(children) - # assert_equal(B.node[left_grandchild]['label'], '3') - # # Get the right grandchild. - # children = B[right] - # assert_equal(len(children), 1) - # right_grandchild = arbitrary_element(children) - # assert_equal(B.node[right_grandchild]['label'], '3') - - def test_already_arborescence(self): - """Tests that a directed acyclic graph that is already an - arborescence produces an isomorphic arborescence as output. - - """ - A = nx.balanced_tree(2, 2, create_using=nx.DiGraph()) - B = nx.dag_to_branching(A) - assert nx.is_isomorphic(A, B) - - def test_already_branching(self): - """Tests that a directed acyclic graph that is already a - branching produces an isomorphic branching as output. - - """ - T1 = nx.balanced_tree(2, 2, create_using=nx.DiGraph()) - T2 = nx.balanced_tree(2, 2, create_using=nx.DiGraph()) - G = nx.disjoint_union(T1, T2) - B = nx.dag_to_branching(G) - assert nx.is_isomorphic(G, B) - - def test_not_acyclic(self): - """Tests that a non-acyclic graph causes an exception.""" - with pytest.raises(nx.HasACycle): - G = nx.DiGraph(pairwise('abc', cyclic=True)) - nx.dag_to_branching(G) - - def test_undirected(self): - with pytest.raises(nx.NetworkXNotImplemented): - nx.dag_to_branching(nx.Graph()) - - def test_multigraph(self): - with pytest.raises(nx.NetworkXNotImplemented): - nx.dag_to_branching(nx.MultiGraph()) - - def test_multidigraph(self): - with pytest.raises(nx.NetworkXNotImplemented): - nx.dag_to_branching(nx.MultiDiGraph()) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_distance_measures.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_distance_measures.py deleted file mode 100644 index 49e4569b..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_distance_measures.py +++ /dev/null @@ -1,259 +0,0 @@ -#!/usr/bin/env python -from random import Random - -import pytest - - -import networkx as nx -from networkx import convert_node_labels_to_integers as cnlti - - -class TestDistance: - def setup_method(self): - G = cnlti(nx.grid_2d_graph(4, 4), first_label=1, ordering="sorted") - self.G = G - - def test_eccentricity(self): - assert nx.eccentricity(self.G, 1) == 6 - e = nx.eccentricity(self.G) - assert e[1] == 6 - - sp = dict(nx.shortest_path_length(self.G)) - e = nx.eccentricity(self.G, sp=sp) - assert e[1] == 6 - - e = nx.eccentricity(self.G, v=1) - assert e == 6 - - # This behavior changed in version 1.8 (ticket #739) - e = nx.eccentricity(self.G, v=[1, 1]) - assert e[1] == 6 - e = nx.eccentricity(self.G, v=[1, 2]) - assert e[1] == 6 - - # test against graph with one node - G = nx.path_graph(1) - e = nx.eccentricity(G) - assert e[0] == 0 - e = nx.eccentricity(G, v=0) - assert e == 0 - pytest.raises(nx.NetworkXError, nx.eccentricity, G, 1) - - # test against empty graph - G = nx.empty_graph() - e = nx.eccentricity(G) - assert e == {} - - def test_diameter(self): - assert nx.diameter(self.G) == 6 - - def test_radius(self): - assert nx.radius(self.G) == 4 - - def test_periphery(self): - assert set(nx.periphery(self.G)) == set([1, 4, 13, 16]) - - def test_center(self): - assert set(nx.center(self.G)) == set([6, 7, 10, 11]) - - def test_bound_diameter(self): - assert nx.diameter(self.G, usebounds=True) == 6 - - def test_bound_radius(self): - assert nx.radius(self.G, usebounds=True) == 4 - - def test_bound_periphery(self): - result = set([1, 4, 13, 16]) - assert set(nx.periphery(self.G, usebounds=True)) == result - - def test_bound_center(self): - result = set([6, 7, 10, 11]) - assert set(nx.center(self.G, usebounds=True)) == result - - def test_radius_exception(self): - G = nx.Graph() - G.add_edge(1, 2) - G.add_edge(3, 4) - pytest.raises(nx.NetworkXError, nx.diameter, G) - - def test_eccentricity_infinite(self): - with pytest.raises(nx.NetworkXError): - G = nx.Graph([(1, 2), (3, 4)]) - e = nx.eccentricity(G) - - def test_eccentricity_undirected_not_connected(self): - with pytest.raises(nx.NetworkXError): - G = nx.Graph([(1, 2), (3, 4)]) - e = nx.eccentricity(G, sp=1) - - def test_eccentricity_directed_weakly_connected(self): - with pytest.raises(nx.NetworkXError): - DG = nx.DiGraph([(1, 2), (1, 3)]) - nx.eccentricity(DG) - - -class TestResistanceDistance: - @classmethod - def setup_class(cls): - global np - global sp_sparse - np = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') - sp_sparse = pytest.importorskip('scipy.sparse') - - def setup_method(self): - G = nx.Graph() - G.add_edge(1, 2, weight=2) - G.add_edge(2, 3, weight=4) - G.add_edge(3, 4, weight=1) - G.add_edge(1, 4, weight=3) - self.G = G - - def test_laplacian_submatrix(self): - from networkx.algorithms.distance_measures import _laplacian_submatrix - M = sp_sparse.csr_matrix([[1, 2, 3], - [4, 5, 6], - [7, 8, 9]], dtype=np.float32) - N = sp_sparse.csr_matrix([[5, 6], - [8, 9]], dtype=np.float32) - Mn, Mn_nodelist = _laplacian_submatrix(1, M, [1, 2, 3]) - assert Mn_nodelist == [2, 3] - assert np.allclose(Mn.toarray(), N.toarray()) - - def test_laplacian_submatrix_square(self): - with pytest.raises(nx.NetworkXError): - from networkx.algorithms.distance_measures import _laplacian_submatrix - M = sp_sparse.csr_matrix([[1, 2], - [4, 5], - [7, 8]], dtype=np.float32) - _laplacian_submatrix(1, M, [1, 2, 3]) - - def test_laplacian_submatrix_matrix_node_dim(self): - with pytest.raises(nx.NetworkXError): - from networkx.algorithms.distance_measures import _laplacian_submatrix - M = sp_sparse.csr_matrix([[1, 2, 3], - [4, 5, 6], - [7, 8, 9]], dtype=np.float32) - _laplacian_submatrix(1, M, [1, 2, 3, 4]) - - def test_resistance_distance(self): - rd = nx.resistance_distance(self.G, 1, 3, 'weight', True) - test_data = 1/(1/(2+4) + 1/(1+3)) - assert round(rd, 5) == round(test_data, 5) - - def test_resistance_distance_noinv(self): - rd = nx.resistance_distance(self.G, 1, 3, 'weight', False) - test_data = 1/(1/(1/2+1/4) + 1/(1/1+1/3)) - assert round(rd, 5) == round(test_data, 5) - - def test_resistance_distance_no_weight(self): - rd = nx.resistance_distance(self.G, 1, 3) - assert round(rd, 5) == 1 - - def test_resistance_distance_neg_weight(self): - self.G[2][3]['weight'] = -4 - rd = nx.resistance_distance(self.G, 1, 3, 'weight', True) - test_data = 1/(1/(2+-4) + 1/(1+3)) - assert round(rd, 5) == round(test_data, 5) - - def test_multigraph(self): - G = nx.MultiGraph() - G.add_edge(1, 2, weight=2) - G.add_edge(2, 3, weight=4) - G.add_edge(3, 4, weight=1) - G.add_edge(1, 4, weight=3) - rd = nx.resistance_distance(G, 1, 3, 'weight', True) - assert np.isclose(rd, 1/(1/(2+4) + 1/(1+3))) - - def test_resistance_distance_div0(self): - with pytest.raises(ZeroDivisionError): - self.G[1][2]['weight'] = 0 - nx.resistance_distance(self.G, 1, 3, 'weight') - - def test_resistance_distance_not_connected(self): - with pytest.raises(nx.NetworkXError): - self.G.add_node(5) - nx.resistance_distance(self.G, 1, 5) - - def test_resistance_distance_same_node(self): - with pytest.raises(nx.NetworkXError): - nx.resistance_distance(self.G, 1, 1) - - def test_resistance_distance_nodeA_not_in_graph(self): - with pytest.raises(nx.NetworkXError): - nx.resistance_distance(self.G, 9, 1) - - def test_resistance_distance_nodeB_not_in_graph(self): - with pytest.raises(nx.NetworkXError): - nx.resistance_distance(self.G, 1, 9) - - -class TestBarycenter(object): - """Test :func:`networkx.algorithms.distance_measures.barycenter`.""" - def barycenter_as_subgraph(self, g, **kwargs): - """Return the subgraph induced on the barycenter of g""" - b = nx.barycenter(g, **kwargs) - assert isinstance(b, list) - assert set(b) <= set(g) - return g.subgraph(b) - - def test_must_be_connected(self): - pytest.raises(nx.NetworkXNoPath, nx.barycenter, nx.empty_graph(5)) - - def test_sp_kwarg(self): - # Complete graph K_5. Normally it works... - K_5 = nx.complete_graph(5) - sp = dict(nx.shortest_path_length(K_5)) - assert nx.barycenter(K_5, sp=sp) == list(K_5) - - # ...but not with the weight argument - for u, v, data in K_5.edges.data(): - data['weight'] = 1 - pytest.raises(ValueError, nx.barycenter, K_5, sp=sp, weight='weight') - - # ...and a corrupted sp can make it seem like K_5 is disconnected - del sp[0][1] - pytest.raises(nx.NetworkXNoPath, nx.barycenter, K_5, sp=sp) - - def test_trees(self): - """The barycenter of a tree is a single vertex or an edge. - - See [West01]_, p. 78. - """ - prng = Random(0xdeadbeef) - for i in range(50): - RT = nx.random_tree(prng.randint(1, 75), prng) - b = self.barycenter_as_subgraph(RT) - if len(b) == 2: - assert b.size() == 1 - else: - assert len(b) == 1 - assert b.size() == 0 - - def test_this_one_specific_tree(self): - """Test the tree pictured at the bottom of [West01]_, p. 78.""" - g = nx.Graph({ - 'a': ['b'], - 'b': ['a', 'x'], - 'x': ['b', 'y'], - 'y': ['x', 'z'], - 'z': ['y', 0, 1, 2, 3, 4], - 0: ['z'], 1: ['z'], 2: ['z'], 3: ['z'], 4: ['z']}) - b = self.barycenter_as_subgraph(g, attr='barycentricity') - assert list(b) == ['z'] - assert not b.edges - expected_barycentricity = {0: 23, 1: 23, 2: 23, 3: 23, 4: 23, - 'a': 35, 'b': 27, 'x': 21, 'y': 17, 'z': 15 - } - for node, barycentricity in expected_barycentricity.items(): - assert g.nodes[node]['barycentricity'] == barycentricity - - # Doubling weights should do nothing but double the barycentricities - for edge in g.edges: - g.edges[edge]['weight'] = 2 - b = self.barycenter_as_subgraph(g, weight='weight', - attr='barycentricity2') - assert list(b) == ['z'] - assert not b.edges - for node, barycentricity in expected_barycentricity.items(): - assert g.nodes[node]['barycentricity2'] == barycentricity*2 diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_distance_regular.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_distance_regular.py deleted file mode 100644 index ac903a6d..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_distance_regular.py +++ /dev/null @@ -1,68 +0,0 @@ - -import networkx as nx -from networkx import is_strongly_regular - - -class TestDistanceRegular(object): - - def test_is_distance_regular(self): - assert nx.is_distance_regular(nx.icosahedral_graph()) - assert nx.is_distance_regular(nx.petersen_graph()) - assert nx.is_distance_regular(nx.cubical_graph()) - assert nx.is_distance_regular(nx.complete_bipartite_graph(3, 3)) - assert nx.is_distance_regular(nx.tetrahedral_graph()) - assert nx.is_distance_regular(nx.dodecahedral_graph()) - assert nx.is_distance_regular(nx.pappus_graph()) - assert nx.is_distance_regular(nx.heawood_graph()) - assert nx.is_distance_regular(nx.cycle_graph(3)) - # no distance regular - assert not nx.is_distance_regular(nx.path_graph(4)) - - def test_not_connected(self): - G = nx.cycle_graph(4) - nx.add_cycle(G, [5, 6, 7]) - assert not nx.is_distance_regular(G) - - def test_global_parameters(self): - b, c = nx.intersection_array(nx.cycle_graph(5)) - g = nx.global_parameters(b, c) - assert list(g) == [(0, 0, 2), (1, 0, 1), (1, 1, 0)] - b, c = nx.intersection_array(nx.cycle_graph(3)) - g = nx.global_parameters(b, c) - assert list(g) == [(0, 0, 2), (1, 1, 0)] - - def test_intersection_array(self): - b, c = nx.intersection_array(nx.cycle_graph(5)) - assert b == [2, 1] - assert c == [1, 1] - b, c = nx.intersection_array(nx.dodecahedral_graph()) - assert b == [3, 2, 1, 1, 1] - assert c == [1, 1, 1, 2, 3] - b, c = nx.intersection_array(nx.icosahedral_graph()) - assert b == [5, 2, 1] - assert c == [1, 2, 5] - - -class TestStronglyRegular(object): - """Unit tests for the :func:`~networkx.is_strongly_regular` - function. - - """ - - def test_cycle_graph(self): - """Tests that the cycle graph on five vertices is strongly - regular. - - """ - G = nx.cycle_graph(5) - assert is_strongly_regular(G) - - def test_petersen_graph(self): - """Tests that the Petersen graph is strongly regular.""" - G = nx.petersen_graph() - assert is_strongly_regular(G) - - def test_path_graph(self): - """Tests that the path graph is not strongly regular.""" - G = nx.path_graph(4) - assert not is_strongly_regular(G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_dominance.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_dominance.py deleted file mode 100644 index 5f1f36fb..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_dominance.py +++ /dev/null @@ -1,260 +0,0 @@ -import networkx as nx -import pytest - - -class TestImmediateDominators(object): - - def test_exceptions(self): - G = nx.Graph() - G.add_node(0) - pytest.raises(nx.NetworkXNotImplemented, nx.immediate_dominators, G, 0) - G = nx.MultiGraph(G) - pytest.raises(nx.NetworkXNotImplemented, nx.immediate_dominators, G, 0) - G = nx.DiGraph([[0, 0]]) - pytest.raises(nx.NetworkXError, nx.immediate_dominators, G, 1) - - def test_singleton(self): - G = nx.DiGraph() - G.add_node(0) - assert nx.immediate_dominators(G, 0) == {0: 0} - G.add_edge(0, 0) - assert nx.immediate_dominators(G, 0) == {0: 0} - - def test_path(self): - n = 5 - G = nx.path_graph(n, create_using=nx.DiGraph()) - assert (nx.immediate_dominators(G, 0) == - {i: max(i - 1, 0) for i in range(n)}) - - def test_cycle(self): - n = 5 - G = nx.cycle_graph(n, create_using=nx.DiGraph()) - assert (nx.immediate_dominators(G, 0) == - {i: max(i - 1, 0) for i in range(n)}) - - def test_unreachable(self): - n = 5 - assert n > 1 - G = nx.path_graph(n, create_using=nx.DiGraph()) - assert (nx.immediate_dominators(G, n // 2) == - {i: max(i - 1, n // 2) for i in range(n // 2, n)}) - - def test_irreducible1(self): - # Graph taken from Figure 2 of - # K. D. Cooper, T. J. Harvey, and K. Kennedy. - # A simple, fast dominance algorithm. - # Software Practice & Experience, 4:110, 2001. - edges = [(1, 2), (2, 1), (3, 2), (4, 1), (5, 3), (5, 4)] - G = nx.DiGraph(edges) - assert (nx.immediate_dominators(G, 5) == - {i: 5 for i in range(1, 6)}) - - def test_irreducible2(self): - # Graph taken from Figure 4 of - # K. D. Cooper, T. J. Harvey, and K. Kennedy. - # A simple, fast dominance algorithm. - # Software Practice & Experience, 4:110, 2001. - edges = [(1, 2), (2, 1), (2, 3), (3, 2), (4, 2), (4, 3), (5, 1), - (6, 4), (6, 5)] - G = nx.DiGraph(edges) - assert (nx.immediate_dominators(G, 6) == - {i: 6 for i in range(1, 7)}) - - def test_domrel_png(self): - # Graph taken from https://commons.wikipedia.org/wiki/File:Domrel.png - edges = [(1, 2), (2, 3), (2, 4), (2, 6), (3, 5), (4, 5), (5, 2)] - G = nx.DiGraph(edges) - assert (nx.immediate_dominators(G, 1) == - {1: 1, 2: 1, 3: 2, 4: 2, 5: 2, 6: 2}) - # Test postdominance. - with nx.utils.reversed(G): - assert (nx.immediate_dominators(G, 6) == - {1: 2, 2: 6, 3: 5, 4: 5, 5: 2, 6: 6}) - - def test_boost_example(self): - # Graph taken from Figure 1 of - # http://www.boost.org/doc/libs/1_56_0/libs/graph/doc/lengauer_tarjan_dominator.htm - edges = [(0, 1), (1, 2), (1, 3), (2, 7), (3, 4), (4, 5), (4, 6), - (5, 7), (6, 4)] - G = nx.DiGraph(edges) - assert (nx.immediate_dominators(G, 0) == - {0: 0, 1: 0, 2: 1, 3: 1, 4: 3, 5: 4, 6: 4, 7: 1}) - # Test postdominance. - with nx.utils.reversed(G): - assert (nx.immediate_dominators(G, 7) == - {0: 1, 1: 7, 2: 7, 3: 4, 4: 5, 5: 7, 6: 4, 7: 7}) - - -class TestDominanceFrontiers(object): - - def test_exceptions(self): - G = nx.Graph() - G.add_node(0) - pytest.raises(nx.NetworkXNotImplemented, nx.dominance_frontiers, G, 0) - G = nx.MultiGraph(G) - pytest.raises(nx.NetworkXNotImplemented, nx.dominance_frontiers, G, 0) - G = nx.DiGraph([[0, 0]]) - pytest.raises(nx.NetworkXError, nx.dominance_frontiers, G, 1) - - def test_singleton(self): - G = nx.DiGraph() - G.add_node(0) - assert nx.dominance_frontiers(G, 0) == {0: set()} - G.add_edge(0, 0) - assert nx.dominance_frontiers(G, 0) == {0: set()} - - def test_path(self): - n = 5 - G = nx.path_graph(n, create_using=nx.DiGraph()) - assert (nx.dominance_frontiers(G, 0) == - {i: set() for i in range(n)}) - - def test_cycle(self): - n = 5 - G = nx.cycle_graph(n, create_using=nx.DiGraph()) - assert (nx.dominance_frontiers(G, 0) == - {i: set() for i in range(n)}) - - def test_unreachable(self): - n = 5 - assert n > 1 - G = nx.path_graph(n, create_using=nx.DiGraph()) - assert (nx.dominance_frontiers(G, n // 2) == - {i: set() for i in range(n // 2, n)}) - - def test_irreducible1(self): - # Graph taken from Figure 2 of - # K. D. Cooper, T. J. Harvey, and K. Kennedy. - # A simple, fast dominance algorithm. - # Software Practice & Experience, 4:110, 2001. - edges = [(1, 2), (2, 1), (3, 2), (4, 1), (5, 3), (5, 4)] - G = nx.DiGraph(edges) - assert ({u: df - for u, df in nx.dominance_frontiers(G, 5).items()} == - {1: set([2]), 2: set([1]), 3: set([2]), - 4: set([1]), 5: set()}) - - def test_irreducible2(self): - # Graph taken from Figure 4 of - # K. D. Cooper, T. J. Harvey, and K. Kennedy. - # A simple, fast dominance algorithm. - # Software Practice & Experience, 4:110, 2001. - edges = [(1, 2), (2, 1), (2, 3), (3, 2), (4, 2), (4, 3), (5, 1), - (6, 4), (6, 5)] - G = nx.DiGraph(edges) - assert (nx.dominance_frontiers(G, 6) == - {1: set([2]), 2: set([1, 3]), 3: set([2]), 4: set([2, 3]), 5: set([1]), 6: set([])}) - - def test_domrel_png(self): - # Graph taken from https://commons.wikipedia.org/wiki/File:Domrel.png - edges = [(1, 2), (2, 3), (2, 4), (2, 6), (3, 5), (4, 5), (5, 2)] - G = nx.DiGraph(edges) - assert (nx.dominance_frontiers(G, 1) == - {1: set([]), 2: set([2]), 3: set([5]), 4: set([5]), - 5: set([2]), 6: set()}) - # Test postdominance. - with nx.utils.reversed(G): - assert (nx.dominance_frontiers(G, 6) == - {1: set(), 2: set([2]), 3: set([2]), 4: set([2]), - 5: set([2]), 6: set()}) - - def test_boost_example(self): - # Graph taken from Figure 1 of - # http://www.boost.org/doc/libs/1_56_0/libs/graph/doc/lengauer_tarjan_dominator.htm - edges = [(0, 1), (1, 2), (1, 3), (2, 7), (3, 4), (4, 5), (4, 6), - (5, 7), (6, 4)] - G = nx.DiGraph(edges) - assert (nx.dominance_frontiers(G, 0) == - {0: set(), 1: set(), 2: set([7]), 3: set([7]), - 4: set([4, 7]), 5: set([7]), 6: set([4]), 7: set()}) - # Test postdominance. - with nx.utils.reversed(G): - assert (nx.dominance_frontiers(G, 7) == - {0: set(), 1: set(), 2: set([1]), 3: set([1]), - 4: set([1, 4]), 5: set([1]), 6: set([4]), 7: set()}) - - def test_discard_issue(self): - # https://github.com/networkx/networkx/issues/2071 - g = nx.DiGraph() - g.add_edges_from([ - ('b0', 'b1'), - ('b1', 'b2'), - ('b2', 'b3'), - ('b3', 'b1'), - ('b1', 'b5'), - ('b5', 'b6'), - ('b5', 'b8'), - ('b6', 'b7'), - ('b8', 'b7'), - ('b7', 'b3'), - ('b3', 'b4') - ] - ) - df = nx.dominance_frontiers(g, 'b0') - assert df == {'b4': set(), 'b5': set(['b3']), 'b6': set(['b7']), - 'b7': set(['b3']), - 'b0': set(), 'b1': set(['b1']), 'b2': set(['b3']), - 'b3': set(['b1']), 'b8': set(['b7'])} - - def test_loop(self): - g = nx.DiGraph() - g.add_edges_from([('a', 'b'), ('b', 'c'), ('b', 'a')]) - df = nx.dominance_frontiers(g, 'a') - assert df == {'a': set(), 'b': set(), 'c': set()} - - def test_missing_immediate_doms(self): - # see https://github.com/networkx/networkx/issues/2070 - g = nx.DiGraph() - edges = [ - ('entry_1', 'b1'), - ('b1', 'b2'), - ('b2', 'b3'), - ('b3', 'exit'), - ('entry_2', 'b3') - ] - - # entry_1 - # | - # b1 - # | - # b2 entry_2 - # | / - # b3 - # | - # exit - - g.add_edges_from(edges) - # formerly raised KeyError on entry_2 when parsing b3 - # because entry_2 does not have immediate doms (no path) - nx.dominance_frontiers(g, 'entry_1') - - def test_loops_larger(self): - # from - # http://ecee.colorado.edu/~waite/Darmstadt/motion.html - g = nx.DiGraph() - edges = [ - ('entry', 'exit'), - ('entry', '1'), - ('1', '2'), - ('2', '3'), - ('3', '4'), - ('4', '5'), - ('5', '6'), - ('6', 'exit'), - ('6', '2'), - ('5', '3'), - ('4', '4') - ] - - g.add_edges_from(edges) - df = nx.dominance_frontiers(g, 'entry') - answer = {'entry': set(), - '1': set(['exit']), - '2': set(['exit', '2']), - '3': set(['exit', '3', '2']), - '4': set(['exit', '4', '3', '2']), - '5': set(['exit', '3', '2']), - '6': set(['exit', '2']), - 'exit': set()} - for n in df: - assert set(df[n]) == set(answer[n]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_dominating.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_dominating.py deleted file mode 100644 index daf085b8..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_dominating.py +++ /dev/null @@ -1,46 +0,0 @@ -import pytest -import networkx as nx - - -def test_dominating_set(): - G = nx.gnp_random_graph(100, 0.1) - D = nx.dominating_set(G) - assert nx.is_dominating_set(G, D) - D = nx.dominating_set(G, start_with=0) - assert nx.is_dominating_set(G, D) - - -def test_complete(): - """ In complete graphs each node is a dominating set. - Thus the dominating set has to be of cardinality 1. - """ - K4 = nx.complete_graph(4) - assert len(nx.dominating_set(K4)) == 1 - K5 = nx.complete_graph(5) - assert len(nx.dominating_set(K5)) == 1 - - -def test_raise_dominating_set(): - with pytest.raises(nx.NetworkXError): - G = nx.path_graph(4) - D = nx.dominating_set(G, start_with=10) - - -def test_is_dominating_set(): - G = nx.path_graph(4) - d = set([1, 3]) - assert nx.is_dominating_set(G, d) - d = set([0, 2]) - assert nx.is_dominating_set(G, d) - d = set([1]) - assert not nx.is_dominating_set(G, d) - - -def test_wikipedia_is_dominating_set(): - """Example from https://en.wikipedia.org/wiki/Dominating_set - """ - G = nx.cycle_graph(4) - G.add_edges_from([(0, 4), (1, 4), (2, 5)]) - assert nx.is_dominating_set(G, set([4, 3, 5])) - assert nx.is_dominating_set(G, set([0, 2])) - assert nx.is_dominating_set(G, set([1, 2])) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_efficiency.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_efficiency.py deleted file mode 100644 index 06a8a6b6..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_efficiency.py +++ /dev/null @@ -1,66 +0,0 @@ -# test_efficiency.py - unit tests for the efficiency module -# -# Copyright 2015-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.efficiency` module.""" - -import networkx as nx - - -class TestEfficiency: - def setup_method(self): - # G1 is a disconnected graph - self.G1 = nx.Graph() - self.G1.add_nodes_from([1, 2, 3]) - # G2 is a cycle graph - self.G2 = nx.cycle_graph(4) - # G3 is the triangle graph with one additional edge - self.G3 = nx.lollipop_graph(3, 1) - - def test_efficiency_disconnected_nodes(self): - """ - When nodes are disconnected, efficiency is 0 - """ - assert nx.efficiency(self.G1, 1, 2) == 0 - - def test_local_efficiency_disconnected_graph(self): - """ - In a disconnected graph the efficiency is 0 - """ - assert nx.local_efficiency(self.G1) == 0 - - def test_efficiency(self): - assert nx.efficiency(self.G2, 0, 1) == 1 - assert nx.efficiency(self.G2, 0, 2) == 1 / 2 - - def test_global_efficiency(self): - assert nx.global_efficiency(self.G2) == 5 / 6 - - def test_global_efficiency_complete_graph(self): - """ - Tests that the average global efficiency of the complete graph is one. - """ - for n in range(2, 10): - G = nx.complete_graph(n) - assert nx.global_efficiency(G) == 1 - - def test_local_efficiency_complete_graph(self): - """ - Test that the local efficiency for a complete graph with at least 3 - nodes should be one. For a graph with only 2 nodes, the induced - subgraph has no edges. - """ - for n in range(3, 10): - G = nx.complete_graph(n) - assert nx.local_efficiency(G) == 1 - - def test_using_ego_graph(self): - """ - Test that the ego graph is used when computing local efficiency. - For more information, see GitHub issue #2710. - """ - assert nx.local_efficiency(self.G3) == 7 / 12 diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_euler.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_euler.py deleted file mode 100644 index af84e070..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_euler.py +++ /dev/null @@ -1,190 +0,0 @@ -from unittest import TestCase -import collections - -import pytest - -import networkx as nx - - -class TestIsEulerian(TestCase): - def test_is_eulerian(self): - assert nx.is_eulerian(nx.complete_graph(5)) - assert nx.is_eulerian(nx.complete_graph(7)) - assert nx.is_eulerian(nx.hypercube_graph(4)) - assert nx.is_eulerian(nx.hypercube_graph(6)) - - assert not nx.is_eulerian(nx.complete_graph(4)) - assert not nx.is_eulerian(nx.complete_graph(6)) - assert not nx.is_eulerian(nx.hypercube_graph(3)) - assert not nx.is_eulerian(nx.hypercube_graph(5)) - - assert not nx.is_eulerian(nx.petersen_graph()) - assert not nx.is_eulerian(nx.path_graph(4)) - - def test_is_eulerian2(self): - # not connected - G = nx.Graph() - G.add_nodes_from([1, 2, 3]) - assert not nx.is_eulerian(G) - # not strongly connected - G = nx.DiGraph() - G.add_nodes_from([1, 2, 3]) - assert not nx.is_eulerian(G) - G = nx.MultiDiGraph() - G.add_edge(1, 2) - G.add_edge(2, 3) - G.add_edge(2, 3) - G.add_edge(3, 1) - assert not nx.is_eulerian(G) - - -class TestEulerianCircuit(TestCase): - def test_eulerian_circuit_cycle(self): - G = nx.cycle_graph(4) - - edges = list(nx.eulerian_circuit(G, source=0)) - nodes = [u for u, v in edges] - assert nodes == [0, 3, 2, 1] - assert edges == [(0, 3), (3, 2), (2, 1), (1, 0)] - - edges = list(nx.eulerian_circuit(G, source=1)) - nodes = [u for u, v in edges] - assert nodes == [1, 2, 3, 0] - assert edges == [(1, 2), (2, 3), (3, 0), (0, 1)] - - G = nx.complete_graph(3) - - edges = list(nx.eulerian_circuit(G, source=0)) - nodes = [u for u, v in edges] - assert nodes == [0, 2, 1] - assert edges == [(0, 2), (2, 1), (1, 0)] - - edges = list(nx.eulerian_circuit(G, source=1)) - nodes = [u for u, v in edges] - assert nodes == [1, 2, 0] - assert edges == [(1, 2), (2, 0), (0, 1)] - - def test_eulerian_circuit_digraph(self): - G = nx.DiGraph() - nx.add_cycle(G, [0, 1, 2, 3]) - - edges = list(nx.eulerian_circuit(G, source=0)) - nodes = [u for u, v in edges] - assert nodes == [0, 1, 2, 3] - assert edges == [(0, 1), (1, 2), (2, 3), (3, 0)] - - edges = list(nx.eulerian_circuit(G, source=1)) - nodes = [u for u, v in edges] - assert nodes == [1, 2, 3, 0] - assert edges == [(1, 2), (2, 3), (3, 0), (0, 1)] - - def test_multigraph(self): - G = nx.MultiGraph() - nx.add_cycle(G, [0, 1, 2, 3]) - G.add_edge(1, 2) - G.add_edge(1, 2) - edges = list(nx.eulerian_circuit(G, source=0)) - nodes = [u for u, v in edges] - assert nodes == [0, 3, 2, 1, 2, 1] - assert edges == [(0, 3), (3, 2), (2, 1), (1, 2), (2, 1), (1, 0)] - - def test_multigraph_with_keys(self): - G = nx.MultiGraph() - nx.add_cycle(G, [0, 1, 2, 3]) - G.add_edge(1, 2) - G.add_edge(1, 2) - edges = list(nx.eulerian_circuit(G, source=0, keys=True)) - nodes = [u for u, v, k in edges] - assert nodes == [0, 3, 2, 1, 2, 1] - assert edges[:2] == [(0, 3, 0), (3, 2, 0)] - assert collections.Counter(edges[2:5]) == collections.Counter([(2, 1, 0), (1, 2, 1), (2, 1, 2)]) - assert edges[5:] == [(1, 0, 0)] - - def test_not_eulerian(self): - with pytest.raises(nx.NetworkXError): - f = list(nx.eulerian_circuit(nx.complete_graph(4))) - - -class TestIsSemiEulerian(TestCase): - def test_is_semieulerian(self): - # Test graphs with Eulerian paths but no cycles return True. - assert nx.is_semieulerian(nx.path_graph(4)) - G = nx.path_graph(6, create_using=nx.DiGraph) - assert nx.is_semieulerian(G) - - # Test graphs with Eulerian cycles return False. - assert not nx.is_semieulerian(nx.complete_graph(5)) - assert not nx.is_semieulerian(nx.complete_graph(7)) - assert not nx.is_semieulerian(nx.hypercube_graph(4)) - assert not nx.is_semieulerian(nx.hypercube_graph(6)) - - -class TestHasEulerianPath(TestCase): - def test_has_eulerian_path_cyclic(self): - # Test graphs with Eulerian cycles return True. - assert nx.has_eulerian_path(nx.complete_graph(5)) - assert nx.has_eulerian_path(nx.complete_graph(7)) - assert nx.has_eulerian_path(nx.hypercube_graph(4)) - assert nx.has_eulerian_path(nx.hypercube_graph(6)) - - def test_has_eulerian_path_non_cyclic(self): - # Test graphs with Eulerian paths but no cycles return True. - assert nx.has_eulerian_path(nx.path_graph(4)) - G = nx.path_graph(6, create_using=nx.DiGraph) - assert nx.has_eulerian_path(G) - - -class TestFindPathStart(TestCase): - def testfind_path_start(self): - find_path_start = nx.algorithms.euler._find_path_start - # Test digraphs return correct starting node. - G = nx.path_graph(6, create_using=nx.DiGraph) - assert find_path_start(G) == 0 - edges = [(0, 1), (1, 2), (2, 0), (4, 0)] - assert find_path_start(nx.DiGraph(edges)) == 4 - - # Test graph with no Eulerian path return None. - edges = [(0, 1), (1, 2), (2, 3), (2, 4)] - assert find_path_start(nx.DiGraph(edges)) == None - - -class TestEulerianPath(TestCase): - def test_eulerian_path(self): - x = [(4, 0), (0, 1), (1, 2), (2, 0)] - for e1, e2 in zip(x, nx.eulerian_path(nx.DiGraph(x))): - assert e1 == e2 - - -class TestEulerize(TestCase): - def test_disconnected(self): - with pytest.raises(nx.NetworkXError): - G = nx.from_edgelist([(0, 1), (2, 3)]) - nx.eulerize(G) - - def test_null_graph(self): - with pytest.raises(nx.NetworkXPointlessConcept): - nx.eulerize(nx.Graph()) - - def test_null_multigraph(self): - with pytest.raises(nx.NetworkXPointlessConcept): - nx.eulerize(nx.MultiGraph()) - - def test_on_empty_graph(self): - with pytest.raises(nx.NetworkXError): - nx.eulerize(nx.empty_graph(3)) - - def test_on_eulerian(self): - G = nx.cycle_graph(3) - H = nx.eulerize(G) - assert nx.is_isomorphic(G, H) - - def test_on_eulerian_multigraph(self): - G = nx.MultiGraph(nx.cycle_graph(3)) - G.add_edge(0, 1) - H = nx.eulerize(G) - assert nx.is_eulerian(H) - - def test_on_complete_graph(self): - G = nx.complete_graph(4) - assert nx.is_eulerian(nx.eulerize(G)) - assert nx.is_eulerian(nx.eulerize(nx.MultiGraph(G))) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_graphical.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_graphical.py deleted file mode 100644 index f4d41aac..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_graphical.py +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/env python -import pytest -import networkx as nx - - -def test_valid_degree_sequence1(): - n = 100 - p = .3 - for i in range(10): - G = nx.erdos_renyi_graph(n, p) - deg = (d for n, d in G.degree()) - assert nx.is_graphical(deg, method='eg') - assert nx.is_graphical(deg, method='hh') - - -def test_valid_degree_sequence2(): - n = 100 - for i in range(10): - G = nx.barabasi_albert_graph(n, 1) - deg = (d for n, d in G.degree()) - assert nx.is_graphical(deg, method='eg') - assert nx.is_graphical(deg, method='hh') - - -def test_string_input(): - pytest.raises(nx.NetworkXException, nx.is_graphical, [], 'foo') - pytest.raises(nx.NetworkXException, nx.is_graphical, ['red'], 'hh') - pytest.raises(nx.NetworkXException, nx.is_graphical, ['red'], 'eg') - - -def test_non_integer_input(): - pytest.raises(nx.NetworkXException, nx.is_graphical, [72.5], 'eg') - pytest.raises(nx.NetworkXException, nx.is_graphical, [72.5], 'hh') - - -def test_negative_input(): - assert not nx.is_graphical([-1], 'hh') - assert not nx.is_graphical([-1], 'eg') - - -class TestAtlas(object): - @classmethod - def setup_class(cls): - global atlas - import platform -# if platform.python_implementation() == 'Jython': -# raise SkipTest('graph atlas not available under Jython.') - import networkx.generators.atlas as atlas - - cls.GAG = atlas.graph_atlas_g() - - def test_atlas(self): - for graph in self.GAG: - deg = (d for n, d in graph.degree()) - assert nx.is_graphical(deg, method='eg') - assert nx.is_graphical(deg, method='hh') - - -def test_small_graph_true(): - z = [5, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - assert nx.is_graphical(z, method='hh') - assert nx.is_graphical(z, method='eg') - z = [10, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2] - assert nx.is_graphical(z, method='hh') - assert nx.is_graphical(z, method='eg') - z = [1, 1, 1, 1, 1, 2, 2, 2, 3, 4] - assert nx.is_graphical(z, method='hh') - assert nx.is_graphical(z, method='eg') - - -def test_small_graph_false(): - z = [1000, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - assert not nx.is_graphical(z, method='hh') - assert not nx.is_graphical(z, method='eg') - z = [6, 5, 4, 4, 2, 1, 1, 1] - assert not nx.is_graphical(z, method='hh') - assert not nx.is_graphical(z, method='eg') - z = [1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4] - assert not nx.is_graphical(z, method='hh') - assert not nx.is_graphical(z, method='eg') - - -def test_directed_degree_sequence(): - # Test a range of valid directed degree sequences - n, r = 100, 10 - p = 1.0 / r - for i in range(r): - G = nx.erdos_renyi_graph(n, p * (i + 1), None, True) - din = (d for n, d in G.in_degree()) - dout = (d for n, d in G.out_degree()) - assert nx.is_digraphical(din, dout) - - -def test_small_directed_sequences(): - dout = [5, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - din = [3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1] - assert nx.is_digraphical(din, dout) - # Test nongraphical directed sequence - dout = [1000, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - din = [103, 102, 102, 102, 102, 102, 102, 102, 102, 102] - assert not nx.is_digraphical(din, dout) - # Test digraphical small sequence - dout = [1, 1, 1, 1, 1, 2, 2, 2, 3, 4] - din = [2, 2, 2, 2, 2, 2, 2, 2, 1, 1] - assert nx.is_digraphical(din, dout) - # Test nonmatching sum - din = [2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1] - assert not nx.is_digraphical(din, dout) - # Test for negative integer in sequence - din = [2, 2, 2, -2, 2, 2, 2, 2, 1, 1, 4] - assert not nx.is_digraphical(din, dout) - # Test for noninteger - din = dout = [1, 1, 1.1, 1] - assert not nx.is_digraphical(din, dout) - din = dout = [1, 1, "rer", 1] - assert not nx.is_digraphical(din, dout) - - -def test_multi_sequence(): - # Test nongraphical multi sequence - seq = [1000, 3, 3, 3, 3, 2, 2, 2, 1, 1] - assert not nx.is_multigraphical(seq) - # Test small graphical multi sequence - seq = [6, 5, 4, 4, 2, 1, 1, 1] - assert nx.is_multigraphical(seq) - # Test for negative integer in sequence - seq = [6, 5, 4, -4, 2, 1, 1, 1] - assert not nx.is_multigraphical(seq) - # Test for sequence with odd sum - seq = [1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4] - assert not nx.is_multigraphical(seq) - # Test for noninteger - seq = [1, 1, 1.1, 1] - assert not nx.is_multigraphical(seq) - seq = [1, 1, "rer", 1] - assert not nx.is_multigraphical(seq) - - -def test_pseudo_sequence(): - # Test small valid pseudo sequence - seq = [1000, 3, 3, 3, 3, 2, 2, 2, 1, 1] - assert nx.is_pseudographical(seq) - # Test for sequence with odd sum - seq = [1000, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - assert not nx.is_pseudographical(seq) - # Test for negative integer in sequence - seq = [1000, 3, 3, 3, 3, 2, 2, -2, 1, 1] - assert not nx.is_pseudographical(seq) - # Test for noninteger - seq = [1, 1, 1.1, 1] - assert not nx.is_pseudographical(seq) - seq = [1, 1, "rer", 1] - assert not nx.is_pseudographical(seq) - - -def test_numpy_degree_sequence(): - numpy = pytest.importorskip('numpy') - ds = numpy.array([1, 2, 2, 2, 1], dtype=numpy.int64) - assert nx.is_graphical(ds, 'eg') - assert nx.is_graphical(ds, 'hh') - ds = numpy.array([1, 2, 2, 2, 1], dtype=numpy.float64) - assert nx.is_graphical(ds, 'eg') - assert nx.is_graphical(ds, 'hh') - ds = numpy.array([1.1, 2, 2, 2, 1], dtype=numpy.float64) - pytest.raises(nx.NetworkXException, nx.is_graphical, ds, 'eg') - pytest.raises(nx.NetworkXException, nx.is_graphical, ds, 'hh') diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_hierarchy.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_hierarchy.py deleted file mode 100644 index 464d1129..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_hierarchy.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python -import pytest -import networkx as nx - - -def test_hierarchy_exception(): - G = nx.cycle_graph(5) - pytest.raises(nx.NetworkXError, nx.flow_hierarchy, G) - - -def test_hierarchy_cycle(): - G = nx.cycle_graph(5, create_using=nx.DiGraph()) - assert nx.flow_hierarchy(G) == 0.0 - - -def test_hierarchy_tree(): - G = nx.full_rary_tree(2, 16, create_using=nx.DiGraph()) - assert nx.flow_hierarchy(G) == 1.0 - - -def test_hierarchy_1(): - G = nx.DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 1), (3, 4), (0, 4)]) - assert nx.flow_hierarchy(G) == 0.5 - - -def test_hierarchy_weight(): - G = nx.DiGraph() - G.add_edges_from([(0, 1, {'weight': .3}), - (1, 2, {'weight': .1}), - (2, 3, {'weight': .1}), - (3, 1, {'weight': .1}), - (3, 4, {'weight': .3}), - (0, 4, {'weight': .3})]) - assert nx.flow_hierarchy(G, weight='weight') == .75 diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_hybrid.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_hybrid.py deleted file mode 100644 index a9fe20f7..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_hybrid.py +++ /dev/null @@ -1,24 +0,0 @@ -import networkx as nx - - -def test_2d_grid_graph(): - # FC article claims 2d grid graph of size n is (3,3)-connected - # and (5,9)-connected, but I don't think it is (5,9)-connected - G = nx.grid_2d_graph(8, 8, periodic=True) - assert nx.is_kl_connected(G, 3, 3) - assert not nx.is_kl_connected(G, 5, 9) - (H, graphOK) = nx.kl_connected_subgraph(G, 5, 9, same_as_graph=True) - assert not graphOK - - -def test_small_graph(): - G = nx.Graph() - G.add_edge(1, 2) - G.add_edge(1, 3) - G.add_edge(2, 3) - assert nx.is_kl_connected(G, 2, 2) - H = nx.kl_connected_subgraph(G, 2, 2) - (H, graphOK) = nx.kl_connected_subgraph(G, 2, 2, - low_memory=True, - same_as_graph=True) - assert graphOK diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_isolate.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_isolate.py deleted file mode 100644 index cd781e5c..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_isolate.py +++ /dev/null @@ -1,34 +0,0 @@ -# test_isolate.py - unit tests for the isolate module -# -# Copyright 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.isolates` module.""" - -import networkx as nx - - -def test_is_isolate(): - G = nx.Graph() - G.add_edge(0, 1) - G.add_node(2) - assert not nx.is_isolate(G, 0) - assert not nx.is_isolate(G, 1) - assert nx.is_isolate(G, 2) - - -def test_isolates(): - G = nx.Graph() - G.add_edge(0, 1) - G.add_nodes_from([2, 3]) - assert sorted(nx.isolates(G)) == [2, 3] - - -def test_number_of_isolates(): - G = nx.Graph() - G.add_edge(0, 1) - G.add_nodes_from([2, 3]) - assert nx.number_of_isolates(G) == 2 diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_link_prediction.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_link_prediction.py deleted file mode 100644 index 3cb9b602..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_link_prediction.py +++ /dev/null @@ -1,506 +0,0 @@ -import math - -from functools import partial -import pytest - -import networkx as nx - - -def _test_func(G, ebunch, expected, predict_func, **kwargs): - result = predict_func(G, ebunch, **kwargs) - exp_dict = dict((tuple(sorted([u, v])), score) for u, v, score in expected) - res_dict = dict((tuple(sorted([u, v])), score) for u, v, score in result) - - assert len(exp_dict) == len(res_dict) - for p in exp_dict: - assert nx.testing.almost_equal(exp_dict[p], res_dict[p]) - - -class TestResourceAllocationIndex(): - @classmethod - def setup_class(cls): - cls.func = staticmethod(nx.resource_allocation_index) - cls.test = partial(_test_func, predict_func=cls.func) - - def test_K5(self): - G = nx.complete_graph(5) - self.test(G, [(0, 1)], [(0, 1, 0.75)]) - - def test_P3(self): - G = nx.path_graph(3) - self.test(G, [(0, 2)], [(0, 2, 0.5)]) - - def test_S4(self): - G = nx.star_graph(4) - self.test(G, [(1, 2)], [(1, 2, 0.25)]) - - def test_notimplemented(self): - assert pytest.raises(nx.NetworkXNotImplemented, self.func, - nx.DiGraph([(0, 1), (1, 2)]), [(0, 2)]) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, - nx.MultiGraph([(0, 1), (1, 2)]), [(0, 2)]) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, - nx.MultiDiGraph([(0, 1), (1, 2)]), [(0, 2)]) - - def test_no_common_neighbor(self): - G = nx.Graph() - G.add_nodes_from([0, 1]) - self.test(G, [(0, 1)], [(0, 1, 0)]) - - def test_equal_nodes(self): - G = nx.complete_graph(4) - self.test(G, [(0, 0)], [(0, 0, 1)]) - - def test_all_nonexistent_edges(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - self.test(G, None, [(0, 3, 0.5), (1, 2, 0.5), (1, 3, 0)]) - - -class TestJaccardCoefficient(): - @classmethod - def setup_class(cls): - cls.func = staticmethod(nx.jaccard_coefficient) - cls.test = partial(_test_func, predict_func=cls.func) - - def test_K5(self): - G = nx.complete_graph(5) - self.test(G, [(0, 1)], [(0, 1, 0.6)]) - - def test_P4(self): - G = nx.path_graph(4) - self.test(G, [(0, 2)], [(0, 2, 0.5)]) - - def test_notimplemented(self): - assert pytest.raises(nx.NetworkXNotImplemented, self.func, - nx.DiGraph([(0, 1), (1, 2)]), [(0, 2)]) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, - nx.MultiGraph([(0, 1), (1, 2)]), [(0, 2)]) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, - nx.MultiDiGraph([(0, 1), (1, 2)]), [(0, 2)]) - - def test_no_common_neighbor(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (2, 3)]) - self.test(G, [(0, 2)], [(0, 2, 0)]) - - def test_isolated_nodes(self): - G = nx.Graph() - G.add_nodes_from([0, 1]) - self.test(G, [(0, 1)], [(0, 1, 0)]) - - def test_all_nonexistent_edges(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - self.test(G, None, [(0, 3, 0.5), (1, 2, 0.5), (1, 3, 0)]) - - -class TestAdamicAdarIndex(): - @classmethod - def setup_class(cls): - cls.func = staticmethod(nx.adamic_adar_index) - cls.test = partial(_test_func, predict_func=cls.func) - - def test_K5(self): - G = nx.complete_graph(5) - self.test(G, [(0, 1)], [(0, 1, 3 / math.log(4))]) - - def test_P3(self): - G = nx.path_graph(3) - self.test(G, [(0, 2)], [(0, 2, 1 / math.log(2))]) - - def test_S4(self): - G = nx.star_graph(4) - self.test(G, [(1, 2)], [(1, 2, 1 / math.log(4))]) - - def test_notimplemented(self): - assert pytest.raises(nx.NetworkXNotImplemented, self.func, - nx.DiGraph([(0, 1), (1, 2)]), [(0, 2)]) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, - nx.MultiGraph([(0, 1), (1, 2)]), [(0, 2)]) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, - nx.MultiDiGraph([(0, 1), (1, 2)]), [(0, 2)]) - - def test_no_common_neighbor(self): - G = nx.Graph() - G.add_nodes_from([0, 1]) - self.test(G, [(0, 1)], [(0, 1, 0)]) - - def test_equal_nodes(self): - G = nx.complete_graph(4) - self.test(G, [(0, 0)], [(0, 0, 3 / math.log(3))]) - - def test_all_nonexistent_edges(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - self.test(G, None, [(0, 3, 1 / math.log(2)), (1, 2, 1 / math.log(2)), - (1, 3, 0)]) - - -class TestPreferentialAttachment(): - @classmethod - def setup_class(cls): - cls.func = staticmethod(nx.preferential_attachment) - cls.test = partial(_test_func, predict_func=cls.func) - - def test_K5(self): - G = nx.complete_graph(5) - self.test(G, [(0, 1)], [(0, 1, 16)]) - - def test_P3(self): - G = nx.path_graph(3) - self.test(G, [(0, 1)], [(0, 1, 2)]) - - def test_S4(self): - G = nx.star_graph(4) - self.test(G, [(0, 2)], [(0, 2, 4)]) - - def test_notimplemented(self): - assert pytest.raises(nx.NetworkXNotImplemented, self.func, - nx.DiGraph([(0, 1), (1, 2)]), [(0, 2)]) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, - nx.MultiGraph([(0, 1), (1, 2)]), [(0, 2)]) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, - nx.MultiDiGraph([(0, 1), (1, 2)]), [(0, 2)]) - - def test_zero_degrees(self): - G = nx.Graph() - G.add_nodes_from([0, 1]) - self.test(G, [(0, 1)], [(0, 1, 0)]) - - def test_all_nonexistent_edges(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - self.test(G, None, [(0, 3, 2), (1, 2, 2), (1, 3, 1)]) - - -class TestCNSoundarajanHopcroft(): - @classmethod - def setup_class(cls): - cls.func = staticmethod(nx.cn_soundarajan_hopcroft) - cls.test = partial(_test_func, predict_func=cls.func, - community='community') - - def test_K5(self): - G = nx.complete_graph(5) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 0 - G.nodes[2]['community'] = 0 - G.nodes[3]['community'] = 0 - G.nodes[4]['community'] = 1 - self.test(G, [(0, 1)], [(0, 1, 5)]) - - def test_P3(self): - G = nx.path_graph(3) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 1 - G.nodes[2]['community'] = 0 - self.test(G, [(0, 2)], [(0, 2, 1)]) - - def test_S4(self): - G = nx.star_graph(4) - G.nodes[0]['community'] = 1 - G.nodes[1]['community'] = 1 - G.nodes[2]['community'] = 1 - G.nodes[3]['community'] = 0 - G.nodes[4]['community'] = 0 - self.test(G, [(1, 2)], [(1, 2, 2)]) - - def test_notimplemented(self): - G = nx.DiGraph([(0, 1), (1, 2)]) - G.add_nodes_from([0, 1, 2], community=0) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, G, [(0, 2)]) - G = nx.MultiGraph([(0, 1), (1, 2)]) - G.add_nodes_from([0, 1, 2], community=0) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, G, [(0, 2)]) - G = nx.MultiDiGraph([(0, 1), (1, 2)]) - G.add_nodes_from([0, 1, 2], community=0) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, G, [(0, 2)]) - - def test_no_common_neighbor(self): - G = nx.Graph() - G.add_nodes_from([0, 1]) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 0 - self.test(G, [(0, 1)], [(0, 1, 0)]) - - def test_equal_nodes(self): - G = nx.complete_graph(3) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 0 - G.nodes[2]['community'] = 0 - self.test(G, [(0, 0)], [(0, 0, 4)]) - - def test_different_community(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 0 - G.nodes[2]['community'] = 0 - G.nodes[3]['community'] = 1 - self.test(G, [(0, 3)], [(0, 3, 2)]) - - def test_no_community_information(self): - G = nx.complete_graph(5) - assert pytest.raises(nx.NetworkXAlgorithmError, list, self.func(G, [(0, 1)])) - - def test_insufficient_community_information(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 0 - G.nodes[3]['community'] = 0 - assert pytest.raises(nx.NetworkXAlgorithmError, list, self.func(G, [(0, 3)])) - - def test_sufficient_community_information(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4), (4, 5)]) - G.nodes[1]['community'] = 0 - G.nodes[2]['community'] = 0 - G.nodes[3]['community'] = 0 - G.nodes[4]['community'] = 0 - self.test(G, [(1, 4)], [(1, 4, 4)]) - - def test_custom_community_attribute_name(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - G.nodes[0]['cmty'] = 0 - G.nodes[1]['cmty'] = 0 - G.nodes[2]['cmty'] = 0 - G.nodes[3]['cmty'] = 1 - self.test(G, [(0, 3)], [(0, 3, 2)], community='cmty') - - def test_all_nonexistent_edges(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 1 - G.nodes[2]['community'] = 0 - G.nodes[3]['community'] = 0 - self.test(G, None, [(0, 3, 2), (1, 2, 1), (1, 3, 0)]) - - -class TestRAIndexSoundarajanHopcroft(): - @classmethod - def setup_class(cls): - cls.func = staticmethod(nx.ra_index_soundarajan_hopcroft) - cls.test = partial(_test_func, predict_func=cls.func, - community='community') - - def test_K5(self): - G = nx.complete_graph(5) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 0 - G.nodes[2]['community'] = 0 - G.nodes[3]['community'] = 0 - G.nodes[4]['community'] = 1 - self.test(G, [(0, 1)], [(0, 1, 0.5)]) - - def test_P3(self): - G = nx.path_graph(3) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 1 - G.nodes[2]['community'] = 0 - self.test(G, [(0, 2)], [(0, 2, 0)]) - - def test_S4(self): - G = nx.star_graph(4) - G.nodes[0]['community'] = 1 - G.nodes[1]['community'] = 1 - G.nodes[2]['community'] = 1 - G.nodes[3]['community'] = 0 - G.nodes[4]['community'] = 0 - self.test(G, [(1, 2)], [(1, 2, 0.25)]) - - def test_notimplemented(self): - G = nx.DiGraph([(0, 1), (1, 2)]) - G.add_nodes_from([0, 1, 2], community=0) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, G, [(0, 2)]) - G = nx.MultiGraph([(0, 1), (1, 2)]) - G.add_nodes_from([0, 1, 2], community=0) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, G, [(0, 2)]) - G = nx.MultiDiGraph([(0, 1), (1, 2)]) - G.add_nodes_from([0, 1, 2], community=0) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, G, [(0, 2)]) - - def test_no_common_neighbor(self): - G = nx.Graph() - G.add_nodes_from([0, 1]) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 0 - self.test(G, [(0, 1)], [(0, 1, 0)]) - - def test_equal_nodes(self): - G = nx.complete_graph(3) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 0 - G.nodes[2]['community'] = 0 - self.test(G, [(0, 0)], [(0, 0, 1)]) - - def test_different_community(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 0 - G.nodes[2]['community'] = 0 - G.nodes[3]['community'] = 1 - self.test(G, [(0, 3)], [(0, 3, 0)]) - - def test_no_community_information(self): - G = nx.complete_graph(5) - assert pytest.raises(nx.NetworkXAlgorithmError, list, self.func(G, [(0, 1)])) - - def test_insufficient_community_information(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 0 - G.nodes[3]['community'] = 0 - assert pytest.raises(nx.NetworkXAlgorithmError, list, self.func(G, [(0, 3)])) - - def test_sufficient_community_information(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4), (4, 5)]) - G.nodes[1]['community'] = 0 - G.nodes[2]['community'] = 0 - G.nodes[3]['community'] = 0 - G.nodes[4]['community'] = 0 - self.test(G, [(1, 4)], [(1, 4, 1)]) - - def test_custom_community_attribute_name(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - G.nodes[0]['cmty'] = 0 - G.nodes[1]['cmty'] = 0 - G.nodes[2]['cmty'] = 0 - G.nodes[3]['cmty'] = 1 - self.test(G, [(0, 3)], [(0, 3, 0)], community='cmty') - - def test_all_nonexistent_edges(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 1 - G.nodes[2]['community'] = 0 - G.nodes[3]['community'] = 0 - self.test(G, None, [(0, 3, 0.5), (1, 2, 0), (1, 3, 0)]) - - -class TestWithinInterCluster(): - @classmethod - def setup_class(cls): - cls.delta = 0.001 - cls.func = staticmethod(nx.within_inter_cluster) - cls.test = partial(_test_func, predict_func=cls.func, - delta=cls.delta, community='community') - - def test_K5(self): - G = nx.complete_graph(5) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 0 - G.nodes[2]['community'] = 0 - G.nodes[3]['community'] = 0 - G.nodes[4]['community'] = 1 - self.test(G, [(0, 1)], [(0, 1, 2 / (1 + self.delta))]) - - def test_P3(self): - G = nx.path_graph(3) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 1 - G.nodes[2]['community'] = 0 - self.test(G, [(0, 2)], [(0, 2, 0)]) - - def test_S4(self): - G = nx.star_graph(4) - G.nodes[0]['community'] = 1 - G.nodes[1]['community'] = 1 - G.nodes[2]['community'] = 1 - G.nodes[3]['community'] = 0 - G.nodes[4]['community'] = 0 - self.test(G, [(1, 2)], [(1, 2, 1 / self.delta)]) - - def test_notimplemented(self): - G = nx.DiGraph([(0, 1), (1, 2)]) - G.add_nodes_from([0, 1, 2], community=0) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, G, [(0, 2)]) - G = nx.MultiGraph([(0, 1), (1, 2)]) - G.add_nodes_from([0, 1, 2], community=0) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, G, [(0, 2)]) - G = nx.MultiDiGraph([(0, 1), (1, 2)]) - G.add_nodes_from([0, 1, 2], community=0) - assert pytest.raises(nx.NetworkXNotImplemented, self.func, G, [(0, 2)]) - - def test_no_common_neighbor(self): - G = nx.Graph() - G.add_nodes_from([0, 1]) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 0 - self.test(G, [(0, 1)], [(0, 1, 0)]) - - def test_equal_nodes(self): - G = nx.complete_graph(3) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 0 - G.nodes[2]['community'] = 0 - self.test(G, [(0, 0)], [(0, 0, 2 / self.delta)]) - - def test_different_community(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 0 - G.nodes[2]['community'] = 0 - G.nodes[3]['community'] = 1 - self.test(G, [(0, 3)], [(0, 3, 0)]) - - def test_no_inter_cluster_common_neighbor(self): - G = nx.complete_graph(4) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 0 - G.nodes[2]['community'] = 0 - G.nodes[3]['community'] = 0 - self.test(G, [(0, 3)], [(0, 3, 2 / self.delta)]) - - def test_no_community_information(self): - G = nx.complete_graph(5) - assert pytest.raises(nx.NetworkXAlgorithmError, list, self.func(G, [(0, 1)])) - - def test_insufficient_community_information(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (1, 3), (2, 3)]) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 0 - G.nodes[3]['community'] = 0 - assert pytest.raises(nx.NetworkXAlgorithmError, list, self.func(G, [(0, 3)])) - - def test_sufficient_community_information(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4), (4, 5)]) - G.nodes[1]['community'] = 0 - G.nodes[2]['community'] = 0 - G.nodes[3]['community'] = 0 - G.nodes[4]['community'] = 0 - self.test(G, [(1, 4)], [(1, 4, 2 / self.delta)]) - - def test_invalid_delta(self): - G = nx.complete_graph(3) - G.add_nodes_from([0, 1, 2], community=0) - assert pytest.raises(nx.NetworkXAlgorithmError, self.func, G, [(0, 1)], 0) - assert pytest.raises(nx.NetworkXAlgorithmError, self.func, G, [(0, 1)], -0.5) - - def test_custom_community_attribute_name(self): - G = nx.complete_graph(4) - G.nodes[0]['cmty'] = 0 - G.nodes[1]['cmty'] = 0 - G.nodes[2]['cmty'] = 0 - G.nodes[3]['cmty'] = 0 - self.test(G, [(0, 3)], [(0, 3, 2 / self.delta)], community='cmty') - - def test_all_nonexistent_edges(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (2, 3)]) - G.nodes[0]['community'] = 0 - G.nodes[1]['community'] = 1 - G.nodes[2]['community'] = 0 - G.nodes[3]['community'] = 0 - self.test(G, None, [(0, 3, 1 / self.delta), (1, 2, 0), (1, 3, 0)]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_lowest_common_ancestors.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_lowest_common_ancestors.py deleted file mode 100644 index c5b4ef03..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_lowest_common_ancestors.py +++ /dev/null @@ -1,306 +0,0 @@ -import pytest -from itertools import chain, combinations, product - -import networkx as nx - -tree_all_pairs_lca = nx.tree_all_pairs_lowest_common_ancestor -all_pairs_lca = nx.all_pairs_lowest_common_ancestor - - -def get_pair(dictionary, n1, n2): - if (n1, n2) in dictionary: - return dictionary[n1, n2] - else: - return dictionary[n2, n1] - - -class TestTreeLCA(object): - @classmethod - def setup_class(cls): - cls.DG = nx.DiGraph() - edges = [(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)] - cls.DG.add_edges_from(edges) - cls.ans = dict(tree_all_pairs_lca(cls.DG, 0)) - gold = dict([((n, n), n) for n in cls.DG]) - gold.update(dict(((0, i), 0) for i in range(1, 7))) - gold.update({(1, 2): 0, - (1, 3): 1, - (1, 4): 1, - (1, 5): 0, - (1, 6): 0, - (2, 3): 0, - (2, 4): 0, - (2, 5): 2, - (2, 6): 2, - (3, 4): 1, - (3, 5): 0, - (3, 6): 0, - (4, 5): 0, - (4, 6): 0, - (5, 6): 2}) - - cls.gold = gold - - @staticmethod - def assert_has_same_pairs(d1, d2): - for (a, b) in ((min(pair), max(pair)) for pair in chain(d1, d2)): - assert get_pair(d1, a, b) == get_pair(d2, a, b) - - def test_tree_all_pairs_lowest_common_ancestor1(self): - """Specifying the root is optional.""" - assert dict(tree_all_pairs_lca(self.DG)) == self.ans - - def test_tree_all_pairs_lowest_common_ancestor2(self): - """Specifying only some pairs gives only those pairs.""" - test_pairs = [(0, 1), (0, 1), (1, 0)] - ans = dict(tree_all_pairs_lca(self.DG, 0, test_pairs)) - assert (0, 1) in ans and (1, 0) in ans - assert len(ans) == 2 - - def test_tree_all_pairs_lowest_common_ancestor3(self): - """Specifying no pairs same as specifying all.""" - all_pairs = chain(combinations(self.DG, 2), - ((node, node) for node in self.DG)) - - ans = dict(tree_all_pairs_lca(self.DG, 0, all_pairs)) - self.assert_has_same_pairs(ans, self.ans) - - def test_tree_all_pairs_lowest_common_ancestor4(self): - """Gives the right answer.""" - ans = dict(tree_all_pairs_lca(self.DG)) - self.assert_has_same_pairs(self.gold, ans) - - def test_tree_all_pairs_lowest_common_ancestor5(self): - """Handles invalid input correctly.""" - empty_digraph = tree_all_pairs_lca(nx.DiGraph()) - pytest.raises(nx.NetworkXPointlessConcept, list, empty_digraph) - - bad_pairs_digraph = tree_all_pairs_lca(self.DG, pairs=[(-1, -2)]) - pytest.raises(nx.NodeNotFound, list, bad_pairs_digraph) - - def test_tree_all_pairs_lowest_common_ancestor6(self): - """Works on subtrees.""" - ans = dict(tree_all_pairs_lca(self.DG, 1)) - gold = dict((pair, lca) for (pair, lca) in self.gold.items() - if all(n in (1, 3, 4) for n in pair)) - self.assert_has_same_pairs(gold, ans) - - def test_tree_all_pairs_lowest_common_ancestor7(self): - """Works on disconnected nodes.""" - G = nx.DiGraph() - G.add_node(1) - assert {(1, 1): 1} == dict(tree_all_pairs_lca(G)) - - G.add_node(0) - assert {(1, 1): 1} == dict(tree_all_pairs_lca(G, 1)) - assert {(0, 0): 0} == dict(tree_all_pairs_lca(G, 0)) - - pytest.raises(nx.NetworkXError, list, tree_all_pairs_lca(G)) - - def test_tree_all_pairs_lowest_common_ancestor8(self): - """Raises right errors if not a tree.""" - # Cycle - G = nx.DiGraph([(1, 2), (2, 1)]) - pytest.raises(nx.NetworkXError, list, tree_all_pairs_lca(G)) - # DAG - G = nx.DiGraph([(0, 2), (1, 2)]) - pytest.raises(nx.NetworkXError, list, tree_all_pairs_lca(G)) - - def test_tree_all_pairs_lowest_common_ancestor9(self): - """Test that pairs works correctly as a generator.""" - pairs = iter([(0, 1), (0, 1), (1, 0)]) - some_pairs = dict(tree_all_pairs_lca(self.DG, 0, pairs)) - assert (0, 1) in some_pairs and (1, 0) in some_pairs - assert len(some_pairs) == 2 - - def test_tree_all_pairs_lowest_common_ancestor10(self): - """Test that pairs not in the graph raises error.""" - lca = tree_all_pairs_lca(self.DG, 0, [(-1, -1)]) - pytest.raises(nx.NodeNotFound, list, lca) - - def test_tree_all_pairs_lowest_common_ancestor11(self): - """Test that None as a node in the graph raises an error.""" - G = nx.DiGraph([(None, 3)]) - pytest.raises(nx.NetworkXError, list, tree_all_pairs_lca(G)) - pytest.raises(nx.NodeNotFound, list, - tree_all_pairs_lca(self.DG, pairs=G.edges())) - - def test_tree_all_pairs_lowest_common_ancestor12(self): - """Test that tree routine bails on DAGs.""" - G = nx.DiGraph([(3, 4), (5, 4)]) - pytest.raises(nx.NetworkXError, list, tree_all_pairs_lca(G)) - - def test_not_implemented_for(self): - NNI = nx.NetworkXNotImplemented - G = nx.Graph([(0, 1)]) - pytest.raises(NNI, tree_all_pairs_lca, G) - pytest.raises(NNI, all_pairs_lca, G) - pytest.raises(NNI, nx.lowest_common_ancestor, G, 0, 1) - G = nx.MultiGraph([(0, 1)]) - pytest.raises(NNI, tree_all_pairs_lca, G) - pytest.raises(NNI, all_pairs_lca, G) - pytest.raises(NNI, nx.lowest_common_ancestor, G, 0, 1) - G = nx.MultiDiGraph([(0, 1)]) - pytest.raises(NNI, tree_all_pairs_lca, G) - pytest.raises(NNI, all_pairs_lca, G) - pytest.raises(NNI, nx.lowest_common_ancestor, G, 0, 1) - - def test_tree_all_pairs_lowest_common_ancestor13(self): - """Test that it works on non-empty trees with no LCAs.""" - G = nx.DiGraph() - G.add_node(3) - ans = list(tree_all_pairs_lca(G)) - assert ans == [((3, 3), 3)] - - -class TestDAGLCA: - @classmethod - def setup_class(cls): - cls.DG = nx.DiGraph() - nx.add_path(cls.DG, (0, 1, 2, 3)) - nx.add_path(cls.DG, (0, 4, 3)) - nx.add_path(cls.DG, (0, 5, 6, 8, 3)) - nx.add_path(cls.DG, (5, 7, 8)) - cls.DG.add_edge(6, 2) - cls.DG.add_edge(7, 2) - - cls.root_distance = nx.shortest_path_length(cls.DG, source=0) - - cls.gold = {(1, 1): 1, - (1, 2): 1, - (1, 3): 1, - (1, 4): 0, - (1, 5): 0, - (1, 6): 0, - (1, 7): 0, - (1, 8): 0, - (2, 2): 2, - (2, 3): 2, - (2, 4): 0, - (2, 5): 5, - (2, 6): 6, - (2, 7): 7, - (2, 8): 7, - (3, 3): 8, - (3, 4): 4, - (3, 5): 5, - (3, 6): 6, - (3, 7): 7, - (3, 8): 8, - (4, 4): 4, - (4, 5): 0, - (4, 6): 0, - (4, 7): 0, - (4, 8): 0, - (5, 5): 5, - (5, 6): 5, - (5, 7): 5, - (5, 8): 5, - (6, 6): 6, - (6, 7): 5, - (6, 8): 6, - (7, 7): 7, - (7, 8): 7, - (8, 8): 8} - cls.gold.update(((0, n), 0) for n in cls.DG) - - def assert_lca_dicts_same(self, d1, d2, G=None): - """Checks if d1 and d2 contain the same pairs and - have a node at the same distance from root for each. - If G is None use self.DG.""" - if G is None: - G = self.DG - root_distance = self.root_distance - else: - roots = [n for n, deg in G.in_degree if deg == 0] - assert(len(roots) == 1) - root_distance = nx.shortest_path_length(G, source=roots[0]) - - for a, b in ((min(pair), max(pair)) for pair in chain(d1, d2)): - assert (root_distance[get_pair(d1, a, b)] == - root_distance[get_pair(d2, a, b)]) - - def test_all_pairs_lowest_common_ancestor1(self): - """Produces the correct results.""" - self.assert_lca_dicts_same(dict(all_pairs_lca(self.DG)), self.gold) - - def test_all_pairs_lowest_common_ancestor2(self): - """Produces the correct results when all pairs given.""" - all_pairs = list(product(self.DG.nodes(), self.DG.nodes())) - ans = all_pairs_lca(self.DG, pairs=all_pairs) - self.assert_lca_dicts_same(dict(ans), self.gold) - - def test_all_pairs_lowest_common_ancestor3(self): - """Produces the correct results when all pairs given as a generator.""" - all_pairs = product(self.DG.nodes(), self.DG.nodes()) - ans = all_pairs_lca(self.DG, pairs=all_pairs) - self.assert_lca_dicts_same(dict(ans), self.gold) - - def test_all_pairs_lowest_common_ancestor4(self): - """Graph with two roots.""" - G = self.DG.copy() - G.add_edge(9, 10) - G.add_edge(9, 4) - gold = self.gold.copy() - gold[9, 9] = 9 - gold[9, 10] = 9 - gold[9, 4] = 9 - gold[9, 3] = 9 - gold[10, 4] = 9 - gold[10, 3] = 9 - gold[10, 10] = 10 - - testing = dict(all_pairs_lca(G)) - - G.add_edge(-1, 9) - G.add_edge(-1, 0) - self.assert_lca_dicts_same(testing, gold, G) - - def test_all_pairs_lowest_common_ancestor5(self): - """Test that pairs not in the graph raises error.""" - pytest.raises(nx.NodeNotFound, all_pairs_lca, self.DG, [(-1, -1)]) - - def test_all_pairs_lowest_common_ancestor6(self): - """Test that pairs with no LCA specified emits nothing.""" - G = self.DG.copy() - G.add_node(-1) - gen = all_pairs_lca(G, [(-1, -1), (-1, 0)]) - assert dict(gen) == {(-1, -1): -1} - - def test_all_pairs_lowest_common_ancestor7(self): - """Test that LCA on null graph bails.""" - pytest.raises(nx.NetworkXPointlessConcept, - all_pairs_lca, - nx.DiGraph()) - - def test_all_pairs_lowest_common_ancestor8(self): - """Test that LCA on non-dags bails.""" - pytest.raises(nx.NetworkXError, all_pairs_lca, - nx.DiGraph([(3, 4), (4, 3)])) - - def test_all_pairs_lowest_common_ancestor9(self): - """Test that it works on non-empty graphs with no LCAs.""" - G = nx.DiGraph() - G.add_node(3) - ans = list(all_pairs_lca(G)) - assert ans == [((3, 3), 3)] - - def test_all_pairs_lowest_common_ancestor10(self): - """Test that it bails on None as a node.""" - G = nx.DiGraph([(None, 3)]) - pytest.raises(nx.NetworkXError, all_pairs_lca, G) - pytest.raises(nx.NodeNotFound, all_pairs_lca, - self.DG, pairs=G.edges()) - - def test_lowest_common_ancestor1(self): - """Test that the one-pair function works on default.""" - G = nx.DiGraph([(0, 1), (2, 1)]) - sentinel = object() - assert (nx.lowest_common_ancestor(G, 0, 2, default=sentinel) is - sentinel) - - def test_lowest_common_ancestor2(self): - """Test that the one-pair function works on identity.""" - G = nx.DiGraph() - G.add_node(3) - assert nx.lowest_common_ancestor(G, 3, 3) == 3 diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_matching.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_matching.py deleted file mode 100644 index e166f8dd..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_matching.py +++ /dev/null @@ -1,354 +0,0 @@ -from itertools import permutations -import math - -import networkx as nx -from networkx.algorithms.matching import matching_dict_to_set -from networkx.testing import assert_edges_equal - - -class TestMaxWeightMatching(object): - """Unit tests for the - :func:`~networkx.algorithms.matching.max_weight_matching` function. - - """ - - def test_trivial1(self): - """Empty graph""" - G = nx.Graph() - assert nx.max_weight_matching(G) == set() - - def test_trivial2(self): - """Self loop""" - G = nx.Graph() - G.add_edge(0, 0, weight=100) - assert nx.max_weight_matching(G) == set() - - def test_trivial3(self): - """Single edge""" - G = nx.Graph() - G.add_edge(0, 1) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({0: 1, 1: 0})) - - def test_trivial4(self): - """Small graph""" - G = nx.Graph() - G.add_edge('one', 'two', weight=10) - G.add_edge('two', 'three', weight=11) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({'three': 'two', 'two': 'three'})) - - def test_trivial5(self): - """Path""" - G = nx.Graph() - G.add_edge(1, 2, weight=5) - G.add_edge(2, 3, weight=11) - G.add_edge(3, 4, weight=5) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({2: 3, 3: 2})) - assert_edges_equal(nx.max_weight_matching(G, 1), - matching_dict_to_set({1: 2, 2: 1, 3: 4, 4: 3})) - - def test_trivial6(self): - """Small graph with arbitrary weight attribute""" - G = nx.Graph() - G.add_edge('one', 'two', weight=10, abcd=11) - G.add_edge('two', 'three', weight=11, abcd=10) - assert_edges_equal(nx.max_weight_matching(G, weight='abcd'), - matching_dict_to_set({'one': 'two', 'two': 'one'})) - - def test_floating_point_weights(self): - """Floating point weights""" - G = nx.Graph() - G.add_edge(1, 2, weight=math.pi) - G.add_edge(2, 3, weight=math.exp(1)) - G.add_edge(1, 3, weight=3.0) - G.add_edge(1, 4, weight=math.sqrt(2.0)) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({1: 4, 2: 3, 3: 2, 4: 1})) - - def test_negative_weights(self): - """Negative weights""" - G = nx.Graph() - G.add_edge(1, 2, weight=2) - G.add_edge(1, 3, weight=-2) - G.add_edge(2, 3, weight=1) - G.add_edge(2, 4, weight=-1) - G.add_edge(3, 4, weight=-6) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({1: 2, 2: 1})) - assert_edges_equal(nx.max_weight_matching(G, 1), - matching_dict_to_set({1: 3, 2: 4, 3: 1, 4: 2})) - - def test_s_blossom(self): - """Create S-blossom and use it for augmentation:""" - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 8), (1, 3, 9), - (2, 3, 10), (3, 4, 7)]) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({1: 2, 2: 1, 3: 4, 4: 3})) - - G.add_weighted_edges_from([(1, 6, 5), (4, 5, 6)]) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({1: 6, 2: 3, 3: 2, 4: 5, 5: 4, 6: 1})) - - def test_s_t_blossom(self): - """Create S-blossom, relabel as T-blossom, use for augmentation:""" - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 9), (1, 3, 8), (2, 3, 10), - (1, 4, 5), (4, 5, 4), (1, 6, 3)]) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({1: 6, 2: 3, 3: 2, 4: 5, 5: 4, 6: 1})) - G.add_edge(4, 5, weight=3) - G.add_edge(1, 6, weight=4) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({1: 6, 2: 3, 3: 2, 4: 5, 5: 4, 6: 1})) - G.remove_edge(1, 6) - G.add_edge(3, 6, weight=4) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({1: 2, 2: 1, 3: 6, 4: 5, 5: 4, 6: 3})) - - def test_nested_s_blossom(self): - """Create nested S-blossom, use for augmentation:""" - - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 9), (1, 3, 9), (2, 3, 10), - (2, 4, 8), (3, 5, 8), (4, 5, 10), - (5, 6, 6)]) - dict_format = {1: 3, 2: 4, 3: 1, 4: 2, 5: 6, 6: 5} - expected = {frozenset(e) for e in matching_dict_to_set(dict_format)} - answer = {frozenset(e) for e in nx.max_weight_matching(G)} - assert answer == expected - - def test_nested_s_blossom_relabel(self): - """Create S-blossom, relabel as S, include in nested S-blossom:""" - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 10), (1, 7, 10), (2, 3, 12), - (3, 4, 20), (3, 5, 20), (4, 5, 25), - (5, 6, 10), (6, 7, 10), (7, 8, 8)]) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({1: 2, 2: 1, 3: 4, 4: 3, 5: 6, 6: 5, 7: 8, 8: 7})) - - def test_nested_s_blossom_expand(self): - """Create nested S-blossom, augment, expand recursively:""" - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 8), (1, 3, 8), (2, 3, 10), - (2, 4, 12), (3, 5, 12), (4, 5, 14), - (4, 6, 12), (5, 7, 12), (6, 7, 14), - (7, 8, 12)]) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({1: 2, 2: 1, 3: 5, 4: 6, 5: 3, 6: 4, 7: 8, 8: 7})) - - def test_s_blossom_relabel_expand(self): - """Create S-blossom, relabel as T, expand:""" - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 23), (1, 5, 22), (1, 6, 15), - (2, 3, 25), (3, 4, 22), (4, 5, 25), - (4, 8, 14), (5, 7, 13)]) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({1: 6, 2: 3, 3: 2, 4: 8, 5: 7, 6: 1, 7: 5, 8: 4})) - - def test_nested_s_blossom_relabel_expand(self): - """Create nested S-blossom, relabel as T, expand:""" - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 19), (1, 3, 20), (1, 8, 8), - (2, 3, 25), (2, 4, 18), (3, 5, 18), - (4, 5, 13), (4, 7, 7), (5, 6, 7)]) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({1: 8, 2: 3, 3: 2, 4: 7, 5: 6, 6: 5, 7: 4, 8: 1})) - - def test_nasty_blossom1(self): - """Create blossom, relabel as T in more than one way, expand, - augment: - """ - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 45), (1, 5, 45), (2, 3, 50), - (3, 4, 45), (4, 5, 50), (1, 6, 30), - (3, 9, 35), (4, 8, 35), (5, 7, 26), - (9, 10, 5)]) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({1: 6, 2: 3, 3: 2, 4: 8, 5: 7, - 6: 1, 7: 5, 8: 4, 9: 10, 10: 9})) - - def test_nasty_blossom2(self): - """Again but slightly different:""" - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 45), (1, 5, 45), (2, 3, 50), - (3, 4, 45), (4, 5, 50), (1, 6, 30), - (3, 9, 35), (4, 8, 26), (5, 7, 40), - (9, 10, 5)]) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({1: 6, 2: 3, 3: 2, 4: 8, 5: 7, - 6: 1, 7: 5, 8: 4, 9: 10, 10: 9})) - - def test_nasty_blossom_least_slack(self): - """Create blossom, relabel as T, expand such that a new - least-slack S-to-free dge is produced, augment: - """ - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 45), (1, 5, 45), (2, 3, 50), - (3, 4, 45), (4, 5, 50), (1, 6, 30), - (3, 9, 35), (4, 8, 28), (5, 7, 26), - (9, 10, 5)]) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({1: 6, 2: 3, 3: 2, 4: 8, 5: 7, - 6: 1, 7: 5, 8: 4, 9: 10, 10: 9})) - - def test_nasty_blossom_augmenting(self): - """Create nested blossom, relabel as T in more than one way""" - # expand outer blossom such that inner blossom ends up on an - # augmenting path: - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 45), (1, 7, 45), (2, 3, 50), - (3, 4, 45), (4, 5, 95), (4, 6, 94), - (5, 6, 94), (6, 7, 50), (1, 8, 30), - (3, 11, 35), (5, 9, 36), (7, 10, 26), - (11, 12, 5)]) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({1: 8, 2: 3, 3: 2, 4: 6, 5: 9, 6: 4, - 7: 10, 8: 1, 9: 5, 10: 7, 11: 12, 12: 11})) - - def test_nasty_blossom_expand_recursively(self): - """Create nested S-blossom, relabel as S, expand recursively:""" - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 40), (1, 3, 40), (2, 3, 60), - (2, 4, 55), (3, 5, 55), (4, 5, 50), - (1, 8, 15), (5, 7, 30), (7, 6, 10), - (8, 10, 10), (4, 9, 30)]) - assert_edges_equal(nx.max_weight_matching(G), - matching_dict_to_set({1: 2, 2: 1, 3: 5, 4: 9, 5: 3, - 6: 7, 7: 6, 8: 10, 9: 4, 10: 8})) - - -class TestIsMatching(object): - """Unit tests for the - :func:`~networkx.algorithms.matching.is_matching` function. - - """ - - def test_dict(self): - G = nx.path_graph(4) - assert nx.is_matching(G, {0: 1, 1: 0, 2: 3, 3: 2}) - - def test_empty_matching(self): - G = nx.path_graph(4) - assert nx.is_matching(G, set()) - - def test_single_edge(self): - G = nx.path_graph(4) - assert nx.is_matching(G, {(1, 2)}) - - def test_edge_order(self): - G = nx.path_graph(4) - assert nx.is_matching(G, {(0, 1), (2, 3)}) - assert nx.is_matching(G, {(1, 0), (2, 3)}) - assert nx.is_matching(G, {(0, 1), (3, 2)}) - assert nx.is_matching(G, {(1, 0), (3, 2)}) - - def test_valid(self): - G = nx.path_graph(4) - assert nx.is_matching(G, {(0, 1), (2, 3)}) - - def test_invalid(self): - G = nx.path_graph(4) - assert not nx.is_matching(G, {(0, 1), (1, 2), (2, 3)}) - - -class TestIsMaximalMatching(object): - """Unit tests for the - :func:`~networkx.algorithms.matching.is_maximal_matching` function. - - """ - - def test_dict(self): - G = nx.path_graph(4) - assert nx.is_maximal_matching(G, {0: 1, 1: 0, 2: 3, 3: 2}) - - def test_valid(self): - G = nx.path_graph(4) - assert nx.is_maximal_matching(G, {(0, 1), (2, 3)}) - - def test_not_matching(self): - G = nx.path_graph(4) - assert not nx.is_maximal_matching(G, {(0, 1), (1, 2), (2, 3)}) - - def test_not_maximal(self): - G = nx.path_graph(4) - assert not nx.is_maximal_matching(G, {(0, 1)}) - - -class TestIsPerfectMatching(object): - """Unit tests for the - :func:`~networkx.algorithms.matching.is_perfect_matching` function. - - """ - - def test_dict(self): - G = nx.path_graph(4) - assert nx.is_perfect_matching(G, {0: 1, 1: 0, 2: 3, 3: 2}) - - def test_valid(self): - G = nx.path_graph(4) - assert nx.is_perfect_matching(G, {(0, 1), (2, 3)}) - - def test_valid_not_path(self): - G = nx.cycle_graph(4) - G.add_edge(0, 4) - G.add_edge(1, 4) - G.add_edge(5, 2) - - assert nx.is_perfect_matching(G, {(1, 4), (0, 3), (5, 2)}) - - def test_not_matching(self): - G = nx.path_graph(4) - assert not nx.is_perfect_matching(G, {(0, 1), (1, 2), (2, 3)}) - - def test_maximal_but_not_perfect(self): - G = nx.cycle_graph(4) - G.add_edge(0, 4) - G.add_edge(1, 4) - - assert not nx.is_perfect_matching(G, {(1, 4), (0, 3)}) - - -class TestMaximalMatching(object): - """Unit tests for the - :func:`~networkx.algorithms.matching.maximal_matching`. - - """ - - def test_valid_matching(self): - edges = [(1, 2), (1, 5), (2, 3), (2, 5), (3, 4), (3, 6), (5, 6)] - G = nx.Graph(edges) - matching = nx.maximal_matching(G) - assert nx.is_maximal_matching(G, matching) - - def test_single_edge_matching(self): - # In the star graph, any maximal matching has just one edge. - G = nx.star_graph(5) - matching = nx.maximal_matching(G) - assert 1 == len(matching) - assert nx.is_maximal_matching(G, matching) - - def test_self_loops(self): - # Create the path graph with two self-loops. - G = nx.path_graph(3) - G.add_edges_from([(0, 0), (1, 1)]) - matching = nx.maximal_matching(G) - assert len(matching) == 1 - # The matching should never include self-loops. - assert not any(u == v for u, v in matching) - assert nx.is_maximal_matching(G, matching) - - def test_ordering(self): - """Tests that a maximal matching is computed correctly - regardless of the order in which nodes are added to the graph. - - """ - for nodes in permutations(range(3)): - G = nx.Graph() - G.add_nodes_from(nodes) - G.add_edges_from([(0, 1), (0, 2)]) - matching = nx.maximal_matching(G) - assert len(matching) == 1 - assert nx.is_maximal_matching(G, matching) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_minors.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_minors.py deleted file mode 100644 index 8541ac2f..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_minors.py +++ /dev/null @@ -1,331 +0,0 @@ -# test_minors.py - unit tests for the minors module -# -# Copyright 2015 Jeffrey Finkelstein . -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.minors` module.""" -import pytest - -import networkx as nx -from networkx.testing.utils import * -from networkx.utils import arbitrary_element - - -class TestQuotient(object): - """Unit tests for computing quotient graphs.""" - - def test_quotient_graph_complete_multipartite(self): - """Tests that the quotient graph of the complete *n*-partite graph - under the "same neighbors" node relation is the complete graph on *n* - nodes. - - """ - G = nx.complete_multipartite_graph(2, 3, 4) - # Two nodes are equivalent if they are not adjacent but have the same - # neighbor set. - - def same_neighbors(u, v): - return (u not in G[v] and v not in G[u] and G[u] == G[v]) - - expected = nx.complete_graph(3) - actual = nx.quotient_graph(G, same_neighbors) - # It won't take too long to run a graph isomorphism algorithm on such - # small graphs. - assert nx.is_isomorphic(expected, actual) - - def test_quotient_graph_complete_bipartite(self): - """Tests that the quotient graph of the complete bipartite graph under - the "same neighbors" node relation is `K_2`. - - """ - G = nx.complete_bipartite_graph(2, 3) - # Two nodes are equivalent if they are not adjacent but have the same - # neighbor set. - - def same_neighbors(u, v): - return (u not in G[v] and v not in G[u] and G[u] == G[v]) - - expected = nx.complete_graph(2) - actual = nx.quotient_graph(G, same_neighbors) - # It won't take too long to run a graph isomorphism algorithm on such - # small graphs. - assert nx.is_isomorphic(expected, actual) - - def test_quotient_graph_edge_relation(self): - """Tests for specifying an alternate edge relation for the quotient - graph. - - """ - G = nx.path_graph(5) - - def identity(u, v): - return u == v - - def same_parity(b, c): - return (arbitrary_element(b) % 2 == arbitrary_element(c) % 2) - - actual = nx.quotient_graph(G, identity, same_parity) - expected = nx.Graph() - expected.add_edges_from([(0, 2), (0, 4), (2, 4)]) - expected.add_edge(1, 3) - assert nx.is_isomorphic(actual, expected) - - def test_condensation_as_quotient(self): - """This tests that the condensation of a graph can be viewed as the - quotient graph under the "in the same connected component" equivalence - relation. - - """ - # This example graph comes from the file `test_strongly_connected.py`. - G = nx.DiGraph() - G.add_edges_from([(1, 2), (2, 3), (2, 11), (2, 12), (3, 4), (4, 3), - (4, 5), (5, 6), (6, 5), (6, 7), (7, 8), (7, 9), - (7, 10), (8, 9), (9, 7), (10, 6), (11, 2), (11, 4), - (11, 6), (12, 6), (12, 11)]) - scc = list(nx.strongly_connected_components(G)) - C = nx.condensation(G, scc) - component_of = C.graph['mapping'] - # Two nodes are equivalent if they are in the same connected component. - - def same_component(u, v): - return component_of[u] == component_of[v] - - Q = nx.quotient_graph(G, same_component) - assert nx.is_isomorphic(C, Q) - - def test_path(self): - G = nx.path_graph(6) - partition = [{0, 1}, {2, 3}, {4, 5}] - M = nx.quotient_graph(G, partition, relabel=True) - assert_nodes_equal(M, [0, 1, 2]) - assert_edges_equal(M.edges(), [(0, 1), (1, 2)]) - for n in M: - assert M.nodes[n]['nedges'] == 1 - assert M.nodes[n]['nnodes'] == 2 - assert M.nodes[n]['density'] == 1 - - def test_multigraph_path(self): - G = nx.MultiGraph(nx.path_graph(6)) - partition = [{0, 1}, {2, 3}, {4, 5}] - M = nx.quotient_graph(G, partition, relabel=True) - assert_nodes_equal(M, [0, 1, 2]) - assert_edges_equal(M.edges(), [(0, 1), (1, 2)]) - for n in M: - assert M.nodes[n]['nedges'] == 1 - assert M.nodes[n]['nnodes'] == 2 - assert M.nodes[n]['density'] == 1 - - def test_directed_path(self): - G = nx.DiGraph() - nx.add_path(G, range(6)) - partition = [{0, 1}, {2, 3}, {4, 5}] - M = nx.quotient_graph(G, partition, relabel=True) - assert_nodes_equal(M, [0, 1, 2]) - assert_edges_equal(M.edges(), [(0, 1), (1, 2)]) - for n in M: - assert M.nodes[n]['nedges'] == 1 - assert M.nodes[n]['nnodes'] == 2 - assert M.nodes[n]['density'] == 0.5 - - def test_directed_multigraph_path(self): - G = nx.MultiDiGraph() - nx.add_path(G, range(6)) - partition = [{0, 1}, {2, 3}, {4, 5}] - M = nx.quotient_graph(G, partition, relabel=True) - assert_nodes_equal(M, [0, 1, 2]) - assert_edges_equal(M.edges(), [(0, 1), (1, 2)]) - for n in M: - assert M.nodes[n]['nedges'] == 1 - assert M.nodes[n]['nnodes'] == 2 - assert M.nodes[n]['density'] == 0.5 - - def test_overlapping_blocks(self): - with pytest.raises(nx.NetworkXException): - G = nx.path_graph(6) - partition = [{0, 1, 2}, {2, 3}, {4, 5}] - nx.quotient_graph(G, partition) - - def test_weighted_path(self): - G = nx.path_graph(6) - for i in range(5): - G[i][i + 1]['weight'] = i + 1 - partition = [{0, 1}, {2, 3}, {4, 5}] - M = nx.quotient_graph(G, partition, relabel=True) - assert_nodes_equal(M, [0, 1, 2]) - assert_edges_equal(M.edges(), [(0, 1), (1, 2)]) - assert M[0][1]['weight'] == 2 - assert M[1][2]['weight'] == 4 - for n in M: - assert M.nodes[n]['nedges'] == 1 - assert M.nodes[n]['nnodes'] == 2 - assert M.nodes[n]['density'] == 1 - - def test_barbell(self): - G = nx.barbell_graph(3, 0) - partition = [{0, 1, 2}, {3, 4, 5}] - M = nx.quotient_graph(G, partition, relabel=True) - assert_nodes_equal(M, [0, 1]) - assert_edges_equal(M.edges(), [(0, 1)]) - for n in M: - assert M.nodes[n]['nedges'] == 3 - assert M.nodes[n]['nnodes'] == 3 - assert M.nodes[n]['density'] == 1 - - def test_barbell_plus(self): - G = nx.barbell_graph(3, 0) - # Add an extra edge joining the bells. - G.add_edge(0, 5) - partition = [{0, 1, 2}, {3, 4, 5}] - M = nx.quotient_graph(G, partition, relabel=True) - assert_nodes_equal(M, [0, 1]) - assert_edges_equal(M.edges(), [(0, 1)]) - assert M[0][1]['weight'] == 2 - for n in M: - assert M.nodes[n]['nedges'] == 3 - assert M.nodes[n]['nnodes'] == 3 - assert M.nodes[n]['density'] == 1 - - def test_blockmodel(self): - G = nx.path_graph(6) - partition = [[0, 1], [2, 3], [4, 5]] - M = nx.quotient_graph(G, partition, relabel=True) - assert_nodes_equal(M.nodes(), [0, 1, 2]) - assert_edges_equal(M.edges(), [(0, 1), (1, 2)]) - for n in M.nodes(): - assert M.nodes[n]['nedges'] == 1 - assert M.nodes[n]['nnodes'] == 2 - assert M.nodes[n]['density'] == 1.0 - - def test_multigraph_blockmodel(self): - G = nx.MultiGraph(nx.path_graph(6)) - partition = [[0, 1], [2, 3], [4, 5]] - M = nx.quotient_graph(G, partition, - create_using=nx.MultiGraph(), relabel=True) - assert_nodes_equal(M.nodes(), [0, 1, 2]) - assert_edges_equal(M.edges(), [(0, 1), (1, 2)]) - for n in M.nodes(): - assert M.nodes[n]['nedges'] == 1 - assert M.nodes[n]['nnodes'] == 2 - assert M.nodes[n]['density'] == 1.0 - - def test_quotient_graph_incomplete_partition(self): - G = nx.path_graph(6) - partition = [] - H = nx.quotient_graph(G, partition, relabel=True) - assert_nodes_equal(H.nodes(), []) - assert_edges_equal(H.edges(), []) - - partition = [[0, 1], [2, 3], [5]] - H = nx.quotient_graph(G, partition, relabel=True) - assert_nodes_equal(H.nodes(), [0, 1, 2]) - assert_edges_equal(H.edges(), [(0, 1)]) - - -class TestContraction(object): - """Unit tests for node and edge contraction functions.""" - - def test_undirected_node_contraction(self): - """Tests for node contraction in an undirected graph.""" - G = nx.cycle_graph(4) - actual = nx.contracted_nodes(G, 0, 1) - expected = nx.complete_graph(3) - expected.add_edge(0, 0) - assert nx.is_isomorphic(actual, expected) - - def test_directed_node_contraction(self): - """Tests for node contraction in a directed graph.""" - G = nx.DiGraph(nx.cycle_graph(4)) - actual = nx.contracted_nodes(G, 0, 1) - expected = nx.DiGraph(nx.complete_graph(3)) - expected.add_edge(0, 0) - expected.add_edge(0, 0) - assert nx.is_isomorphic(actual, expected) - - def test_create_multigraph(self): - """Tests that using a MultiGraph creates multiple edges.""" - G = nx.path_graph(3, create_using=nx.MultiGraph()) - G.add_edge(0, 1) - G.add_edge(0, 0) - G.add_edge(0, 2) - actual = nx.contracted_nodes(G, 0, 2) - expected = nx.MultiGraph() - expected.add_edge(0, 1) - expected.add_edge(0, 1) - expected.add_edge(0, 1) - expected.add_edge(0, 0) - expected.add_edge(0, 0) - assert_edges_equal(actual.edges, expected.edges) - - def test_multigraph_keys(self): - """Tests that multiedge keys are reset in new graph.""" - G = nx.path_graph(3, create_using=nx.MultiGraph()) - G.add_edge(0, 1, 5) - G.add_edge(0, 0, 0) - G.add_edge(0, 2, 5) - actual = nx.contracted_nodes(G, 0, 2) - expected = nx.MultiGraph() - expected.add_edge(0, 1, 0) - expected.add_edge(0, 1, 5) - expected.add_edge(0, 1, 2) # keyed as 2 b/c 2 edges already in G - expected.add_edge(0, 0, 0) - expected.add_edge(0, 0, 1) # this comes from (0, 2, 5) - assert_edges_equal(actual.edges, expected.edges) - - def test_node_attributes(self): - """Tests that node contraction preserves node attributes.""" - G = nx.cycle_graph(4) - # Add some data to the two nodes being contracted. - G.nodes[0]['foo'] = 'bar' - G.nodes[1]['baz'] = 'xyzzy' - actual = nx.contracted_nodes(G, 0, 1) - # We expect that contracting the nodes 0 and 1 in C_4 yields K_3, but - # with nodes labeled 0, 2, and 3, and with a self-loop on 0. - expected = nx.complete_graph(3) - expected = nx.relabel_nodes(expected, {1: 2, 2: 3}) - expected.add_edge(0, 0) - cdict = {1: {'baz': 'xyzzy'}} - expected.nodes[0].update(dict(foo='bar', contraction=cdict)) - assert nx.is_isomorphic(actual, expected) - assert actual.nodes == expected.nodes - - def test_without_self_loops(self): - """Tests for node contraction without preserving self-loops.""" - G = nx.cycle_graph(4) - actual = nx.contracted_nodes(G, 0, 1, self_loops=False) - expected = nx.complete_graph(3) - assert nx.is_isomorphic(actual, expected) - - def test_contract_selfloop_graph(self): - """Tests for node contraction when nodes have selfloops.""" - G = nx.cycle_graph(4) - G.add_edge(0, 0) - actual = nx.contracted_nodes(G, 0, 1) - expected = nx.complete_graph([0, 2, 3]) - expected.add_edge(0, 0) - expected.add_edge(0, 0) - assert_edges_equal(actual.edges, expected.edges) - actual = nx.contracted_nodes(G, 1, 0) - expected = nx.complete_graph([1, 2, 3]) - expected.add_edge(1, 1) - expected.add_edge(1, 1) - assert_edges_equal(actual.edges, expected.edges) - - def test_undirected_edge_contraction(self): - """Tests for edge contraction in an undirected graph.""" - G = nx.cycle_graph(4) - actual = nx.contracted_edge(G, (0, 1)) - expected = nx.complete_graph(3) - expected.add_edge(0, 0) - assert nx.is_isomorphic(actual, expected) - - def test_nonexistent_edge(self): - """Tests that attempting to contract a non-existent edge raises an - exception. - - """ - with pytest.raises(ValueError): - G = nx.cycle_graph(4) - nx.contracted_edge(G, (0, 2)) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_mis.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_mis.py deleted file mode 100644 index eb36fd3b..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_mis.py +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# $Id: test_maximal_independent_set.py 577 2011-03-01 06:07:53Z lleeoo $ -# Copyright (C) 2004-2019 by -# Leo Lopes -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Author: Leo Lopes -""" -Tests for maximal (not maximum) independent sets. - -""" - -import pytest -import networkx as nx -import random - - -class TestMaximalIndependantSet(object): - def setup(self): - self.florentine = nx.Graph() - self.florentine.add_edge('Acciaiuoli', 'Medici') - self.florentine.add_edge('Castellani', 'Peruzzi') - self.florentine.add_edge('Castellani', 'Strozzi') - self.florentine.add_edge('Castellani', 'Barbadori') - self.florentine.add_edge('Medici', 'Barbadori') - self.florentine.add_edge('Medici', 'Ridolfi') - self.florentine.add_edge('Medici', 'Tornabuoni') - self.florentine.add_edge('Medici', 'Albizzi') - self.florentine.add_edge('Medici', 'Salviati') - self.florentine.add_edge('Salviati', 'Pazzi') - self.florentine.add_edge('Peruzzi', 'Strozzi') - self.florentine.add_edge('Peruzzi', 'Bischeri') - self.florentine.add_edge('Strozzi', 'Ridolfi') - self.florentine.add_edge('Strozzi', 'Bischeri') - self.florentine.add_edge('Ridolfi', 'Tornabuoni') - self.florentine.add_edge('Tornabuoni', 'Guadagni') - self.florentine.add_edge('Albizzi', 'Ginori') - self.florentine.add_edge('Albizzi', 'Guadagni') - self.florentine.add_edge('Bischeri', 'Guadagni') - self.florentine.add_edge('Guadagni', 'Lamberteschi') - - def test_random_seed(self): - G = nx.complete_graph(5) - for node in G: - assert nx.maximal_independent_set(G, [node], seed=1) == [node] - - def test_K5(self): - """Maximal independent set: K5""" - G = nx.complete_graph(5) - for node in G: - assert nx.maximal_independent_set(G, [node]) == [node] - - def test_K55(self): - """Maximal independent set: K55""" - G = nx.complete_graph(55) - for node in G: - assert nx.maximal_independent_set(G, [node]) == [node] - - def test_exception(self): - """Bad input should raise exception.""" - G = self.florentine - pytest.raises(nx.NetworkXUnfeasible, - nx.maximal_independent_set, G, ["Smith"]) - pytest.raises(nx.NetworkXUnfeasible, - nx.maximal_independent_set, G, ["Salviati", "Pazzi"]) - - def test_digraph_exception(self): - G = nx.DiGraph([(1, 2), (3, 4)]) - pytest.raises(nx.NetworkXNotImplemented, nx.maximal_independent_set, G) - - def test_florentine_family(self): - G = self.florentine - indep = nx.maximal_independent_set(G, ["Medici", "Bischeri"]) - assert (sorted(indep) == - sorted(["Medici", "Bischeri", "Castellani", "Pazzi", - "Ginori", "Lamberteschi"])) - - def test_bipartite(self): - G = nx.complete_bipartite_graph(12, 34) - indep = nx.maximal_independent_set(G, [4, 5, 9, 10]) - assert sorted(indep) == list(range(12)) - - def test_random_graphs(self): - """Generate 50 random graphs of different types and sizes and - make sure that all sets are independent and maximal.""" - for i in range(0, 50, 10): - G = nx.random_graphs.erdos_renyi_graph(i * 10 + 1, random.random()) - IS = nx.maximal_independent_set(G) - assert not list(G.subgraph(IS).edges()) - neighbors_of_MIS = set.union(*(set(G.neighbors(v)) for v in IS)) - for v in set(G.nodes()).difference(IS): - assert v in neighbors_of_MIS diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_moral.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_moral.py deleted file mode 100644 index c9f4de94..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_moral.py +++ /dev/null @@ -1,17 +0,0 @@ -import networkx as nx - -from networkx.algorithms.moral import moral_graph - - - -def test_get_moral_graph(): - graph = nx.DiGraph() - graph.add_nodes_from([1, 2, 3, 4, 5, 6, 7]) - graph.add_edges_from([(1, 2), (3, 2), (4, 1), (4, 5), (6, 5), (7, 5)]) - H = moral_graph(graph) - assert not H.is_directed() - assert H.has_edge(1, 3) - assert H.has_edge(4, 6) - assert H.has_edge(6, 7) - assert H.has_edge(4, 7) - assert not H.has_edge(1, 5) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_non_randomness.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_non_randomness.py deleted file mode 100644 index d5bfa0f3..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_non_randomness.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env python -import networkx as nx - -import pytest -numpy = pytest.importorskip('numpy') -npt = pytest.importorskip('numpy.testing') - - -def test_non_randomness(): - G = nx.karate_club_graph() - npt.assert_almost_equal(nx.non_randomness(G, 2)[0], 11.7, decimal=2) - npt.assert_almost_equal(nx.non_randomness(G)[0], - 7.21, decimal=2) # infers 3 communities diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_planar_drawing.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_planar_drawing.py deleted file mode 100644 index d9100d19..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_planar_drawing.py +++ /dev/null @@ -1,250 +0,0 @@ -import pytest -import networkx as nx -from networkx.algorithms.planar_drawing import triangulate_embedding -import math - - -def test_graph1(): - embedding_data = {0: [1, 2, 3], 1: [2, 0], 2: [3, 0, 1], 3: [2, 0]} - check_embedding_data(embedding_data) - - -def test_graph2(): - embedding_data = { - 0: [8, 6], 1: [2, 6, 9], 2: [8, 1, 7, 9, 6, 4], 3: [9], 4: [2], - 5: [6, 8], 6: [9, 1, 0, 5, 2], 7: [9, 2], 8: [0, 2, 5], - 9: [1, 6, 2, 7, 3] - } - check_embedding_data(embedding_data) - - -def test_circle_graph(): - embedding_data = { - 0: [1, 9], 1: [0, 2], 2: [1, 3], 3: [2, 4], 4: [3, 5], - 5: [4, 6], 6: [5, 7], 7: [6, 8], 8: [7, 9], 9: [8, 0] - } - check_embedding_data(embedding_data) - - -def test_grid_graph(): - embedding_data = { - (0, 1): [(0, 0), (1, 1), (0, 2)], (1, 2): [(1, 1), (2, 2), (0, 2)], - (0, 0): [(0, 1), (1, 0)], (2, 1): [(2, 0), (2, 2), (1, 1)], - (1, 1): [(2, 1), (1, 2), (0, 1), (1, 0)], - (2, 0): [(1, 0), (2, 1)], (2, 2): [(1, 2), (2, 1)], - (1, 0): [(0, 0), (2, 0), (1, 1)], (0, 2): [(1, 2), (0, 1)] - } - check_embedding_data(embedding_data) - - -def test_one_node_graph(): - embedding_data = {0: []} - check_embedding_data(embedding_data) - - -def test_two_node_graph(): - embedding_data = {0: [1], 1: [0]} - check_embedding_data(embedding_data) - - -def test_three_node_graph(): - embedding_data = {0: [1, 2], 1: [0, 2], 2: [0, 1]} - check_embedding_data(embedding_data) - - -def test_multiple_component_graph1(): - embedding_data = {0: [], 1: []} - check_embedding_data(embedding_data) - - -def test_multiple_component_graph2(): - embedding_data = { - 0: [1, 2], 1: [0, 2], 2: [0, 1], - 3: [4, 5], 4: [3, 5], 5: [3, 4] - } - check_embedding_data(embedding_data) - - -def test_invalid_half_edge(): - with pytest.raises(nx.NetworkXException): - embedding_data = {1: [2, 3, 4], 2: [1, 3, 4], 3: [1, 2, 4], 4: [1, 2, 3]} - embedding = nx.PlanarEmbedding() - embedding.set_data(embedding_data) - nx.combinatorial_embedding_to_pos(embedding) - - -def test_triangulate_embedding1(): - embedding = nx.PlanarEmbedding() - embedding.add_node(1) - expected_embedding = {1: []} - check_triangulation(embedding, expected_embedding) - - -def test_triangulate_embedding2(): - embedding = nx.PlanarEmbedding() - embedding.connect_components(1, 2) - expected_embedding = {1: [2], 2: [1]} - check_triangulation(embedding, expected_embedding) - - -def check_triangulation(embedding, expected_embedding): - res_embedding, _ = triangulate_embedding(embedding, True) - assert res_embedding.get_data() == expected_embedding, "Expected embedding incorrect" - res_embedding, _ = triangulate_embedding(embedding, False) - assert res_embedding.get_data() == expected_embedding, "Expected embedding incorrect" - - -def check_embedding_data(embedding_data): - """Checks that the planar embedding of the input is correct""" - embedding = nx.PlanarEmbedding() - embedding.set_data(embedding_data) - pos_fully = nx.combinatorial_embedding_to_pos(embedding, False) - msg = "Planar drawing does not conform to the embedding (fully " \ - "triangulation)" - assert planar_drawing_conforms_to_embedding(embedding, pos_fully), msg - check_edge_intersections(embedding, pos_fully) - pos_internally = nx.combinatorial_embedding_to_pos(embedding, True) - msg = "Planar drawing does not conform to the embedding (internal " \ - "triangulation)" - assert planar_drawing_conforms_to_embedding(embedding, - pos_internally), msg - check_edge_intersections(embedding, pos_internally) - - -def is_close(a, b, rel_tol=1e-09, abs_tol=0.0): - # Check if float numbers are basically equal, for python >=3.5 there is - # function for that in the standard library - return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol) - - -def point_in_between(a, b, p): - # checks if p is on the line between a and b - x1, y1 = a - x2, y2 = b - px, py = p - dist_1_2 = math.sqrt((x1 - x2)**2 + (y1 - y2)**2) - dist_1_p = math.sqrt((x1 - px)**2 + (y1 - py)**2) - dist_2_p = math.sqrt((x2 - px)**2 + (y2 - py)**2) - return is_close(dist_1_p+dist_2_p, dist_1_2) - - -def check_edge_intersections(G, pos): - """Check all edges in G for intersections. - - Raises an exception if an intersection is found. - - Parameters - ---------- - G : NetworkX graph - pos : dict - Maps every node to a tuple (x, y) representing its position - - """ - for a, b in G.edges(): - for c, d in G.edges(): - # Check if end points are different - if a != c and b != d and b != c and a != d: - x1, y1 = pos[a] - x2, y2 = pos[b] - x3, y3 = pos[c] - x4, y4 = pos[d] - determinant = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4) - if determinant != 0: # the lines are not parallel - # calculate intersection point, see: - # https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection - px = ((x1 * y2 - y1 * x2) * (x3 - x4) - - (x1 - x2) * (x3 * y4 - y3 * x4) / float(determinant)) - py = ((x1 * y2 - y1 * x2) * (y3 - y4) - - (y1 - y2) * (x3 * y4 - y3 * x4) / float(determinant)) - - # Check if intersection lies between the points - if (point_in_between(pos[a], pos[b], (px, py)) and - point_in_between(pos[c], pos[d], (px, py))): - msg = "There is an intersection at {},{}".format(px, - py) - raise nx.NetworkXException(msg) - - # Check overlap - msg = "A node lies on a edge connecting two other nodes" - if (point_in_between(pos[a], pos[b], pos[c]) or - point_in_between(pos[a], pos[b], pos[d]) or - point_in_between(pos[c], pos[d], pos[a]) or - point_in_between(pos[c], pos[d], pos[b])): - raise nx.NetworkXException(msg) - # No edge intersection found - - -class Vector(object): - """Compare vectors by their angle without loss of precision - - All vectors in direction [0, 1] are the smallest. - The vectors grow in clockwise direction. - """ - __slots__ = ['x', 'y', 'node', 'quadrant'] - - def __init__(self, x, y, node): - self.x = x - self.y = y - self.node = node - if self.x >= 0 and self.y > 0: - self.quadrant = 1 - elif self.x > 0 and self.y <= 0: - self.quadrant = 2 - elif self.x <= 0 and self.y < 0: - self.quadrant = 3 - else: - self.quadrant = 4 - - def __eq__(self, other): - return (self.quadrant == other.quadrant and - self.x * other.y == self.y * other.x) - - def __lt__(self, other): - if self.quadrant < other.quadrant: - return True - elif self.quadrant > other.quadrant: - return False - else: - return self.x * other.y < self.y * other.x - - def __ne__(self, other): - return not self == other - - def __le__(self, other): - return not other < self - - def __gt__(self, other): - return other < self - - def __ge__(self, other): - return not self < other - - -def planar_drawing_conforms_to_embedding(embedding, pos): - """Checks if pos conforms to the planar embedding - - Returns true iff the neighbors are actually oriented in the orientation - specified of the embedding - """ - for v in embedding: - nbr_vectors = [] - v_pos = pos[v] - for nbr in embedding[v]: - new_vector = Vector(pos[nbr][0] - v_pos[0], pos[nbr][1] - v_pos[1], - nbr) - nbr_vectors.append(new_vector) - # Sort neighbors according to their phi angle - nbr_vectors.sort() - for idx, nbr_vector in enumerate(nbr_vectors): - cw_vector = nbr_vectors[(idx + 1) % len(nbr_vectors)] - ccw_vector = nbr_vectors[idx - 1] - if (embedding[v][nbr_vector.node]['cw'] != cw_vector.node or - embedding[v][nbr_vector.node]['ccw'] != ccw_vector.node): - return False - if cw_vector.node != nbr_vector.node and cw_vector == nbr_vector: - # Lines overlap - return False - if ccw_vector.node != nbr_vector.node and ccw_vector == nbr_vector: - # Lines overlap - return False - return True diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_planarity.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_planarity.py deleted file mode 100644 index 833dd024..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_planarity.py +++ /dev/null @@ -1,341 +0,0 @@ -import pytest -import networkx as nx -from networkx.algorithms.planarity import get_counterexample -from networkx.algorithms.planarity import get_counterexample_recursive -from networkx.algorithms.planarity import check_planarity_recursive - - -class TestLRPlanarity: - """Nose Unit tests for the :mod:`networkx.algorithms.planarity` module. - - Tests three things: - 1. Check that the result is correct - (returns planar if and only if the graph is actually planar) - 2. In case a counter example is returned: Check if it is correct - 3. In case an embedding is returned: Check if its actually an embedding - """ - - @staticmethod - def check_graph(G, is_planar=None): - """Raises an exception if the lr_planarity check returns a wrong result - - Parameters - ---------- - G : NetworkX graph - is_planar : bool - The expected result of the planarity check. - If set to None only counter example or embedding are verified. - - """ - - # obtain results of planarity check - is_planar_lr, result = nx.check_planarity(G, True) - is_planar_lr_rec, result_rec = check_planarity_recursive(G, True) - - if is_planar is not None: - # set a message for the assert - if is_planar: - msg = "Wrong planarity check result. Should be planar." - else: - msg = "Wrong planarity check result. Should be non-planar." - - # check if the result is as expected - assert is_planar == is_planar_lr, msg - assert is_planar == is_planar_lr_rec, msg - - if is_planar_lr: - # check embedding - check_embedding(G, result) - check_embedding(G, result_rec) - else: - # check counter example - check_counterexample(G, result) - check_counterexample(G, result_rec) - - def test_simple_planar_graph(self): - e = [(1, 2), (2, 3), (3, 4), (4, 6), (6, 7), (7, 1), (1, 5), - (5, 2), (2, 4), (4, 5), (5, 7)] - self.check_graph(nx.Graph(e), is_planar=True) - - def test_planar_with_selfloop(self): - e = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (1, 2), (1, 3), - (1, 5), (2, 5), (2, 4), (3, 4), (3, 5), (4, 5)] - self.check_graph(nx.Graph(e), is_planar=True) - - def test_k3_3(self): - self.check_graph(nx.complete_bipartite_graph(3, 3), is_planar=False) - - def test_k5(self): - self.check_graph(nx.complete_graph(5), is_planar=False) - - def test_multiple_components_planar(self): - e = [(1, 2), (2, 3), (3, 1), (4, 5), (5, 6), (6, 4)] - self.check_graph(nx.Graph(e), is_planar=True) - - def test_multiple_components_non_planar(self): - G = nx.complete_graph(5) - # add another planar component to the non planar component - # G stays non planar - G.add_edges_from([(6, 7), (7, 8), (8, 6)]) - self.check_graph(G, is_planar=False) - - def test_non_planar_with_selfloop(self): - G = nx.complete_graph(5) - # add self loops - for i in range(5): - G.add_edge(i, i) - self.check_graph(G, is_planar=False) - - def test_non_planar1(self): - # tests a graph that has no subgraph directly isomorph to K5 or K3_3 - e = [(1, 5), (1, 6), (1, 7), (2, 6), (2, 3), (3, 5), (3, 7), (4, 5), - (4, 6), (4, 7)] - self.check_graph(nx.Graph(e), is_planar=False) - - def test_loop(self): - # test a graph with a selfloop - e = [(1, 2), (2, 2)] - G = nx.Graph(e) - self.check_graph(G, is_planar=True) - - def test_comp(self): - # test multiple component graph - e = [(1, 2), (3, 4)] - G = nx.Graph(e) - G.remove_edge(1, 2) - self.check_graph(G, is_planar=True) - - def test_goldner_harary(self): - # test goldner-harary graph (a maximal planar graph) - e = [ - (1, 2), (1, 3), (1, 4), (1, 5), (1, 7), (1, 8), (1, 10), - (1, 11), (2, 3), (2, 4), (2, 6), (2, 7), (2, 9), (2, 10), - (2, 11), (3, 4), (4, 5), (4, 6), (4, 7), (5, 7), (6, 7), - (7, 8), (7, 9), (7, 10), (8, 10), (9, 10), (10, 11) - ] - G = nx.Graph(e) - self.check_graph(G, is_planar=True) - - def test_planar_multigraph(self): - G = nx.MultiGraph([(1, 2), (1, 2), (1, 2), (1, 2), (2, 3), (3, 1)]) - self.check_graph(G, is_planar=True) - - def test_non_planar_multigraph(self): - G = nx.MultiGraph(nx.complete_graph(5)) - G.add_edges_from([(1, 2)]*5) - self.check_graph(G, is_planar=False) - - def test_planar_digraph(self): - G = nx.DiGraph([ - (1, 2), (2, 3), (2, 4), (4, 1), (4, 2), (1, 4), (3, 2) - ]) - self.check_graph(G, is_planar=True) - - def test_non_planar_digraph(self): - G = nx.DiGraph(nx.complete_graph(5)) - G.remove_edge(1, 2) - G.remove_edge(4, 1) - self.check_graph(G, is_planar=False) - - def test_single_component(self): - # Test a graph with only a single node - G = nx.Graph() - G.add_node(1) - self.check_graph(G, is_planar=True) - - def test_graph1(self): - G = nx.OrderedGraph([ - (3, 10), (2, 13), (1, 13), (7, 11), (0, 8), (8, 13), (0, 2), - (0, 7), (0, 10), (1, 7) - ]) - self.check_graph(G, is_planar=True) - - def test_graph2(self): - G = nx.OrderedGraph([ - (1, 2), (4, 13), (0, 13), (4, 5), (7, 10), (1, 7), (0, 3), (2, 6), - (5, 6), (7, 13), (4, 8), (0, 8), (0, 9), (2, 13), (6, 7), (3, 6), - (2, 8) - ]) - self.check_graph(G, is_planar=False) - - def test_graph3(self): - G = nx.OrderedGraph([ - (0, 7), (3, 11), (3, 4), (8, 9), (4, 11), (1, 7), (1, 13), (1, 11), - (3, 5), (5, 7), (1, 3), (0, 4), (5, 11), (5, 13) - ]) - self.check_graph(G, is_planar=False) - - def test_counterexample_planar(self): - with pytest.raises(nx.NetworkXException): - # Try to get a counterexample of a planar graph - G = nx.Graph() - G.add_node(1) - get_counterexample(G) - - def test_counterexample_planar_recursive(self): - with pytest.raises(nx.NetworkXException): - # Try to get a counterexample of a planar graph - G = nx.Graph() - G.add_node(1) - get_counterexample_recursive(G) - - -def check_embedding(G, embedding): - """Raises an exception if the combinatorial embedding is not correct - - Parameters - ---------- - G : NetworkX graph - embedding : a dict mapping nodes to a list of edges - This specifies the ordering of the outgoing edges from a node for - a combinatorial embedding - - Notes - ----- - Checks the following things: - - The type of the embedding is correct - - The nodes and edges match the original graph - - Every half edge has its matching opposite half edge - - No intersections of edges (checked by Euler's formula) - """ - - if not isinstance(embedding, nx.PlanarEmbedding): - raise nx.NetworkXException( - "Bad embedding. Not of type nx.PlanarEmbedding") - - # Check structure - embedding.check_structure() - - # Check that graphs are equivalent - - assert set(G.nodes) == set(embedding.nodes), "Bad embedding. Nodes don't match the original graph." - - # Check that the edges are equal - g_edges = set() - for edge in G.edges: - if edge[0] != edge[1]: - g_edges.add((edge[0], edge[1])) - g_edges.add((edge[1], edge[0])) - assert g_edges == set(embedding.edges), "Bad embedding. Edges don't match the original graph." - - -def check_counterexample(G, sub_graph): - """Raises an exception if the counterexample is wrong. - - Parameters - ---------- - G : NetworkX graph - subdivision_nodes : set - A set of nodes inducing a subgraph as a counterexample - """ - # 1. Create the sub graph - sub_graph = nx.Graph(sub_graph) - - # 2. Remove self loops - for u in sub_graph: - if sub_graph.has_edge(u, u): - sub_graph.remove_edge(u, u) - - # keep track of nodes we might need to contract - contract = list(sub_graph) - - # 3. Contract Edges - while len(contract) > 0: - contract_node = contract.pop() - if contract_node not in sub_graph: - # Node was already contracted - continue - degree = sub_graph.degree[contract_node] - # Check if we can remove the node - if degree == 2: - # Get the two neighbors - neighbors = iter(sub_graph[contract_node]) - u = next(neighbors) - v = next(neighbors) - # Save nodes for later - contract.append(u) - contract.append(v) - # Contract edge - sub_graph.remove_node(contract_node) - sub_graph.add_edge(u, v) - - # 4. Check for isomorphism with K5 or K3_3 graphs - if len(sub_graph) == 5: - if not nx.is_isomorphic(nx.complete_graph(5), sub_graph): - raise nx.NetworkXException("Bad counter example.") - elif len(sub_graph) == 6: - if not nx.is_isomorphic(nx.complete_bipartite_graph(3, 3), sub_graph): - raise nx.NetworkXException("Bad counter example.") - else: - raise nx.NetworkXException("Bad counter example.") - - -class TestPlanarEmbeddingClass: - def test_get_data(self): - embedding = self.get_star_embedding(3) - data = embedding.get_data() - data_cmp = {0: [2, 1], 1: [0], 2: [0]} - assert data == data_cmp - - def test_missing_edge_orientation(self): - with pytest.raises(nx.NetworkXException): - embedding = nx.PlanarEmbedding() - embedding.add_edge(1, 2) - embedding.add_edge(2, 1) - # Invalid structure because the orientation of the edge was not set - embedding.check_structure() - - def test_invalid_edge_orientation(self): - with pytest.raises(nx.NetworkXException): - embedding = nx.PlanarEmbedding() - embedding.add_half_edge_first(1, 2) - embedding.add_half_edge_first(2, 1) - embedding.add_edge(1, 3) - embedding.check_structure() - - def test_missing_half_edge(self): - with pytest.raises(nx.NetworkXException): - embedding = nx.PlanarEmbedding() - embedding.add_half_edge_first(1, 2) - # Invalid structure because other half edge is missing - embedding.check_structure() - - def test_not_fulfilling_euler_formula(self): - with pytest.raises(nx.NetworkXException): - embedding = nx.PlanarEmbedding() - for i in range(5): - for j in range(5): - if i != j: - embedding.add_half_edge_first(i, j) - embedding.check_structure() - - def test_missing_reference(self): - with pytest.raises(nx.NetworkXException): - embedding = nx.PlanarEmbedding() - embedding.add_half_edge_cw(1, 2, 3) - - def test_connect_components(self): - embedding = nx.PlanarEmbedding() - embedding.connect_components(1, 2) - - def test_successful_face_traversal(self): - embedding = nx.PlanarEmbedding() - embedding.add_half_edge_first(1, 2) - embedding.add_half_edge_first(2, 1) - face = embedding.traverse_face(1, 2) - assert face == [1, 2] - - def test_unsuccessful_face_traversal(self): - with pytest.raises(nx.NetworkXException): - embedding = nx.PlanarEmbedding() - embedding.add_edge(1, 2, ccw=2, cw=3) - embedding.add_edge(2, 1, ccw=1, cw=3) - embedding.traverse_face(1, 2) - - @staticmethod - def get_star_embedding(n): - embedding = nx.PlanarEmbedding() - for i in range(1, n): - embedding.add_half_edge_first(0, i) - embedding.add_half_edge_first(i, 0) - return embedding diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_reciprocity.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_reciprocity.py deleted file mode 100644 index 1729dc60..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_reciprocity.py +++ /dev/null @@ -1,37 +0,0 @@ -import pytest -import networkx as nx - - -class TestReciprocity(object): - - # test overall reicprocity by passing whole graph - def test_reciprocity_digraph(self): - DG = nx.DiGraph([(1, 2), (2, 1)]) - reciprocity = nx.reciprocity(DG) - assert reciprocity == 1.0 - - # test empty graph's overall reciprocity which will throw an error - def test_overall_reciprocity_empty_graph(self): - with pytest.raises(nx.NetworkXError): - DG = nx.DiGraph() - nx.overall_reciprocity(DG) - - # test for reciprocity for a list of nodes - def test_reciprocity_graph_nodes(self): - DG = nx.DiGraph([(1, 2), (2, 3), (3, 2)]) - reciprocity = nx.reciprocity(DG, [1, 2]) - expected_reciprocity = {1: 0.0, 2: 0.6666666666666666} - assert reciprocity == expected_reciprocity - - # test for reciprocity for a single node - def test_reciprocity_graph_node(self): - DG = nx.DiGraph([(1, 2), (2, 3), (3, 2)]) - reciprocity = nx.reciprocity(DG, 2) - assert reciprocity == 0.6666666666666666 - - # test for reciprocity for an isolated node - def test_reciprocity_graph_isolated_nodes(self): - with pytest.raises(nx.NetworkXError): - DG = nx.DiGraph([(1, 2)]) - DG.add_node(4) - nx.reciprocity(DG, 4) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_richclub.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_richclub.py deleted file mode 100644 index a55ffd27..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_richclub.py +++ /dev/null @@ -1,82 +0,0 @@ -import pytest -import networkx as nx - - -def test_richclub(): - G = nx.Graph([(0, 1), (0, 2), (1, 2), (1, 3), (1, 4), (4, 5)]) - rc = nx.richclub.rich_club_coefficient(G, normalized=False) - assert rc == {0: 12.0 / 30, 1: 8.0 / 12} - - # test single value - rc0 = nx.richclub.rich_club_coefficient(G, normalized=False)[0] - assert rc0 == 12.0 / 30.0 - - -def test_richclub_seed(): - G = nx.Graph([(0, 1), (0, 2), (1, 2), (1, 3), (1, 4), (4, 5)]) - rcNorm = nx.richclub.rich_club_coefficient(G, Q=2, seed=1) - assert rcNorm == {0: 1.0, 1: 1.0} - - -def test_richclub_normalized(): - G = nx.Graph([(0, 1), (0, 2), (1, 2), (1, 3), (1, 4), (4, 5)]) - rcNorm = nx.richclub.rich_club_coefficient(G, Q=2) - assert rcNorm == {0: 1.0, 1: 1.0} - - -def test_richclub2(): - T = nx.balanced_tree(2, 10) - rc = nx.richclub.rich_club_coefficient(T, normalized=False) - assert rc == {0: 4092 / (2047 * 2046.0), - 1: (2044.0 / (1023 * 1022)), - 2: (2040.0 / (1022 * 1021))} - - -def test_richclub3(): - # tests edgecase - G = nx.karate_club_graph() - rc = nx.rich_club_coefficient(G, normalized=False) - assert rc == {0: 156.0 / 1122, - 1: 154.0 / 1056, - 2: 110.0 / 462, - 3: 78.0 / 240, - 4: 44.0 / 90, - 5: 22.0 / 42, - 6: 10.0 / 20, - 7: 10.0 / 20, - 8: 10.0 / 20, - 9: 6.0 / 12, - 10: 2.0 / 6, - 11: 2.0 / 6, - 12: 0.0, - 13: 0.0, - 14: 0.0, - 15: 0.0, } - - -def test_richclub4(): - G = nx.Graph() - G.add_edges_from([(0, 1), (0, 2), (0, 3), (0, 4), (4, 5), (5, 9), (6, 9), (7, 9), (8, 9)]) - rc = nx.rich_club_coefficient(G, normalized=False) - assert rc == {0: 18 / 90.0, - 1: 6 / 12.0, - 2: 0.0, - 3: 0.0} - - -def test_richclub_exception(): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.DiGraph() - nx.rich_club_coefficient(G) - - -def test_rich_club_exception2(): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.MultiGraph() - nx.rich_club_coefficient(G) - - -# def test_richclub2_normalized(): -# T = nx.balanced_tree(2,10) -# rcNorm = nx.richclub.rich_club_coefficient(T,Q=2) -# assert_true(rcNorm[0] ==1.0 and rcNorm[1] < 0.9 and rcNorm[2] < 0.9) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_similarity.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_similarity.py deleted file mode 100644 index b43bff86..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_similarity.py +++ /dev/null @@ -1,483 +0,0 @@ -#!/usr/bin/env python -import pytest - -import networkx as nx -from networkx.algorithms.similarity import * -from networkx.generators.classic import * - - -def nmatch(n1, n2): - return n1 == n2 - -def ematch(e1, e2): - return e1 == e2 - -def getCanonical(): - G = nx.Graph() - G.add_node('A', label='A') - G.add_node('B', label='B') - G.add_node('C', label='C') - G.add_node('D', label='D') - G.add_edge('A', 'B', label='a-b') - G.add_edge('B', 'C', label='b-c') - G.add_edge('B', 'D', label='b-d') - return G - - -class TestSimilarity: - - @classmethod - def setup_class(cls): - global numpy - global scipy - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') - - def test_graph_edit_distance(self): - G0 = nx.Graph() - G1 = path_graph(6) - G2 = cycle_graph(6) - G3 = wheel_graph(7) - - assert graph_edit_distance(G0, G0) == 0 - assert graph_edit_distance(G0, G1) == 11 - assert graph_edit_distance(G1, G0) == 11 - assert graph_edit_distance(G0, G2) == 12 - assert graph_edit_distance(G2, G0) == 12 - assert graph_edit_distance(G0, G3) == 19 - assert graph_edit_distance(G3, G0) == 19 - - assert graph_edit_distance(G1, G1) == 0 - assert graph_edit_distance(G1, G2) == 1 - assert graph_edit_distance(G2, G1) == 1 - assert graph_edit_distance(G1, G3) == 8 - assert graph_edit_distance(G3, G1) == 8 - - assert graph_edit_distance(G2, G2) == 0 - assert graph_edit_distance(G2, G3) == 7 - assert graph_edit_distance(G3, G2) == 7 - - assert graph_edit_distance(G3, G3) == 0 - - def test_graph_edit_distance_node_match(self): - G1 = cycle_graph(5) - G2 = cycle_graph(5) - for n, attr in G1.nodes.items(): - attr['color'] = 'red' if n % 2 == 0 else 'blue' - for n, attr in G2.nodes.items(): - attr['color'] = 'red' if n % 2 == 1 else 'blue' - assert graph_edit_distance(G1, G2) == 0 - assert graph_edit_distance(G1, G2, node_match=lambda n1, n2: n1['color'] == n2['color']) == 1 - - def test_graph_edit_distance_edge_match(self): - G1 = path_graph(6) - G2 = path_graph(6) - for e, attr in G1.edges.items(): - attr['color'] = 'red' if min(e) % 2 == 0 else 'blue' - for e, attr in G2.edges.items(): - attr['color'] = 'red' if min(e) // 3 == 0 else 'blue' - assert graph_edit_distance(G1, G2) == 0 - assert graph_edit_distance(G1, G2, edge_match=lambda e1, e2: e1['color'] == e2['color']) == 2 - - def test_graph_edit_distance_node_cost(self): - G1 = path_graph(6) - G2 = path_graph(6) - for n, attr in G1.nodes.items(): - attr['color'] = 'red' if n % 2 == 0 else 'blue' - for n, attr in G2.nodes.items(): - attr['color'] = 'red' if n % 2 == 1 else 'blue' - - def node_subst_cost(uattr, vattr): - if uattr['color'] == vattr['color']: - return 1 - else: - return 10 - - def node_del_cost(attr): - if attr['color'] == 'blue': - return 20 - else: - return 50 - - def node_ins_cost(attr): - if attr['color'] == 'blue': - return 40 - else: - return 100 - - assert graph_edit_distance(G1, G2, - node_subst_cost=node_subst_cost, - node_del_cost=node_del_cost, - node_ins_cost=node_ins_cost) == 6 - - def test_graph_edit_distance_edge_cost(self): - G1 = path_graph(6) - G2 = path_graph(6) - for e, attr in G1.edges.items(): - attr['color'] = 'red' if min(e) % 2 == 0 else 'blue' - for e, attr in G2.edges.items(): - attr['color'] = 'red' if min(e) // 3 == 0 else 'blue' - - def edge_subst_cost(gattr, hattr): - if gattr['color'] == hattr['color']: - return 0.01 - else: - return 0.1 - - def edge_del_cost(attr): - if attr['color'] == 'blue': - return 0.2 - else: - return 0.5 - - def edge_ins_cost(attr): - if attr['color'] == 'blue': - return 0.4 - else: - return 1.0 - - assert graph_edit_distance(G1, G2, - edge_subst_cost=edge_subst_cost, - edge_del_cost=edge_del_cost, - edge_ins_cost=edge_ins_cost) == 0.23 - - def test_graph_edit_distance_upper_bound(self): - G1 = circular_ladder_graph(2) - G2 = circular_ladder_graph(6) - assert graph_edit_distance(G1, G2, upper_bound=5) == None - assert graph_edit_distance(G1, G2, upper_bound=24) == 22 - assert graph_edit_distance(G1, G2) == 22 - - def test_optimal_edit_paths(self): - G1 = path_graph(3) - G2 = cycle_graph(3) - paths, cost = optimal_edit_paths(G1, G2) - assert cost == 1 - assert len(paths) == 6 - - def canonical(vertex_path, edge_path): - return tuple(sorted(vertex_path)), tuple(sorted(edge_path, key=lambda x: (None in x, x))) - - expected_paths = [([(0, 0), (1, 1), (2, 2)], [((0, 1), (0, 1)), ((1, 2), (1, 2)), (None, (0, 2))]), - ([(0, 0), (1, 2), (2, 1)], [((0, 1), (0, 2)), ((1, 2), (1, 2)), (None, (0, 1))]), - ([(0, 1), (1, 0), (2, 2)], [((0, 1), (0, 1)), ((1, 2), (0, 2)), (None, (1, 2))]), - ([(0, 1), (1, 2), (2, 0)], [((0, 1), (1, 2)), ((1, 2), (0, 2)), (None, (0, 1))]), - ([(0, 2), (1, 0), (2, 1)], [((0, 1), (0, 2)), ((1, 2), (0, 1)), (None, (1, 2))]), - ([(0, 2), (1, 1), (2, 0)], [((0, 1), (1, 2)), ((1, 2), (0, 1)), (None, (0, 2))])] - assert (set(canonical(*p) for p in paths) == - set(canonical(*p) for p in expected_paths)) - - def test_optimize_graph_edit_distance(self): - G1 = circular_ladder_graph(2) - G2 = circular_ladder_graph(6) - bestcost = 1000 - for cost in optimize_graph_edit_distance(G1, G2): - assert cost < bestcost - bestcost = cost - assert bestcost == 22 - - # def test_graph_edit_distance_bigger(self): - # G1 = circular_ladder_graph(12) - # G2 = circular_ladder_graph(16) - # assert_equal(graph_edit_distance(G1, G2), 22) - - def test_selfloops(self): - G0 = nx.Graph() - G1 = nx.Graph() - G1.add_edges_from((('A', 'A'), ('A', 'B'))) - G2 = nx.Graph() - G2.add_edges_from((('A', 'B'), ('B', 'B'))) - G3 = nx.Graph() - G3.add_edges_from((('A', 'A'), ('A', 'B'), ('B', 'B'))) - - assert graph_edit_distance(G0, G0) == 0 - assert graph_edit_distance(G0, G1) == 4 - assert graph_edit_distance(G1, G0) == 4 - assert graph_edit_distance(G0, G2) == 4 - assert graph_edit_distance(G2, G0) == 4 - assert graph_edit_distance(G0, G3) == 5 - assert graph_edit_distance(G3, G0) == 5 - - assert graph_edit_distance(G1, G1) == 0 - assert graph_edit_distance(G1, G2) == 0 - assert graph_edit_distance(G2, G1) == 0 - assert graph_edit_distance(G1, G3) == 1 - assert graph_edit_distance(G3, G1) == 1 - - assert graph_edit_distance(G2, G2) == 0 - assert graph_edit_distance(G2, G3) == 1 - assert graph_edit_distance(G3, G2) == 1 - - assert graph_edit_distance(G3, G3) == 0 - - def test_digraph(self): - G0 = nx.DiGraph() - G1 = nx.DiGraph() - G1.add_edges_from((('A', 'B'), ('B', 'C'), ('C', 'D'), ('D', 'A'))) - G2 = nx.DiGraph() - G2.add_edges_from((('A', 'B'), ('B', 'C'), ('C', 'D'), ('A', 'D'))) - G3 = nx.DiGraph() - G3.add_edges_from((('A', 'B'), ('A', 'C'), ('B', 'D'), ('C', 'D'))) - - assert graph_edit_distance(G0, G0) == 0 - assert graph_edit_distance(G0, G1) == 8 - assert graph_edit_distance(G1, G0) == 8 - assert graph_edit_distance(G0, G2) == 8 - assert graph_edit_distance(G2, G0) == 8 - assert graph_edit_distance(G0, G3) == 8 - assert graph_edit_distance(G3, G0) == 8 - - assert graph_edit_distance(G1, G1) == 0 - assert graph_edit_distance(G1, G2) == 2 - assert graph_edit_distance(G2, G1) == 2 - assert graph_edit_distance(G1, G3) == 4 - assert graph_edit_distance(G3, G1) == 4 - - assert graph_edit_distance(G2, G2) == 0 - assert graph_edit_distance(G2, G3) == 2 - assert graph_edit_distance(G3, G2) == 2 - - assert graph_edit_distance(G3, G3) == 0 - - def test_multigraph(self): - G0 = nx.MultiGraph() - G1 = nx.MultiGraph() - G1.add_edges_from((('A', 'B'), ('B', 'C'), ('A', 'C'))) - G2 = nx.MultiGraph() - G2.add_edges_from((('A', 'B'), ('B', 'C'), ('B', 'C'), ('A', 'C'))) - G3 = nx.MultiGraph() - G3.add_edges_from((('A', 'B'), ('B', 'C'), ('A', 'C'), ('A', 'C'), ('A', 'C'))) - - assert graph_edit_distance(G0, G0) == 0 - assert graph_edit_distance(G0, G1) == 6 - assert graph_edit_distance(G1, G0) == 6 - assert graph_edit_distance(G0, G2) == 7 - assert graph_edit_distance(G2, G0) == 7 - assert graph_edit_distance(G0, G3) == 8 - assert graph_edit_distance(G3, G0) == 8 - - assert graph_edit_distance(G1, G1) == 0 - assert graph_edit_distance(G1, G2) == 1 - assert graph_edit_distance(G2, G1) == 1 - assert graph_edit_distance(G1, G3) == 2 - assert graph_edit_distance(G3, G1) == 2 - - assert graph_edit_distance(G2, G2) == 0 - assert graph_edit_distance(G2, G3) == 1 - assert graph_edit_distance(G3, G2) == 1 - - assert graph_edit_distance(G3, G3) == 0 - - def test_multidigraph(self): - G1 = nx.MultiDiGraph() - G1.add_edges_from((('hardware', 'kernel'), ('kernel', 'hardware'), ('kernel', 'userspace'), ('userspace', 'kernel'))) - G2 = nx.MultiDiGraph() - G2.add_edges_from((('winter', 'spring'), ('spring', 'summer'), ('summer', 'autumn'), ('autumn', 'winter'))) - - assert graph_edit_distance(G1, G2) == 5 - assert graph_edit_distance(G2, G1) == 5 - - # by https://github.com/jfbeaumont - def testCopy(self): - G = nx.Graph() - G.add_node('A', label='A') - G.add_node('B', label='B') - G.add_edge('A', 'B', label='a-b') - assert graph_edit_distance(G, G.copy(), node_match=nmatch, edge_match=ematch) == 0 - - def testSame(self): - G1 = nx.Graph() - G1.add_node('A', label='A') - G1.add_node('B', label='B') - G1.add_edge('A', 'B', label='a-b') - G2 = nx.Graph() - G2.add_node('A', label='A') - G2.add_node('B', label='B') - G2.add_edge('A', 'B', label='a-b') - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 0 - - def testOneEdgeLabelDiff(self): - G1 = nx.Graph() - G1.add_node('A', label='A') - G1.add_node('B', label='B') - G1.add_edge('A', 'B', label='a-b') - G2 = nx.Graph() - G2.add_node('A', label='A') - G2.add_node('B', label='B') - G2.add_edge('A', 'B', label='bad') - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 1 - - def testOneNodeLabelDiff(self): - G1 = nx.Graph() - G1.add_node('A', label='A') - G1.add_node('B', label='B') - G1.add_edge('A', 'B', label='a-b') - G2 = nx.Graph() - G2.add_node('A', label='Z') - G2.add_node('B', label='B') - G2.add_edge('A', 'B', label='a-b') - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 1 - - def testOneExtraNode(self): - G1 = nx.Graph() - G1.add_node('A', label='A') - G1.add_node('B', label='B') - G1.add_edge('A', 'B', label='a-b') - G2 = nx.Graph() - G2.add_node('A', label='A') - G2.add_node('B', label='B') - G2.add_edge('A', 'B', label='a-b') - G2.add_node('C', label='C') - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 1 - - def testOneExtraEdge(self): - G1 = nx.Graph() - G1.add_node('A', label='A') - G1.add_node('B', label='B') - G1.add_node('C', label='C') - G1.add_node('C', label='C') - G1.add_edge('A', 'B', label='a-b') - G2 = nx.Graph() - G2.add_node('A', label='A') - G2.add_node('B', label='B') - G2.add_node('C', label='C') - G2.add_edge('A', 'B', label='a-b') - G2.add_edge('A', 'C', label='a-c') - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 1 - - def testOneExtraNodeAndEdge(self): - G1 = nx.Graph() - G1.add_node('A', label='A') - G1.add_node('B', label='B') - G1.add_edge('A', 'B', label='a-b') - G2 = nx.Graph() - G2.add_node('A', label='A') - G2.add_node('B', label='B') - G2.add_node('C', label='C') - G2.add_edge('A', 'B', label='a-b') - G2.add_edge('A', 'C', label='a-c') - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 2 - - def testGraph1(self): - G1 = getCanonical() - G2 = nx.Graph() - G2.add_node('A', label='A') - G2.add_node('B', label='B') - G2.add_node('D', label='D') - G2.add_node('E', label='E') - G2.add_edge('A', 'B', label='a-b') - G2.add_edge('B', 'D', label='b-d') - G2.add_edge('D', 'E', label='d-e') - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 3 - - def testGraph2(self): - G1 = getCanonical() - G2 = nx.Graph() - G2.add_node('A', label='A') - G2.add_node('B', label='B') - G2.add_node('C', label='C') - G2.add_node('D', label='D') - G2.add_node('E', label='E') - G2.add_edge('A', 'B', label='a-b') - G2.add_edge('B', 'C', label='b-c') - G2.add_edge('C', 'D', label='c-d') - G2.add_edge('C', 'E', label='c-e') - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 4 - - def testGraph3(self): - G1 = getCanonical() - G2 = nx.Graph() - G2.add_node('A', label='A') - G2.add_node('B', label='B') - G2.add_node('C', label='C') - G2.add_node('D', label='D') - G2.add_node('E', label='E') - G2.add_node('F', label='F') - G2.add_node('G', label='G') - G2.add_edge('A', 'C', label='a-c') - G2.add_edge('A', 'D', label='a-d') - G2.add_edge('D', 'E', label='d-e') - G2.add_edge('D', 'F', label='d-f') - G2.add_edge('D', 'G', label='d-g') - G2.add_edge('E', 'B', label='e-b') - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 12 - - def testGraph4(self): - G1 = getCanonical() - G2 = nx.Graph() - G2.add_node('A', label='A') - G2.add_node('B', label='B') - G2.add_node('C', label='C') - G2.add_node('D', label='D') - G2.add_edge('A', 'B', label='a-b') - G2.add_edge('B', 'C', label='b-c') - G2.add_edge('C', 'D', label='c-d') - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 2 - - def testGraph4_a(self): - G1 = getCanonical() - G2 = nx.Graph() - G2.add_node('A', label='A') - G2.add_node('B', label='B') - G2.add_node('C', label='C') - G2.add_node('D', label='D') - G2.add_edge('A', 'B', label='a-b') - G2.add_edge('B', 'C', label='b-c') - G2.add_edge('A', 'D', label='a-d') - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 2 - - def testGraph4_b(self): - G1 = getCanonical() - G2 = nx.Graph() - G2.add_node('A', label='A') - G2.add_node('B', label='B') - G2.add_node('C', label='C') - G2.add_node('D', label='D') - G2.add_edge('A', 'B', label='a-b') - G2.add_edge('B', 'C', label='b-c') - G2.add_edge('B', 'D', label='bad') - assert graph_edit_distance(G1, G2, node_match=nmatch, edge_match=ematch) == 1 - - def test_simrank_no_source_no_target(self): - G = nx.cycle_graph(5) - expected = {0: {0: 1, 1: 0.3951219505902448, 2: 0.5707317069281646, 3: 0.5707317069281646, 4: 0.3951219505902449}, 1: {0: 0.3951219505902448, 1: 1, 2: 0.3951219505902449, 3: 0.5707317069281646, 4: 0.5707317069281646}, 2: {0: 0.5707317069281646, 1: 0.3951219505902449, 2: 1, 3: 0.3951219505902449, 4: 0.5707317069281646}, 3: {0: 0.5707317069281646, 1: 0.5707317069281646, 2: 0.3951219505902449, 3: 1, 4: 0.3951219505902449}, 4: {0: 0.3951219505902449, 1: 0.5707317069281646, 2: 0.5707317069281646, 3: 0.3951219505902449, 4: 1}} - actual = nx.simrank_similarity(G) - assert expected == actual - - def test_simrank_source_no_target(self): - G = nx.cycle_graph(5) - expected = {0: 1, 1: 0.3951219505902448, 2: 0.5707317069281646, 3: 0.5707317069281646, 4: 0.3951219505902449} - actual = nx.simrank_similarity(G, source=0) - assert expected == actual - - def test_simrank_source_and_target(self): - G = nx.cycle_graph(5) - expected = 1 - actual = nx.simrank_similarity(G, source=0, target=0) - assert expected == actual - - def test_simrank_numpy_no_source_no_target(self): - G = nx.cycle_graph(5) - expected = numpy.array([ - [1.0, 0.3947180735764555, 0.570482097206368, 0.570482097206368, 0.3947180735764555], - [0.3947180735764555, 1.0, 0.3947180735764555, 0.570482097206368, 0.570482097206368], - [0.570482097206368, 0.3947180735764555, 1.0, 0.3947180735764555, 0.570482097206368], - [0.570482097206368, 0.570482097206368, 0.3947180735764555, 1.0, 0.3947180735764555], - [0.3947180735764555, 0.570482097206368, 0.570482097206368, 0.3947180735764555, 1.0] - ]) - actual = nx.simrank_similarity_numpy(G) - numpy.testing.assert_allclose(expected, actual, atol=1e-7) - - def test_simrank_numpy_source_no_target(self): - G = nx.cycle_graph(5) - expected = numpy.array( - [1.0, 0.3947180735764555, 0.570482097206368, 0.570482097206368, 0.3947180735764555], - ) - actual = nx.simrank_similarity_numpy(G, source=0) - numpy.testing.assert_allclose(expected, actual, atol=1e-7) - - def test_simrank_numpy_source_and_target(self): - G = nx.cycle_graph(5) - expected = 1.0 - actual = nx.simrank_similarity_numpy(G, source=0, target=0) - numpy.testing.assert_allclose(expected, actual, atol=1e-7) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_simple_paths.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_simple_paths.py deleted file mode 100644 index 52993c9c..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_simple_paths.py +++ /dev/null @@ -1,534 +0,0 @@ -import random - -import pytest - -import networkx as nx -from networkx import convert_node_labels_to_integers as cnlti -from networkx.algorithms.simple_paths import _bidirectional_dijkstra -from networkx.algorithms.simple_paths import _bidirectional_shortest_path -from networkx.utils import arbitrary_element - - -class TestIsSimplePath(object): - """Unit tests for the - :func:`networkx.algorithms.simple_paths.is_simple_path` function. - - """ - - def test_empty_list(self): - """Tests that the empty list is not a valid path, since there - should be a one-to-one correspondence between paths as lists of - nodes and paths as lists of edges. - - """ - G = nx.trivial_graph() - assert not nx.is_simple_path(G, []) - - def test_trivial_path(self): - """Tests that the trivial path, a path of length one, is - considered a simple path in a graph. - - """ - G = nx.trivial_graph() - assert nx.is_simple_path(G, [0]) - - def test_trivial_nonpath(self): - """Tests that a list whose sole element is an object not in the - graph is not considered a simple path. - - """ - G = nx.trivial_graph() - assert not nx.is_simple_path(G, ['not a node']) - - def test_simple_path(self): - G = nx.path_graph(2) - assert nx.is_simple_path(G, [0, 1]) - - def test_non_simple_path(self): - G = nx.path_graph(2) - assert not nx.is_simple_path(G, [0, 1, 0]) - - def test_cycle(self): - G = nx.cycle_graph(3) - assert not nx.is_simple_path(G, [0, 1, 2, 0]) - - def test_missing_node(self): - G = nx.path_graph(2) - assert not nx.is_simple_path(G, [0, 2]) - - def test_directed_path(self): - G = nx.DiGraph([(0, 1), (1, 2)]) - assert nx.is_simple_path(G, [0, 1, 2]) - - def test_directed_non_path(self): - G = nx.DiGraph([(0, 1), (1, 2)]) - assert not nx.is_simple_path(G, [2, 1, 0]) - - def test_directed_cycle(self): - G = nx.DiGraph([(0, 1), (1, 2), (2, 0)]) - assert not nx.is_simple_path(G, [0, 1, 2, 0]) - - def test_multigraph(self): - G = nx.MultiGraph([(0, 1), (0, 1)]) - assert nx.is_simple_path(G, [0, 1]) - - def test_multidigraph(self): - G = nx.MultiDiGraph([(0, 1), (0, 1), (1, 0), (1, 0)]) - assert nx.is_simple_path(G, [0, 1]) - - -# Tests for all_simple_paths -def test_all_simple_paths(): - G = nx.path_graph(4) - paths = nx.all_simple_paths(G, 0, 3) - assert set(tuple(p) for p in paths) == {(0, 1, 2, 3)} - - -def test_all_simple_paths_with_two_targets_emits_two_paths(): - G = nx.path_graph(4) - G.add_edge(2, 4) - paths = nx.all_simple_paths(G, 0, [3, 4]) - assert set(tuple(p) for p in paths) == {(0, 1, 2, 3), (0, 1, 2, 4)} - - -def test_digraph_all_simple_paths_with_two_targets_emits_two_paths(): - G = nx.path_graph(4, create_using=nx.DiGraph()) - G.add_edge(2, 4) - paths = nx.all_simple_paths(G, 0, [3, 4]) - assert set(tuple(p) for p in paths) == {(0, 1, 2, 3), (0, 1, 2, 4)} - - -def test_all_simple_paths_with_two_targets_cutoff(): - G = nx.path_graph(4) - G.add_edge(2, 4) - paths = nx.all_simple_paths(G, 0, [3, 4], cutoff=3) - assert set(tuple(p) for p in paths) == {(0, 1, 2, 3), (0, 1, 2, 4)} - - -def test_digraph_all_simple_paths_with_two_targets_cutoff(): - G = nx.path_graph(4, create_using=nx.DiGraph()) - G.add_edge(2, 4) - paths = nx.all_simple_paths(G, 0, [3, 4], cutoff=3) - assert set(tuple(p) for p in paths) == {(0, 1, 2, 3), (0, 1, 2, 4)} - - -def test_all_simple_paths_with_two_targets_in_line_emits_two_paths(): - G = nx.path_graph(4) - paths = nx.all_simple_paths(G, 0, [2, 3]) - assert set(tuple(p) for p in paths) == {(0, 1, 2), (0, 1, 2, 3)} - - -def test_all_simple_paths_ignores_cycle(): - G = nx.cycle_graph(3, create_using=nx.DiGraph()) - G.add_edge(1, 3) - paths = nx.all_simple_paths(G, 0, 3) - assert set(tuple(p) for p in paths) == {(0, 1, 3)} - - -def test_all_simple_paths_with_two_targets_inside_cycle_emits_two_paths(): - G = nx.cycle_graph(3, create_using=nx.DiGraph()) - G.add_edge(1, 3) - paths = nx.all_simple_paths(G, 0, [2, 3]) - assert set(tuple(p) for p in paths) == {(0, 1, 2), (0, 1, 3)} - - -def test_all_simple_paths_source_target(): - G = nx.path_graph(4) - paths = nx.all_simple_paths(G, 1, 1) - assert paths == [] - - -def test_all_simple_paths_cutoff(): - G = nx.complete_graph(4) - paths = nx.all_simple_paths(G, 0, 1, cutoff=1) - assert set(tuple(p) for p in paths) == {(0, 1)} - paths = nx.all_simple_paths(G, 0, 1, cutoff=2) - assert set(tuple(p) for p in paths) == {(0, 1), (0, 2, 1), (0, 3, 1)} - - -def test_all_simple_paths_on_non_trivial_graph(): - ''' you may need to draw this graph to make sure it is reasonable ''' - G = nx.path_graph(5, create_using=nx.DiGraph()) - G.add_edges_from([(0, 5), (1, 5), (1, 3), (5, 4), (4, 2), (4, 3)]) - paths = nx.all_simple_paths(G, 1, [2, 3]) - assert set(tuple(p) for p in paths) == { - (1, 2), (1, 3, 4, 2), (1, 5, 4, 2), (1, 3), (1, 2, 3), (1, 5, 4, 3), - (1, 5, 4, 2, 3)} - paths = nx.all_simple_paths(G, 1, [2, 3], cutoff=3) - assert set(tuple(p) for p in paths) == { - (1, 2), (1, 3, 4, 2), (1, 5, 4, 2), (1, 3), (1, 2, 3), (1, 5, 4, 3)} - paths = nx.all_simple_paths(G, 1, [2, 3], cutoff=2) - assert set(tuple(p) for p in paths) == {(1, 2), (1, 3), (1, 2, 3)} - - -def test_all_simple_paths_multigraph(): - G = nx.MultiGraph([(1, 2), (1, 2)]) - paths = nx.all_simple_paths(G, 1, 1) - assert paths == [] - nx.add_path(G, [3, 1, 10, 2]) - paths = list(nx.all_simple_paths(G, 1, 2)) - assert len(paths) == 3 - assert set(tuple(p) for p in paths) == {(1, 2), (1, 2), (1, 10, 2)} - - -def test_all_simple_paths_multigraph_with_cutoff(): - G = nx.MultiGraph([(1, 2), (1, 2), (1, 10), (10, 2)]) - paths = list(nx.all_simple_paths(G, 1, 2, cutoff=1)) - assert len(paths) == 2 - assert set(tuple(p) for p in paths) == {(1, 2), (1, 2)} - - -def test_all_simple_paths_directed(): - G = nx.DiGraph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [3, 2, 1]) - paths = nx.all_simple_paths(G, 1, 3) - assert set(tuple(p) for p in paths) == {(1, 2, 3)} - - -def test_all_simple_paths_empty(): - G = nx.path_graph(4) - paths = nx.all_simple_paths(G, 0, 3, cutoff=2) - assert list(paths) == [] - - -def test_all_simple_paths_corner_cases(): - assert list(nx.all_simple_paths(nx.empty_graph(2), 0, 0)) == [] - assert list(nx.all_simple_paths(nx.empty_graph(2), 0, 1)) == [] - assert list(nx.all_simple_paths(nx.path_graph(9), 0, 8, 0)) == [] - - -def hamiltonian_path(G, source): - source = arbitrary_element(G) - neighbors = set(G[source]) - set([source]) - n = len(G) - for target in neighbors: - for path in nx.all_simple_paths(G, source, target): - if len(path) == n: - yield path - - -def test_hamiltonian_path(): - from itertools import permutations - G = nx.complete_graph(4) - paths = [list(p) for p in hamiltonian_path(G, 0)] - exact = [[0] + list(p) for p in permutations([1, 2, 3], 3)] - assert sorted(paths) == sorted(exact) - - -def test_cutoff_zero(): - G = nx.complete_graph(4) - paths = nx.all_simple_paths(G, 0, 3, cutoff=0) - assert list(list(p) for p in paths) == [] - paths = nx.all_simple_paths(nx.MultiGraph(G), 0, 3, cutoff=0) - assert list(list(p) for p in paths) == [] - - -def test_source_missing(): - with pytest.raises(nx.NodeNotFound): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - paths = list(nx.all_simple_paths(nx.MultiGraph(G), 0, 3)) - - -def test_target_missing(): - with pytest.raises(nx.NodeNotFound): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - paths = list(nx.all_simple_paths(nx.MultiGraph(G), 1, 4)) - - -# Tests for shortest_simple_paths -def test_shortest_simple_paths(): - G = cnlti(nx.grid_2d_graph(4, 4), first_label=1, ordering="sorted") - paths = nx.shortest_simple_paths(G, 1, 12) - assert next(paths) == [1, 2, 3, 4, 8, 12] - assert next(paths) == [1, 5, 6, 7, 8, 12] - assert ([len(path) for path in nx.shortest_simple_paths(G, 1, 12)] == - sorted([len(path) for path in nx.all_simple_paths(G, 1, 12)])) - - -def test_shortest_simple_paths_directed(): - G = nx.cycle_graph(7, create_using=nx.DiGraph()) - paths = nx.shortest_simple_paths(G, 0, 3) - assert [path for path in paths] == [[0, 1, 2, 3]] - - -def test_Greg_Bernstein(): - g1 = nx.Graph() - g1.add_nodes_from(["N0", "N1", "N2", "N3", "N4"]) - g1.add_edge("N4", "N1", weight=10.0, capacity=50, name="L5") - g1.add_edge("N4", "N0", weight=7.0, capacity=40, name="L4") - g1.add_edge("N0", "N1", weight=10.0, capacity=45, name="L1") - g1.add_edge("N3", "N0", weight=10.0, capacity=50, name="L0") - g1.add_edge("N2", "N3", weight=12.0, capacity=30, name="L2") - g1.add_edge("N1", "N2", weight=15.0, capacity=42, name="L3") - solution = [['N1', 'N0', 'N3'], ['N1', 'N2', 'N3'], ['N1', 'N4', 'N0', 'N3']] - result = list(nx.shortest_simple_paths(g1, 'N1', 'N3', weight='weight')) - assert result == solution - - -def test_weighted_shortest_simple_path(): - def cost_func(path): - return sum(G.adj[u][v]['weight'] for (u, v) in zip(path, path[1:])) - - G = nx.complete_graph(5) - weight = {(u, v): random.randint(1, 100) for (u, v) in G.edges()} - nx.set_edge_attributes(G, weight, 'weight') - cost = 0 - for path in nx.shortest_simple_paths(G, 0, 3, weight='weight'): - this_cost = cost_func(path) - assert cost <= this_cost - cost = this_cost - - -def test_directed_weighted_shortest_simple_path(): - def cost_func(path): - return sum(G.adj[u][v]['weight'] for (u, v) in zip(path, path[1:])) - - G = nx.complete_graph(5) - G = G.to_directed() - weight = {(u, v): random.randint(1, 100) for (u, v) in G.edges()} - nx.set_edge_attributes(G, weight, 'weight') - cost = 0 - for path in nx.shortest_simple_paths(G, 0, 3, weight='weight'): - this_cost = cost_func(path) - assert cost <= this_cost - cost = this_cost - - -def test_weighted_shortest_simple_path_issue2427(): - G = nx.Graph() - G.add_edge('IN', 'OUT', weight=2) - G.add_edge('IN', 'A', weight=1) - G.add_edge('IN', 'B', weight=2) - G.add_edge('B', 'OUT', weight=2) - assert (list(nx.shortest_simple_paths(G, 'IN', 'OUT', weight="weight")) == - [['IN', 'OUT'], ['IN', 'B', 'OUT']]) - G = nx.Graph() - G.add_edge('IN', 'OUT', weight=10) - G.add_edge('IN', 'A', weight=1) - G.add_edge('IN', 'B', weight=1) - G.add_edge('B', 'OUT', weight=1) - assert (list(nx.shortest_simple_paths(G, 'IN', 'OUT', weight="weight")) == - [['IN', 'B', 'OUT'], ['IN', 'OUT']]) - - -def test_directed_weighted_shortest_simple_path_issue2427(): - G = nx.DiGraph() - G.add_edge('IN', 'OUT', weight=2) - G.add_edge('IN', 'A', weight=1) - G.add_edge('IN', 'B', weight=2) - G.add_edge('B', 'OUT', weight=2) - assert (list(nx.shortest_simple_paths(G, 'IN', 'OUT', weight="weight")) == - [['IN', 'OUT'], ['IN', 'B', 'OUT']]) - G = nx.DiGraph() - G.add_edge('IN', 'OUT', weight=10) - G.add_edge('IN', 'A', weight=1) - G.add_edge('IN', 'B', weight=1) - G.add_edge('B', 'OUT', weight=1) - assert (list(nx.shortest_simple_paths(G, 'IN', 'OUT', weight="weight")) == - [['IN', 'B', 'OUT'], ['IN', 'OUT']]) - - -def test_weight_name(): - G = nx.cycle_graph(7) - nx.set_edge_attributes(G, 1, 'weight') - nx.set_edge_attributes(G, 1, 'foo') - G.adj[1][2]['foo'] = 7 - paths = list(nx.shortest_simple_paths(G, 0, 3, weight='foo')) - solution = [[0, 6, 5, 4, 3], [0, 1, 2, 3]] - assert paths == solution - - -def test_ssp_source_missing(): - with pytest.raises(nx.NodeNotFound): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - paths = list(nx.shortest_simple_paths(G, 0, 3)) - - -def test_ssp_target_missing(): - with pytest.raises(nx.NodeNotFound): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - paths = list(nx.shortest_simple_paths(G, 1, 4)) - - -def test_ssp_multigraph(): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.MultiGraph() - nx.add_path(G, [1, 2, 3]) - paths = list(nx.shortest_simple_paths(G, 1, 4)) - - -def test_ssp_source_missing(): - with pytest.raises(nx.NetworkXNoPath): - G = nx.Graph() - nx.add_path(G, [0, 1, 2]) - nx.add_path(G, [3, 4, 5]) - paths = list(nx.shortest_simple_paths(G, 0, 3)) - - -def test_bidirectional_shortest_path_restricted_cycle(): - cycle = nx.cycle_graph(7) - length, path = _bidirectional_shortest_path(cycle, 0, 3) - assert path == [0, 1, 2, 3] - length, path = _bidirectional_shortest_path(cycle, 0, 3, ignore_nodes=[1]) - assert path == [0, 6, 5, 4, 3] - - -def test_bidirectional_shortest_path_restricted_wheel(): - wheel = nx.wheel_graph(6) - length, path = _bidirectional_shortest_path(wheel, 1, 3) - assert path in [[1, 0, 3], [1, 2, 3]] - length, path = _bidirectional_shortest_path(wheel, 1, 3, ignore_nodes=[0]) - assert path == [1, 2, 3] - length, path = _bidirectional_shortest_path(wheel, 1, 3, ignore_nodes=[0, 2]) - assert path == [1, 5, 4, 3] - length, path = _bidirectional_shortest_path(wheel, 1, 3, - ignore_edges=[(1, 0), (5, 0), (2, 3)]) - assert path in [[1, 2, 0, 3], [1, 5, 4, 3]] - - -def test_bidirectional_shortest_path_restricted_directed_cycle(): - directed_cycle = nx.cycle_graph(7, create_using=nx.DiGraph()) - length, path = _bidirectional_shortest_path(directed_cycle, 0, 3) - assert path == [0, 1, 2, 3] - pytest.raises( - nx.NetworkXNoPath, - _bidirectional_shortest_path, - directed_cycle, - 0, 3, - ignore_nodes=[1], - ) - length, path = _bidirectional_shortest_path(directed_cycle, 0, 3, - ignore_edges=[(2, 1)]) - assert path == [0, 1, 2, 3] - pytest.raises( - nx.NetworkXNoPath, - _bidirectional_shortest_path, - directed_cycle, - 0, 3, - ignore_edges=[(1, 2)], - ) - - -def test_bidirectional_shortest_path_ignore(): - G = nx.Graph() - nx.add_path(G, [1, 2]) - nx.add_path(G, [1, 3]) - nx.add_path(G, [1, 4]) - pytest.raises( - nx.NetworkXNoPath, - _bidirectional_shortest_path, - G, - 1, 2, - ignore_nodes=[1], - ) - pytest.raises( - nx.NetworkXNoPath, - _bidirectional_shortest_path, - G, - 1, 2, - ignore_nodes=[2], - ) - G = nx.Graph() - nx.add_path(G, [1, 3]) - nx.add_path(G, [1, 4]) - nx.add_path(G, [3, 2]) - pytest.raises( - nx.NetworkXNoPath, - _bidirectional_shortest_path, - G, - 1, 2, - ignore_nodes=[1, 2], - ) - - -def validate_path(G, s, t, soln_len, path): - assert path[0] == s - assert path[-1] == t - assert soln_len == sum(G[u][v].get('weight', 1) - for u, v in zip(path[:-1], path[1:])) - - -def validate_length_path(G, s, t, soln_len, length, path): - assert soln_len == length - validate_path(G, s, t, length, path) - - -def test_bidirectional_dijksta_restricted(): - XG = nx.DiGraph() - XG.add_weighted_edges_from([('s', 'u', 10), ('s', 'x', 5), - ('u', 'v', 1), ('u', 'x', 2), - ('v', 'y', 1), ('x', 'u', 3), - ('x', 'v', 5), ('x', 'y', 2), - ('y', 's', 7), ('y', 'v', 6)]) - - XG3 = nx.Graph() - XG3.add_weighted_edges_from([[0, 1, 2], [1, 2, 12], - [2, 3, 1], [3, 4, 5], - [4, 5, 1], [5, 0, 10]]) - validate_length_path(XG, 's', 'v', 9, - *_bidirectional_dijkstra(XG, 's', 'v')) - validate_length_path(XG, 's', 'v', 10, - *_bidirectional_dijkstra(XG, 's', 'v', ignore_nodes=['u'])) - validate_length_path(XG, 's', 'v', 11, - *_bidirectional_dijkstra(XG, 's', 'v', ignore_edges=[('s', 'x')])) - pytest.raises( - nx.NetworkXNoPath, - _bidirectional_dijkstra, - XG, - 's', 'v', - ignore_nodes=['u'], - ignore_edges=[('s', 'x')], - ) - validate_length_path(XG3, 0, 3, 15, *_bidirectional_dijkstra(XG3, 0, 3)) - validate_length_path(XG3, 0, 3, 16, - *_bidirectional_dijkstra(XG3, 0, 3, ignore_nodes=[1])) - validate_length_path(XG3, 0, 3, 16, - *_bidirectional_dijkstra(XG3, 0, 3, ignore_edges=[(2, 3)])) - pytest.raises( - nx.NetworkXNoPath, - _bidirectional_dijkstra, - XG3, - 0, 3, - ignore_nodes=[1], - ignore_edges=[(5, 4)], - ) - - -def test_bidirectional_dijkstra_no_path(): - with pytest.raises(nx.NetworkXNoPath): - G = nx.Graph() - nx.add_path(G, [1, 2, 3]) - nx.add_path(G, [4, 5, 6]) - path = _bidirectional_dijkstra(G, 1, 6) - - -def test_bidirectional_dijkstra_ignore(): - G = nx.Graph() - nx.add_path(G, [1, 2, 10]) - nx.add_path(G, [1, 3, 10]) - pytest.raises( - nx.NetworkXNoPath, - _bidirectional_dijkstra, - G, - 1, 2, - ignore_nodes=[1], - ) - pytest.raises( - nx.NetworkXNoPath, - _bidirectional_dijkstra, - G, - 1, 2, - ignore_nodes=[2], - ) - pytest.raises( - nx.NetworkXNoPath, - _bidirectional_dijkstra, - G, - 1, 2, - ignore_nodes=[1, 2], - ) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_smallworld.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_smallworld.py deleted file mode 100644 index 5d253c85..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_smallworld.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python -import pytest -numpy = pytest.importorskip('numpy') - -import random - -from networkx import random_reference, lattice_reference, sigma, omega -import networkx as nx - -rng = random.Random(0) -rng = 42 - - -def test_random_reference(): - G = nx.connected_watts_strogatz_graph(50, 6, 0.1, seed=rng) - Gr = random_reference(G, niter=1, seed=rng) - C = nx.average_clustering(G) - Cr = nx.average_clustering(Gr) - assert C > Cr - - pytest.raises(nx.NetworkXError, random_reference, nx.Graph()) - pytest.raises(nx.NetworkXNotImplemented, random_reference, nx.DiGraph()) - - H = nx.Graph(((0, 1), (2, 3))) - Hl = random_reference(H, niter=1, seed=rng) - - -def test_lattice_reference(): - G = nx.connected_watts_strogatz_graph(50, 6, 1, seed=rng) - Gl = lattice_reference(G, niter=1, seed=rng) - L = nx.average_shortest_path_length(G) - Ll = nx.average_shortest_path_length(Gl) - assert Ll > L - - pytest.raises(nx.NetworkXError, lattice_reference, nx.Graph()) - pytest.raises(nx.NetworkXNotImplemented, lattice_reference, nx.DiGraph()) - - H = nx.Graph(((0, 1), (2, 3))) - Hl = lattice_reference(H, niter=1) - - -def test_sigma(): - Gs = nx.connected_watts_strogatz_graph(50, 6, 0.1, seed=rng) - Gr = nx.connected_watts_strogatz_graph(50, 6, 1, seed=rng) - sigmas = sigma(Gs, niter=1, nrand=2, seed=rng) - sigmar = sigma(Gr, niter=1, nrand=2, seed=rng) - assert sigmar < sigmas - - -def test_omega(): - Gl = nx.connected_watts_strogatz_graph(50, 6, 0, seed=rng) - Gr = nx.connected_watts_strogatz_graph(50, 6, 1, seed=rng) - Gs = nx.connected_watts_strogatz_graph(50, 6, 0.1, seed=rng) - omegal = omega(Gl, niter=1, nrand=1, seed=rng) - omegar = omega(Gr, niter=1, nrand=1, seed=rng) - omegas = omega(Gs, niter=1, nrand=1, seed=rng) - print("omegas, omegal, omegar") - print(omegas, omegal, omegar) - assert omegal < omegas and omegas < omegar diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_smetric.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_smetric.py deleted file mode 100644 index b1d1e81e..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_smetric.py +++ /dev/null @@ -1,20 +0,0 @@ -import pytest - -import networkx as nx - - -def test_smetric(): - g = nx.Graph() - g.add_edge(1, 2) - g.add_edge(2, 3) - g.add_edge(2, 4) - g.add_edge(1, 4) - sm = nx.s_metric(g, normalized=False) - assert sm == 19.0 -# smNorm = nx.s_metric(g,normalized=True) -# assert_equal(smNorm, 0.95) - - -def test_normalized(): - with pytest.raises(nx.NetworkXError): - sm = nx.s_metric(nx.Graph(), normalized=True) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_sparsifiers.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_sparsifiers.py deleted file mode 100644 index 1c9afcd8..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_sparsifiers.py +++ /dev/null @@ -1,141 +0,0 @@ -# Copyright (C) 2018 -# Robert Gmyr -# All rights reserved. -# BSD license. -"""Unit tests for the sparsifier computation functions.""" -import pytest -import networkx as nx -from networkx.utils import py_random_state - - -_seed = 2 - - -def _test_spanner(G, spanner, stretch, weight=None): - """Test whether a spanner is valid. - - This function tests whether the given spanner is a subgraph of the - given graph G with the same node set. It also tests for all shortest - paths whether they adhere to the given stretch. - - Parameters - ---------- - G : NetworkX graph - The original graph for which the spanner was constructed. - - spanner : NetworkX graph - The spanner to be tested. - - stretch : float - The proclaimed stretch of the spanner. - - weight : object - The edge attribute to use as distance. - """ - # check node set - assert set(G.nodes()) == set(spanner.nodes()) - - # check edge set and weights - for u, v in spanner.edges(): - assert G.has_edge(u, v) - if weight: - assert spanner[u][v][weight] == G[u][v][weight] - - # check connectivity and stretch - original_length = dict(nx.shortest_path_length(G, weight=weight)) - spanner_length = dict(nx.shortest_path_length(spanner, weight=weight)) - for u in G.nodes(): - for v in G.nodes(): - if u in original_length and v in original_length[u]: - assert spanner_length[u][v] <= stretch * original_length[u][v] - - -@py_random_state(1) -def _assign_random_weights(G, seed=None): - """Assigns random weights to the edges of a graph. - - Parameters - ---------- - - G : NetworkX graph - The original graph for which the spanner was constructed. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - """ - for u, v in G.edges(): - G[u][v]['weight'] = seed.random() - - -def test_spanner_trivial(): - """Test a trivial spanner with stretch 1.""" - G = nx.complete_graph(20) - spanner = nx.spanner(G, 1, seed=_seed) - - for u, v in G.edges: - assert(spanner.has_edge(u, v)) - - -def test_spanner_unweighted_complete_graph(): - """Test spanner construction on a complete unweighted graph.""" - G = nx.complete_graph(20) - - spanner = nx.spanner(G, 4, seed=_seed) - _test_spanner(G, spanner, 4) - - spanner = nx.spanner(G, 10, seed=_seed) - _test_spanner(G, spanner, 10) - - -def test_spanner_weighted_complete_graph(): - """Test spanner construction on a complete weighted graph.""" - G = nx.complete_graph(20) - _assign_random_weights(G, seed=_seed) - - spanner = nx.spanner(G, 4, weight='weight', seed=_seed) - _test_spanner(G, spanner, 4, weight='weight') - - spanner = nx.spanner(G, 10, weight='weight', seed=_seed) - _test_spanner(G, spanner, 10, weight='weight') - - -def test_spanner_unweighted_gnp_graph(): - """Test spanner construction on an unweighted gnp graph.""" - G = nx.gnp_random_graph(20, 0.4, seed=_seed) - - spanner = nx.spanner(G, 4, seed=_seed) - _test_spanner(G, spanner, 4) - - spanner = nx.spanner(G, 10, seed=_seed) - _test_spanner(G, spanner, 10) - - -def test_spanner_weighted_gnp_graph(): - """Test spanner construction on an weighted gnp graph.""" - G = nx.gnp_random_graph(20, 0.4, seed=_seed) - _assign_random_weights(G, seed=_seed) - - spanner = nx.spanner(G, 4, weight='weight', seed=_seed) - _test_spanner(G, spanner, 4, weight='weight') - - spanner = nx.spanner(G, 10, weight='weight', seed=_seed) - _test_spanner(G, spanner, 10, weight='weight') - - -def test_spanner_unweighted_disconnected_graph(): - """Test spanner construction on a disconnected graph.""" - G = nx.disjoint_union(nx.complete_graph(10), nx.complete_graph(10)) - - spanner = nx.spanner(G, 4, seed=_seed) - _test_spanner(G, spanner, 4) - - spanner = nx.spanner(G, 10, seed=_seed) - _test_spanner(G, spanner, 10) - - -def test_spanner_invalid_stretch(): - """Check whether an invalid stretch is caught.""" - with pytest.raises(ValueError): - G = nx.empty_graph() - nx.spanner(G, 0) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_structuralholes.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_structuralholes.py deleted file mode 100644 index 2f6e7a70..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_structuralholes.py +++ /dev/null @@ -1,124 +0,0 @@ -# test_structuralholes.py - unit tests for the structuralholes module -# -# Copyright 2017 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.structuralholes` module.""" -import math -import networkx as nx -from networkx.testing import almost_equal - - -class TestStructuralHoles(object): - """Unit tests for computing measures of structural holes. - - The expected values for these functions were originally computed using the - proprietary software `UCINET`_ and the free software `IGraph`_ , and then - computed by hand to make sure that the results are correct. - - .. _UCINET: https://sites.google.com/site/ucinetsoftware/home - .. _IGraph: http://igraph.org/ - - """ - - def setup(self): - self.D = nx.DiGraph() - self.D.add_edges_from([(0, 1), (0, 2), (1, 0), (2, 1)]) - self.D_weights = {(0, 1): 2, (0, 2): 2, (1, 0): 1, (2, 1): 1} - # Example from http://www.analytictech.com/connections/v20(1)/holes.htm - self.G = nx.Graph() - self.G.add_edges_from([ - ('A', 'B'), ('A', 'F'), ('A', 'G'), ('A', 'E'), ('E', 'G'), - ('F', 'G'), ('B', 'G'), ('B', 'D'), ('D', 'G'), ('G', 'C'), - ]) - self.G_weights = { - ('A', 'B'): 2, ('A', 'F'): 3, ('A', 'G'): 5, ('A', 'E'): 2, - ('E', 'G'): 8, ('F', 'G'): 3, ('B', 'G'): 4, ('B', 'D'): 1, - ('D', 'G'): 3, ('G', 'C'): 10, - } - - def test_constraint_directed(self): - constraint = nx.constraint(self.D) - assert almost_equal(constraint[0], 1.003, places=3) - assert almost_equal(constraint[1], 1.003, places=3) - assert almost_equal(constraint[2], 1.389, places=3) - - def test_effective_size_directed(self): - effective_size = nx.effective_size(self.D) - assert almost_equal(effective_size[0], 1.167, places=3) - assert almost_equal(effective_size[1], 1.167, places=3) - assert almost_equal(effective_size[2], 1, places=3) - - def test_constraint_weighted_directed(self): - D = self.D.copy() - nx.set_edge_attributes(D, self.D_weights, 'weight') - constraint = nx.constraint(D, weight='weight') - assert almost_equal(constraint[0], 0.840, places=3) - assert almost_equal(constraint[1], 1.143, places=3) - assert almost_equal(constraint[2], 1.378, places=3) - - def test_effective_size_weighted_directed(self): - D = self.D.copy() - nx.set_edge_attributes(D, self.D_weights, 'weight') - effective_size = nx.effective_size(D, weight='weight') - assert almost_equal(effective_size[0], 1.567, places=3) - assert almost_equal(effective_size[1], 1.083, places=3) - assert almost_equal(effective_size[2], 1, places=3) - - def test_constraint_undirected(self): - constraint = nx.constraint(self.G) - assert almost_equal(constraint['G'], 0.400, places=3) - assert almost_equal(constraint['A'], 0.595, places=3) - assert almost_equal(constraint['C'], 1, places=3) - - def test_effective_size_undirected_borgatti(self): - effective_size = nx.effective_size(self.G) - assert almost_equal(effective_size['G'], 4.67, places=2) - assert almost_equal(effective_size['A'], 2.50, places=2) - assert almost_equal(effective_size['C'], 1, places=2) - - def test_effective_size_undirected(self): - G = self.G.copy() - nx.set_edge_attributes(G, 1, 'weight') - effective_size = nx.effective_size(G, weight='weight') - assert almost_equal(effective_size['G'], 4.67, places=2) - assert almost_equal(effective_size['A'], 2.50, places=2) - assert almost_equal(effective_size['C'], 1, places=2) - - def test_constraint_weighted_undirected(self): - G = self.G.copy() - nx.set_edge_attributes(G, self.G_weights, 'weight') - constraint = nx.constraint(G, weight='weight') - assert almost_equal(constraint['G'], 0.299, places=3) - assert almost_equal(constraint['A'], 0.795, places=3) - assert almost_equal(constraint['C'], 1, places=3) - - def test_effective_size_weighted_undirected(self): - G = self.G.copy() - nx.set_edge_attributes(G, self.G_weights, 'weight') - effective_size = nx.effective_size(G, weight='weight') - assert almost_equal(effective_size['G'], 5.47, places=2) - assert almost_equal(effective_size['A'], 2.47, places=2) - assert almost_equal(effective_size['C'], 1, places=2) - - def test_constraint_isolated(self): - G = self.G.copy() - G.add_node(1) - constraint = nx.constraint(G) - assert math.isnan(constraint[1]) - - def test_effective_size_isolated(self): - G = self.G.copy() - G.add_node(1) - nx.set_edge_attributes(G, self.G_weights, 'weight') - effective_size = nx.effective_size(G, weight='weight') - assert math.isnan(effective_size[1]) - - def test_effective_size_borgatti_isolated(self): - G = self.G.copy() - G.add_node(1) - effective_size = nx.effective_size(G) - assert math.isnan(effective_size[1]) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_swap.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_swap.py deleted file mode 100644 index cde16c22..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_swap.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python -import pytest -import networkx as nx - -#import random -#random.seed(0) - - -def test_double_edge_swap(): - graph = nx.barabasi_albert_graph(200, 1) - degrees = sorted(d for n, d in graph.degree()) - G = nx.double_edge_swap(graph, 40) - assert degrees == sorted(d for n, d in graph.degree()) - - -def test_double_edge_swap_seed(): - graph = nx.barabasi_albert_graph(200, 1) - degrees = sorted(d for n, d in graph.degree()) - G = nx.double_edge_swap(graph, 40, seed=1) - assert degrees == sorted(d for n, d in graph.degree()) - - -def test_connected_double_edge_swap(): - graph = nx.barabasi_albert_graph(200, 1) - degrees = sorted(d for n, d in graph.degree()) - G = nx.connected_double_edge_swap(graph, 40, seed=1) - assert nx.is_connected(graph) - assert degrees == sorted(d for n, d in graph.degree()) - - -def test_double_edge_swap_small(): - with pytest.raises(nx.NetworkXError): - G = nx.double_edge_swap(nx.path_graph(3)) - - -def test_double_edge_swap_tries(): - with pytest.raises(nx.NetworkXError): - G = nx.double_edge_swap(nx.path_graph(10), nswap=1, max_tries=0) - - -def test_connected_double_edge_swap_small(): - with pytest.raises(nx.NetworkXError): - G = nx.connected_double_edge_swap(nx.path_graph(3)) - - -def test_connected_double_edge_swap_not_connected(): - with pytest.raises(nx.NetworkXError): - G = nx.path_graph(3) - nx.add_path(G, [10, 11, 12]) - G = nx.connected_double_edge_swap(G) - - -def test_degree_seq_c4(): - G = nx.cycle_graph(4) - degrees = sorted(d for n, d in G.degree()) - G = nx.double_edge_swap(G, 1, 100) - assert degrees == sorted(d for n, d in G.degree()) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_threshold.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_threshold.py deleted file mode 100644 index dbf0a726..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_threshold.py +++ /dev/null @@ -1,241 +0,0 @@ -#!/usr/bin/env python -""" -Threshold Graphs -================ -""" - -import pytest - -import networkx as nx -import networkx.algorithms.threshold as nxt -from networkx.algorithms.isomorphism.isomorph import graph_could_be_isomorphic -from networkx.testing import almost_equal - -cnlti = nx.convert_node_labels_to_integers - - -class TestGeneratorThreshold(): - def test_threshold_sequence_graph_test(self): - G = nx.star_graph(10) - assert nxt.is_threshold_graph(G) - assert nxt.is_threshold_sequence(list(d for n, d in G.degree())) - - G = nx.complete_graph(10) - assert nxt.is_threshold_graph(G) - assert nxt.is_threshold_sequence(list(d for n, d in G.degree())) - - deg = [3, 2, 2, 1, 1, 1] - assert not nxt.is_threshold_sequence(deg) - - deg = [3, 2, 2, 1] - assert nxt.is_threshold_sequence(deg) - - G = nx.generators.havel_hakimi_graph(deg) - assert nxt.is_threshold_graph(G) - - def test_creation_sequences(self): - deg = [3, 2, 2, 1] - G = nx.generators.havel_hakimi_graph(deg) - - with pytest.raises(ValueError): - nxt.creation_sequence(deg, with_labels=True, compact=True) - - cs0 = nxt.creation_sequence(deg) - H0 = nxt.threshold_graph(cs0) - assert ''.join(cs0) == 'ddid' - - cs1 = nxt.creation_sequence(deg, with_labels=True) - H1 = nxt.threshold_graph(cs1) - assert cs1 == [(1, 'd'), (2, 'd'), (3, 'i'), (0, 'd')] - - cs2 = nxt.creation_sequence(deg, compact=True) - H2 = nxt.threshold_graph(cs2) - assert cs2 == [2, 1, 1] - assert ''.join(nxt.uncompact(cs2)) == 'ddid' - assert graph_could_be_isomorphic(H0, G) - assert graph_could_be_isomorphic(H0, H1) - assert graph_could_be_isomorphic(H0, H2) - - def test_make_compact(self): - assert nxt.make_compact(['d', 'd', 'd', 'i', 'd', 'd']) == [3, 1, 2] - assert nxt.make_compact([3, 1, 2]) == [3, 1, 2] - assert pytest.raises(TypeError, nxt.make_compact, [3., 1., 2.]) - - def test_uncompact(self): - assert nxt.uncompact([3, 1, 2]) == ['d', 'd', 'd', 'i', 'd', 'd'] - assert nxt.uncompact(['d', 'd', 'i', 'd']) == ['d', 'd', 'i', 'd'] - assert (nxt.uncompact(nxt.uncompact([(1, 'd'), (2, 'd'), (3, 'i'), (0, 'd')])) == - nxt.uncompact([(1, 'd'), (2, 'd'), (3, 'i'), (0, 'd')])) - assert pytest.raises(TypeError, nxt.uncompact, [3., 1., 2.]) - - def test_creation_sequence_to_weights(self): - assert nxt.creation_sequence_to_weights([3, 1, 2]) == [0.5, 0.5, 0.5, 0.25, 0.75, 0.75] - assert pytest.raises(TypeError, nxt.creation_sequence_to_weights, [3., 1., 2.]) - - def test_weights_to_creation_sequence(self): - deg = [3, 2, 2, 1] - with pytest.raises(ValueError): - nxt.weights_to_creation_sequence(deg, with_labels=True, compact=True) - assert (nxt.weights_to_creation_sequence(deg, with_labels=True) == - [(3, 'd'), (1, 'd'), (2, 'd'), (0, 'd')]) - assert nxt.weights_to_creation_sequence(deg, compact=True) == [4] - - def test_find_alternating_4_cycle(self): - G = nx.Graph() - G.add_edge(1, 2) - assert not nxt.find_alternating_4_cycle(G) - - def test_shortest_path(self): - deg = [3, 2, 2, 1] - G = nx.generators.havel_hakimi_graph(deg) - cs1 = nxt.creation_sequence(deg, with_labels=True) - for n, m in [(3, 0), (0, 3), (0, 2), (0, 1), (1, 3), - (3, 1), (1, 2), (2, 3)]: - assert (nxt.shortest_path(cs1, n, m) == - nx.shortest_path(G, n, m)) - - spl = nxt.shortest_path_length(cs1, 3) - spl2 = nxt.shortest_path_length([t for v, t in cs1], 2) - assert spl == spl2 - - spld = {} - for j, pl in enumerate(spl): - n = cs1[j][0] - spld[n] = pl - assert spld == nx.single_source_shortest_path_length(G, 3) - - assert nxt.shortest_path(['d', 'd', 'd', 'i', 'd', 'd'], 1, 2) == [1, 2] - assert nxt.shortest_path([3, 1, 2], 1, 2) == [1, 2] - assert pytest.raises(TypeError, nxt.shortest_path, [3., 1., 2.], 1, 2) - assert pytest.raises(ValueError, nxt.shortest_path, [3, 1, 2], 'a', 2) - assert pytest.raises(ValueError, nxt.shortest_path, [3, 1, 2], 1, 'b') - assert nxt.shortest_path([3, 1, 2], 1, 1) == [1] - - def test_shortest_path_length(self): - assert nxt.shortest_path_length([3, 1, 2], 1) == [1, 0, 1, 2, 1, 1] - assert (nxt.shortest_path_length(['d', 'd', 'd', 'i', 'd', 'd'], 1) == - [1, 0, 1, 2, 1, 1]) - assert (nxt.shortest_path_length(('d', 'd', 'd', 'i', 'd', 'd'), 1) == - [1, 0, 1, 2, 1, 1]) - assert pytest.raises(TypeError, nxt.shortest_path, [3., 1., 2.], 1) - - def random_threshold_sequence(self): - assert len(nxt.random_threshold_sequence(10, 0.5)) == 10 - assert (nxt.random_threshold_sequence(10, 0.5, seed=42) == - ['d', 'i', 'd', 'd', 'd', 'i', 'i', 'i', 'd', 'd']) - assert pytest.raises(ValueError, nxt.random_threshold_sequence, 10, 1.5) - - def test_right_d_threshold_sequence(self): - assert nxt.right_d_threshold_sequence(3, 2) == ['d', 'i', 'd'] - assert pytest.raises(ValueError, nxt.right_d_threshold_sequence, 2, 3) - - def test_left_d_threshold_sequence(self): - assert nxt.left_d_threshold_sequence(3, 2) == ['d', 'i', 'd'] - assert pytest.raises(ValueError, nxt.left_d_threshold_sequence, 2, 3) - - def test_weights_thresholds(self): - wseq = [3, 4, 3, 3, 5, 6, 5, 4, 5, 6] - cs = nxt.weights_to_creation_sequence(wseq, threshold=10) - wseq = nxt.creation_sequence_to_weights(cs) - cs2 = nxt.weights_to_creation_sequence(wseq) - assert cs == cs2 - - wseq = nxt.creation_sequence_to_weights(nxt.uncompact([3, 1, 2, 3, 3, 2, 3])) - assert (wseq == - [s * 0.125 for s in [4, 4, 4, 3, 5, 5, 2, 2, 2, 6, 6, 6, 1, 1, 7, 7, 7]]) - - wseq = nxt.creation_sequence_to_weights([3, 1, 2, 3, 3, 2, 3]) - assert (wseq == - [s * 0.125 for s in [4, 4, 4, 3, 5, 5, 2, 2, 2, 6, 6, 6, 1, 1, 7, 7, 7]]) - - wseq = nxt.creation_sequence_to_weights(list(enumerate('ddidiiidididi'))) - assert (wseq == - [s * 0.1 for s in [5, 5, 4, 6, 3, 3, 3, 7, 2, 8, 1, 9, 0]]) - - wseq = nxt.creation_sequence_to_weights('ddidiiidididi') - assert (wseq == - [s * 0.1 for s in [5, 5, 4, 6, 3, 3, 3, 7, 2, 8, 1, 9, 0]]) - - wseq = nxt.creation_sequence_to_weights('ddidiiidididid') - ws = [s / float(12) for s in [6, 6, 5, 7, 4, 4, 4, 8, 3, 9, 2, 10, 1, 11]] - assert sum([abs(c - d) for c, d in zip(wseq, ws)]) < 1e-14 - - def test_finding_routines(self): - G = nx.Graph({1: [2], 2: [3], 3: [4], 4: [5], 5: [6]}) - G.add_edge(2, 4) - G.add_edge(2, 5) - G.add_edge(2, 7) - G.add_edge(3, 6) - G.add_edge(4, 6) - - # Alternating 4 cycle - assert nxt.find_alternating_4_cycle(G) == [1, 2, 3, 6] - - # Threshold graph - TG = nxt.find_threshold_graph(G) - assert nxt.is_threshold_graph(TG) - assert sorted(TG.nodes()) == [1, 2, 3, 4, 5, 7] - - cs = nxt.creation_sequence(dict(TG.degree()), with_labels=True) - assert nxt.find_creation_sequence(G) == cs - - def test_fast_versions_properties_threshold_graphs(self): - cs = 'ddiiddid' - G = nxt.threshold_graph(cs) - assert nxt.density('ddiiddid') == nx.density(G) - assert (sorted(nxt.degree_sequence(cs)) == - sorted(d for n, d in G.degree())) - - ts = nxt.triangle_sequence(cs) - assert ts == list(nx.triangles(G).values()) - assert sum(ts) // 3 == nxt.triangles(cs) - - c1 = nxt.cluster_sequence(cs) - c2 = list(nx.clustering(G).values()) - assert almost_equal(sum([abs(c - d) for c, d in zip(c1, c2)]), 0) - - b1 = nx.betweenness_centrality(G).values() - b2 = nxt.betweenness_sequence(cs) - assert sum([abs(c - d) for c, d in zip(b1, b2)]) < 1e-14 - - assert nxt.eigenvalues(cs) == [0, 1, 3, 3, 5, 7, 7, 8] - - # Degree Correlation - assert abs(nxt.degree_correlation(cs) + 0.593038821954) < 1e-12 - assert nxt.degree_correlation('diiiddi') == -0.8 - assert nxt.degree_correlation('did') == -1.0 - assert nxt.degree_correlation('ddd') == 1.0 - assert nxt.eigenvalues('dddiii') == [0, 0, 0, 0, 3, 3] - assert nxt.eigenvalues('dddiiid') == [0, 1, 1, 1, 4, 4, 7] - - def test_tg_creation_routines(self): - s = nxt.left_d_threshold_sequence(5, 7) - s = nxt.right_d_threshold_sequence(5, 7) - s1 = nxt.swap_d(s, 1.0, 1.0) - s1 = nxt.swap_d(s, 1.0, 1.0, seed=1) - - def test_eigenvectors(self): - np = pytest.importorskip('numpy') - eigenval = np.linalg.eigvals - scipy = pytest.importorskip('scipy') - - cs = 'ddiiddid' - G = nxt.threshold_graph(cs) - (tgeval, tgevec) = nxt.eigenvectors(cs) - dot = np.dot - assert [abs(dot(lv, lv) - 1.0) < 1e-9 for lv in tgevec] == [True] * 8 - lapl = nx.laplacian_matrix(G) -# tgev=[ dot(lv,dot(lapl,lv)) for lv in tgevec ] -# assert_true(sum([abs(c-d) for c,d in zip(tgev,tgeval)]) < 1e-9) -# tgev.sort() -# lev=list(eigenval(lapl)) -# lev.sort() -# assert_true(sum([abs(c-d) for c,d in zip(tgev,lev)]) < 1e-9) - - def test_create_using(self): - cs = 'ddiiddid' - G = nxt.threshold_graph(cs) - assert pytest.raises(nx.exception.NetworkXError, - nxt.threshold_graph, cs, create_using=nx.DiGraph()) - MG = nxt.threshold_graph(cs, create_using=nx.MultiGraph()) - assert sorted(MG.edges()) == sorted(G.edges()) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_tournament.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_tournament.py deleted file mode 100644 index 82e997b5..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_tournament.py +++ /dev/null @@ -1,139 +0,0 @@ -# test_tournament.py - unit tests for the tournament module -# -# Copyright 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.tournament` module.""" -from itertools import combinations - - -from networkx import DiGraph -from networkx.algorithms.tournament import is_reachable -from networkx.algorithms.tournament import is_strongly_connected -from networkx.algorithms.tournament import is_tournament -from networkx.algorithms.tournament import random_tournament -from networkx.algorithms.tournament import hamiltonian_path - - -class TestIsTournament(object): - """Unit tests for the :func:`networkx.tournament.is_tournament` - function. - - """ - - def test_is_tournament(self): - G = DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 0), (1, 3), (0, 2)]) - assert is_tournament(G) - - def test_self_loops(self): - """A tournament must have no self-loops.""" - G = DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 0), (1, 3), (0, 2)]) - G.add_edge(0, 0) - assert not is_tournament(G) - - def test_missing_edges(self): - """A tournament must not have any pair of nodes without at least - one edge joining the pair. - - """ - G = DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 0), (1, 3)]) - assert not is_tournament(G) - - def test_bidirectional_edges(self): - """A tournament must not have any pair of nodes with greater - than one edge joining the pair. - - """ - G = DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 0), (1, 3), (0, 2)]) - G.add_edge(1, 0) - assert not is_tournament(G) - - -class TestRandomTournament(object): - """Unit tests for the :func:`networkx.tournament.random_tournament` - function. - - """ - def test_graph_is_tournament(self): - for n in range(10): - G = random_tournament(5) - assert is_tournament(G) - - def test_graph_is_tournament_seed(self): - for n in range(10): - G = random_tournament(5, seed=1) - assert is_tournament(G) - - -class TestHamiltonianPath(object): - """Unit tests for the :func:`networkx.tournament.hamiltonian_path` - function. - - """ - - def test_path_is_hamiltonian(self): - G = DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 0), (1, 3), (0, 2)]) - path = hamiltonian_path(G) - assert len(path) == 4 - assert all(v in G[u] for u, v in zip(path, path[1:])) - - def test_hamiltonian_cycle(self): - """Tests that :func:`networkx.tournament.hamiltonian_path` - returns a Hamiltonian cycle when provided a strongly connected - tournament. - - """ - G = DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 0), (1, 3), (0, 2)]) - path = hamiltonian_path(G) - assert len(path) == 4 - assert all(v in G[u] for u, v in zip(path, path[1:])) - assert path[0] in G[path[-1]] - - -class TestReachability(object): - """Unit tests for the :func:`networkx.tournament.is_reachable` - function. - - """ - - def test_reachable_pair(self): - """Tests for a reachable pair of nodes.""" - G = DiGraph([(0, 1), (1, 2), (2, 0)]) - assert is_reachable(G, 0, 2) - - def test_same_node_is_reachable(self): - """Tests that a node is always reachable from itself.""" - # G is an arbitrary tournament on ten nodes. - G = DiGraph(sorted(p) for p in combinations(range(10), 2)) - assert all(is_reachable(G, v, v) for v in G) - - def test_unreachable_pair(self): - """Tests for an unreachable pair of nodes.""" - G = DiGraph([(0, 1), (0, 2), (1, 2)]) - assert not is_reachable(G, 1, 0) - - -class TestStronglyConnected(object): - """Unit tests for the - :func:`networkx.tournament.is_strongly_connected` function. - - """ - - def test_is_strongly_connected(self): - """Tests for a strongly connected tournament.""" - G = DiGraph([(0, 1), (1, 2), (2, 0)]) - assert is_strongly_connected(G) - - def test_not_strongly_connected(self): - """Tests for a tournament that is not strongly connected.""" - G = DiGraph([(0, 1), (0, 2), (1, 2)]) - assert not is_strongly_connected(G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_triads.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_triads.py deleted file mode 100644 index 34795df5..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_triads.py +++ /dev/null @@ -1,24 +0,0 @@ -# test_triads.py - unit tests for the triads module -# -# Copyright 2015 NetworkX developers. -# Copyright 2009 Diederik van Liere . -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.triads` module.""" - -import networkx as nx - - -def test_triadic_census(): - """Tests the triadic census function.""" - G = nx.DiGraph() - G.add_edges_from(['01', '02', '03', '04', '05', '12', '16', '51', '56', - '65']) - expected = {'030T': 2, '120C': 1, '210': 0, '120U': 0, '012': 9, '102': 3, - '021U': 0, '111U': 0, '003': 8, '030C': 0, '021D': 9, '201': 0, - '111D': 1, '300': 0, '120D': 0, '021C': 2} - actual = nx.triadic_census(G) - assert expected == actual diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_vitality.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_vitality.py deleted file mode 100644 index 5fbbe972..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_vitality.py +++ /dev/null @@ -1,43 +0,0 @@ - -import networkx as nx - - -class TestClosenessVitality(object): - - def test_unweighted(self): - G = nx.cycle_graph(3) - vitality = nx.closeness_vitality(G) - assert vitality == {0: 2, 1: 2, 2: 2} - - def test_weighted(self): - G = nx.Graph() - nx.add_cycle(G, [0, 1, 2], weight=2) - vitality = nx.closeness_vitality(G, weight='weight') - assert vitality == {0: 4, 1: 4, 2: 4} - - def test_unweighted_digraph(self): - G = nx.DiGraph(nx.cycle_graph(3)) - vitality = nx.closeness_vitality(G) - assert vitality == {0: 4, 1: 4, 2: 4} - - def test_weighted_digraph(self): - G = nx.DiGraph() - nx.add_cycle(G, [0, 1, 2], weight=2) - nx.add_cycle(G, [2, 1, 0], weight=2) - vitality = nx.closeness_vitality(G, weight='weight') - assert vitality == {0: 8, 1: 8, 2: 8} - - def test_weighted_multidigraph(self): - G = nx.MultiDiGraph() - nx.add_cycle(G, [0, 1, 2], weight=2) - nx.add_cycle(G, [2, 1, 0], weight=2) - vitality = nx.closeness_vitality(G, weight='weight') - assert vitality == {0: 8, 1: 8, 2: 8} - - def test_disconnecting_graph(self): - """Tests that the closeness vitality of a node whose removal - disconnects the graph is negative infinity. - - """ - G = nx.path_graph(3) - assert nx.closeness_vitality(G, node=1) == -float('inf') diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_voronoi.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_voronoi.py deleted file mode 100644 index 390a032e..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_voronoi.py +++ /dev/null @@ -1,105 +0,0 @@ -# test_voronoi.py - unit tests for the networkx.algorithms.voronoi module -# -# Copyright 2016-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. - -import networkx as nx -from networkx.utils import pairwise - - -class TestVoronoiCells(object): - """Unit tests for the Voronoi cells function.""" - - def test_isolates(self): - """Tests that a graph with isolated nodes has all isolates in - one block of the partition. - - """ - G = nx.empty_graph(5) - cells = nx.voronoi_cells(G, {0, 2, 4}) - expected = {0: {0}, 2: {2}, 4: {4}, 'unreachable': {1, 3}} - assert expected == cells - - def test_undirected_unweighted(self): - G = nx.cycle_graph(6) - cells = nx.voronoi_cells(G, {0, 3}) - expected = {0: {0, 1, 5}, 3: {2, 3, 4}} - assert expected == cells - - def test_directed_unweighted(self): - # This is the singly-linked directed cycle graph on six nodes. - G = nx.DiGraph(pairwise(range(6), cyclic=True)) - cells = nx.voronoi_cells(G, {0, 3}) - expected = {0: {0, 1, 2}, 3: {3, 4, 5}} - assert expected == cells - - def test_directed_inward(self): - """Tests that reversing the graph gives the "inward" Voronoi - partition. - - """ - # This is the singly-linked reverse directed cycle graph on six nodes. - G = nx.DiGraph(pairwise(range(6), cyclic=True)) - G = G.reverse(copy=False) - cells = nx.voronoi_cells(G, {0, 3}) - expected = {0: {0, 4, 5}, 3: {1, 2, 3}} - assert expected == cells - - def test_undirected_weighted(self): - edges = [(0, 1, 10), (1, 2, 1), (2, 3, 1)] - G = nx.Graph() - G.add_weighted_edges_from(edges) - cells = nx.voronoi_cells(G, {0, 3}) - expected = {0: {0}, 3: {1, 2, 3}} - assert expected == cells - - def test_directed_weighted(self): - edges = [(0, 1, 10), (1, 2, 1), (2, 3, 1), (3, 2, 1), (2, 1, 1)] - G = nx.DiGraph() - G.add_weighted_edges_from(edges) - cells = nx.voronoi_cells(G, {0, 3}) - expected = {0: {0}, 3: {1, 2, 3}} - assert expected == cells - - def test_multigraph_unweighted(self): - """Tests that the Voronoi cells for a multigraph are the same as - for a simple graph. - - """ - edges = [(0, 1), (1, 2), (2, 3)] - G = nx.MultiGraph(2 * edges) - H = nx.Graph(G) - G_cells = nx.voronoi_cells(G, {0, 3}) - H_cells = nx.voronoi_cells(H, {0, 3}) - assert G_cells == H_cells - - def test_multidigraph_unweighted(self): - # This is the twice-singly-linked directed cycle graph on six nodes. - edges = list(pairwise(range(6), cyclic=True)) - G = nx.MultiDiGraph(2 * edges) - H = nx.DiGraph(G) - G_cells = nx.voronoi_cells(G, {0, 3}) - H_cells = nx.voronoi_cells(H, {0, 3}) - assert G_cells == H_cells - - def test_multigraph_weighted(self): - edges = [(0, 1, 10), (0, 1, 10), (1, 2, 1), (1, 2, 100), (2, 3, 1), - (2, 3, 100)] - G = nx.MultiGraph() - G.add_weighted_edges_from(edges) - cells = nx.voronoi_cells(G, {0, 3}) - expected = {0: {0}, 3: {1, 2, 3}} - assert expected == cells - - def test_multidigraph_weighted(self): - edges = [(0, 1, 10), (0, 1, 10), (1, 2, 1), (2, 3, 1), (3, 2, 10), - (3, 2, 1), (2, 1, 10), (2, 1, 1)] - G = nx.MultiDiGraph() - G.add_weighted_edges_from(edges) - cells = nx.voronoi_cells(G, {0, 3}) - expected = {0: {0}, 3: {1, 2, 3}} - assert expected == cells diff --git a/extensions/fablabchemnitz/networkx/algorithms/tests/test_wiener.py b/extensions/fablabchemnitz/networkx/algorithms/tests/test_wiener.py deleted file mode 100644 index d99217f2..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tests/test_wiener.py +++ /dev/null @@ -1,78 +0,0 @@ -# test_wiener.py - unit tests for the wiener module -# -# Copyright 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.wiener` module.""" - - -from networkx import complete_graph -from networkx import DiGraph -from networkx import empty_graph -from networkx import path_graph -from networkx import wiener_index - - -class TestWienerIndex(object): - """Unit tests for computing the Wiener index of a graph.""" - - def test_disconnected_graph(self): - """Tests that the Wiener index of a disconnected graph is - positive infinity. - - """ - assert wiener_index(empty_graph(2)) == float('inf') - - def test_directed(self): - """Tests that each pair of nodes in the directed graph is - counted once when computing the Wiener index. - - """ - G = complete_graph(3) - H = DiGraph(G) - assert (2 * wiener_index(G)) == wiener_index(H) - - def test_complete_graph(self): - """Tests that the Wiener index of the complete graph is simply - the number of edges. - - """ - n = 10 - G = complete_graph(n) - assert wiener_index(G) == (n * (n - 1) / 2) - - def test_path_graph(self): - """Tests that the Wiener index of the path graph is correctly - computed. - - """ - # In P_n, there are n - 1 pairs of vertices at distance one, n - - # 2 pairs at distance two, n - 3 at distance three, ..., 1 at - # distance n - 1, so the Wiener index should be - # - # 1 * (n - 1) + 2 * (n - 2) + ... + (n - 2) * 2 + (n - 1) * 1 - # - # For example, in P_5, - # - # 1 * 4 + 2 * 3 + 3 * 2 + 4 * 1 = 2 (1 * 4 + 2 * 3) - # - # and in P_6, - # - # 1 * 5 + 2 * 4 + 3 * 3 + 4 * 2 + 5 * 1 = 2 (1 * 5 + 2 * 4) + 3 * 3 - # - # assuming n is *odd*, this gives the formula - # - # 2 \sum_{i = 1}^{(n - 1) / 2} [i * (n - i)] - # - # assuming n is *even*, this gives the formula - # - # 2 \sum_{i = 1}^{n / 2} [i * (n - i)] - (n / 2) ** 2 - # - n = 9 - G = path_graph(n) - expected = 2 * sum(i * (n - i) for i in range(1, (n // 2) + 1)) - actual = wiener_index(G) - assert expected == actual diff --git a/extensions/fablabchemnitz/networkx/algorithms/threshold.py b/extensions/fablabchemnitz/networkx/algorithms/threshold.py deleted file mode 100644 index 73231af0..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/threshold.py +++ /dev/null @@ -1,931 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg (hagberg@lanl.gov) -# Pieter Swart (swart@lanl.gov) -# Dan Schult (dschult@colgate.edu) -""" -Threshold Graphs - Creation, manipulation and identification. -""" -from math import sqrt -import networkx as nx -from networkx.utils import py_random_state - -__all__ = ['is_threshold_graph', 'find_threshold_graph'] - - -def is_threshold_graph(G): - """ - Returns True if G is a threshold graph. - """ - return is_threshold_sequence(list(d for n, d in G.degree())) - - -def is_threshold_sequence(degree_sequence): - """ - Returns True if the sequence is a threshold degree seqeunce. - - Uses the property that a threshold graph must be constructed by - adding either dominating or isolated nodes. Thus, it can be - deconstructed iteratively by removing a node of degree zero or a - node that connects to the remaining nodes. If this deconstruction - failes then the sequence is not a threshold sequence. - """ - ds = degree_sequence[:] # get a copy so we don't destroy original - ds.sort() - while ds: - if ds[0] == 0: # if isolated node - ds.pop(0) # remove it - continue - if ds[-1] != len(ds) - 1: # is the largest degree node dominating? - return False # no, not a threshold degree sequence - ds.pop() # yes, largest is the dominating node - ds = [d - 1 for d in ds] # remove it and decrement all degrees - return True - - -def creation_sequence(degree_sequence, with_labels=False, compact=False): - """ - Determines the creation sequence for the given threshold degree sequence. - - The creation sequence is a list of single characters 'd' - or 'i': 'd' for dominating or 'i' for isolated vertices. - Dominating vertices are connected to all vertices present when it - is added. The first node added is by convention 'd'. - This list can be converted to a string if desired using "".join(cs) - - If with_labels==True: - Returns a list of 2-tuples containing the vertex number - and a character 'd' or 'i' which describes the type of vertex. - - If compact==True: - Returns the creation sequence in a compact form that is the number - of 'i's and 'd's alternating. - Examples: - [1,2,2,3] represents d,i,i,d,d,i,i,i - [3,1,2] represents d,d,d,i,d,d - - Notice that the first number is the first vertex to be used for - construction and so is always 'd'. - - with_labels and compact cannot both be True. - - Returns None if the sequence is not a threshold sequence - """ - if with_labels and compact: - raise ValueError("compact sequences cannot be labeled") - - # make an indexed copy - if isinstance(degree_sequence, dict): # labeled degree seqeunce - ds = [[degree, label] for (label, degree) in degree_sequence.items()] - else: - ds = [[d, i] for i, d in enumerate(degree_sequence)] - ds.sort() - cs = [] # creation sequence - while ds: - if ds[0][0] == 0: # isolated node - (d, v) = ds.pop(0) - if len(ds) > 0: # make sure we start with a d - cs.insert(0, (v, 'i')) - else: - cs.insert(0, (v, 'd')) - continue - if ds[-1][0] != len(ds) - 1: # Not dominating node - return None # not a threshold degree sequence - (d, v) = ds.pop() - cs.insert(0, (v, 'd')) - ds = [[d[0] - 1, d[1]] for d in ds] # decrement due to removing node - - if with_labels: - return cs - if compact: - return make_compact(cs) - return [v[1] for v in cs] # not labeled - - -def make_compact(creation_sequence): - """ - Returns the creation sequence in a compact form - that is the number of 'i's and 'd's alternating. - - Examples - -------- - >>> from networkx.algorithms.threshold import make_compact - >>> make_compact(['d', 'i', 'i', 'd', 'd', 'i', 'i', 'i']) - [1, 2, 2, 3] - >>> make_compact(['d', 'd', 'd', 'i', 'd', 'd']) - [3, 1, 2] - - Notice that the first number is the first vertex - to be used for construction and so is always 'd'. - - Labeled creation sequences lose their labels in the - compact representation. - - >>> make_compact([3, 1, 2]) - [3, 1, 2] - """ - first = creation_sequence[0] - if isinstance(first, str): # creation sequence - cs = creation_sequence[:] - elif isinstance(first, tuple): # labeled creation sequence - cs = [s[1] for s in creation_sequence] - elif isinstance(first, int): # compact creation sequence - return creation_sequence - else: - raise TypeError("Not a valid creation sequence type") - - ccs = [] - count = 1 # count the run lengths of d's or i's. - for i in range(1, len(cs)): - if cs[i] == cs[i - 1]: - count += 1 - else: - ccs.append(count) - count = 1 - ccs.append(count) # don't forget the last one - return ccs - - -def uncompact(creation_sequence): - """ - Converts a compact creation sequence for a threshold - graph to a standard creation sequence (unlabeled). - If the creation_sequence is already standard, return it. - See creation_sequence. - """ - first = creation_sequence[0] - if isinstance(first, str): # creation sequence - return creation_sequence - elif isinstance(first, tuple): # labeled creation sequence - return creation_sequence - elif isinstance(first, int): # compact creation sequence - ccscopy = creation_sequence[:] - else: - raise TypeError("Not a valid creation sequence type") - cs = [] - while ccscopy: - cs.extend(ccscopy.pop(0) * ['d']) - if ccscopy: - cs.extend(ccscopy.pop(0) * ['i']) - return cs - - -def creation_sequence_to_weights(creation_sequence): - """ - Returns a list of node weights which create the threshold - graph designated by the creation sequence. The weights - are scaled so that the threshold is 1.0. The order of the - nodes is the same as that in the creation sequence. - """ - # Turn input sequence into a labeled creation sequence - first = creation_sequence[0] - if isinstance(first, str): # creation sequence - if isinstance(creation_sequence, list): - wseq = creation_sequence[:] - else: - wseq = list(creation_sequence) # string like 'ddidid' - elif isinstance(first, tuple): # labeled creation sequence - wseq = [v[1] for v in creation_sequence] - elif isinstance(first, int): # compact creation sequence - wseq = uncompact(creation_sequence) - else: - raise TypeError("Not a valid creation sequence type") - # pass through twice--first backwards - wseq.reverse() - w = 0 - prev = 'i' - for j, s in enumerate(wseq): - if s == 'i': - wseq[j] = w - prev = s - elif prev == 'i': - prev = s - w += 1 - wseq.reverse() # now pass through forwards - for j, s in enumerate(wseq): - if s == 'd': - wseq[j] = w - prev = s - elif prev == 'd': - prev = s - w += 1 - # Now scale weights - if prev == 'd': - w += 1 - wscale = 1. / float(w) - return [ww * wscale for ww in wseq] - # return wseq - - -def weights_to_creation_sequence(weights, threshold=1, with_labels=False, compact=False): - """ - Returns a creation sequence for a threshold graph - determined by the weights and threshold given as input. - If the sum of two node weights is greater than the - threshold value, an edge is created between these nodes. - - The creation sequence is a list of single characters 'd' - or 'i': 'd' for dominating or 'i' for isolated vertices. - Dominating vertices are connected to all vertices present - when it is added. The first node added is by convention 'd'. - - If with_labels==True: - Returns a list of 2-tuples containing the vertex number - and a character 'd' or 'i' which describes the type of vertex. - - If compact==True: - Returns the creation sequence in a compact form that is the number - of 'i's and 'd's alternating. - Examples: - [1,2,2,3] represents d,i,i,d,d,i,i,i - [3,1,2] represents d,d,d,i,d,d - - Notice that the first number is the first vertex to be used for - construction and so is always 'd'. - - with_labels and compact cannot both be True. - """ - if with_labels and compact: - raise ValueError("compact sequences cannot be labeled") - - # make an indexed copy - if isinstance(weights, dict): # labeled weights - wseq = [[w, label] for (label, w) in weights.items()] - else: - wseq = [[w, i] for i, w in enumerate(weights)] - wseq.sort() - cs = [] # creation sequence - cutoff = threshold - wseq[-1][0] - while wseq: - if wseq[0][0] < cutoff: # isolated node - (w, label) = wseq.pop(0) - cs.append((label, 'i')) - else: - (w, label) = wseq.pop() - cs.append((label, 'd')) - cutoff = threshold - wseq[-1][0] - if len(wseq) == 1: # make sure we start with a d - (w, label) = wseq.pop() - cs.append((label, 'd')) - # put in correct order - cs.reverse() - - if with_labels: - return cs - if compact: - return make_compact(cs) - return [v[1] for v in cs] # not labeled - - -# Manipulating NetworkX.Graphs in context of threshold graphs -def threshold_graph(creation_sequence, create_using=None): - """ - Create a threshold graph from the creation sequence or compact - creation_sequence. - - The input sequence can be a - - creation sequence (e.g. ['d','i','d','d','d','i']) - labeled creation sequence (e.g. [(0,'d'),(2,'d'),(1,'i')]) - compact creation sequence (e.g. [2,1,1,2,0]) - - Use cs=creation_sequence(degree_sequence,labeled=True) - to convert a degree sequence to a creation sequence. - - Returns None if the sequence is not valid - """ - # Turn input sequence into a labeled creation sequence - first = creation_sequence[0] - if isinstance(first, str): # creation sequence - ci = list(enumerate(creation_sequence)) - elif isinstance(first, tuple): # labeled creation sequence - ci = creation_sequence[:] - elif isinstance(first, int): # compact creation sequence - cs = uncompact(creation_sequence) - ci = list(enumerate(cs)) - else: - print("not a valid creation sequence type") - return None - - G = nx.empty_graph(0, create_using) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - G.name = "Threshold Graph" - - # add nodes and edges - # if type is 'i' just add nodea - # if type is a d connect to everything previous - while ci: - (v, node_type) = ci.pop(0) - if node_type == 'd': # dominating type, connect to all existing nodes - # We use `for u in list(G):` instead of - # `for u in G:` because we edit the graph `G` in - # the loop. Hence using an iterator will result in - # `RuntimeError: dictionary changed size during iteration` - for u in list(G): - G.add_edge(v, u) - G.add_node(v) - return G - - -def find_alternating_4_cycle(G): - """ - Returns False if there aren't any alternating 4 cycles. - Otherwise returns the cycle as [a,b,c,d] where (a,b) - and (c,d) are edges and (a,c) and (b,d) are not. - """ - for (u, v) in G.edges(): - for w in G.nodes(): - if not G.has_edge(u, w) and u != w: - for x in G.neighbors(w): - if not G.has_edge(v, x) and v != x: - return [u, v, w, x] - return False - - -def find_threshold_graph(G, create_using=None): - """ - Return a threshold subgraph that is close to largest in G. - The threshold graph will contain the largest degree node in G. - - """ - return threshold_graph(find_creation_sequence(G), create_using) - - -def find_creation_sequence(G): - """ - Find a threshold subgraph that is close to largest in G. - Returns the labeled creation sequence of that threshold graph. - """ - cs = [] - # get a local pointer to the working part of the graph - H = G - while H.order() > 0: - # get new degree sequence on subgraph - dsdict = dict(H.degree()) - ds = [(d, v) for v, d in dsdict.items()] - ds.sort() - # Update threshold graph nodes - if ds[-1][0] == 0: # all are isolated - cs.extend(zip(dsdict, ['i'] * (len(ds) - 1) + ['d'])) - break # Done! - # pull off isolated nodes - while ds[0][0] == 0: - (d, iso) = ds.pop(0) - cs.append((iso, 'i')) - # find new biggest node - (d, bigv) = ds.pop() - # add edges of star to t_g - cs.append((bigv, 'd')) - # form subgraph of neighbors of big node - H = H.subgraph(H.neighbors(bigv)) - cs.reverse() - return cs - - -# Properties of Threshold Graphs -def triangles(creation_sequence): - """ - Compute number of triangles in the threshold graph with the - given creation sequence. - """ - # shortcut algorithm that doesn't require computing number - # of triangles at each node. - cs = creation_sequence # alias - dr = cs.count("d") # number of d's in sequence - ntri = dr * (dr - 1) * (dr - 2) / 6 # number of triangles in clique of nd d's - # now add dr choose 2 triangles for every 'i' in sequence where - # dr is the number of d's to the right of the current i - for i, typ in enumerate(cs): - if typ == "i": - ntri += dr * (dr - 1) / 2 - else: - dr -= 1 - return ntri - - -def triangle_sequence(creation_sequence): - """ - Return triangle sequence for the given threshold graph creation sequence. - - """ - cs = creation_sequence - seq = [] - dr = cs.count("d") # number of d's to the right of the current pos - dcur = (dr - 1) * (dr - 2) // 2 # number of triangles through a node of clique dr - irun = 0 # number of i's in the last run - drun = 0 # number of d's in the last run - for i, sym in enumerate(cs): - if sym == "d": - drun += 1 - tri = dcur + (dr - 1) * irun # new triangles at this d - else: # cs[i]="i": - if prevsym == "d": # new string of i's - dcur += (dr - 1) * irun # accumulate shared shortest paths - irun = 0 # reset i run counter - dr -= drun # reduce number of d's to right - drun = 0 # reset d run counter - irun += 1 - tri = dr * (dr - 1) // 2 # new triangles at this i - seq.append(tri) - prevsym = sym - return seq - - -def cluster_sequence(creation_sequence): - """ - Return cluster sequence for the given threshold graph creation sequence. - """ - triseq = triangle_sequence(creation_sequence) - degseq = degree_sequence(creation_sequence) - cseq = [] - for i, deg in enumerate(degseq): - tri = triseq[i] - if deg <= 1: # isolated vertex or single pair gets cc 0 - cseq.append(0) - continue - max_size = (deg * (deg - 1)) // 2 - cseq.append(float(tri) / float(max_size)) - return cseq - - -def degree_sequence(creation_sequence): - """ - Return degree sequence for the threshold graph with the given - creation sequence - """ - cs = creation_sequence # alias - seq = [] - rd = cs.count("d") # number of d to the right - for i, sym in enumerate(cs): - if sym == "d": - rd -= 1 - seq.append(rd + i) - else: - seq.append(rd) - return seq - - -def density(creation_sequence): - """ - Return the density of the graph with this creation_sequence. - The density is the fraction of possible edges present. - """ - N = len(creation_sequence) - two_size = sum(degree_sequence(creation_sequence)) - two_possible = N * (N - 1) - den = two_size / float(two_possible) - return den - - -def degree_correlation(creation_sequence): - """ - Return the degree-degree correlation over all edges. - """ - cs = creation_sequence - s1 = 0 # deg_i*deg_j - s2 = 0 # deg_i^2+deg_j^2 - s3 = 0 # deg_i+deg_j - m = 0 # number of edges - rd = cs.count("d") # number of d nodes to the right - rdi = [i for i, sym in enumerate(cs) if sym == "d"] # index of "d"s - ds = degree_sequence(cs) - for i, sym in enumerate(cs): - if sym == "d": - if i != rdi[0]: - print("Logic error in degree_correlation", i, rdi) - raise ValueError - rdi.pop(0) - degi = ds[i] - for dj in rdi: - degj = ds[dj] - s1 += degj * degi - s2 += degi**2 + degj**2 - s3 += degi + degj - m += 1 - denom = (2 * m * s2 - s3 * s3) - numer = (4 * m * s1 - s3 * s3) - if denom == 0: - if numer == 0: - return 1 - raise ValueError("Zero Denominator but Numerator is %s" % numer) - return numer / float(denom) - - -def shortest_path(creation_sequence, u, v): - """ - Find the shortest path between u and v in a - threshold graph G with the given creation_sequence. - - For an unlabeled creation_sequence, the vertices - u and v must be integers in (0,len(sequence)) referring - to the position of the desired vertices in the sequence. - - For a labeled creation_sequence, u and v are labels of veritices. - - Use cs=creation_sequence(degree_sequence,with_labels=True) - to convert a degree sequence to a creation sequence. - - Returns a list of vertices from u to v. - Example: if they are neighbors, it returns [u,v] - """ - # Turn input sequence into a labeled creation sequence - first = creation_sequence[0] - if isinstance(first, str): # creation sequence - cs = [(i, creation_sequence[i]) for i in range(len(creation_sequence))] - elif isinstance(first, tuple): # labeled creation sequence - cs = creation_sequence[:] - elif isinstance(first, int): # compact creation sequence - ci = uncompact(creation_sequence) - cs = [(i, ci[i]) for i in range(len(ci))] - else: - raise TypeError("Not a valid creation sequence type") - - verts = [s[0] for s in cs] - if v not in verts: - raise ValueError("Vertex %s not in graph from creation_sequence" % v) - if u not in verts: - raise ValueError("Vertex %s not in graph from creation_sequence" % u) - # Done checking - if u == v: - return [u] - - uindex = verts.index(u) - vindex = verts.index(v) - bigind = max(uindex, vindex) - if cs[bigind][1] == 'd': - return [u, v] - # must be that cs[bigind][1]=='i' - cs = cs[bigind:] - while cs: - vert = cs.pop() - if vert[1] == 'd': - return [u, vert[0], v] - # All after u are type 'i' so no connection - return -1 - - -def shortest_path_length(creation_sequence, i): - """ - Return the shortest path length from indicated node to - every other node for the threshold graph with the given - creation sequence. - Node is indicated by index i in creation_sequence unless - creation_sequence is labeled in which case, i is taken to - be the label of the node. - - Paths lengths in threshold graphs are at most 2. - Length to unreachable nodes is set to -1. - """ - # Turn input sequence into a labeled creation sequence - first = creation_sequence[0] - if isinstance(first, str): # creation sequence - if isinstance(creation_sequence, list): - cs = creation_sequence[:] - else: - cs = list(creation_sequence) - elif isinstance(first, tuple): # labeled creation sequence - cs = [v[1] for v in creation_sequence] - i = [v[0] for v in creation_sequence].index(i) - elif isinstance(first, int): # compact creation sequence - cs = uncompact(creation_sequence) - else: - raise TypeError("Not a valid creation sequence type") - - # Compute - N = len(cs) - spl = [2] * N # length 2 to every node - spl[i] = 0 # except self which is 0 - # 1 for all d's to the right - for j in range(i + 1, N): - if cs[j] == "d": - spl[j] = 1 - if cs[i] == 'd': # 1 for all nodes to the left - for j in range(i): - spl[j] = 1 - # and -1 for any trailing i to indicate unreachable - for j in range(N - 1, 0, -1): - if cs[j] == "d": - break - spl[j] = -1 - return spl - - -def betweenness_sequence(creation_sequence, normalized=True): - """ - Return betweenness for the threshold graph with the given creation - sequence. The result is unscaled. To scale the values - to the iterval [0,1] divide by (n-1)*(n-2). - """ - cs = creation_sequence - seq = [] # betweenness - lastchar = 'd' # first node is always a 'd' - dr = float(cs.count("d")) # number of d's to the right of curren pos - irun = 0 # number of i's in the last run - drun = 0 # number of d's in the last run - dlast = 0.0 # betweenness of last d - for i, c in enumerate(cs): - if c == 'd': # cs[i]=="d": - # betweennees = amt shared with eariler d's and i's - # + new isolated nodes covered - # + new paths to all previous nodes - b = dlast + (irun - 1) * irun / dr + 2 * irun * (i - drun - irun) / dr - drun += 1 # update counter - else: # cs[i]="i": - if lastchar == 'd': # if this is a new run of i's - dlast = b # accumulate betweenness - dr -= drun # update number of d's to the right - drun = 0 # reset d counter - irun = 0 # reset i counter - b = 0 # isolated nodes have zero betweenness - irun += 1 # add another i to the run - seq.append(float(b)) - lastchar = c - - # normalize by the number of possible shortest paths - if normalized: - order = len(cs) - scale = 1.0 / ((order - 1) * (order - 2)) - seq = [s * scale for s in seq] - - return seq - - -def eigenvectors(creation_sequence): - """ - Return a 2-tuple of Laplacian eigenvalues and eigenvectors - for the threshold network with creation_sequence. - The first value is a list of eigenvalues. - The second value is a list of eigenvectors. - The lists are in the same order so corresponding eigenvectors - and eigenvalues are in the same position in the two lists. - - Notice that the order of the eigenvalues returned by eigenvalues(cs) - may not correspond to the order of these eigenvectors. - """ - ccs = make_compact(creation_sequence) - N = sum(ccs) - vec = [0] * N - val = vec[:] - # get number of type d nodes to the right (all for first node) - dr = sum(ccs[::2]) - - nn = ccs[0] - vec[0] = [1. / sqrt(N)] * N - val[0] = 0 - e = dr - dr -= nn - type_d = True - i = 1 - dd = 1 - while dd < nn: - scale = 1. / sqrt(dd * dd + i) - vec[i] = i * [-scale] + [dd * scale] + [0] * (N - i - 1) - val[i] = e - i += 1 - dd += 1 - if len(ccs) == 1: - return (val, vec) - for nn in ccs[1:]: - scale = 1. / sqrt(nn * i * (i + nn)) - vec[i] = i * [-nn * scale] + nn * [i * scale] + [0] * (N - i - nn) - # find eigenvalue - type_d = not type_d - if type_d: - e = i + dr - dr -= nn - else: - e = dr - val[i] = e - st = i - i += 1 - dd = 1 - while dd < nn: - scale = 1. / sqrt(i - st + dd * dd) - vec[i] = [0] * st + (i - st) * [-scale] + [dd * scale] + [0] * (N - i - 1) - val[i] = e - i += 1 - dd += 1 - return (val, vec) - - -def spectral_projection(u, eigenpairs): - """ - Returns the coefficients of each eigenvector - in a projection of the vector u onto the normalized - eigenvectors which are contained in eigenpairs. - - eigenpairs should be a list of two objects. The - first is a list of eigenvalues and the second a list - of eigenvectors. The eigenvectors should be lists. - - There's not a lot of error checking on lengths of - arrays, etc. so be careful. - """ - coeff = [] - evect = eigenpairs[1] - for ev in evect: - c = sum([evv * uv for (evv, uv) in zip(ev, u)]) - coeff.append(c) - return coeff - - -def eigenvalues(creation_sequence): - """ - Return sequence of eigenvalues of the Laplacian of the threshold - graph for the given creation_sequence. - - Based on the Ferrer's diagram method. The spectrum is integral - and is the conjugate of the degree sequence. - - See:: - - @Article{degree-merris-1994, - author = {Russel Merris}, - title = {Degree maximal graphs are Laplacian integral}, - journal = {Linear Algebra Appl.}, - year = {1994}, - volume = {199}, - pages = {381--389}, - } - - """ - degseq = degree_sequence(creation_sequence) - degseq.sort() - eiglist = [] # zero is always one eigenvalue - eig = 0 - row = len(degseq) - bigdeg = degseq.pop() - while row: - if bigdeg < row: - eiglist.append(eig) - row -= 1 - else: - eig += 1 - if degseq: - bigdeg = degseq.pop() - else: - bigdeg = 0 - return eiglist - - -# Threshold graph creation routines - -@py_random_state(2) -def random_threshold_sequence(n, p, seed=None): - """ - Create a random threshold sequence of size n. - A creation sequence is built by randomly choosing d's with - probabiliy p and i's with probability 1-p. - - s=nx.random_threshold_sequence(10,0.5) - - returns a threshold sequence of length 10 with equal - probably of an i or a d at each position. - - A "random" threshold graph can be built with - - G=nx.threshold_graph(s) - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - """ - if not (0 <= p <= 1): - raise ValueError("p must be in [0,1]") - - cs = ['d'] # threshold sequences always start with a d - for i in range(1, n): - if seed.random() < p: - cs.append('d') - else: - cs.append('i') - return cs - - -# maybe *_d_threshold_sequence routines should -# be (or be called from) a single routine with a more descriptive name -# and a keyword parameter? -def right_d_threshold_sequence(n, m): - """ - Create a skewed threshold graph with a given number - of vertices (n) and a given number of edges (m). - - The routine returns an unlabeled creation sequence - for the threshold graph. - - FIXME: describe algorithm - - """ - cs = ['d'] + ['i'] * (n - 1) # create sequence with n insolated nodes - - # m n * (n - 1) / 2: - raise ValueError("Too many edges for this many nodes.") - - # connected case m >n-1 - ind = n - 1 - sum = n - 1 - while sum < m: - cs[ind] = 'd' - ind -= 1 - sum += ind - ind = m - (sum - ind) - cs[ind] = 'd' - return cs - - -def left_d_threshold_sequence(n, m): - """ - Create a skewed threshold graph with a given number - of vertices (n) and a given number of edges (m). - - The routine returns an unlabeled creation sequence - for the threshold graph. - - FIXME: describe algorithm - - """ - cs = ['d'] + ['i'] * (n - 1) # create sequence with n insolated nodes - - # m n * (n - 1) / 2: - raise ValueError("Too many edges for this many nodes.") - - # Connected case when M>N-1 - cs[n - 1] = 'd' - sum = n - 1 - ind = 1 - while sum < m: - cs[ind] = 'd' - sum += ind - ind += 1 - if sum > m: # be sure not to change the first vertex - cs[sum - m] = 'i' - return cs - - -@py_random_state(3) -def swap_d(cs, p_split=1.0, p_combine=1.0, seed=None): - """ - Perform a "swap" operation on a threshold sequence. - - The swap preserves the number of nodes and edges - in the graph for the given sequence. - The resulting sequence is still a threshold sequence. - - Perform one split and one combine operation on the - 'd's of a creation sequence for a threshold graph. - This operation maintains the number of nodes and edges - in the graph, but shifts the edges from node to node - maintaining the threshold quality of the graph. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - """ - # preprocess the creation sequence - dlist = [i for (i, node_type) in enumerate(cs[1:-1]) if node_type == 'd'] - # split - if seed.random() < p_split: - choice = seed.choice(dlist) - split_to = seed.choice(range(choice)) - flip_side = choice - split_to - if split_to != flip_side and cs[split_to] == 'i' and cs[flip_side] == 'i': - cs[choice] = 'i' - cs[split_to] = 'd' - cs[flip_side] = 'd' - dlist.remove(choice) - # don't add or combine may reverse this action - # dlist.extend([split_to,flip_side]) -# print >>sys.stderr,"split at %s to %s and %s"%(choice,split_to,flip_side) - # combine - if seed.random() < p_combine and dlist: - first_choice = seed.choice(dlist) - second_choice = seed.choice(dlist) - target = first_choice + second_choice - if target >= len(cs) or cs[target] == 'd' or first_choice == second_choice: - return cs - # OK to combine - cs[first_choice] = 'i' - cs[second_choice] = 'i' - cs[target] = 'd' -# print >>sys.stderr,"combine %s and %s to make %s."%(first_choice,second_choice,target) - - return cs diff --git a/extensions/fablabchemnitz/networkx/algorithms/tournament.py b/extensions/fablabchemnitz/networkx/algorithms/tournament.py deleted file mode 100644 index 1000f4ce..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tournament.py +++ /dev/null @@ -1,355 +0,0 @@ -# tournament.py - functions for tournament graphs -# -# Copyright 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Functions concerning tournament graphs. - -A `tournament graph`_ is a complete oriented graph. In other words, it -is a directed graph in which there is exactly one directed edge joining -each pair of distinct nodes. For each function in this module that -accepts a graph as input, you must provide a tournament graph. The -responsibility is on the caller to ensure that the graph is a tournament -graph. - -To access the functions in this module, you must access them through the -:mod:`networkx.algorithms.tournament` module:: - - >>> import networkx as nx - >>> from networkx.algorithms import tournament - >>> G = nx.DiGraph([(0, 1), (1, 2), (2, 0)]) - >>> tournament.is_tournament(G) - True - -.. _tournament graph: https://en.wikipedia.org/wiki/Tournament_%28graph_theory%29 - -""" -from itertools import combinations - -import networkx as nx -from networkx.algorithms.simple_paths import is_simple_path as is_path -from networkx.utils import arbitrary_element -from networkx.utils import not_implemented_for -from networkx.utils import py_random_state - -__all__ = ['hamiltonian_path', 'is_reachable', 'is_strongly_connected', - 'is_tournament', 'random_tournament', 'score_sequence'] - - -def index_satisfying(iterable, condition): - """Returns the index of the first element in `iterable` that - satisfies the given condition. - - If no such element is found (that is, when the iterable is - exhausted), this returns the length of the iterable (that is, one - greater than the last index of the iterable). - - `iterable` must not be empty. If `iterable` is empty, this - function raises :exc:`ValueError`. - - """ - # Pre-condition: iterable must not be empty. - for i, x in enumerate(iterable): - if condition(x): - return i - # If we reach the end of the iterable without finding an element - # that satisfies the condition, return the length of the iterable, - # which is one greater than the index of its last element. If the - # iterable was empty, `i` will not be defined, so we raise an - # exception. - try: - return i + 1 - except NameError: - raise ValueError('iterable must be non-empty') - - -@not_implemented_for('undirected') -@not_implemented_for('multigraph') -def is_tournament(G): - """Returns True if and only if `G` is a tournament. - - A tournament is a directed graph, with neither self-loops nor - multi-edges, in which there is exactly one directed edge joining - each pair of distinct nodes. - - Parameters - ---------- - G : NetworkX graph - A directed graph representing a tournament. - - Returns - ------- - bool - Whether the given graph is a tournament graph. - - Notes - ----- - Some definitions require a self-loop on each node, but that is not - the convention used here. - - """ - # In a tournament, there is exactly one directed edge joining each pair. - return (all((v in G[u]) ^ (u in G[v]) for u, v in combinations(G, 2)) and - nx.number_of_selfloops(G) == 0) - - -@not_implemented_for('undirected') -@not_implemented_for('multigraph') -def hamiltonian_path(G): - """Returns a Hamiltonian path in the given tournament graph. - - Each tournament has a Hamiltonian path. If furthermore, the - tournament is strongly connected, then the returned Hamiltonian path - is a Hamiltonian cycle (by joining the endpoints of the path). - - Parameters - ---------- - G : NetworkX graph - A directed graph representing a tournament. - - Returns - ------- - bool - Whether the given graph is a tournament graph. - - Notes - ----- - This is a recursive implementation with an asymptotic running time - of $O(n^2)$, ignoring multiplicative polylogarithmic factors, where - $n$ is the number of nodes in the graph. - - """ - if len(G) == 0: - return [] - if len(G) == 1: - return [arbitrary_element(G)] - v = arbitrary_element(G) - hampath = hamiltonian_path(G.subgraph(set(G) - {v})) - # Get the index of the first node in the path that does *not* have - # an edge to `v`, then insert `v` before that node. - index = index_satisfying(hampath, lambda u: v not in G[u]) - hampath.insert(index, v) - return hampath - - -@py_random_state(1) -def random_tournament(n, seed=None): - r"""Returns a random tournament graph on `n` nodes. - - Parameters - ---------- - n : int - The number of nodes in the returned graph. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - bool - Whether the given graph is a tournament graph. - - Notes - ----- - This algorithm adds, for each pair of distinct nodes, an edge with - uniformly random orientation. In other words, `\binom{n}{2}` flips - of an unbiased coin decide the orientations of the edges in the - graph. - - """ - # Flip an unbiased coin for each pair of distinct nodes. - coins = (seed.random() for i in range((n * (n - 1)) // 2)) - pairs = combinations(range(n), 2) - edges = ((u, v) if r < 0.5 else (v, u) for (u, v), r in zip(pairs, coins)) - return nx.DiGraph(edges) - - -@not_implemented_for('undirected') -@not_implemented_for('multigraph') -def score_sequence(G): - """Returns the score sequence for the given tournament graph. - - The score sequence is the sorted list of the out-degrees of the - nodes of the graph. - - Parameters - ---------- - G : NetworkX graph - A directed graph representing a tournament. - - Returns - ------- - list - A sorted list of the out-degrees of the nodes of `G`. - - """ - return sorted(d for v, d in G.out_degree()) - - -@not_implemented_for('undirected') -@not_implemented_for('multigraph') -def tournament_matrix(G): - r"""Returns the tournament matrix for the given tournament graph. - - This function requires SciPy. - - The *tournament matrix* of a tournament graph with edge set *E* is - the matrix *T* defined by - - .. math:: - - T_{i j} = - \begin{cases} - +1 & \text{if } (i, j) \in E \\ - -1 & \text{if } (j, i) \in E \\ - 0 & \text{if } i == j. - \end{cases} - - An equivalent definition is `T = A - A^T`, where *A* is the - adjacency matrix of the graph `G`. - - Parameters - ---------- - G : NetworkX graph - A directed graph representing a tournament. - - Returns - ------- - SciPy sparse matrix - The tournament matrix of the tournament graph `G`. - - Raises - ------ - ImportError - If SciPy is not available. - - """ - A = nx.adjacency_matrix(G) - return A - A.T - - -@not_implemented_for('undirected') -@not_implemented_for('multigraph') -def is_reachable(G, s, t): - """Decides whether there is a path from `s` to `t` in the - tournament. - - This function is more theoretically efficient than the reachability - checks than the shortest path algorithms in - :mod:`networkx.algorithms.shortest_paths`. - - The given graph **must** be a tournament, otherwise this function's - behavior is undefined. - - Parameters - ---------- - G : NetworkX graph - A directed graph representing a tournament. - - s : node - A node in the graph. - - t : node - A node in the graph. - - Returns - ------- - bool - Whether there is a path from `s` to `t` in `G`. - - Notes - ----- - Although this function is more theoretically efficient than the - generic shortest path functions, a speedup requires the use of - parallelism. Though it may in the future, the current implementation - does not use parallelism, thus you may not see much of a speedup. - - This algorithm comes from [1]. - - References - ---------- - .. [1] Tantau, Till. - "A note on the complexity of the reachability problem for - tournaments." - *Electronic Colloquium on Computational Complexity*. 2001. - - - """ - - def two_neighborhood(G, v): - """Returns the set of nodes at distance at most two from `v`. - - `G` must be a graph and `v` a node in that graph. - - The returned set includes the nodes at distance zero (that is, - the node `v` itself), the nodes at distance one (that is, the - out-neighbors of `v`), and the nodes at distance two. - - """ - # TODO This is trivially parallelizable. - return {x for x in G - if x == v or x in G[v] or - any(is_path(G, [v, z, x]) for z in G)} - - def is_closed(G, nodes): - """Decides whether the given set of nodes is closed. - - A set *S* of nodes is *closed* if for each node *u* in the graph - not in *S* and for each node *v* in *S*, there is an edge from - *u* to *v*. - - """ - # TODO This is trivially parallelizable. - return all(v in G[u] for u in set(G) - nodes for v in nodes) - - # TODO This is trivially parallelizable. - neighborhoods = [two_neighborhood(G, v) for v in G] - return all(not (is_closed(G, S) and s in S and t not in S) - for S in neighborhoods) - - -@not_implemented_for('undirected') -@not_implemented_for('multigraph') -def is_strongly_connected(G): - """Decides whether the given tournament is strongly connected. - - This function is more theoretically efficient than the - :func:`~networkx.algorithms.components.is_strongly_connected` - function. - - The given graph **must** be a tournament, otherwise this function's - behavior is undefined. - - Parameters - ---------- - G : NetworkX graph - A directed graph representing a tournament. - - Returns - ------- - bool - Whether the tournament is strongly connected. - - Notes - ----- - Although this function is more theoretically efficient than the - generic strong connectivity function, a speedup requires the use of - parallelism. Though it may in the future, the current implementation - does not use parallelism, thus you may not see much of a speedup. - - This algorithm comes from [1]. - - References - ---------- - .. [1] Tantau, Till. - "A note on the complexity of the reachability problem for - tournaments." - *Electronic Colloquium on Computational Complexity*. 2001. - - - """ - # TODO This is trivially parallelizable. - return all(is_reachable(G, u, v) for u in G for v in G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/traversal/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/traversal/__init__.py deleted file mode 100644 index 93e6cdd0..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/traversal/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .beamsearch import * -from .breadth_first_search import * -from .depth_first_search import * -from .edgedfs import * -from .edgebfs import * diff --git a/extensions/fablabchemnitz/networkx/algorithms/traversal/beamsearch.py b/extensions/fablabchemnitz/networkx/algorithms/traversal/beamsearch.py deleted file mode 100644 index 181c68c7..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/traversal/beamsearch.py +++ /dev/null @@ -1,98 +0,0 @@ -# beamsearch.py - breadth-first search with limited queueing -# -# Copyright 2016-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Basic algorithms for breadth-first searching the nodes of a graph.""" - -import networkx as nx -from .breadth_first_search import generic_bfs_edges - -__all__ = ['bfs_beam_edges'] - - -def bfs_beam_edges(G, source, value, width=None): - """Iterates over edges in a beam search. - - The beam search is a generalized breadth-first search in which only - the "best" *w* neighbors of the current node are enqueued, where *w* - is the beam width and "best" is an application-specific - heuristic. In general, a beam search with a small beam width might - not visit each node in the graph. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for the breadth-first search; this function - iterates over only those edges in the component reachable from - this node. - - value : function - A function that takes a node of the graph as input and returns a - real number indicating how "good" it is. A higher value means it - is more likely to be visited sooner during the search. When - visiting a new node, only the `width` neighbors with the highest - `value` are enqueued (in decreasing order of `value`). - - width : int (default = None) - The beam width for the search. This is the number of neighbors - (ordered by `value`) to enqueue when visiting each new node. - - Yields - ------ - edge - Edges in the beam search starting from `source`, given as a pair - of nodes. - - Examples - -------- - To give nodes with, for example, a higher centrality precedence - during the search, set the `value` function to return the centrality - value of the node:: - - >>> G = nx.karate_club_graph() - >>> centrality = nx.eigenvector_centrality(G) - >>> source = 0 - >>> width = 5 - >>> for u, v in nx.bfs_beam_edges(G, source, centrality.get, width): - ... print((u, v)) # doctest: +SKIP - - """ - - if width is None: - width = len(G) - - def successors(v): - """Returns a list of the best neighbors of a node. - - `v` is a node in the graph `G`. - - The "best" neighbors are chosen according to the `value` - function (higher is better). Only the `width` best neighbors of - `v` are returned. - - The list returned by this function is in decreasing value as - measured by the `value` function. - - """ - # TODO The Python documentation states that for small values, it - # is better to use `heapq.nlargest`. We should determine the - # threshold at which its better to use `heapq.nlargest()` - # instead of `sorted()[:]` and apply that optimization here. - # - # If `width` is greater than the number of neighbors of `v`, all - # neighbors are returned by the semantics of slicing in - # Python. This occurs in the special case that the user did not - # specify a `width`: in this case all neighbors are always - # returned, so this is just a (slower) implementation of - # `bfs_edges(G, source)` but with a sorted enqueue step. - return iter(sorted(G.neighbors(v), key=value, reverse=True)[:width]) - - # TODO In Python 3.3+, this should be `yield from ...` - for e in generic_bfs_edges(G, source, successors): - yield e diff --git a/extensions/fablabchemnitz/networkx/algorithms/traversal/breadth_first_search.py b/extensions/fablabchemnitz/networkx/algorithms/traversal/breadth_first_search.py deleted file mode 100644 index 68e7727d..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/traversal/breadth_first_search.py +++ /dev/null @@ -1,379 +0,0 @@ -# breadth_first_search.py - breadth-first traversal of a graph -# -# Copyright (C) 2004-2019 NetworkX Developers -# Aric Hagberg -# Dan Schult -# Pieter Swart -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -# -# Authors: -# Aric Hagberg -# -"""Basic algorithms for breadth-first searching the nodes of a graph.""" -import networkx as nx -from collections import deque - -__all__ = [ - 'bfs_edges', 'bfs_tree', 'bfs_predecessors', 'bfs_successors', - 'descendants_at_distance' -] - - -def generic_bfs_edges(G, source, neighbors=None, depth_limit=None): - """Iterate over edges in a breadth-first search. - - The breadth-first search begins at `source` and enqueues the - neighbors of newly visited nodes specified by the `neighbors` - function. - - Parameters - ---------- - G : NetworkX graph - - source : node - Starting node for the breadth-first search; this function - iterates over only those edges in the component reachable from - this node. - - neighbors : function - A function that takes a newly visited node of the graph as input - and returns an *iterator* (not just a list) of nodes that are - neighbors of that node. If not specified, this is just the - ``G.neighbors`` method, but in general it can be any function - that returns an iterator over some or all of the neighbors of a - given node, in any order. - - depth_limit : int, optional(default=len(G)) - Specify the maximum search depth - - Yields - ------ - edge - Edges in the breadth-first search starting from `source`. - - Examples - -------- - >>> G = nx.path_graph(3) - >>> print(list(nx.bfs_edges(G,0))) - [(0, 1), (1, 2)] - >>> print(list(nx.bfs_edges(G, source=0, depth_limit=1))) - [(0, 1)] - - Notes - ----- - This implementation is from `PADS`_, which was in the public domain - when it was first accessed in July, 2004. The modifications - to allow depth limits are based on the Wikipedia article - "`Depth-limited-search`_". - - .. _PADS: http://www.ics.uci.edu/~eppstein/PADS/BFS.py - .. _Depth-limited-search: https://en.wikipedia.org/wiki/Depth-limited_search - """ - visited = {source} - if depth_limit is None: - depth_limit = len(G) - queue = deque([(source, depth_limit, neighbors(source))]) - while queue: - parent, depth_now, children = queue[0] - try: - child = next(children) - if child not in visited: - yield parent, child - visited.add(child) - if depth_now > 1: - queue.append((child, depth_now - 1, neighbors(child))) - except StopIteration: - queue.popleft() - - -def bfs_edges(G, source, reverse=False, depth_limit=None): - """Iterate over edges in a breadth-first-search starting at source. - - Parameters - ---------- - G : NetworkX graph - - source : node - Specify starting node for breadth-first search; this function - iterates over only those edges in the component reachable from - this node. - - reverse : bool, optional - If True traverse a directed graph in the reverse direction - - depth_limit : int, optional(default=len(G)) - Specify the maximum search depth - - Returns - ------- - edges: generator - A generator of edges in the breadth-first-search. - - Examples - -------- - To get the edges in a breadth-first search:: - - >>> G = nx.path_graph(3) - >>> list(nx.bfs_edges(G, 0)) - [(0, 1), (1, 2)] - >>> list(nx.bfs_edges(G, source=0, depth_limit=1)) - [(0, 1)] - - To get the nodes in a breadth-first search order:: - - >>> G = nx.path_graph(3) - >>> root = 2 - >>> edges = nx.bfs_edges(G, root) - >>> nodes = [root] + [v for u, v in edges] - >>> nodes - [2, 1, 0] - - Notes - ----- - The naming of this function is very similar to bfs_edges. The difference - is that 'edge_bfs' yields edges even if they extend back to an already - explored node while 'bfs_edges' yields the edges of the tree that results - from a breadth-first-search (BFS) so no edges are reported if they extend - to already explored nodes. That means 'edge_bfs' reports all edges while - 'bfs_edges' only report those traversed by a node-based BFS. Yet another - description is that 'bfs_edges' reports the edges traversed during BFS - while 'edge_bfs' reports all edges in the order they are explored. - - Based on http://www.ics.uci.edu/~eppstein/PADS/BFS.py. - by D. Eppstein, July 2004. The modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited-search`_". - - .. _Depth-limited-search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - bfs_tree - dfs_edges - edge_bfs - - """ - if reverse and G.is_directed(): - successors = G.predecessors - else: - successors = G.neighbors - # TODO In Python 3.3+, this should be `yield from ...` - for e in generic_bfs_edges(G, source, successors, depth_limit): - yield e - - -def bfs_tree(G, source, reverse=False, depth_limit=None): - """Returns an oriented tree constructed from of a breadth-first-search - starting at source. - - Parameters - ---------- - G : NetworkX graph - - source : node - Specify starting node for breadth-first search - - reverse : bool, optional - If True traverse a directed graph in the reverse direction - - depth_limit : int, optional(default=len(G)) - Specify the maximum search depth - - Returns - ------- - T: NetworkX DiGraph - An oriented tree - - Examples - -------- - >>> G = nx.path_graph(3) - >>> print(list(nx.bfs_tree(G,1).edges())) - [(1, 0), (1, 2)] - >>> H = nx.Graph() - >>> nx.add_path(H, [0, 1, 2, 3, 4, 5, 6]) - >>> nx.add_path(H, [2, 7, 8, 9, 10]) - >>> print(sorted(list(nx.bfs_tree(H, source=3, depth_limit=3).edges()))) - [(1, 0), (2, 1), (2, 7), (3, 2), (3, 4), (4, 5), (5, 6), (7, 8)] - - - Notes - ----- - Based on http://www.ics.uci.edu/~eppstein/PADS/BFS.py - by D. Eppstein, July 2004. The modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited-search`_". - - .. _Depth-limited-search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - dfs_tree - bfs_edges - edge_bfs - """ - T = nx.DiGraph() - T.add_node(source) - edges_gen = bfs_edges(G, source, reverse=reverse, depth_limit=depth_limit) - T.add_edges_from(edges_gen) - return T - - -def bfs_predecessors(G, source, depth_limit=None): - """Returns an iterator of predecessors in breadth-first-search from source. - - Parameters - ---------- - G : NetworkX graph - - source : node - Specify starting node for breadth-first search - - depth_limit : int, optional(default=len(G)) - Specify the maximum search depth - - Returns - ------- - pred: iterator - (node, predecessors) iterator where predecessors is the list of - predecessors of the node. - - Examples - -------- - >>> G = nx.path_graph(3) - >>> print(dict(nx.bfs_predecessors(G, 0))) - {1: 0, 2: 1} - >>> H = nx.Graph() - >>> H.add_edges_from([(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)]) - >>> print(dict(nx.bfs_predecessors(H, 0))) - {1: 0, 2: 0, 3: 1, 4: 1, 5: 2, 6: 2} - >>> M = nx.Graph() - >>> nx.add_path(M, [0, 1, 2, 3, 4, 5, 6]) - >>> nx.add_path(M, [2, 7, 8, 9, 10]) - >>> print(sorted(nx.bfs_predecessors(M, source=1, depth_limit=3))) - [(0, 1), (2, 1), (3, 2), (4, 3), (7, 2), (8, 7)] - - - Notes - ----- - Based on http://www.ics.uci.edu/~eppstein/PADS/BFS.py - by D. Eppstein, July 2004. The modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited-search`_". - - .. _Depth-limited-search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - bfs_tree - bfs_edges - edge_bfs - """ - for s, t in bfs_edges(G, source, depth_limit=depth_limit): - yield (t, s) - - -def bfs_successors(G, source, depth_limit=None): - """Returns an iterator of successors in breadth-first-search from source. - - Parameters - ---------- - G : NetworkX graph - - source : node - Specify starting node for breadth-first search - - depth_limit : int, optional(default=len(G)) - Specify the maximum search depth - - Returns - ------- - succ: iterator - (node, successors) iterator where successors is the list of - successors of the node. - - Examples - -------- - >>> G = nx.path_graph(3) - >>> print(dict(nx.bfs_successors(G,0))) - {0: [1], 1: [2]} - >>> H = nx.Graph() - >>> H.add_edges_from([(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)]) - >>> print(dict(nx.bfs_successors(H, 0))) - {0: [1, 2], 1: [3, 4], 2: [5, 6]} - >>> G = nx.Graph() - >>> nx.add_path(G, [0, 1, 2, 3, 4, 5, 6]) - >>> nx.add_path(G, [2, 7, 8, 9, 10]) - >>> print(dict(nx.bfs_successors(G, source=1, depth_limit=3))) - {1: [0, 2], 2: [3, 7], 3: [4], 7: [8]} - - - Notes - ----- - Based on http://www.ics.uci.edu/~eppstein/PADS/BFS.py - by D. Eppstein, July 2004.The modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited-search`_". - - .. _Depth-limited-search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - bfs_tree - bfs_edges - edge_bfs - """ - parent = source - children = [] - for p, c in bfs_edges(G, source, depth_limit=depth_limit): - if p == parent: - children.append(c) - continue - yield (parent, children) - children = [c] - parent = p - yield (parent, children) - - -def descendants_at_distance(G, source, distance): - """Returns all nodes at a fixed `distance` from `source` in `G`. - - Parameters - ---------- - G : NetworkX DiGraph - A directed graph - source : node in `G` - distance : the distance of the wanted nodes from `source` - - Returns - ------- - set() - The descendants of `source` in `G` at the given `distance` from `source` - """ - if not G.has_node(source): - raise nx.NetworkXError("The node %s is not in the graph." % source) - current_distance = 0 - queue = {source} - visited = {source} - - # this is basically BFS, except that the queue only stores the nodes at - # current_distance from source at each iteration - while queue: - if current_distance == distance: - return queue - - current_distance += 1 - - next_vertices = set() - for vertex in queue: - for child in G[vertex]: - if child not in visited: - visited.add(child) - next_vertices.add(child) - - queue = next_vertices - - return set() diff --git a/extensions/fablabchemnitz/networkx/algorithms/traversal/depth_first_search.py b/extensions/fablabchemnitz/networkx/algorithms/traversal/depth_first_search.py deleted file mode 100644 index f3ea3439..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/traversal/depth_first_search.py +++ /dev/null @@ -1,445 +0,0 @@ -# depth_first_search.py - depth-first traversals of a graph -# -# Copyright 2004-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -# -# Author: -# Aric Hagberg -"""Basic algorithms for depth-first searching the nodes of a graph.""" -import networkx as nx -from collections import defaultdict - -__all__ = ['dfs_edges', 'dfs_tree', - 'dfs_predecessors', 'dfs_successors', - 'dfs_preorder_nodes', 'dfs_postorder_nodes', - 'dfs_labeled_edges'] - - -def dfs_edges(G, source=None, depth_limit=None): - """Iterate over edges in a depth-first-search (DFS). - - Perform a depth-first-search over the nodes of G and yield - the edges in order. This may not generate all edges in G (see edge_dfs). - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Specify starting node for depth-first search and return edges in - the component reachable from source. - - depth_limit : int, optional (default=len(G)) - Specify the maximum search depth. - - Returns - ------- - edges: generator - A generator of edges in the depth-first-search. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> list(nx.dfs_edges(G, source=0)) - [(0, 1), (1, 2), (2, 3), (3, 4)] - >>> list(nx.dfs_edges(G, source=0, depth_limit=2)) - [(0, 1), (1, 2)] - - Notes - ----- - If a source is not specified then a source is chosen arbitrarily and - repeatedly until all components in the graph are searched. - - The implementation of this function is adapted from David Eppstein's - depth-first search function in `PADS`_, with modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited search`_". - - .. _PADS: http://www.ics.uci.edu/~eppstein/PADS - .. _Depth-limited search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - dfs_preorder_nodes - dfs_postorder_nodes - dfs_labeled_edges - edge_dfs - bfs_edges - """ - if source is None: - # edges for all components - nodes = G - else: - # edges for components with source - nodes = [source] - visited = set() - if depth_limit is None: - depth_limit = len(G) - for start in nodes: - if start in visited: - continue - visited.add(start) - stack = [(start, depth_limit, iter(G[start]))] - while stack: - parent, depth_now, children = stack[-1] - try: - child = next(children) - if child not in visited: - yield parent, child - visited.add(child) - if depth_now > 1: - stack.append((child, depth_now - 1, iter(G[child]))) - except StopIteration: - stack.pop() - - -def dfs_tree(G, source=None, depth_limit=None): - """Returns oriented tree constructed from a depth-first-search from source. - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Specify starting node for depth-first search. - - depth_limit : int, optional (default=len(G)) - Specify the maximum search depth. - - Returns - ------- - T : NetworkX DiGraph - An oriented tree - - Examples - -------- - >>> G = nx.path_graph(5) - >>> T = nx.dfs_tree(G, source=0, depth_limit=2) - >>> list(T.edges()) - [(0, 1), (1, 2)] - >>> T = nx.dfs_tree(G, source=0) - >>> list(T.edges()) - [(0, 1), (1, 2), (2, 3), (3, 4)] - - See Also - -------- - dfs_preorder_nodes - dfs_postorder_nodes - dfs_labeled_edges - edge_dfs - bfs_tree - """ - T = nx.DiGraph() - if source is None: - T.add_nodes_from(G) - else: - T.add_node(source) - T.add_edges_from(dfs_edges(G, source, depth_limit)) - return T - - -def dfs_predecessors(G, source=None, depth_limit=None): - """Returns dictionary of predecessors in depth-first-search from source. - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Specify starting node for depth-first search. - - depth_limit : int, optional (default=len(G)) - Specify the maximum search depth. - - Returns - ------- - pred: dict - A dictionary with nodes as keys and predecessor nodes as values. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.dfs_predecessors(G, source=0) - {1: 0, 2: 1, 3: 2} - >>> nx.dfs_predecessors(G, source=0, depth_limit=2) - {1: 0, 2: 1} - - Notes - ----- - If a source is not specified then a source is chosen arbitrarily and - repeatedly until all components in the graph are searched. - - The implementation of this function is adapted from David Eppstein's - depth-first search function in `PADS`_, with modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited search`_". - - .. _PADS: http://www.ics.uci.edu/~eppstein/PADS - .. _Depth-limited search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - dfs_preorder_nodes - dfs_postorder_nodes - dfs_labeled_edges - edge_dfs - bfs_tree - """ - return {t: s for s, t in dfs_edges(G, source, depth_limit)} - - -def dfs_successors(G, source=None, depth_limit=None): - """Returns dictionary of successors in depth-first-search from source. - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Specify starting node for depth-first search. - - depth_limit : int, optional (default=len(G)) - Specify the maximum search depth. - - Returns - ------- - succ: dict - A dictionary with nodes as keys and list of successor nodes as values. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> nx.dfs_successors(G, source=0) - {0: [1], 1: [2], 2: [3], 3: [4]} - >>> nx.dfs_successors(G, source=0, depth_limit=2) - {0: [1], 1: [2]} - - Notes - ----- - If a source is not specified then a source is chosen arbitrarily and - repeatedly until all components in the graph are searched. - - The implementation of this function is adapted from David Eppstein's - depth-first search function in `PADS`_, with modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited search`_". - - .. _PADS: http://www.ics.uci.edu/~eppstein/PADS - .. _Depth-limited search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - dfs_preorder_nodes - dfs_postorder_nodes - dfs_labeled_edges - edge_dfs - bfs_tree - """ - d = defaultdict(list) - for s, t in dfs_edges(G, source=source, depth_limit=depth_limit): - d[s].append(t) - return dict(d) - - -def dfs_postorder_nodes(G, source=None, depth_limit=None): - """Generate nodes in a depth-first-search post-ordering starting at source. - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Specify starting node for depth-first search. - - depth_limit : int, optional (default=len(G)) - Specify the maximum search depth. - - Returns - ------- - nodes: generator - A generator of nodes in a depth-first-search post-ordering. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> list(nx.dfs_postorder_nodes(G, source=0)) - [4, 3, 2, 1, 0] - >>> list(nx.dfs_postorder_nodes(G, source=0, depth_limit=2)) - [1, 0] - - Notes - ----- - If a source is not specified then a source is chosen arbitrarily and - repeatedly until all components in the graph are searched. - - The implementation of this function is adapted from David Eppstein's - depth-first search function in `PADS`_, with modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited search`_". - - .. _PADS: http://www.ics.uci.edu/~eppstein/PADS - .. _Depth-limited search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - dfs_edges - dfs_preorder_nodes - dfs_labeled_edges - edge_dfs - bfs_tree - """ - edges = nx.dfs_labeled_edges(G, source=source, depth_limit=depth_limit) - return (v for u, v, d in edges if d == 'reverse') - - -def dfs_preorder_nodes(G, source=None, depth_limit=None): - """Generate nodes in a depth-first-search pre-ordering starting at source. - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Specify starting node for depth-first search and return nodes in - the component reachable from source. - - depth_limit : int, optional (default=len(G)) - Specify the maximum search depth. - - Returns - ------- - nodes: generator - A generator of nodes in a depth-first-search pre-ordering. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> list(nx.dfs_preorder_nodes(G, source=0)) - [0, 1, 2, 3, 4] - >>> list(nx.dfs_preorder_nodes(G, source=0, depth_limit=2)) - [0, 1, 2] - - Notes - ----- - If a source is not specified then a source is chosen arbitrarily and - repeatedly until all components in the graph are searched. - - The implementation of this function is adapted from David Eppstein's - depth-first search function in `PADS`_, with modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited search`_". - - .. _PADS: http://www.ics.uci.edu/~eppstein/PADS - .. _Depth-limited search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - dfs_edges - dfs_postorder_nodes - dfs_labeled_edges - bfs_edges - """ - edges = nx.dfs_labeled_edges(G, source=source, depth_limit=depth_limit) - return (v for u, v, d in edges if d == 'forward') - - -def dfs_labeled_edges(G, source=None, depth_limit=None): - """Iterate over edges in a depth-first-search (DFS) labeled by type. - - Parameters - ---------- - G : NetworkX graph - - source : node, optional - Specify starting node for depth-first search and return edges in - the component reachable from source. - - depth_limit : int, optional (default=len(G)) - Specify the maximum search depth. - - Returns - ------- - edges: generator - A generator of triples of the form (*u*, *v*, *d*), where (*u*, - *v*) is the edge being explored in the depth-first search and *d* - is one of the strings 'forward', 'nontree', or 'reverse'. A - 'forward' edge is one in which *u* has been visited but *v* has - not. A 'nontree' edge is one in which both *u* and *v* have been - visited but the edge is not in the DFS tree. A 'reverse' edge is - on in which both *u* and *v* have been visited and the edge is in - the DFS tree. - - Examples - -------- - - The labels reveal the complete transcript of the depth-first search - algorithm in more detail than, for example, :func:`dfs_edges`:: - - >>> from pprint import pprint - >>> - >>> G = nx.DiGraph([(0, 1), (1, 2), (2, 1)]) - >>> pprint(list(nx.dfs_labeled_edges(G, source=0))) - [(0, 0, 'forward'), - (0, 1, 'forward'), - (1, 2, 'forward'), - (2, 1, 'nontree'), - (1, 2, 'reverse'), - (0, 1, 'reverse'), - (0, 0, 'reverse')] - - Notes - ----- - If a source is not specified then a source is chosen arbitrarily and - repeatedly until all components in the graph are searched. - - The implementation of this function is adapted from David Eppstein's - depth-first search function in `PADS`_, with modifications - to allow depth limits based on the Wikipedia article - "`Depth-limited search`_". - - .. _PADS: http://www.ics.uci.edu/~eppstein/PADS - .. _Depth-limited search: https://en.wikipedia.org/wiki/Depth-limited_search - - See Also - -------- - dfs_edges - dfs_preorder_nodes - dfs_postorder_nodes - """ - # Based on http://www.ics.uci.edu/~eppstein/PADS/DFS.py - # by D. Eppstein, July 2004. - if source is None: - # edges for all components - nodes = G - else: - # edges for components with source - nodes = [source] - visited = set() - if depth_limit is None: - depth_limit = len(G) - for start in nodes: - if start in visited: - continue - yield start, start, 'forward' - visited.add(start) - stack = [(start, depth_limit, iter(G[start]))] - while stack: - parent, depth_now, children = stack[-1] - try: - child = next(children) - if child in visited: - yield parent, child, 'nontree' - else: - yield parent, child, 'forward' - visited.add(child) - if depth_now > 1: - stack.append((child, depth_now - 1, iter(G[child]))) - except StopIteration: - stack.pop() - if stack: - yield stack[-1][0], parent, 'reverse' - yield start, start, 'reverse' diff --git a/extensions/fablabchemnitz/networkx/algorithms/traversal/edgebfs.py b/extensions/fablabchemnitz/networkx/algorithms/traversal/edgebfs.py deleted file mode 100644 index cd9c9f7d..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/traversal/edgebfs.py +++ /dev/null @@ -1,165 +0,0 @@ -""" -============================= -Breadth First Search on Edges -============================= - -Algorithms for a breadth-first traversal of edges in a graph. - -""" -from collections import deque -import networkx as nx - -FORWARD = 'forward' -REVERSE = 'reverse' - -__all__ = ['edge_bfs'] - - -def edge_bfs(G, source=None, orientation=None): - """A directed, breadth-first-search of edges in `G`, beginning at `source`. - - Yield the edges of G in a breadth-first-search order continuing until - all edges are generated. - - Parameters - ---------- - G : graph - A directed/undirected graph/multigraph. - - source : node, list of nodes - The node from which the traversal begins. If None, then a source - is chosen arbitrarily and repeatedly until all edges from each node in - the graph are searched. - - orientation : None | 'original' | 'reverse' | 'ignore' (default: None) - For directed graphs and directed multigraphs, edge traversals need not - respect the original orientation of the edges. - When set to 'reverse' every edge is traversed in the reverse direction. - When set to 'ignore', every edge is treated as undirected. - When set to 'original', every edge is treated as directed. - In all three cases, the yielded edge tuples add a last entry to - indicate the direction in which that edge was traversed. - If orientation is None, the yielded edge has no direction indicated. - The direction is respected, but not reported. - - Yields - ------ - edge : directed edge - A directed edge indicating the path taken by the breadth-first-search. - For graphs, `edge` is of the form `(u, v)` where `u` and `v` - are the tail and head of the edge as determined by the traversal. - For multigraphs, `edge` is of the form `(u, v, key)`, where `key` is - the key of the edge. When the graph is directed, then `u` and `v` - are always in the order of the actual directed edge. - If orientation is not None then the edge tuple is extended to include - the direction of traversal ('forward' or 'reverse') on that edge. - - Examples - -------- - >>> import networkx as nx - >>> nodes = [0, 1, 2, 3] - >>> edges = [(0, 1), (1, 0), (1, 0), (2, 0), (2, 1), (3, 1)] - - >>> list(nx.edge_bfs(nx.Graph(edges), nodes)) - [(0, 1), (0, 2), (1, 2), (1, 3)] - - >>> list(nx.edge_bfs(nx.DiGraph(edges), nodes)) - [(0, 1), (1, 0), (2, 0), (2, 1), (3, 1)] - - >>> list(nx.edge_bfs(nx.MultiGraph(edges), nodes)) - [(0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (1, 2, 0), (1, 3, 0)] - - >>> list(nx.edge_bfs(nx.MultiDiGraph(edges), nodes)) - [(0, 1, 0), (1, 0, 0), (1, 0, 1), (2, 0, 0), (2, 1, 0), (3, 1, 0)] - - >>> list(nx.edge_bfs(nx.DiGraph(edges), nodes, orientation='ignore')) - [(0, 1, 'forward'), (1, 0, 'reverse'), (2, 0, 'reverse'), (2, 1, 'reverse'), (3, 1, 'reverse')] - - >>> list(nx.edge_bfs(nx.MultiDiGraph(edges), nodes, orientation='ignore')) - [(0, 1, 0, 'forward'), (1, 0, 0, 'reverse'), (1, 0, 1, 'reverse'), (2, 0, 0, 'reverse'), (2, 1, 0, 'reverse'), (3, 1, 0, 'reverse')] - - Notes - ----- - The goal of this function is to visit edges. It differs from the more - familiar breadth-first-search of nodes, as provided by - :func:`networkx.algorithms.traversal.breadth_first_search.bfs_edges`, in - that it does not stop once every node has been visited. In a directed graph - with edges [(0, 1), (1, 2), (2, 1)], the edge (2, 1) would not be visited - if not for the functionality provided by this function. - - The naming of this function is very similar to bfs_edges. The difference - is that 'edge_bfs' yields edges even if they extend back to an already - explored node while 'bfs_edges' yields the edges of the tree that results - from a breadth-first-search (BFS) so no edges are reported if they extend - to already explored nodes. That means 'edge_bfs' reports all edges while - 'bfs_edges' only report those traversed by a node-based BFS. Yet another - description is that 'bfs_edges' reports the edges traversed during BFS - while 'edge_bfs' reports all edges in the order they are explored. - - See Also - -------- - bfs_edges - bfs_tree - edge_dfs - - """ - nodes = list(G.nbunch_iter(source)) - if not nodes: - return - - directed = G.is_directed() - kwds = {'data': False} - if G.is_multigraph() is True: - kwds['keys'] = True - - # set up edge lookup - if orientation is None: - def edges_from(node): - return iter(G.edges(node, **kwds)) - elif not directed or orientation == 'original': - def edges_from(node): - for e in G.edges(node, **kwds): - yield e + (FORWARD,) - elif orientation == 'reverse': - def edges_from(node): - for e in G.in_edges(node, **kwds): - yield e + (REVERSE,) - elif orientation == 'ignore': - def edges_from(node): - for e in G.edges(node, **kwds): - yield e + (FORWARD,) - for e in G.in_edges(node, **kwds): - yield e + (REVERSE,) - else: - raise nx.NetworkXError("invalid orientation argument.") - - if directed: - neighbors = G.successors - def edge_id(edge): - # remove direction indicator - return edge[:-1] if orientation is not None else edge - else: - neighbors = G.neighbors - def edge_id(edge): - return (frozenset(edge[:2]),) +edge[2:] - - check_reverse = directed and orientation in ('reverse', 'ignore') - - # start BFS - visited_nodes = {n for n in nodes} - visited_edges = set() - queue = deque([(n, edges_from(n)) for n in nodes]) - while queue: - parent, children_edges = queue.popleft() - for edge in children_edges: - if check_reverse and edge[-1] == REVERSE: - child = edge[0] - else: - child = edge[1] - if child not in visited_nodes: - visited_nodes.add(child) - queue.append((child, edges_from(child))) - edgeid = edge_id(edge) - if edgeid not in visited_edges: - visited_edges.add(edgeid) - yield edge diff --git a/extensions/fablabchemnitz/networkx/algorithms/traversal/edgedfs.py b/extensions/fablabchemnitz/networkx/algorithms/traversal/edgedfs.py deleted file mode 100644 index e13f5719..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/traversal/edgedfs.py +++ /dev/null @@ -1,164 +0,0 @@ -""" -=========================== -Depth First Search on Edges -=========================== - -Algorithms for a depth-first traversal of edges in a graph. - -""" -import networkx as nx - -FORWARD = 'forward' -REVERSE = 'reverse' - -__all__ = ['edge_dfs'] - - -def edge_dfs(G, source=None, orientation=None): - """A directed, depth-first-search of edges in `G`, beginning at `source`. - - Yield the edges of G in a depth-first-search order continuing until - all edges are generated. - - Parameters - ---------- - G : graph - A directed/undirected graph/multigraph. - - source : node, list of nodes - The node from which the traversal begins. If None, then a source - is chosen arbitrarily and repeatedly until all edges from each node in - the graph are searched. - - orientation : None | 'original' | 'reverse' | 'ignore' (default: None) - For directed graphs and directed multigraphs, edge traversals need not - respect the original orientation of the edges. - When set to 'reverse' every edge is traversed in the reverse direction. - When set to 'ignore', every edge is treated as undirected. - When set to 'original', every edge is treated as directed. - In all three cases, the yielded edge tuples add a last entry to - indicate the direction in which that edge was traversed. - If orientation is None, the yielded edge has no direction indicated. - The direction is respected, but not reported. - - Yields - ------ - edge : directed edge - A directed edge indicating the path taken by the depth-first traversal. - For graphs, `edge` is of the form `(u, v)` where `u` and `v` - are the tail and head of the edge as determined by the traversal. - For multigraphs, `edge` is of the form `(u, v, key)`, where `key` is - the key of the edge. When the graph is directed, then `u` and `v` - are always in the order of the actual directed edge. - If orientation is not None then the edge tuple is extended to include - the direction of traversal ('forward' or 'reverse') on that edge. - - Examples - -------- - >>> import networkx as nx - >>> nodes = [0, 1, 2, 3] - >>> edges = [(0, 1), (1, 0), (1, 0), (2, 1), (3, 1)] - - >>> list(nx.edge_dfs(nx.Graph(edges), nodes)) - [(0, 1), (1, 2), (1, 3)] - - >>> list(nx.edge_dfs(nx.DiGraph(edges), nodes)) - [(0, 1), (1, 0), (2, 1), (3, 1)] - - >>> list(nx.edge_dfs(nx.MultiGraph(edges), nodes)) - [(0, 1, 0), (1, 0, 1), (0, 1, 2), (1, 2, 0), (1, 3, 0)] - - >>> list(nx.edge_dfs(nx.MultiDiGraph(edges), nodes)) - [(0, 1, 0), (1, 0, 0), (1, 0, 1), (2, 1, 0), (3, 1, 0)] - - >>> list(nx.edge_dfs(nx.DiGraph(edges), nodes, orientation='ignore')) - [(0, 1, 'forward'), (1, 0, 'forward'), (2, 1, 'reverse'), (3, 1, 'reverse')] - - >>> list(nx.edge_dfs(nx.MultiDiGraph(edges), nodes, orientation='ignore')) - [(0, 1, 0, 'forward'), (1, 0, 0, 'forward'), (1, 0, 1, 'reverse'), (2, 1, 0, 'reverse'), (3, 1, 0, 'reverse')] - - Notes - ----- - The goal of this function is to visit edges. It differs from the more - familiar depth-first traversal of nodes, as provided by - :func:`networkx.algorithms.traversal.depth_first_search.dfs_edges`, in - that it does not stop once every node has been visited. In a directed graph - with edges [(0, 1), (1, 2), (2, 1)], the edge (2, 1) would not be visited - if not for the functionality provided by this function. - - See Also - -------- - dfs_edges - - """ - nodes = list(G.nbunch_iter(source)) - if not nodes: - return - - directed = G.is_directed() - kwds = {'data': False} - if G.is_multigraph() is True: - kwds['keys'] = True - - # set up edge lookup - if orientation is None: - def edges_from(node): - return iter(G.edges(node, **kwds)) - elif not directed or orientation == 'original': - def edges_from(node): - for e in G.edges(node, **kwds): - yield e + (FORWARD,) - elif orientation == 'reverse': - def edges_from(node): - for e in G.in_edges(node, **kwds): - yield e + (REVERSE,) - elif orientation == 'ignore': - def edges_from(node): - for e in G.edges(node, **kwds): - yield e + (FORWARD,) - for e in G.in_edges(node, **kwds): - yield e + (REVERSE,) - else: - raise nx.NetworkXError("invalid orientation argument.") - - # set up formation of edge_id to easily look up if edge already returned - if directed: - def edge_id(edge): - # remove direction indicator - return edge[:-1] if orientation is not None else edge - else: - def edge_id(edge): - # single id for undirected requires frozenset on nodes - return (frozenset(edge[:2]),) + edge[2:] - - # Basic setup - check_reverse = directed and orientation in ('reverse', 'ignore') - - visited_edges = set() - visited_nodes = set() - edges = {} - - # start DFS - for start_node in nodes: - stack = [start_node] - while stack: - current_node = stack[-1] - if current_node not in visited_nodes: - edges[current_node] = edges_from(current_node) - visited_nodes.add(current_node) - - try: - edge = next(edges[current_node]) - except StopIteration: - # No more edges from the current node. - stack.pop() - else: - edgeid = edge_id(edge) - if edgeid not in visited_edges: - visited_edges.add(edgeid) - # Mark the traversed "to" node as to-be-explored. - if check_reverse and edge[-1] == REVERSE: - stack.append(edge[0]) - else: - stack.append(edge[1]) - yield edge diff --git a/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/test_beamsearch.py b/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/test_beamsearch.py deleted file mode 100644 index 760f0018..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/test_beamsearch.py +++ /dev/null @@ -1,37 +0,0 @@ -# test_beamsearch.py - unit tests for the beamsearch module -# -# Copyright 2016-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the beam search functions.""" -from unittest import TestCase - - -import networkx as nx - - -def identity(x): - return x - - -class TestBeamSearch(TestCase): - """Unit tests for the beam search function.""" - - def test_narrow(self): - """Tests that a narrow beam width may cause an incomplete search.""" - # In this search, we enqueue only the neighbor 3 at the first - # step, then only the neighbor 2 at the second step. Once at - # node 2, the search chooses node 3, since it has a higher value - # that node 1, but node 3 has already been visited, so the - # search terminates. - G = nx.cycle_graph(4) - edges = nx.bfs_beam_edges(G, 0, identity, width=1) - assert list(edges) == [(0, 3), (3, 2)] - - def test_wide(self): - G = nx.cycle_graph(4) - edges = nx.bfs_beam_edges(G, 0, identity, width=2) - assert list(edges) == [(0, 3), (0, 1), (3, 2)] diff --git a/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/test_bfs.py b/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/test_bfs.py deleted file mode 100644 index 966ab4d2..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/test_bfs.py +++ /dev/null @@ -1,82 +0,0 @@ -import networkx as nx - - -class TestBFS: - - @classmethod - def setup_class(cls): - # simple graph - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4)]) - cls.G = G - - def test_successor(self): - assert (dict(nx.bfs_successors(self.G, source=0)) == - {0: [1], 1: [2, 3], 2: [4]}) - - def test_predecessor(self): - assert (dict(nx.bfs_predecessors(self.G, source=0)) == - {1: 0, 2: 1, 3: 1, 4: 2}) - - def test_bfs_tree(self): - T = nx.bfs_tree(self.G, source=0) - assert sorted(T.nodes()) == sorted(self.G.nodes()) - assert sorted(T.edges()) == [(0, 1), (1, 2), (1, 3), (2, 4)] - - def test_bfs_edges(self): - edges = nx.bfs_edges(self.G, source=0) - assert list(edges) == [(0, 1), (1, 2), (1, 3), (2, 4)] - - def test_bfs_edges_reverse(self): - D = nx.DiGraph() - D.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4)]) - edges = nx.bfs_edges(D, source=4, reverse=True) - assert list(edges) == [(4, 2), (4, 3), (2, 1), (1, 0)] - - def test_bfs_tree_isolates(self): - G = nx.Graph() - G.add_node(1) - G.add_node(2) - T = nx.bfs_tree(G, source=1) - assert sorted(T.nodes()) == [1] - assert sorted(T.edges()) == [] - - -class TestBreadthLimitedSearch: - - @classmethod - def setup_class(cls): - # a tree - G = nx.Graph() - nx.add_path(G, [0, 1, 2, 3, 4, 5, 6]) - nx.add_path(G, [2, 7, 8, 9, 10]) - cls.G = G - # a disconnected graph - D = nx.Graph() - D.add_edges_from([(0, 1), (2, 3)]) - nx.add_path(D, [2, 7, 8, 9, 10]) - cls.D = D - - def bfs_test_successor(self): - assert (dict(nx.bfs_successors(self.G, source=1, depth_limit=3)) == - {1: [0, 2], 2: [3, 7], 3: [4], 7: [8]}) - result = {n: sorted(s) for n, s in nx.bfs_successors(self.D, source=7, - depth_limit=2)} - assert result == {8: [9], 2: [3], 7: [2, 8]} - - def bfs_test_predecessor(self): - assert (dict(nx.bfs_predecessors(self.G, source=1, - depth_limit=3)) == - {0: 1, 2: 1, 3: 2, 4: 3, 7: 2, 8: 7}) - assert (dict(nx.bfs_predecessors(self.D, source=7, - depth_limit=2)) == - {2: 7, 3: 2, 8: 7, 9: 8}) - - def bfs_test_tree(self): - T = nx.bfs_tree(self.G, source=3, depth_limit=1) - assert sorted(T.edges()) == [(3, 2), (3, 4)] - - def bfs_test_edges(self): - edges = nx.bfs_edges(self.G, source=9, depth_limit=4) - assert list(edges) == [(9, 8), (9, 10), (8, 7), - (7, 2), (2, 1), (2, 3)] diff --git a/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/test_dfs.py b/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/test_dfs.py deleted file mode 100644 index 75e25693..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/test_dfs.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env python -import networkx as nx - - -class TestDFS: - - @classmethod - def setup_class(cls): - # simple graph - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4)]) - cls.G = G - # simple graph, disconnected - D = nx.Graph() - D.add_edges_from([(0, 1), (2, 3)]) - cls.D = D - - def test_preorder_nodes(self): - assert (list(nx.dfs_preorder_nodes(self.G, source=0)) == - [0, 1, 2, 4, 3]) - assert list(nx.dfs_preorder_nodes(self.D)) == [0, 1, 2, 3] - - def test_postorder_nodes(self): - assert (list(nx.dfs_postorder_nodes(self.G, source=0)) == - [3, 4, 2, 1, 0]) - assert list(nx.dfs_postorder_nodes(self.D)) == [1, 0, 3, 2] - - def test_successor(self): - assert (nx.dfs_successors(self.G, source=0) == - {0: [1], 1: [2], 2: [4], 4: [3]}) - assert nx.dfs_successors(self.D) == {0: [1], 2: [3]} - - def test_predecessor(self): - assert (nx.dfs_predecessors(self.G, source=0) == - {1: 0, 2: 1, 3: 4, 4: 2}) - assert nx.dfs_predecessors(self.D) == {1: 0, 3: 2} - - def test_dfs_tree(self): - exp_nodes = sorted(self.G.nodes()) - exp_edges = [(0, 1), (1, 2), (2, 4), (4, 3)] - # Search from first node - T = nx.dfs_tree(self.G, source=0) - assert sorted(T.nodes()) == exp_nodes - assert sorted(T.edges()) == exp_edges - # Check source=None - T = nx.dfs_tree(self.G, source=None) - assert sorted(T.nodes()) == exp_nodes - assert sorted(T.edges()) == exp_edges - # Check source=None is the default - T = nx.dfs_tree(self.G) - assert sorted(T.nodes()) == exp_nodes - assert sorted(T.edges()) == exp_edges - - def test_dfs_edges(self): - edges = nx.dfs_edges(self.G, source=0) - assert list(edges) == [(0, 1), (1, 2), (2, 4), (4, 3)] - edges = nx.dfs_edges(self.D) - assert list(edges) == [(0, 1), (2, 3)] - - def test_dfs_labeled_edges(self): - edges = list(nx.dfs_labeled_edges(self.G, source=0)) - forward = [(u, v) for (u, v, d) in edges if d == 'forward'] - assert forward == [(0, 0), (0, 1), (1, 2), (2, 4), (4, 3)] - - def test_dfs_labeled_disconnected_edges(self): - edges = list(nx.dfs_labeled_edges(self.D)) - forward = [(u, v) for (u, v, d) in edges if d == 'forward'] - assert forward == [(0, 0), (0, 1), (2, 2), (2, 3)] - - def test_dfs_tree_isolates(self): - G = nx.Graph() - G.add_node(1) - G.add_node(2) - T = nx.dfs_tree(G, source=1) - assert sorted(T.nodes()) == [1] - assert sorted(T.edges()) == [] - T = nx.dfs_tree(G, source=None) - assert sorted(T.nodes()) == [1, 2] - assert sorted(T.edges()) == [] - - -class TestDepthLimitedSearch: - - @classmethod - def setup_class(cls): - # a tree - G = nx.Graph() - nx.add_path(G, [0, 1, 2, 3, 4, 5, 6]) - nx.add_path(G, [2, 7, 8, 9, 10]) - cls.G = G - # a disconnected graph - D = nx.Graph() - D.add_edges_from([(0, 1), (2, 3)]) - nx.add_path(D, [2, 7, 8, 9, 10]) - cls.D = D - - def dls_test_preorder_nodes(self): - assert list(nx.dfs_preorder_nodes(self.G, source=0, - depth_limit=2)) == [0, 1, 2] - assert list(nx.dfs_preorder_nodes(self.D, source=1, - depth_limit=2)) == ([1, 0]) - - def dls_test_postorder_nodes(self): - assert list(nx.dfs_postorder_nodes(self.G, - source=3, depth_limit=3)) == [1, 7, 2, 5, 4, 3] - assert list(nx.dfs_postorder_nodes(self.D, - source=2, depth_limit=2)) == ([3, 7, 2]) - - def dls_test_successor(self): - result = nx.dfs_successors(self.G, source=4, depth_limit=3) - assert ({n: set(v) for n, v in result.items()} == - {2: {1, 7}, 3: {2}, 4: {3, 5}, 5: {6}}) - result = nx.dfs_successors(self.D, source=7, depth_limit=2) - assert ({n: set(v) for n, v in result.items()} == - {8: {9}, 2: {3}, 7: {8, 2}}) - - def dls_test_predecessor(self): - assert (nx.dfs_predecessors(self.G, source=0, depth_limit=3) == - {1: 0, 2: 1, 3: 2, 7: 2}) - assert (nx.dfs_predecessors(self.D, source=2, depth_limit=3) == - {8: 7, 9: 8, 3: 2, 7: 2}) - - def test_dls_tree(self): - T = nx.dfs_tree(self.G, source=3, depth_limit=1) - assert sorted(T.edges()) == [(3, 2), (3, 4)] - - def test_dls_edges(self): - edges = nx.dfs_edges(self.G, source=9, depth_limit=4) - assert list(edges) == [(9, 8), (8, 7), - (7, 2), (2, 1), (2, 3), (9, 10)] - - def test_dls_labeled_edges(self): - edges = list(nx.dfs_labeled_edges(self.G, source=5, depth_limit=1)) - forward = [(u, v) for (u, v, d) in edges if d == 'forward'] - assert forward == [(5, 5), (5, 4), (5, 6)] - - def test_dls_labeled_disconnected_edges(self): - edges = list(nx.dfs_labeled_edges(self.G, source=6, depth_limit=2)) - forward = [(u, v) for (u, v, d) in edges if d == 'forward'] - assert forward == [(6, 6), (6, 5), (5, 4)] diff --git a/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/test_edgebfs.py b/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/test_edgebfs.py deleted file mode 100644 index 93d70038..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/test_edgebfs.py +++ /dev/null @@ -1,130 +0,0 @@ -import pytest - -import networkx as nx - -edge_bfs = nx.edge_bfs - -FORWARD = nx.algorithms.edgedfs.FORWARD -REVERSE = nx.algorithms.edgedfs.REVERSE - - -class TestEdgeBFS(object): - @classmethod - def setup_class(cls): - cls.nodes = [0, 1, 2, 3] - cls.edges = [(0, 1), (1, 0), (1, 0), (2, 0), (2, 1), (3, 1)] - - def test_empty(self): - G = nx.Graph() - edges = list(edge_bfs(G)) - assert edges == [] - - def test_graph_single_source(self): - G = nx.Graph(self.edges) - G.add_edge(4, 5) - x = list(edge_bfs(G, [0])) - x_ = [(0, 1), (0, 2), (1, 2), (1, 3)] - assert x == x_ - - def test_graph(self): - G = nx.Graph(self.edges) - x = list(edge_bfs(G, self.nodes)) - x_ = [(0, 1), (0, 2), (1, 2), (1, 3)] - assert x == x_ - - def test_digraph(self): - G = nx.DiGraph(self.edges) - x = list(edge_bfs(G, self.nodes)) - x_ = [(0, 1), (1, 0), (2, 0), (2, 1), (3, 1)] - assert x == x_ - - def test_digraph_orientation_invalid(self): - G = nx.DiGraph(self.edges) - edge_iterator = edge_bfs(G, self.nodes, orientation='hello') - pytest.raises(nx.NetworkXError, list, edge_iterator) - - def test_digraph_orientation_none(self): - G = nx.DiGraph(self.edges) - x = list(edge_bfs(G, self.nodes, orientation=None)) - x_ = [(0, 1), (1, 0), (2, 0), (2, 1), (3, 1)] - assert x == x_ - - def test_digraph_orientation_original(self): - G = nx.DiGraph(self.edges) - x = list(edge_bfs(G, self.nodes, orientation='original')) - x_ = [(0, 1, FORWARD), (1, 0, FORWARD), (2, 0, FORWARD), - (2, 1, FORWARD), (3, 1, FORWARD)] - assert x == x_ - - def test_digraph2(self): - G = nx.DiGraph() - nx.add_path(G, range(4)) - x = list(edge_bfs(G, [0])) - x_ = [(0, 1), (1, 2), (2, 3)] - assert x == x_ - - def test_digraph_rev(self): - G = nx.DiGraph(self.edges) - x = list(edge_bfs(G, self.nodes, orientation='reverse')) - x_ = [(1, 0, REVERSE), (2, 0, REVERSE), (0, 1, REVERSE), - (2, 1, REVERSE), (3, 1, REVERSE)] - assert x == x_ - - def test_digraph_rev2(self): - G = nx.DiGraph() - nx.add_path(G, range(4)) - x = list(edge_bfs(G, [3], orientation='reverse')) - x_ = [(2, 3, REVERSE), (1, 2, REVERSE), (0, 1, REVERSE)] - assert x == x_ - - def test_multigraph(self): - G = nx.MultiGraph(self.edges) - x = list(edge_bfs(G, self.nodes)) - x_ = [(0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), (1, 2, 0), (1, 3, 0)] - # This is an example of where hash randomization can break. - # There are 3! * 2 alternative outputs, such as: - # [(0, 1, 1), (1, 0, 0), (0, 1, 2), (1, 3, 0), (1, 2, 0)] - # But note, the edges (1,2,0) and (1,3,0) always follow the (0,1,k) - # edges. So the algorithm only guarantees a partial order. A total - # order is guaranteed only if the graph data structures are ordered. - assert x == x_ - - def test_multidigraph(self): - G = nx.MultiDiGraph(self.edges) - x = list(edge_bfs(G, self.nodes)) - x_ = [(0, 1, 0), (1, 0, 0), (1, 0, 1), (2, 0, 0), (2, 1, 0), (3, 1, 0)] - assert x == x_ - - def test_multidigraph_rev(self): - G = nx.MultiDiGraph(self.edges) - x = list(edge_bfs(G, self.nodes, orientation='reverse')) - x_ = [(1, 0, 0, REVERSE), - (1, 0, 1, REVERSE), - (2, 0, 0, REVERSE), - (0, 1, 0, REVERSE), - (2, 1, 0, REVERSE), - (3, 1, 0, REVERSE)] - assert x == x_ - - def test_digraph_ignore(self): - G = nx.DiGraph(self.edges) - x = list(edge_bfs(G, self.nodes, orientation='ignore')) - x_ = [(0, 1, FORWARD), (1, 0, REVERSE), (2, 0, REVERSE), - (2, 1, REVERSE), (3, 1, REVERSE)] - assert x == x_ - - def test_digraph_ignore2(self): - G = nx.DiGraph() - nx.add_path(G, range(4)) - x = list(edge_bfs(G, [0], orientation='ignore')) - x_ = [(0, 1, FORWARD), (1, 2, FORWARD), (2, 3, FORWARD)] - assert x == x_ - - def test_multidigraph_ignore(self): - G = nx.MultiDiGraph(self.edges) - x = list(edge_bfs(G, self.nodes, orientation='ignore')) - x_ = [(0, 1, 0, FORWARD), (1, 0, 0, REVERSE), - (1, 0, 1, REVERSE), (2, 0, 0, REVERSE), - (2, 1, 0, REVERSE), (3, 1, 0, REVERSE), - ] - assert x == x_ diff --git a/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/test_edgedfs.py b/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/test_edgedfs.py deleted file mode 100644 index 9410090b..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/traversal/tests/test_edgedfs.py +++ /dev/null @@ -1,131 +0,0 @@ -import pytest - -import networkx as nx - -edge_dfs = nx.algorithms.edge_dfs - -FORWARD = nx.algorithms.edgedfs.FORWARD -REVERSE = nx.algorithms.edgedfs.REVERSE - -# These tests can fail with hash randomization. The easiest and clearest way -# to write these unit tests is for the edges to be output in an expected total -# order, but we cannot guarantee the order amongst outgoing edges from a node, -# unless each class uses an ordered data structure for neighbors. This is -# painful to do with the current API. The alternative is that the tests are -# written (IMO confusingly) so that there is not a total order over the edges, -# but only a partial order. Due to the small size of the graphs, hopefully -# failures due to hash randomization will not occur. For an example of how -# this can fail, see TestEdgeDFS.test_multigraph. - - -class TestEdgeDFS(object): - @classmethod - def setup_class(cls): - cls.nodes = [0, 1, 2, 3] - cls.edges = [(0, 1), (1, 0), (1, 0), (2, 1), (3, 1)] - - def test_empty(self): - G = nx.Graph() - edges = list(edge_dfs(G)) - assert edges == [] - - def test_graph(self): - G = nx.Graph(self.edges) - x = list(edge_dfs(G, self.nodes)) - x_ = [(0, 1), (1, 2), (1, 3)] - assert x == x_ - - def test_digraph(self): - G = nx.DiGraph(self.edges) - x = list(edge_dfs(G, self.nodes)) - x_ = [(0, 1), (1, 0), (2, 1), (3, 1)] - assert x == x_ - - def test_digraph_orientation_invalid(self): - G = nx.DiGraph(self.edges) - edge_iterator = edge_dfs(G, self.nodes, orientation='hello') - pytest.raises(nx.NetworkXError, list, edge_iterator) - - def test_digraph_orientation_none(self): - G = nx.DiGraph(self.edges) - x = list(edge_dfs(G, self.nodes, orientation=None)) - x_ = [(0, 1), (1, 0), (2, 1), (3, 1)] - assert x == x_ - - def test_digraph_orientation_original(self): - G = nx.DiGraph(self.edges) - x = list(edge_dfs(G, self.nodes, orientation='original')) - x_ = [(0, 1, FORWARD), (1, 0, FORWARD), - (2, 1, FORWARD), (3, 1, FORWARD)] - assert x == x_ - - def test_digraph2(self): - G = nx.DiGraph() - nx.add_path(G, range(4)) - x = list(edge_dfs(G, [0])) - x_ = [(0, 1), (1, 2), (2, 3)] - assert x == x_ - - def test_digraph_rev(self): - G = nx.DiGraph(self.edges) - x = list(edge_dfs(G, self.nodes, orientation='reverse')) - x_ = [(1, 0, REVERSE), (0, 1, REVERSE), - (2, 1, REVERSE), (3, 1, REVERSE)] - assert x == x_ - - def test_digraph_rev2(self): - G = nx.DiGraph() - nx.add_path(G, range(4)) - x = list(edge_dfs(G, [3], orientation='reverse')) - x_ = [(2, 3, REVERSE), (1, 2, REVERSE), (0, 1, REVERSE)] - assert x == x_ - - def test_multigraph(self): - G = nx.MultiGraph(self.edges) - x = list(edge_dfs(G, self.nodes)) - x_ = [(0, 1, 0), (1, 0, 1), (0, 1, 2), (1, 2, 0), (1, 3, 0)] - # This is an example of where hash randomization can break. - # There are 3! * 2 alternative outputs, such as: - # [(0, 1, 1), (1, 0, 0), (0, 1, 2), (1, 3, 0), (1, 2, 0)] - # But note, the edges (1,2,0) and (1,3,0) always follow the (0,1,k) - # edges. So the algorithm only guarantees a partial order. A total - # order is guaranteed only if the graph data structures are ordered. - assert x == x_ - - def test_multidigraph(self): - G = nx.MultiDiGraph(self.edges) - x = list(edge_dfs(G, self.nodes)) - x_ = [(0, 1, 0), (1, 0, 0), (1, 0, 1), (2, 1, 0), (3, 1, 0)] - assert x == x_ - - def test_multidigraph_rev(self): - G = nx.MultiDiGraph(self.edges) - x = list(edge_dfs(G, self.nodes, orientation='reverse')) - x_ = [(1, 0, 0, REVERSE), - (0, 1, 0, REVERSE), - (1, 0, 1, REVERSE), - (2, 1, 0, REVERSE), - (3, 1, 0, REVERSE)] - assert x == x_ - - def test_digraph_ignore(self): - G = nx.DiGraph(self.edges) - x = list(edge_dfs(G, self.nodes, orientation='ignore')) - x_ = [(0, 1, FORWARD), (1, 0, FORWARD), - (2, 1, REVERSE), (3, 1, REVERSE)] - assert x == x_ - - def test_digraph_ignore2(self): - G = nx.DiGraph() - nx.add_path(G, range(4)) - x = list(edge_dfs(G, [0], orientation='ignore')) - x_ = [(0, 1, FORWARD), (1, 2, FORWARD), (2, 3, FORWARD)] - assert x == x_ - - def test_multidigraph_ignore(self): - G = nx.MultiDiGraph(self.edges) - x = list(edge_dfs(G, self.nodes, orientation='ignore')) - x_ = [(0, 1, 0, FORWARD), (1, 0, 0, FORWARD), - (1, 0, 1, REVERSE), (2, 1, 0, REVERSE), - (3, 1, 0, REVERSE)] - assert x == x_ diff --git a/extensions/fablabchemnitz/networkx/algorithms/tree/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/tree/__init__.py deleted file mode 100644 index 0bb8fd44..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tree/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from .branchings import * -from .coding import * -from .mst import * -from .recognition import * -from .operations import * diff --git a/extensions/fablabchemnitz/networkx/algorithms/tree/branchings.py b/extensions/fablabchemnitz/networkx/algorithms/tree/branchings.py deleted file mode 100644 index dde17832..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tree/branchings.py +++ /dev/null @@ -1,711 +0,0 @@ -# encoding: utf-8 -""" -Algorithms for finding optimum branchings and spanning arborescences. - -This implementation is based on: - - J. Edmonds, Optimum branchings, J. Res. Natl. Bur. Standards 71B (1967), - 233–240. URL: http://archive.org/details/jresv71Bn4p233 - -""" -# TODO: Implement method from Gabow, Galil, Spence and Tarjan: -# -#@article{ -# year={1986}, -# issn={0209-9683}, -# journal={Combinatorica}, -# volume={6}, -# number={2}, -# doi={10.1007/BF02579168}, -# title={Efficient algorithms for finding minimum spanning trees in -# undirected and directed graphs}, -# url={https://doi.org/10.1007/BF02579168}, -# publisher={Springer-Verlag}, -# keywords={68 B 15; 68 C 05}, -# author={Gabow, Harold N. and Galil, Zvi and Spencer, Thomas and Tarjan, -# Robert E.}, -# pages={109-122}, -# language={English} -#} - - -import string -import random -from operator import itemgetter - -import networkx as nx -from networkx.utils import py_random_state - -from .recognition import * - -__all__ = [ - 'branching_weight', 'greedy_branching', - 'maximum_branching', 'minimum_branching', - 'maximum_spanning_arborescence', 'minimum_spanning_arborescence', - 'Edmonds' -] - -KINDS = set(['max', 'min']) - -STYLES = { - 'branching': 'branching', - 'arborescence': 'arborescence', - 'spanning arborescence': 'arborescence' -} - -INF = float('inf') - - -@py_random_state(1) -def random_string(L=15, seed=None): - return ''.join([seed.choice(string.ascii_letters) for n in range(L)]) - - -def _min_weight(weight): - return -weight - - -def _max_weight(weight): - return weight - - -def branching_weight(G, attr='weight', default=1): - """ - Returns the total weight of a branching. - - """ - return sum(edge[2].get(attr, default) for edge in G.edges(data=True)) - - -@py_random_state(4) -def greedy_branching(G, attr='weight', default=1, kind='max', seed=None): - """ - Returns a branching obtained through a greedy algorithm. - - This algorithm is wrong, and cannot give a proper optimal branching. - However, we include it for pedagogical reasons, as it can be helpful to - see what its outputs are. - - The output is a branching, and possibly, a spanning arborescence. However, - it is not guaranteed to be optimal in either case. - - Parameters - ---------- - G : DiGraph - The directed graph to scan. - attr : str - The attribute to use as weights. If None, then each edge will be - treated equally with a weight of 1. - default : float - When `attr` is not None, then if an edge does not have that attribute, - `default` specifies what value it should take. - kind : str - The type of optimum to search for: 'min' or 'max' greedy branching. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - B : directed graph - The greedily obtained branching. - - """ - if kind not in KINDS: - raise nx.NetworkXException("Unknown value for `kind`.") - - if kind == 'min': - reverse = False - else: - reverse = True - - if attr is None: - # Generate a random string the graph probably won't have. - attr = random_string(seed=seed) - - edges = [(u, v, data.get(attr, default)) - for (u, v, data) in G.edges(data=True)] - - # We sort by weight, but also by nodes to normalize behavior across runs. - try: - edges.sort(key=itemgetter(2, 0, 1), reverse=reverse) - except TypeError: - # This will fail in Python 3.x if the nodes are of varying types. - # In that case, we use the arbitrary order. - edges.sort(key=itemgetter(2), reverse=reverse) - - # The branching begins with a forest of no edges. - B = nx.DiGraph() - B.add_nodes_from(G) - - # Now we add edges greedily so long we maintain the branching. - uf = nx.utils.UnionFind() - for i, (u, v, w) in enumerate(edges): - if uf[u] == uf[v]: - # Adding this edge would form a directed cycle. - continue - elif B.in_degree(v) == 1: - # The edge would increase the degree to be greater than one. - continue - else: - # If attr was None, then don't insert weights... - data = {} - if attr is not None: - data[attr] = w - B.add_edge(u, v, **data) - uf.union(u, v) - - return B - - -class MultiDiGraph_EdgeKey(nx.MultiDiGraph): - """ - MultiDiGraph which assigns unique keys to every edge. - - Adds a dictionary edge_index which maps edge keys to (u, v, data) tuples. - - This is not a complete implementation. For Edmonds algorithm, we only use - add_node and add_edge, so that is all that is implemented here. During - additions, any specified keys are ignored---this means that you also - cannot update edge attributes through add_node and add_edge. - - Why do we need this? Edmonds algorithm requires that we track edges, even - as we change the head and tail of an edge, and even changing the weight - of edges. We must reliably track edges across graph mutations. - - """ - - def __init__(self, incoming_graph_data=None, **attr): - cls = super(MultiDiGraph_EdgeKey, self) - cls.__init__(incoming_graph_data=incoming_graph_data, **attr) - - self._cls = cls - self.edge_index = {} - - def remove_node(self, n): - keys = set([]) - for keydict in self.pred[n].values(): - keys.update(keydict) - for keydict in self.succ[n].values(): - keys.update(keydict) - - for key in keys: - del self.edge_index[key] - - self._cls.remove_node(n) - - def remove_nodes_from(self, nbunch): - for n in nbunch: - self.remove_node(n) - - def add_edge(self, u_for_edge, v_for_edge, key_for_edge, **attr): - """ - Key is now required. - - """ - u, v, key = u_for_edge, v_for_edge, key_for_edge - if key in self.edge_index: - uu, vv, _ = self.edge_index[key] - if (u != uu) or (v != vv): - raise Exception("Key {0!r} is already in use.".format(key)) - - self._cls.add_edge(u, v, key, **attr) - self.edge_index[key] = (u, v, self.succ[u][v][key]) - - def add_edges_from(self, ebunch_to_add, **attr): - for u, v, k, d in ebunch_to_add: - self.add_edge(u, v, k, **d) - - def remove_edge_with_key(self, key): - try: - u, v, _ = self.edge_index[key] - except KeyError: - raise KeyError('Invalid edge key {0!r}'.format(key)) - else: - del self.edge_index[key] - self._cls.remove_edge(u, v, key) - - def remove_edges_from(self, ebunch): - raise NotImplementedError - - -def get_path(G, u, v): - """ - Returns the edge keys of the unique path between u and v. - - This is not a generic function. G must be a branching and an instance of - MultiDiGraph_EdgeKey. - - """ - nodes = nx.shortest_path(G, u, v) - # We are guaranteed that there is only one edge connected every node - # in the shortest path. - - def first_key(i, vv): - # Needed for 2.x/3.x compatibilitity - keys = G[nodes[i]][vv].keys() - # Normalize behavior - keys = list(keys) - return keys[0] - - edges = [first_key(i, vv) for i, vv in enumerate(nodes[1:])] - return nodes, edges - - -class Edmonds(object): - """ - Edmonds algorithm for finding optimal branchings and spanning arborescences. - - """ - - def __init__(self, G, seed=None): - self.G_original = G - - # Need to fix this. We need the whole tree. - self.store = True - - # The final answer. - self.edges = [] - - # Since we will be creating graphs with new nodes, we need to make - # sure that our node names do not conflict with the real node names. - self.template = random_string(seed=seed) + '_{0}' - - - def _init(self, attr, default, kind, style, preserve_attrs, seed): - if kind not in KINDS: - raise nx.NetworkXException("Unknown value for `kind`.") - - # Store inputs. - self.attr = attr - self.default = default - self.kind = kind - self.style = style - - # Determine how we are going to transform the weights. - if kind == 'min': - self.trans = trans = _min_weight - else: - self.trans = trans = _max_weight - - if attr is None: - # Generate a random attr the graph probably won't have. - attr = random_string(seed=seed) - - # This is the actual attribute used by the algorithm. - self._attr = attr - - # This attribute is used to store whether a particular edge is still - # a candidate. We generate a random attr to remove clashes with - # preserved edges - self.candidate_attr = 'candidate_' + random_string(seed=seed) - - # The object we manipulate at each step is a multidigraph. - self.G = G = MultiDiGraph_EdgeKey() - for key, (u, v, data) in enumerate(self.G_original.edges(data=True)): - d = {attr: trans(data.get(attr, default))} - - if preserve_attrs: - for (d_k, d_v) in data.items(): - if d_k != attr: - d[d_k] = d_v - - G.add_edge(u, v, key, **d) - - self.level = 0 - - # These are the "buckets" from the paper. - # - # As in the paper, G^i are modified versions of the original graph. - # D^i and E^i are nodes and edges of the maximal edges that are - # consistent with G^i. These are dashed edges in figures A-F of the - # paper. In this implementation, we store D^i and E^i together as a - # graph B^i. So we will have strictly more B^i than the paper does. - self.B = MultiDiGraph_EdgeKey() - self.B.edge_index = {} - self.graphs = [] # G^i - self.branchings = [] # B^i - self.uf = nx.utils.UnionFind() - - # A list of lists of edge indexes. Each list is a circuit for graph G^i. - # Note the edge list will not, in general, be a circuit in graph G^0. - self.circuits = [] - # Stores the index of the minimum edge in the circuit found in G^i and B^i. - # The ordering of the edges seems to preserve the weight ordering from G^0. - # So even if the circuit does not form a circuit in G^0, it is still true - # that the minimum edge of the circuit in G^i is still the minimum edge - # in circuit G^0 (depsite their weights being different). - self.minedge_circuit = [] - - def find_optimum(self, attr='weight', default=1, kind='max', - style='branching', preserve_attrs=False, seed=None): - """ - Returns a branching from G. - - Parameters - ---------- - attr : str - The edge attribute used to in determining optimality. - default : float - The value of the edge attribute used if an edge does not have - the attribute `attr`. - kind : {'min', 'max'} - The type of optimum to search for, either 'min' or 'max'. - style : {'branching', 'arborescence'} - If 'branching', then an optimal branching is found. If `style` is - 'arborescence', then a branching is found, such that if the - branching is also an arborescence, then the branching is an - optimal spanning arborescences. A given graph G need not have - an optimal spanning arborescence. - preserve_attrs : bool - If True, preserve the other edge attributes of the original - graph (that are not the one passed to `attr`) - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - H : (multi)digraph - The branching. - - """ - self._init(attr, default, kind, style, preserve_attrs, seed) - uf = self.uf - - # This enormous while loop could use some refactoring... - - G, B = self.G, self.B - D = set([]) - nodes = iter(list(G.nodes())) - attr = self._attr - G_pred = G.pred - - def desired_edge(v): - """ - Find the edge directed toward v with maximal weight. - - """ - edge = None - weight = -INF - for u, _, key, data in G.in_edges(v, data=True, keys=True): - new_weight = data[attr] - if new_weight > weight: - weight = new_weight - edge = (u, v, key, new_weight) - - return edge, weight - - while True: - # (I1): Choose a node v in G^i not in D^i. - try: - v = next(nodes) - except StopIteration: - # If there are no more new nodes to consider, then we *should* - # meet the break condition (b) from the paper: - # (b) every node of G^i is in D^i and E^i is a branching - # Construction guarantees that it's a branching. - assert(len(G) == len(B)) - if len(B): - assert(is_branching(B)) - - if self.store: - self.graphs.append(G.copy()) - self.branchings.append(B.copy()) - - # Add these to keep the lengths equal. Element i is the - # circuit at level i that was merged to form branching i+1. - # There is no circuit for the last level. - self.circuits.append([]) - self.minedge_circuit.append(None) - break - else: - if v in D: - #print("v in D", v) - continue - - # Put v into bucket D^i. - #print("Adding node {0}".format(v)) - D.add(v) - B.add_node(v) - - edge, weight = desired_edge(v) - #print("Max edge is {0!r}".format(edge)) - if edge is None: - # If there is no edge, continue with a new node at (I1). - continue - else: - # Determine if adding the edge to E^i would mean its no longer - # a branching. Presently, v has indegree 0 in B---it is a root. - u = edge[0] - - if uf[u] == uf[v]: - # Then adding the edge will create a circuit. Then B - # contains a unique path P from v to u. So condition (a) - # from the paper does hold. We need to store the circuit - # for future reference. - Q_nodes, Q_edges = get_path(B, v, u) - Q_edges.append(edge[2]) - else: - # Then B with the edge is still a branching and condition - # (a) from the paper does not hold. - Q_nodes, Q_edges = None, None - - # Conditions for adding the edge. - # If weight < 0, then it cannot help in finding a maximum branching. - if self.style == 'branching' and weight <= 0: - acceptable = False - else: - acceptable = True - - #print("Edge is acceptable: {0}".format(acceptable)) - if acceptable: - dd = {attr: weight} - B.add_edge(u, v, edge[2], **dd) - G[u][v][edge[2]][self.candidate_attr] = True - uf.union(u, v) - if Q_edges is not None: - #print("Edge introduced a simple cycle:") - #print(Q_nodes, Q_edges) - - # Move to method - # Previous meaning of u and v is no longer important. - - # Apply (I2). - # Get the edge in the cycle with the minimum weight. - # Also, save the incoming weights for each node. - minweight = INF - minedge = None - Q_incoming_weight = {} - for edge_key in Q_edges: - u, v, data = B.edge_index[edge_key] - w = data[attr] - Q_incoming_weight[v] = w - if w < minweight: - minweight = w - minedge = edge_key - - self.circuits.append(Q_edges) - self.minedge_circuit.append(minedge) - - if self.store: - self.graphs.append(G.copy()) - # Always need the branching with circuits. - self.branchings.append(B.copy()) - - # Now we mutate it. - new_node = self.template.format(self.level) - - #print(minweight, minedge, Q_incoming_weight) - - G.add_node(new_node) - new_edges = [] - for u, v, key, data in G.edges(data=True, keys=True): - if u in Q_incoming_weight: - if v in Q_incoming_weight: - # Circuit edge, do nothing for now. - # Eventually delete it. - continue - else: - # Outgoing edge. Make it from new node - dd = data.copy() - new_edges.append((new_node, v, key, dd)) - else: - if v in Q_incoming_weight: - # Incoming edge. Change its weight - w = data[attr] - w += minweight - Q_incoming_weight[v] - dd = data.copy() - dd[attr] = w - new_edges.append((u, new_node, key, dd)) - else: - # Outside edge. No modification necessary. - continue - - G.remove_nodes_from(Q_nodes) - B.remove_nodes_from(Q_nodes) - D.difference_update(set(Q_nodes)) - - for u, v, key, data in new_edges: - G.add_edge(u, v, key, **data) - if self.candidate_attr in data: - del data[self.candidate_attr] - B.add_edge(u, v, key, **data) - uf.union(u, v) - - nodes = iter(list(G.nodes())) - self.level += 1 - - # (I3) Branch construction. - # print(self.level) - H = self.G_original.__class__() - - def is_root(G, u, edgekeys): - """ - Returns True if `u` is a root node in G. - - Node `u` will be a root node if its in-degree, restricted to the - specified edges, is equal to 0. - - """ - if u not in G: - #print(G.nodes(), u) - raise Exception('{0!r} not in G'.format(u)) - for v in G.pred[u]: - for edgekey in G.pred[u][v]: - if edgekey in edgekeys: - return False, edgekey - else: - return True, None - - # Start with the branching edges in the last level. - edges = set(self.branchings[self.level].edge_index) - while self.level > 0: - self.level -= 1 - - # The current level is i, and we start counting from 0. - - # We need the node at level i+1 that results from merging a circuit - # at level i. randomname_0 is the first merged node and this - # happens at level 1. That is, randomname_0 is a node at level 1 - # that results from merging a circuit at level 0. - merged_node = self.template.format(self.level) - - # The circuit at level i that was merged as a node the graph - # at level i+1. - circuit = self.circuits[self.level] - # print - #print(merged_node, self.level, circuit) - #print("before", edges) - # Note, we ask if it is a root in the full graph, not the branching. - # The branching alone doesn't have all the edges. - - isroot, edgekey = is_root(self.graphs[self.level + 1], - merged_node, edges) - edges.update(circuit) - if isroot: - minedge = self.minedge_circuit[self.level] - if minedge is None: - raise Exception - - # Remove the edge in the cycle with minimum weight. - edges.remove(minedge) - else: - # We have identified an edge at next higher level that - # transitions into the merged node at the level. That edge - # transitions to some corresponding node at the current level. - # We want to remove an edge from the cycle that transitions - # into the corresponding node. - #print("edgekey is: ", edgekey) - #print("circuit is: ", circuit) - # The branching at level i - G = self.graphs[self.level] - # print(G.edge_index) - target = G.edge_index[edgekey][1] - for edgekey in circuit: - u, v, data = G.edge_index[edgekey] - if v == target: - break - else: - raise Exception("Couldn't find edge incoming to merged node.") - #print("not a root. removing {0}".format(edgekey)) - - edges.remove(edgekey) - - self.edges = edges - - H.add_nodes_from(self.G_original) - for edgekey in edges: - u, v, d = self.graphs[0].edge_index[edgekey] - dd = {self.attr: self.trans(d[self.attr])} - - # Optionally, preserve the other edge attributes of the original - # graph - if preserve_attrs: - for (key, value) in d.items(): - if key not in [self.attr, self.candidate_attr]: - dd[key] = value - - # TODO: make this preserve the key. - H.add_edge(u, v, **dd) - - return H - - -def maximum_branching(G, attr='weight', default=1, preserve_attrs=False): - ed = Edmonds(G) - B = ed.find_optimum(attr, default, kind='max', style='branching', - preserve_attrs=preserve_attrs) - return B - - -def minimum_branching(G, attr='weight', default=1, preserve_attrs=False): - ed = Edmonds(G) - B = ed.find_optimum(attr, default, kind='min', style='branching', - preserve_attrs=preserve_attrs) - return B - - -def maximum_spanning_arborescence(G, attr='weight', default=1, - preserve_attrs=False): - ed = Edmonds(G) - B = ed.find_optimum(attr, default, kind='max', style='arborescence', - preserve_attrs=preserve_attrs) - if not is_arborescence(B): - msg = 'No maximum spanning arborescence in G.' - raise nx.exception.NetworkXException(msg) - return B - - -def minimum_spanning_arborescence(G, attr='weight', default=1, - preserve_attrs=False): - ed = Edmonds(G) - B = ed.find_optimum(attr, default, kind='min', style='arborescence', - preserve_attrs=preserve_attrs) - if not is_arborescence(B): - msg = 'No minimum spanning arborescence in G.' - raise nx.exception.NetworkXException(msg) - return B - - -docstring_branching = """ -Returns a {kind} {style} from G. - -Parameters ----------- -G : (multi)digraph-like - The graph to be searched. -attr : str - The edge attribute used to in determining optimality. -default : float - The value of the edge attribute used if an edge does not have - the attribute `attr`. -preserve_attrs : bool - If True, preserve the other attributes of the original graph (that are not - passed to `attr`) - -Returns -------- -B : (multi)digraph-like - A {kind} {style}. -""" - -docstring_arborescence = docstring_branching + """ -Raises ------- -NetworkXException - If the graph does not contain a {kind} {style}. - -""" - -maximum_branching.__doc__ = \ - docstring_branching.format(kind='maximum', style='branching') - -minimum_branching.__doc__ = \ - docstring_branching.format(kind='minimum', style='branching') - -maximum_spanning_arborescence.__doc__ = \ - docstring_arborescence.format(kind='maximum', style='spanning arborescence') - -minimum_spanning_arborescence.__doc__ = \ - docstring_arborescence.format(kind='minimum', style='spanning arborescence') diff --git a/extensions/fablabchemnitz/networkx/algorithms/tree/coding.py b/extensions/fablabchemnitz/networkx/algorithms/tree/coding.py deleted file mode 100644 index 30c44fb4..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tree/coding.py +++ /dev/null @@ -1,403 +0,0 @@ -# -*- encoding: utf-8 -*- -# -# coding.py - functions for encoding and decoding trees as sequences -# -# Copyright 2015-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Functions for encoding and decoding trees. - -Since a tree is a highly restricted form of graph, it can be represented -concisely in several ways. This module includes functions for encoding -and decoding trees in the form of nested tuples and Prüfer -sequences. The former requires a rooted tree, whereas the latter can be -applied to unrooted trees. Furthermore, there is a bijection from Prüfer -sequences to labeled trees. - -""" -from collections import Counter -from itertools import chain - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ['from_nested_tuple', 'from_prufer_sequence', 'NotATree', - 'to_nested_tuple', 'to_prufer_sequence'] - - -class NotATree(nx.NetworkXException): - """Raised when a function expects a tree (that is, a connected - undirected graph with no cycles) but gets a non-tree graph as input - instead. - - """ - - -@not_implemented_for('directed') -def to_nested_tuple(T, root, canonical_form=False): - """Returns a nested tuple representation of the given tree. - - The nested tuple representation of a tree is defined - recursively. The tree with one node and no edges is represented by - the empty tuple, ``()``. A tree with ``k`` subtrees is represented - by a tuple of length ``k`` in which each element is the nested tuple - representation of a subtree. - - Parameters - ---------- - T : NetworkX graph - An undirected graph object representing a tree. - - root : node - The node in ``T`` to interpret as the root of the tree. - - canonical_form : bool - If ``True``, each tuple is sorted so that the function returns - a canonical form for rooted trees. This means "lighter" subtrees - will appear as nested tuples before "heavier" subtrees. In this - way, each isomorphic rooted tree has the same nested tuple - representation. - - Returns - ------- - tuple - A nested tuple representation of the tree. - - Notes - ----- - This function is *not* the inverse of :func:`from_nested_tuple`; the - only guarantee is that the rooted trees are isomorphic. - - See also - -------- - from_nested_tuple - to_prufer_sequence - - Examples - -------- - The tree need not be a balanced binary tree:: - - >>> T = nx.Graph() - >>> T.add_edges_from([(0, 1), (0, 2), (0, 3)]) - >>> T.add_edges_from([(1, 4), (1, 5)]) - >>> T.add_edges_from([(3, 6), (3, 7)]) - >>> root = 0 - >>> nx.to_nested_tuple(T, root) - (((), ()), (), ((), ())) - - Continuing the above example, if ``canonical_form`` is ``True``, the - nested tuples will be sorted:: - - >>> nx.to_nested_tuple(T, root, canonical_form=True) - ((), ((), ()), ((), ())) - - Even the path graph can be interpreted as a tree:: - - >>> T = nx.path_graph(4) - >>> root = 0 - >>> nx.to_nested_tuple(T, root) - ((((),),),) - - """ - - def _make_tuple(T, root, _parent): - """Recursively compute the nested tuple representation of the - given rooted tree. - - ``_parent`` is the parent node of ``root`` in the supertree in - which ``T`` is a subtree, or ``None`` if ``root`` is the root of - the supertree. This argument is used to determine which - neighbors of ``root`` are children and which is the parent. - - """ - # Get the neighbors of `root` that are not the parent node. We - # are guaranteed that `root` is always in `T` by construction. - children = set(T[root]) - {_parent} - if len(children) == 0: - return () - nested = (_make_tuple(T, v, root) for v in children) - if canonical_form: - nested = sorted(nested) - return tuple(nested) - - # Do some sanity checks on the input. - if not nx.is_tree(T): - raise nx.NotATree('provided graph is not a tree') - if root not in T: - raise nx.NodeNotFound('Graph {} contains no node {}'.format(T, root)) - - return _make_tuple(T, root, None) - - -def from_nested_tuple(sequence, sensible_relabeling=False): - """Returns the rooted tree corresponding to the given nested tuple. - - The nested tuple representation of a tree is defined - recursively. The tree with one node and no edges is represented by - the empty tuple, ``()``. A tree with ``k`` subtrees is represented - by a tuple of length ``k`` in which each element is the nested tuple - representation of a subtree. - - Parameters - ---------- - sequence : tuple - A nested tuple representing a rooted tree. - - sensible_relabeling : bool - Whether to relabel the nodes of the tree so that nodes are - labeled in increasing order according to their breadth-first - search order from the root node. - - Returns - ------- - NetworkX graph - The tree corresponding to the given nested tuple, whose root - node is node 0. If ``sensible_labeling`` is ``True``, nodes will - be labeled in breadth-first search order starting from the root - node. - - Notes - ----- - This function is *not* the inverse of :func:`to_nested_tuple`; the - only guarantee is that the rooted trees are isomorphic. - - See also - -------- - to_nested_tuple - from_prufer_sequence - - Examples - -------- - Sensible relabeling ensures that the nodes are labeled from the root - starting at 0:: - - >>> balanced = (((), ()), ((), ())) - >>> T = nx.from_nested_tuple(balanced, sensible_relabeling=True) - >>> edges = [(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)] - >>> all((u, v) in T.edges() or (v, u) in T.edges() for (u, v) in edges) - True - - """ - - def _make_tree(sequence): - """Recursively creates a tree from the given sequence of nested - tuples. - - This function employs the :func:`~networkx.tree.join` function - to recursively join subtrees into a larger tree. - - """ - # The empty sequence represents the empty tree, which is the - # (unique) graph with a single node. We mark the single node - # with an attribute that indicates that it is the root of the - # graph. - if len(sequence) == 0: - return nx.empty_graph(1) - # For a nonempty sequence, get the subtrees for each child - # sequence and join all the subtrees at their roots. After - # joining the subtrees, the root is node 0. - return nx.tree.join([(_make_tree(child), 0) for child in sequence]) - - # Make the tree and remove the `is_root` node attribute added by the - # helper function. - T = _make_tree(sequence) - if sensible_relabeling: - # Relabel the nodes according to their breadth-first search - # order, starting from the root node (that is, the node 0). - bfs_nodes = chain([0], (v for u, v in nx.bfs_edges(T, 0))) - labels = {v: i for i, v in enumerate(bfs_nodes)} - # We would like to use `copy=False`, but `relabel_nodes` doesn't - # allow a relabel mapping that can't be topologically sorted. - T = nx.relabel_nodes(T, labels) - return T - - -@not_implemented_for('directed') -def to_prufer_sequence(T): - r"""Returns the Prüfer sequence of the given tree. - - A *Prüfer sequence* is a list of *n* - 2 numbers between 0 and - *n* - 1, inclusive. The tree corresponding to a given Prüfer - sequence can be recovered by repeatedly joining a node in the - sequence with a node with the smallest potential degree according to - the sequence. - - Parameters - ---------- - T : NetworkX graph - An undirected graph object representing a tree. - - Returns - ------- - list - The Prüfer sequence of the given tree. - - Raises - ------ - NetworkXPointlessConcept - If the number of nodes in `T` is less than two. - - NotATree - If `T` is not a tree. - - KeyError - If the set of nodes in `T` is not {0, …, *n* - 1}. - - Notes - ----- - There is a bijection from labeled trees to Prüfer sequences. This - function is the inverse of the :func:`from_prufer_sequence` - function. - - Sometimes Prüfer sequences use nodes labeled from 1 to *n* instead - of from 0 to *n* - 1. This function requires nodes to be labeled in - the latter form. You can use :func:`~networkx.relabel_nodes` to - relabel the nodes of your tree to the appropriate format. - - This implementation is from [1]_ and has a running time of - $O(n)$. - - See also - -------- - to_nested_tuple - from_prufer_sequence - - References - ---------- - .. [1] Wang, Xiaodong, Lei Wang, and Yingjie Wu. - "An optimal algorithm for Prufer codes." - *Journal of Software Engineering and Applications* 2.02 (2009): 111. - - - Examples - -------- - There is a bijection between Prüfer sequences and labeled trees, so - this function is the inverse of the :func:`from_prufer_sequence` - function: - - >>> edges = [(0, 3), (1, 3), (2, 3), (3, 4), (4, 5)] - >>> tree = nx.Graph(edges) - >>> sequence = nx.to_prufer_sequence(tree) - >>> sequence - [3, 3, 3, 4] - >>> tree2 = nx.from_prufer_sequence(sequence) - >>> list(tree2.edges()) == edges - True - - """ - # Perform some sanity checks on the input. - n = len(T) - if n < 2: - msg = 'Prüfer sequence undefined for trees with fewer than two nodes' - raise nx.NetworkXPointlessConcept(msg) - if not nx.is_tree(T): - raise nx.NotATree('provided graph is not a tree') - if set(T) != set(range(n)): - raise KeyError('tree must have node labels {0, ..., n - 1}') - - degree = dict(T.degree()) - - def parents(u): - return next(v for v in T[u] if degree[v] > 1) - - index = u = next(k for k in range(n) if degree[k] == 1) - result = [] - for i in range(n - 2): - v = parents(u) - result.append(v) - degree[v] -= 1 - if v < index and degree[v] == 1: - u = v - else: - index = u = next(k for k in range(index + 1, n) if degree[k] == 1) - return result - - -def from_prufer_sequence(sequence): - r"""Returns the tree corresponding to the given Prüfer sequence. - - A *Prüfer sequence* is a list of *n* - 2 numbers between 0 and - *n* - 1, inclusive. The tree corresponding to a given Prüfer - sequence can be recovered by repeatedly joining a node in the - sequence with a node with the smallest potential degree according to - the sequence. - - Parameters - ---------- - sequence : list - A Prüfer sequence, which is a list of *n* - 2 integers between - zero and *n* - 1, inclusive. - - Returns - ------- - NetworkX graph - The tree corresponding to the given Prüfer sequence. - - Notes - ----- - There is a bijection from labeled trees to Prüfer sequences. This - function is the inverse of the :func:`from_prufer_sequence` function. - - Sometimes Prüfer sequences use nodes labeled from 1 to *n* instead - of from 0 to *n* - 1. This function requires nodes to be labeled in - the latter form. You can use :func:`networkx.relabel_nodes` to - relabel the nodes of your tree to the appropriate format. - - This implementation is from [1]_ and has a running time of - $O(n)$. - - References - ---------- - .. [1] Wang, Xiaodong, Lei Wang, and Yingjie Wu. - "An optimal algorithm for Prufer codes." - *Journal of Software Engineering and Applications* 2.02 (2009): 111. - - - See also - -------- - from_nested_tuple - to_prufer_sequence - - Examples - -------- - There is a bijection between Prüfer sequences and labeled trees, so - this function is the inverse of the :func:`to_prufer_sequence` - function: - - >>> edges = [(0, 3), (1, 3), (2, 3), (3, 4), (4, 5)] - >>> tree = nx.Graph(edges) - >>> sequence = nx.to_prufer_sequence(tree) - >>> sequence - [3, 3, 3, 4] - >>> tree2 = nx.from_prufer_sequence(sequence) - >>> list(tree2.edges()) == edges - True - - """ - n = len(sequence) + 2 - # `degree` stores the remaining degree (plus one) for each node. The - # degree of a node in the decoded tree is one more than the number - # of times it appears in the code. - degree = Counter(chain(sequence, range(n))) - T = nx.empty_graph(n) - # `not_orphaned` is the set of nodes that have a parent in the - # tree. After the loop, there should be exactly two nodes that are - # not in this set. - not_orphaned = set() - index = u = next(k for k in range(n) if degree[k] == 1) - for v in sequence: - T.add_edge(u, v) - not_orphaned.add(u) - degree[v] -= 1 - if v < index and degree[v] == 1: - u = v - else: - index = u = next(k for k in range(index + 1, n) if degree[k] == 1) - # At this point, there must be exactly two orphaned nodes; join them. - orphans = set(T) - not_orphaned - u, v = orphans - T.add_edge(u, v) - return T diff --git a/extensions/fablabchemnitz/networkx/algorithms/tree/mst.py b/extensions/fablabchemnitz/networkx/algorithms/tree/mst.py deleted file mode 100644 index e77a0d9f..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tree/mst.py +++ /dev/null @@ -1,611 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2017 NetworkX Developers -# Aric Hagberg -# Dan Schult -# Pieter Swart -# Loïc Séguin-C. -# All rights reserved. -# BSD license. -""" -Algorithms for calculating min/max spanning trees/forests. - -""" -from heapq import heappop, heappush -from operator import itemgetter -from itertools import count -from math import isnan - -import networkx as nx -from networkx.utils import UnionFind, not_implemented_for - -__all__ = [ - 'minimum_spanning_edges', 'maximum_spanning_edges', - 'minimum_spanning_tree', 'maximum_spanning_tree', -] - - -@not_implemented_for('multigraph') -def boruvka_mst_edges(G, minimum=True, weight='weight', - keys=False, data=True, ignore_nan=False): - """Iterate over edges of a Borůvka's algorithm min/max spanning tree. - - Parameters - ---------- - G : NetworkX Graph - The edges of `G` must have distinct weights, - otherwise the edges may not form a tree. - - minimum : bool (default: True) - Find the minimum (True) or maximum (False) spanning tree. - - weight : string (default: 'weight') - The name of the edge attribute holding the edge weights. - - keys : bool (default: True) - This argument is ignored since this function is not - implemented for multigraphs; it exists only for consistency - with the other minimum spanning tree functions. - - data : bool (default: True) - Flag for whether to yield edge attribute dicts. - If True, yield edges `(u, v, d)`, where `d` is the attribute dict. - If False, yield edges `(u, v)`. - - ignore_nan : bool (default: False) - If a NaN is found as an edge weight normally an exception is raised. - If `ignore_nan is True` then that edge is ignored instead. - - """ - # Initialize a forest, assuming initially that it is the discrete - # partition of the nodes of the graph. - forest = UnionFind(G) - - def best_edge(component): - """Returns the optimum (minimum or maximum) edge on the edge - boundary of the given set of nodes. - - A return value of ``None`` indicates an empty boundary. - - """ - sign = 1 if minimum else -1 - minwt = float('inf') - boundary = None - for e in nx.edge_boundary(G, component, data=True): - wt = e[-1].get(weight, 1) * sign - if isnan(wt): - if ignore_nan: - continue - msg = "NaN found as an edge weight. Edge %s" - raise ValueError(msg % (e,)) - if wt < minwt: - minwt = wt - boundary = e - return boundary - - # Determine the optimum edge in the edge boundary of each component - # in the forest. - best_edges = (best_edge(component) for component in forest.to_sets()) - best_edges = [edge for edge in best_edges if edge is not None] - # If each entry was ``None``, that means the graph was disconnected, - # so we are done generating the forest. - while best_edges: - # Determine the optimum edge in the edge boundary of each - # component in the forest. - # - # This must be a sequence, not an iterator. In this list, the - # same edge may appear twice, in different orientations (but - # that's okay, since a union operation will be called on the - # endpoints the first time it is seen, but not the second time). - # - # Any ``None`` indicates that the edge boundary for that - # component was empty, so that part of the forest has been - # completed. - # - # TODO This can be parallelized, both in the outer loop over - # each component in the forest and in the computation of the - # minimum. (Same goes for the identical lines outside the loop.) - best_edges = (best_edge(component) for component in forest.to_sets()) - best_edges = [edge for edge in best_edges if edge is not None] - # Join trees in the forest using the best edges, and yield that - # edge, since it is part of the spanning tree. - # - # TODO This loop can be parallelized, to an extent (the union - # operation must be atomic). - for u, v, d in best_edges: - if forest[u] != forest[v]: - if data: - yield u, v, d - else: - yield u, v - forest.union(u, v) - - -def kruskal_mst_edges(G, minimum, weight='weight', - keys=True, data=True, ignore_nan=False): - """Iterate over edges of a Kruskal's algorithm min/max spanning tree. - - Parameters - ---------- - G : NetworkX Graph - The graph holding the tree of interest. - - minimum : bool (default: True) - Find the minimum (True) or maximum (False) spanning tree. - - weight : string (default: 'weight') - The name of the edge attribute holding the edge weights. - - keys : bool (default: True) - If `G` is a multigraph, `keys` controls whether edge keys ar yielded. - Otherwise `keys` is ignored. - - data : bool (default: True) - Flag for whether to yield edge attribute dicts. - If True, yield edges `(u, v, d)`, where `d` is the attribute dict. - If False, yield edges `(u, v)`. - - ignore_nan : bool (default: False) - If a NaN is found as an edge weight normally an exception is raised. - If `ignore_nan is True` then that edge is ignored instead. - - """ - subtrees = UnionFind() - if G.is_multigraph(): - edges = G.edges(keys=True, data=True) - - def filter_nan_edges(edges=edges, weight=weight): - sign = 1 if minimum else -1 - for u, v, k, d in edges: - wt = d.get(weight, 1) * sign - if isnan(wt): - if ignore_nan: - continue - msg = "NaN found as an edge weight. Edge %s" - raise ValueError(msg % ((u, v, k, d),)) - yield wt, u, v, k, d - else: - edges = G.edges(data=True) - - def filter_nan_edges(edges=edges, weight=weight): - sign = 1 if minimum else -1 - for u, v, d in edges: - wt = d.get(weight, 1) * sign - if isnan(wt): - if ignore_nan: - continue - msg = "NaN found as an edge weight. Edge %s" - raise ValueError(msg % ((u, v, d),)) - yield wt, u, v, d - edges = sorted(filter_nan_edges(), key=itemgetter(0)) - # Multigraphs need to handle edge keys in addition to edge data. - if G.is_multigraph(): - for wt, u, v, k, d in edges: - if subtrees[u] != subtrees[v]: - if keys: - if data: - yield u, v, k, d - else: - yield u, v, k - else: - if data: - yield u, v, d - else: - yield u, v - subtrees.union(u, v) - else: - for wt, u, v, d in edges: - if subtrees[u] != subtrees[v]: - if data: - yield (u, v, d) - else: - yield (u, v) - subtrees.union(u, v) - - -def prim_mst_edges(G, minimum, weight='weight', - keys=True, data=True, ignore_nan=False): - """Iterate over edges of Prim's algorithm min/max spanning tree. - - Parameters - ---------- - G : NetworkX Graph - The graph holding the tree of interest. - - minimum : bool (default: True) - Find the minimum (True) or maximum (False) spanning tree. - - weight : string (default: 'weight') - The name of the edge attribute holding the edge weights. - - keys : bool (default: True) - If `G` is a multigraph, `keys` controls whether edge keys ar yielded. - Otherwise `keys` is ignored. - - data : bool (default: True) - Flag for whether to yield edge attribute dicts. - If True, yield edges `(u, v, d)`, where `d` is the attribute dict. - If False, yield edges `(u, v)`. - - ignore_nan : bool (default: False) - If a NaN is found as an edge weight normally an exception is raised. - If `ignore_nan is True` then that edge is ignored instead. - - """ - is_multigraph = G.is_multigraph() - push = heappush - pop = heappop - - nodes = set(G) - c = count() - - sign = 1 if minimum else -1 - - while nodes: - u = nodes.pop() - frontier = [] - visited = {u} - if is_multigraph: - for v, keydict in G.adj[u].items(): - for k, d in keydict.items(): - wt = d.get(weight, 1) * sign - if isnan(wt): - if ignore_nan: - continue - msg = "NaN found as an edge weight. Edge %s" - raise ValueError(msg % ((u, v, k, d),)) - push(frontier, (wt, next(c), u, v, k, d)) - else: - for v, d in G.adj[u].items(): - wt = d.get(weight, 1) * sign - if isnan(wt): - if ignore_nan: - continue - msg = "NaN found as an edge weight. Edge %s" - raise ValueError(msg % ((u, v, d),)) - push(frontier, (wt, next(c), u, v, d)) - while frontier: - if is_multigraph: - W, _, u, v, k, d = pop(frontier) - else: - W, _, u, v, d = pop(frontier) - if v in visited or v not in nodes: - continue - # Multigraphs need to handle edge keys in addition to edge data. - if is_multigraph and keys: - if data: - yield u, v, k, d - else: - yield u, v, k - else: - if data: - yield u, v, d - else: - yield u, v - # update frontier - visited.add(v) - nodes.discard(v) - if is_multigraph: - for w, keydict in G.adj[v].items(): - if w in visited: - continue - for k2, d2 in keydict.items(): - new_weight = d2.get(weight, 1) * sign - push(frontier, (new_weight, next(c), v, w, k2, d2)) - else: - for w, d2 in G.adj[v].items(): - if w in visited: - continue - new_weight = d2.get(weight, 1) * sign - push(frontier, (new_weight, next(c), v, w, d2)) - - -ALGORITHMS = { - 'boruvka': boruvka_mst_edges, - u'borůvka': boruvka_mst_edges, - 'kruskal': kruskal_mst_edges, - 'prim': prim_mst_edges -} - - -@not_implemented_for('directed') -def minimum_spanning_edges(G, algorithm='kruskal', weight='weight', - keys=True, data=True, ignore_nan=False): - """Generate edges in a minimum spanning forest of an undirected - weighted graph. - - A minimum spanning tree is a subgraph of the graph (a tree) - with the minimum sum of edge weights. A spanning forest is a - union of the spanning trees for each connected component of the graph. - - Parameters - ---------- - G : undirected Graph - An undirected graph. If `G` is connected, then the algorithm finds a - spanning tree. Otherwise, a spanning forest is found. - - algorithm : string - The algorithm to use when finding a minimum spanning tree. Valid - choices are 'kruskal', 'prim', or 'boruvka'. The default is 'kruskal'. - - weight : string - Edge data key to use for weight (default 'weight'). - - keys : bool - Whether to yield edge key in multigraphs in addition to the edge. - If `G` is not a multigraph, this is ignored. - - data : bool, optional - If True yield the edge data along with the edge. - - ignore_nan : bool (default: False) - If a NaN is found as an edge weight normally an exception is raised. - If `ignore_nan is True` then that edge is ignored instead. - - Returns - ------- - edges : iterator - An iterator over edges in a maximum spanning tree of `G`. - Edges connecting nodes `u` and `v` are represented as tuples: - `(u, v, k, d)` or `(u, v, k)` or `(u, v, d)` or `(u, v)` - - If `G` is a multigraph, `keys` indicates whether the edge key `k` will - be reported in the third position in the edge tuple. `data` indicates - whether the edge datadict `d` will appear at the end of the edge tuple. - - If `G` is not a multigraph, the tuples are `(u, v, d)` if `data` is True - or `(u, v)` if `data` is False. - - Examples - -------- - >>> from networkx.algorithms import tree - - Find minimum spanning edges by Kruskal's algorithm - - >>> G = nx.cycle_graph(4) - >>> G.add_edge(0, 3, weight=2) - >>> mst = tree.minimum_spanning_edges(G, algorithm='kruskal', data=False) - >>> edgelist = list(mst) - >>> sorted(sorted(e) for e in edgelist) - [[0, 1], [1, 2], [2, 3]] - - Find minimum spanning edges by Prim's algorithm - - >>> G = nx.cycle_graph(4) - >>> G.add_edge(0, 3, weight=2) - >>> mst = tree.minimum_spanning_edges(G, algorithm='prim', data=False) - >>> edgelist = list(mst) - >>> sorted(sorted(e) for e in edgelist) - [[0, 1], [1, 2], [2, 3]] - - Notes - ----- - For Borůvka's algorithm, each edge must have a weight attribute, and - each edge weight must be distinct. - - For the other algorithms, if the graph edges do not have a weight - attribute a default weight of 1 will be used. - - Modified code from David Eppstein, April 2006 - http://www.ics.uci.edu/~eppstein/PADS/ - - """ - try: - algo = ALGORITHMS[algorithm] - except KeyError: - msg = '{} is not a valid choice for an algorithm.'.format(algorithm) - raise ValueError(msg) - - return algo(G, minimum=True, weight=weight, keys=keys, data=data, - ignore_nan=ignore_nan) - - -@not_implemented_for('directed') -def maximum_spanning_edges(G, algorithm='kruskal', weight='weight', - keys=True, data=True, ignore_nan=False): - """Generate edges in a maximum spanning forest of an undirected - weighted graph. - - A maximum spanning tree is a subgraph of the graph (a tree) - with the maximum possible sum of edge weights. A spanning forest is a - union of the spanning trees for each connected component of the graph. - - Parameters - ---------- - G : undirected Graph - An undirected graph. If `G` is connected, then the algorithm finds a - spanning tree. Otherwise, a spanning forest is found. - - algorithm : string - The algorithm to use when finding a maximum spanning tree. Valid - choices are 'kruskal', 'prim', or 'boruvka'. The default is 'kruskal'. - - weight : string - Edge data key to use for weight (default 'weight'). - - keys : bool - Whether to yield edge key in multigraphs in addition to the edge. - If `G` is not a multigraph, this is ignored. - - data : bool, optional - If True yield the edge data along with the edge. - - ignore_nan : bool (default: False) - If a NaN is found as an edge weight normally an exception is raised. - If `ignore_nan is True` then that edge is ignored instead. - - Returns - ------- - edges : iterator - An iterator over edges in a maximum spanning tree of `G`. - Edges connecting nodes `u` and `v` are represented as tuples: - `(u, v, k, d)` or `(u, v, k)` or `(u, v, d)` or `(u, v)` - - If `G` is a multigraph, `keys` indicates whether the edge key `k` will - be reported in the third position in the edge tuple. `data` indicates - whether the edge datadict `d` will appear at the end of the edge tuple. - - If `G` is not a multigraph, the tuples are `(u, v, d)` if `data` is True - or `(u, v)` if `data` is False. - - Examples - -------- - >>> from networkx.algorithms import tree - - Find maximum spanning edges by Kruskal's algorithm - - >>> G = nx.cycle_graph(4) - >>> G.add_edge(0, 3, weight=2) - >>> mst = tree.maximum_spanning_edges(G, algorithm='kruskal', data=False) - >>> edgelist = list(mst) - >>> sorted(sorted(e) for e in edgelist) - [[0, 1], [0, 3], [1, 2]] - - Find maximum spanning edges by Prim's algorithm - - >>> G = nx.cycle_graph(4) - >>> G.add_edge(0, 3, weight=2) # assign weight 2 to edge 0-3 - >>> mst = tree.maximum_spanning_edges(G, algorithm='prim', data=False) - >>> edgelist = list(mst) - >>> sorted(sorted(e) for e in edgelist) - [[0, 1], [0, 3], [2, 3]] - - Notes - ----- - For Borůvka's algorithm, each edge must have a weight attribute, and - each edge weight must be distinct. - - For the other algorithms, if the graph edges do not have a weight - attribute a default weight of 1 will be used. - - Modified code from David Eppstein, April 2006 - http://www.ics.uci.edu/~eppstein/PADS/ - """ - try: - algo = ALGORITHMS[algorithm] - except KeyError: - msg = '{} is not a valid choice for an algorithm.'.format(algorithm) - raise ValueError(msg) - - return algo(G, minimum=False, weight=weight, keys=keys, data=data, - ignore_nan=ignore_nan) - - -def minimum_spanning_tree(G, weight='weight', algorithm='kruskal', - ignore_nan=False): - """Returns a minimum spanning tree or forest on an undirected graph `G`. - - Parameters - ---------- - G : undirected graph - An undirected graph. If `G` is connected, then the algorithm finds a - spanning tree. Otherwise, a spanning forest is found. - - weight : str - Data key to use for edge weights. - - algorithm : string - The algorithm to use when finding a minimum spanning tree. Valid - choices are 'kruskal', 'prim', or 'boruvka'. The default is - 'kruskal'. - - ignore_nan : bool (default: False) - If a NaN is found as an edge weight normally an exception is raised. - If `ignore_nan is True` then that edge is ignored instead. - - Returns - ------- - G : NetworkX Graph - A minimum spanning tree or forest. - - Examples - -------- - >>> G = nx.cycle_graph(4) - >>> G.add_edge(0, 3, weight=2) - >>> T = nx.minimum_spanning_tree(G) - >>> sorted(T.edges(data=True)) - [(0, 1, {}), (1, 2, {}), (2, 3, {})] - - - Notes - ----- - For Borůvka's algorithm, each edge must have a weight attribute, and - each edge weight must be distinct. - - For the other algorithms, if the graph edges do not have a weight - attribute a default weight of 1 will be used. - - There may be more than one tree with the same minimum or maximum weight. - See :mod:`networkx.tree.recognition` for more detailed definitions. - - Isolated nodes with self-loops are in the tree as edgeless isolated nodes. - - """ - edges = minimum_spanning_edges(G, algorithm, weight, keys=True, - data=True, ignore_nan=ignore_nan) - T = G.__class__() # Same graph class as G - T.graph.update(G.graph) - T.add_nodes_from(G.nodes.items()) - T.add_edges_from(edges) - return T - - -def maximum_spanning_tree(G, weight='weight', algorithm='kruskal', - ignore_nan=False): - """Returns a maximum spanning tree or forest on an undirected graph `G`. - - Parameters - ---------- - G : undirected graph - An undirected graph. If `G` is connected, then the algorithm finds a - spanning tree. Otherwise, a spanning forest is found. - - weight : str - Data key to use for edge weights. - - algorithm : string - The algorithm to use when finding a maximum spanning tree. Valid - choices are 'kruskal', 'prim', or 'boruvka'. The default is - 'kruskal'. - - ignore_nan : bool (default: False) - If a NaN is found as an edge weight normally an exception is raised. - If `ignore_nan is True` then that edge is ignored instead. - - - Returns - ------- - G : NetworkX Graph - A maximum spanning tree or forest. - - - Examples - -------- - >>> G = nx.cycle_graph(4) - >>> G.add_edge(0, 3, weight=2) - >>> T = nx.maximum_spanning_tree(G) - >>> sorted(T.edges(data=True)) - [(0, 1, {}), (0, 3, {'weight': 2}), (1, 2, {})] - - - Notes - ----- - For Borůvka's algorithm, each edge must have a weight attribute, and - each edge weight must be distinct. - - For the other algorithms, if the graph edges do not have a weight - attribute a default weight of 1 will be used. - - There may be more than one tree with the same minimum or maximum weight. - See :mod:`networkx.tree.recognition` for more detailed definitions. - - Isolated nodes with self-loops are in the tree as edgeless isolated nodes. - - """ - edges = maximum_spanning_edges(G, algorithm, weight, keys=True, - data=True, ignore_nan=ignore_nan) - edges = list(edges) - T = G.__class__() # Same graph class as G - T.graph.update(G.graph) - T.add_nodes_from(G.nodes.items()) - T.add_edges_from(edges) - return T diff --git a/extensions/fablabchemnitz/networkx/algorithms/tree/operations.py b/extensions/fablabchemnitz/networkx/algorithms/tree/operations.py deleted file mode 100644 index a65f7ff7..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tree/operations.py +++ /dev/null @@ -1,110 +0,0 @@ -# operations.py - binary operations on trees -# -# Copyright 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Operations on trees.""" -from functools import partial -from itertools import chain - -import networkx as nx -from networkx.utils import accumulate - -__all__ = ['join'] - - -def join(rooted_trees, label_attribute=None): - """Returns a new rooted tree with a root node joined with the roots - of each of the given rooted trees. - - Parameters - ---------- - rooted_trees : list - A list of pairs in which each left element is a NetworkX graph - object representing a tree and each right element is the root - node of that tree. The nodes of these trees will be relabeled to - integers. - - label_attribute : str - If provided, the old node labels will be stored in the new tree - under this node attribute. If not provided, the node attribute - ``'_old'`` will store the original label of the node in the - rooted trees given in the input. - - Returns - ------- - NetworkX graph - The rooted tree whose subtrees are the given rooted trees. The - new root node is labeled 0. Each non-root node has an attribute, - as described under the keyword argument ``label_attribute``, - that indicates the label of the original node in the input tree. - - Notes - ----- - Graph, edge, and node attributes are propagated from the given - rooted trees to the created tree. If there are any overlapping graph - attributes, those from later trees will overwrite those from earlier - trees in the tuple of positional arguments. - - Examples - -------- - Join two full balanced binary trees of height *h* to get a full - balanced binary tree of depth *h* + 1:: - - >>> h = 4 - >>> left = nx.balanced_tree(2, h) - >>> right = nx.balanced_tree(2, h) - >>> joined_tree = nx.join([(left, 0), (right, 0)]) - >>> nx.is_isomorphic(joined_tree, nx.balanced_tree(2, h + 1)) - True - - """ - if len(rooted_trees) == 0: - return nx.empty_graph(1) - - # Unzip the zipped list of (tree, root) pairs. - trees, roots = zip(*rooted_trees) - - # The join of the trees has the same type as the type of the first - # tree. - R = type(trees[0])() - - # Relabel the nodes so that their union is the integers starting at 1. - if label_attribute is None: - label_attribute = '_old' - relabel = partial(nx.convert_node_labels_to_integers, - label_attribute=label_attribute) - lengths = (len(tree) for tree in trees[:-1]) - first_labels = chain([0], accumulate(lengths)) - trees = [relabel(tree, first_label=first_label + 1) - for tree, first_label in zip(trees, first_labels)] - - # Get the relabeled roots. - roots = [next(v for v, d in tree.nodes(data=True) if d.get('_old') == root) - for tree, root in zip(trees, roots)] - - # Remove the old node labels. - for tree in trees: - for v in tree: - tree.nodes[v].pop('_old') - - # Add all sets of nodes and edges, with data. - nodes = (tree.nodes(data=True) for tree in trees) - edges = (tree.edges(data=True) for tree in trees) - R.add_nodes_from(chain.from_iterable(nodes)) - R.add_edges_from(chain.from_iterable(edges)) - - # Add graph attributes; later attributes take precedent over earlier - # attributes. - for tree in trees: - R.graph.update(tree.graph) - - # Finally, join the subtrees at the root. We know 0 is unused by the - # way we relabeled the subtrees. - R.add_node(0) - R.add_edges_from((0, root) for root in roots) - - return R diff --git a/extensions/fablabchemnitz/networkx/algorithms/tree/recognition.py b/extensions/fablabchemnitz/networkx/algorithms/tree/recognition.py deleted file mode 100644 index d29002d8..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tree/recognition.py +++ /dev/null @@ -1,226 +0,0 @@ -#-*- coding: utf-8 -*- -""" -Recognition Tests -================= - -A *forest* is an acyclic, undirected graph, and a *tree* is a connected forest. -Depending on the subfield, there are various conventions for generalizing these -definitions to directed graphs. - -In one convention, directed variants of forest and tree are defined in an -identical manner, except that the direction of the edges is ignored. In effect, -each directed edge is treated as a single undirected edge. Then, additional -restrictions are imposed to define *branchings* and *arborescences*. - -In another convention, directed variants of forest and tree correspond to -the previous convention's branchings and arborescences, respectively. Then two -new terms, *polyforest* and *polytree*, are defined to correspond to the other -convention's forest and tree. - -Summarizing:: - - +-----------------------------+ - | Convention A | Convention B | - +=============================+ - | forest | polyforest | - | tree | polytree | - | branching | forest | - | arborescence | tree | - +-----------------------------+ - -Each convention has its reasons. The first convention emphasizes definitional -similarity in that directed forests and trees are only concerned with -acyclicity and do not have an in-degree constraint, just as their undirected -counterparts do not. The second convention emphasizes functional similarity -in the sense that the directed analog of a spanning tree is a spanning -arborescence. That is, take any spanning tree and choose one node as the root. -Then every edge is assigned a direction such there is a directed path from the -root to every other node. The result is a spanning arborescence. - -NetworkX follows convention "A". Explicitly, these are: - -undirected forest - An undirected graph with no undirected cycles. - -undirected tree - A connected, undirected forest. - -directed forest - A directed graph with no undirected cycles. Equivalently, the underlying - graph structure (which ignores edge orientations) is an undirected forest. - In convention B, this is known as a polyforest. - -directed tree - A weakly connected, directed forest. Equivalently, the underlying graph - structure (which ignores edge orientations) is an undirected tree. In - convention B, this is known as a polytree. - -branching - A directed forest with each node having, at most, one parent. So the maximum - in-degree is equal to 1. In convention B, this is known as a forest. - -arborescence - A directed tree with each node having, at most, one parent. So the maximum - in-degree is equal to 1. In convention B, this is known as a tree. - -For trees and arborescences, the adjective "spanning" may be added to designate -that the graph, when considered as a forest/branching, consists of a single -tree/arborescence that includes all nodes in the graph. It is true, by -definition, that every tree/arborescence is spanning with respect to the nodes -that define the tree/arborescence and so, it might seem redundant to introduce -the notion of "spanning". However, the nodes may represent a subset of -nodes from a larger graph, and it is in this context that the term "spanning" -becomes a useful notion. - -""" - -import networkx as nx - -__author__ = """\n""".join([ - 'Ferdinando Papale ', - 'chebee7i ', -]) - - -__all__ = ['is_arborescence', 'is_branching', 'is_forest', 'is_tree'] - - -@nx.utils.not_implemented_for('undirected') -def is_arborescence(G): - """ - Returns True if `G` is an arborescence. - - An arborescence is a directed tree with maximum in-degree equal to 1. - - Parameters - ---------- - G : graph - The graph to test. - - Returns - ------- - b : bool - A boolean that is True if `G` is an arborescence. - - Notes - ----- - In another convention, an arborescence is known as a *tree*. - - See Also - -------- - is_tree - - """ - return is_tree(G) and max(d for n, d in G.in_degree()) <= 1 - - -@nx.utils.not_implemented_for('undirected') -def is_branching(G): - """ - Returns True if `G` is a branching. - - A branching is a directed forest with maximum in-degree equal to 1. - - Parameters - ---------- - G : directed graph - The directed graph to test. - - Returns - ------- - b : bool - A boolean that is True if `G` is a branching. - - Notes - ----- - In another convention, a branching is also known as a *forest*. - - See Also - -------- - is_forest - - """ - return is_forest(G) and max(d for n, d in G.in_degree()) <= 1 - - -def is_forest(G): - """ - Returns True if `G` is a forest. - - A forest is a graph with no undirected cycles. - - For directed graphs, `G` is a forest if the underlying graph is a forest. - The underlying graph is obtained by treating each directed edge as a single - undirected edge in a multigraph. - - Parameters - ---------- - G : graph - The graph to test. - - Returns - ------- - b : bool - A boolean that is True if `G` is a forest. - - Notes - ----- - In another convention, a directed forest is known as a *polyforest* and - then *forest* corresponds to a *branching*. - - See Also - -------- - is_branching - - """ - if len(G) == 0: - raise nx.exception.NetworkXPointlessConcept('G has no nodes.') - - if G.is_directed(): - components = (G.subgraph(c) for c in nx.weakly_connected_components(G)) - else: - components = (G.subgraph(c) for c in nx.connected_components(G)) - - return all(len(c) - 1 == c.number_of_edges() for c in components) - - -def is_tree(G): - """ - Returns True if `G` is a tree. - - A tree is a connected graph with no undirected cycles. - - For directed graphs, `G` is a tree if the underlying graph is a tree. The - underlying graph is obtained by treating each directed edge as a single - undirected edge in a multigraph. - - Parameters - ---------- - G : graph - The graph to test. - - Returns - ------- - b : bool - A boolean that is True if `G` is a tree. - - Notes - ----- - In another convention, a directed tree is known as a *polytree* and then - *tree* corresponds to an *arborescence*. - - See Also - -------- - is_arborescence - - """ - if len(G) == 0: - raise nx.exception.NetworkXPointlessConcept('G has no nodes.') - - if G.is_directed(): - is_connected = nx.is_weakly_connected - else: - is_connected = nx.is_connected - - # A connected graph with no cycles has n-1 edges. - return len(G) - 1 == G.number_of_edges() and is_connected(G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tree/tests/__init__.py b/extensions/fablabchemnitz/networkx/algorithms/tree/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/algorithms/tree/tests/test_branchings.py b/extensions/fablabchemnitz/networkx/algorithms/tree/tests/test_branchings.py deleted file mode 100644 index ba83a47d..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tree/tests/test_branchings.py +++ /dev/null @@ -1,384 +0,0 @@ -import pytest -np = pytest.importorskip('numpy') - -import networkx as nx - - -from networkx.algorithms.tree import branchings -from networkx.algorithms.tree import recognition -from networkx.testing import * - -# -# Explicitly discussed examples from Edmonds paper. -# - -# Used in Figures A-F. -# -G_array = np.array([ - # 0 1 2 3 4 5 6 7 8 - [0, 0, 12, 0, 12, 0, 0, 0, 0], # 0 - [4, 0, 0, 0, 0, 13, 0, 0, 0], # 1 - [0, 17, 0, 21, 0, 12, 0, 0, 0], # 2 - [5, 0, 0, 0, 17, 0, 18, 0, 0], # 3 - [0, 0, 0, 0, 0, 0, 0, 12, 0], # 4 - [0, 0, 0, 0, 0, 0, 14, 0, 12], # 5 - [0, 0, 21, 0, 0, 0, 0, 0, 15], # 6 - [0, 0, 0, 19, 0, 0, 15, 0, 0], # 7 - [0, 0, 0, 0, 0, 0, 0, 18, 0], # 8 -], dtype=int) - -# We convert to MultiDiGraph after using from_numpy_matrix -# https://github.com/networkx/networkx/pull/1305 - - -def G1(): - G = nx.DiGraph() - G = nx.from_numpy_matrix(G_array, create_using=G) - G = nx.MultiDiGraph(G) - return G - - -def G2(): - # Now we shift all the weights by -10. - # Should not affect optimal arborescence, but does affect optimal branching. - G = nx.DiGraph() - Garr = G_array.copy() - Garr[np.nonzero(Garr)] -= 10 - G = nx.from_numpy_matrix(Garr, create_using=G) - G = nx.MultiDiGraph(G) - return G - - -# An optimal branching for G1 that is also a spanning arborescence. So it is -# also an optimal spanning arborescence. -# -optimal_arborescence_1 = [ - (0, 2, 12), (2, 1, 17), (2, 3, 21), (1, 5, 13), - (3, 4, 17), (3, 6, 18), (6, 8, 15), (8, 7, 18), -] - -# For G2, the optimal branching of G1 (with shifted weights) is no longer -# an optimal branching, but it is still an optimal spanning arborescence -# (just with shifted weights). An optimal branching for G2 is similar to what -# appears in figure G (this is greedy_subopt_branching_1a below), but with the -# edge (3, 0, 5), which is now (3, 0, -5), removed. Thus, the optimal branching -# is not a spanning arborescence. The code finds optimal_branching_2a. -# An alternative and equivalent branching is optimal_branching_2b. We would -# need to modify the code to iterate through all equivalent optimal branchings. -# -# These are maximal branchings or arborescences. -optimal_branching_2a = [ - (5, 6, 4), (6, 2, 11), (6, 8, 5), (8, 7, 8), - (2, 1, 7), (2, 3, 11), (3, 4, 7), -] -optimal_branching_2b = [ - (8, 7, 8), (7, 3, 9), (3, 4, 7), (3, 6, 8), - (6, 2, 11), (2, 1, 7), (1, 5, 3), -] -optimal_arborescence_2 = [ - (0, 2, 2), (2, 1, 7), (2, 3, 11), (1, 5, 3), - (3, 4, 7), (3, 6, 8), (6, 8, 5), (8, 7, 8), -] - -# Two suboptimal maximal branchings on G1 obtained from a greedy algorithm. -# 1a matches what is shown in Figure G in Edmonds's paper. -greedy_subopt_branching_1a = [ - (5, 6, 14), (6, 2, 21), (6, 8, 15), (8, 7, 18), - (2, 1, 17), (2, 3, 21), (3, 0, 5), (3, 4, 17), -] -greedy_subopt_branching_1b = [ - (8, 7, 18), (7, 6, 15), (6, 2, 21), (2, 1, 17), - (2, 3, 21), (1, 5, 13), (3, 0, 5), (3, 4, 17), -] - - -def build_branching(edges): - G = nx.DiGraph() - for u, v, weight in edges: - G.add_edge(u, v, weight=weight) - return G - - -def sorted_edges(G, attr='weight', default=1): - edges = [(u, v, data.get(attr, default)) for (u, v, data) in G.edges(data=True)] - edges = sorted(edges, key=lambda x: (x[2], x[1], x[0])) - return edges - - -def assert_equal_branchings(G1, G2, attr='weight', default=1): - edges1 = list(G1.edges(data=True)) - edges2 = list(G2.edges(data=True)) - assert len(edges1) == len(edges2) - - # Grab the weights only. - e1 = sorted_edges(G1, attr, default) - e2 = sorted_edges(G2, attr, default) - - # If we have an exception, let's see the edges. - print(e1) - print(e2) - print - - for a, b in zip(e1, e2): - assert a[:2] == b[:2] - np.testing.assert_almost_equal(a[2], b[2]) - - -################ - -def test_optimal_branching1(): - G = build_branching(optimal_arborescence_1) - assert recognition.is_arborescence(G), True - assert branchings.branching_weight(G) == 131 - - -def test_optimal_branching2a(): - G = build_branching(optimal_branching_2a) - assert recognition.is_arborescence(G), True - assert branchings.branching_weight(G) == 53 - - -def test_optimal_branching2b(): - G = build_branching(optimal_branching_2b) - assert recognition.is_arborescence(G), True - assert branchings.branching_weight(G) == 53 - - -def test_optimal_arborescence2(): - G = build_branching(optimal_arborescence_2) - assert recognition.is_arborescence(G), True - assert branchings.branching_weight(G) == 51 - - -def test_greedy_suboptimal_branching1a(): - G = build_branching(greedy_subopt_branching_1a) - assert recognition.is_arborescence(G), True - assert branchings.branching_weight(G) == 128 - - -def test_greedy_suboptimal_branching1b(): - G = build_branching(greedy_subopt_branching_1b) - assert recognition.is_arborescence(G), True - assert branchings.branching_weight(G) == 127 - - -def test_greedy_max1(): - # Standard test. - # - G = G1() - B = branchings.greedy_branching(G) - # There are only two possible greedy branchings. The sorting is such - # that it should equal the second suboptimal branching: 1b. - B_ = build_branching(greedy_subopt_branching_1b) - assert_equal_branchings(B, B_) - - -def test_greedy_max2(): - # Different default weight. - # - G = G1() - del G[1][0][0]['weight'] - B = branchings.greedy_branching(G, default=6) - # Chosen so that edge (3,0,5) is not selected and (1,0,6) is instead. - - edges = [ - (1, 0, 6), (1, 5, 13), (7, 6, 15), (2, 1, 17), - (3, 4, 17), (8, 7, 18), (2, 3, 21), (6, 2, 21), - ] - B_ = build_branching(edges) - assert_equal_branchings(B, B_) - - -def test_greedy_max3(): - # All equal weights. - # - G = G1() - B = branchings.greedy_branching(G, attr=None) - - # This is mostly arbitrary...the output was generated by running the algo. - edges = [ - (2, 1, 1), (3, 0, 1), (3, 4, 1), (5, 8, 1), - (6, 2, 1), (7, 3, 1), (7, 6, 1), (8, 7, 1), - ] - B_ = build_branching(edges) - assert_equal_branchings(B, B_, default=1) - - -def test_greedy_min(): - G = G1() - B = branchings.greedy_branching(G, kind='min') - - edges = [ - (1, 0, 4), (0, 2, 12), (0, 4, 12), (2, 5, 12), - (4, 7, 12), (5, 8, 12), (5, 6, 14), (7, 3, 19) - ] - B_ = build_branching(edges) - assert_equal_branchings(B, B_) - - -def test_edmonds1_maxbranch(): - G = G1() - x = branchings.maximum_branching(G) - x_ = build_branching(optimal_arborescence_1) - assert_equal_branchings(x, x_) - - -def test_edmonds1_maxarbor(): - G = G1() - x = branchings.maximum_spanning_arborescence(G) - x_ = build_branching(optimal_arborescence_1) - assert_equal_branchings(x, x_) - - -def test_edmonds2_maxbranch(): - G = G2() - x = branchings.maximum_branching(G) - x_ = build_branching(optimal_branching_2a) - assert_equal_branchings(x, x_) - - -def test_edmonds2_maxarbor(): - G = G2() - x = branchings.maximum_spanning_arborescence(G) - x_ = build_branching(optimal_arborescence_2) - assert_equal_branchings(x, x_) - - -def test_edmonds2_minarbor(): - G = G1() - x = branchings.minimum_spanning_arborescence(G) - # This was obtained from algorithm. Need to verify it independently. - # Branch weight is: 96 - edges = [ - (3, 0, 5), (0, 2, 12), (0, 4, 12), (2, 5, 12), - (4, 7, 12), (5, 8, 12), (5, 6, 14), (2, 1, 17) - ] - x_ = build_branching(edges) - assert_equal_branchings(x, x_) - - -def test_edmonds3_minbranch1(): - G = G1() - x = branchings.minimum_branching(G) - edges = [] - x_ = build_branching(edges) - assert_equal_branchings(x, x_) - - -def test_edmonds3_minbranch2(): - G = G1() - G.add_edge(8, 9, weight=-10) - x = branchings.minimum_branching(G) - edges = [(8, 9, -10)] - x_ = build_branching(edges) - assert_equal_branchings(x, x_) - -# Need more tests - - -def test_mst(): - # Make sure we get the same results for undirected graphs. - # Example from: https://en.wikipedia.org/wiki/Kruskal's_algorithm - G = nx.Graph() - edgelist = [(0, 3, [('weight', 5)]), - (0, 1, [('weight', 7)]), - (1, 3, [('weight', 9)]), - (1, 2, [('weight', 8)]), - (1, 4, [('weight', 7)]), - (3, 4, [('weight', 15)]), - (3, 5, [('weight', 6)]), - (2, 4, [('weight', 5)]), - (4, 5, [('weight', 8)]), - (4, 6, [('weight', 9)]), - (5, 6, [('weight', 11)])] - G.add_edges_from(edgelist) - G = G.to_directed() - x = branchings.minimum_spanning_arborescence(G) - - edges = [(set([0, 1]), 7), (set([0, 3]), 5), (set([3, 5]), 6), - (set([1, 4]), 7), (set([4, 2]), 5), (set([4, 6]), 9)] - - assert x.number_of_edges() == len(edges) - for u, v, d in x.edges(data=True): - assert (set([u, v]), d['weight']) in edges - - -def test_mixed_nodetypes(): - # Smoke test to make sure no TypeError is raised for mixed node types. - G = nx.Graph() - edgelist = [(0, 3, [('weight', 5)]), - (0, '1', [('weight', 5)])] - G.add_edges_from(edgelist) - G = G.to_directed() - x = branchings.minimum_spanning_arborescence(G) - - -def test_edmonds1_minbranch(): - # Using -G_array and min should give the same as optimal_arborescence_1, - # but with all edges negative. - edges = [(u, v, -w) for (u, v, w) in optimal_arborescence_1] - - G = nx.DiGraph() - G = nx.from_numpy_matrix(-G_array, create_using=G) - - # Quickly make sure max branching is empty. - x = branchings.maximum_branching(G) - x_ = build_branching([]) - assert_equal_branchings(x, x_) - - # Now test the min branching. - x = branchings.minimum_branching(G) - x_ = build_branching(edges) - assert_equal_branchings(x, x_) - - -def test_edge_attribute_preservation_normal_graph(): - # Test that edge attributes are preserved when finding an optimum graph - # using the Edmonds class for normal graphs. - G = nx.Graph() - - edgelist = [(0, 1, [('weight', 5), ('otherattr', 1), ('otherattr2', 3)]), - (0, 2, [('weight', 5), ('otherattr', 2), ('otherattr2', 2)]), - (1, 2, [('weight', 6), ('otherattr', 3), ('otherattr2', 1)])] - G.add_edges_from(edgelist) - - ed = branchings.Edmonds(G) - B = ed.find_optimum('weight', preserve_attrs=True, seed=1) - - assert B[0][1]['otherattr'] == 1 - assert B[0][1]['otherattr2'] == 3 - - -def test_edge_attribute_preservation_multigraph(): - - # Test that edge attributes are preserved when finding an optimum graph - # using the Edmonds class for multigraphs. - G = nx.MultiGraph() - - edgelist = [(0, 1, [('weight', 5), ('otherattr', 1), ('otherattr2', 3)]), - (0, 2, [('weight', 5), ('otherattr', 2), ('otherattr2', 2)]), - (1, 2, [('weight', 6), ('otherattr', 3), ('otherattr2', 1)])] - G.add_edges_from(edgelist * 2) # Make sure we have duplicate edge paths - - ed = branchings.Edmonds(G) - B = ed.find_optimum('weight', preserve_attrs=True) - - assert B[0][1][0]['otherattr'] == 1 - assert B[0][1][0]['otherattr2'] == 3 - - -def test_edge_attribute_discard(): - # Test that edge attributes are discarded if we do not specify to keep them - G = nx.Graph() - - edgelist = [(0, 1, [('weight', 5), ('otherattr', 1), ('otherattr2', 3)]), - (0, 2, [('weight', 5), ('otherattr', 2), ('otherattr2', 2)]), - (1, 2, [('weight', 6), ('otherattr', 3), ('otherattr2', 1)])] - G.add_edges_from(edgelist) - - ed = branchings.Edmonds(G) - B = ed.find_optimum('weight', preserve_attrs=False) - - edge_dict = B[0][1] - with pytest.raises(KeyError): - _ = edge_dict['otherattr'] diff --git a/extensions/fablabchemnitz/networkx/algorithms/tree/tests/test_coding.py b/extensions/fablabchemnitz/networkx/algorithms/tree/tests/test_coding.py deleted file mode 100644 index 8fc5d634..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tree/tests/test_coding.py +++ /dev/null @@ -1,126 +0,0 @@ -# -*- encoding: utf-8 -*- -# test_coding.py - unit tests for the coding module -# -# Copyright 2015-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`~networkx.algorithms.tree.coding` module.""" -from itertools import product - -import pytest -import networkx as nx -from networkx.testing import assert_nodes_equal -from networkx.testing import assert_edges_equal - - -class TestPruferSequence(object): - """Unit tests for the Prüfer sequence encoding and decoding - functions. - - """ - - def test_nontree(self): - with pytest.raises(nx.NotATree): - G = nx.cycle_graph(3) - nx.to_prufer_sequence(G) - - def test_null_graph(self): - with pytest.raises(nx.NetworkXPointlessConcept): - nx.to_prufer_sequence(nx.null_graph()) - - def test_trivial_graph(self): - with pytest.raises(nx.NetworkXPointlessConcept): - nx.to_prufer_sequence(nx.trivial_graph()) - - def test_bad_integer_labels(self): - with pytest.raises(KeyError): - T = nx.Graph(nx.utils.pairwise('abc')) - nx.to_prufer_sequence(T) - - def test_encoding(self): - """Tests for encoding a tree as a Prüfer sequence using the - iterative strategy. - - """ - # Example from Wikipedia. - tree = nx.Graph([(0, 3), (1, 3), (2, 3), (3, 4), (4, 5)]) - sequence = nx.to_prufer_sequence(tree) - assert sequence == [3, 3, 3, 4] - - def test_decoding(self): - """Tests for decoding a tree from a Prüfer sequence.""" - # Example from Wikipedia. - sequence = [3, 3, 3, 4] - tree = nx.from_prufer_sequence(sequence) - assert_nodes_equal(list(tree), list(range(6))) - edges = [(0, 3), (1, 3), (2, 3), (3, 4), (4, 5)] - assert_edges_equal(list(tree.edges()), edges) - - def test_decoding2(self): - # Example from "An Optimal Algorithm for Prufer Codes". - sequence = [2, 4, 0, 1, 3, 3] - tree = nx.from_prufer_sequence(sequence) - assert_nodes_equal(list(tree), list(range(8))) - edges = [(0, 1), (0, 4), (1, 3), (2, 4), (2, 5), (3, 6), (3, 7)] - assert_edges_equal(list(tree.edges()), edges) - - def test_inverse(self): - """Tests that the encoding and decoding functions are inverses. - - """ - for T in nx.nonisomorphic_trees(4): - T2 = nx.from_prufer_sequence(nx.to_prufer_sequence(T)) - assert_nodes_equal(list(T), list(T2)) - assert_edges_equal(list(T.edges()), list(T2.edges())) - - for seq in product(range(4), repeat=2): - seq2 = nx.to_prufer_sequence(nx.from_prufer_sequence(seq)) - assert list(seq) == seq2 - - -class TestNestedTuple(object): - """Unit tests for the nested tuple encoding and decoding functions. - - """ - - def test_nontree(self): - with pytest.raises(nx.NotATree): - G = nx.cycle_graph(3) - nx.to_nested_tuple(G, 0) - - def test_unknown_root(self): - with pytest.raises(nx.NodeNotFound): - G = nx.path_graph(2) - nx.to_nested_tuple(G, 'bogus') - - def test_encoding(self): - T = nx.full_rary_tree(2, 2 ** 3 - 1) - expected = (((), ()), ((), ())) - actual = nx.to_nested_tuple(T, 0) - assert_nodes_equal(expected, actual) - - def test_canonical_form(self): - T = nx.Graph() - T.add_edges_from([(0, 1), (0, 2), (0, 3)]) - T.add_edges_from([(1, 4), (1, 5)]) - T.add_edges_from([(3, 6), (3, 7)]) - root = 0 - actual = nx.to_nested_tuple(T, root, canonical_form=True) - expected = ((), ((), ()), ((), ())) - assert actual == expected - - def test_decoding(self): - balanced = (((), ()), ((), ())) - expected = nx.full_rary_tree(2, 2 ** 3 - 1) - actual = nx.from_nested_tuple(balanced) - assert nx.is_isomorphic(expected, actual) - - def test_sensible_relabeling(self): - balanced = (((), ()), ((), ())) - T = nx.from_nested_tuple(balanced, sensible_relabeling=True) - edges = [(0, 1), (0, 2), (1, 3), (1, 4), (2, 5), (2, 6)] - assert_nodes_equal(list(T), list(range(2 ** 3 - 1))) - assert_edges_equal(list(T.edges()), edges) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tree/tests/test_mst.py b/extensions/fablabchemnitz/networkx/algorithms/tree/tests/test_mst.py deleted file mode 100644 index b22f42fb..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tree/tests/test_mst.py +++ /dev/null @@ -1,256 +0,0 @@ -# -*- encoding: utf-8 -*- -# test_mst.py - unit tests for minimum spanning tree functions -# -# Copyright 2016-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.tree.mst` module.""" -from unittest import TestCase - -import pytest - -import networkx as nx -from networkx.testing import (assert_graphs_equal, assert_nodes_equal, - assert_edges_equal) - - -def test_unknown_algorithm(): - with pytest.raises(ValueError): - nx.minimum_spanning_tree(nx.Graph(), algorithm='random') - - -class MinimumSpanningTreeTestBase(object): - """Base class for test classes for minimum spanning tree algorithms. - - This class contains some common tests that will be inherited by - subclasses. Each subclass must have a class attribute - :data:`algorithm` that is a string representing the algorithm to - run, as described under the ``algorithm`` keyword argument for the - :func:`networkx.minimum_spanning_edges` function. Subclasses can - then implement any algorithm-specific tests. - - """ - - def setup_method(self, method): - """Creates an example graph and stores the expected minimum and - maximum spanning tree edges. - - """ - # This stores the class attribute `algorithm` in an instance attribute. - self.algo = self.algorithm - # This example graph comes from Wikipedia: - # https://en.wikipedia.org/wiki/Kruskal's_algorithm - edges = [(0, 1, 7), (0, 3, 5), (1, 2, 8), (1, 3, 9), (1, 4, 7), - (2, 4, 5), (3, 4, 15), (3, 5, 6), (4, 5, 8), (4, 6, 9), - (5, 6, 11)] - self.G = nx.Graph() - self.G.add_weighted_edges_from(edges) - self.minimum_spanning_edgelist = [(0, 1, {'weight': 7}), - (0, 3, {'weight': 5}), - (1, 4, {'weight': 7}), - (2, 4, {'weight': 5}), - (3, 5, {'weight': 6}), - (4, 6, {'weight': 9})] - self.maximum_spanning_edgelist = [(0, 1, {'weight': 7}), - (1, 2, {'weight': 8}), - (1, 3, {'weight': 9}), - (3, 4, {'weight': 15}), - (4, 6, {'weight': 9}), - (5, 6, {'weight': 11})] - - def test_minimum_edges(self): - edges = nx.minimum_spanning_edges(self.G, algorithm=self.algo) - # Edges from the spanning edges functions don't come in sorted - # orientation, so we need to sort each edge individually. - actual = sorted((min(u, v), max(u, v), d) for u, v, d in edges) - assert_edges_equal(actual, self.minimum_spanning_edgelist) - - def test_maximum_edges(self): - edges = nx.maximum_spanning_edges(self.G, algorithm=self.algo) - # Edges from the spanning edges functions don't come in sorted - # orientation, so we need to sort each edge individually. - actual = sorted((min(u, v), max(u, v), d) for u, v, d in edges) - assert_edges_equal(actual, self.maximum_spanning_edgelist) - - def test_without_data(self): - edges = nx.minimum_spanning_edges(self.G, algorithm=self.algo, - data=False) - # Edges from the spanning edges functions don't come in sorted - # orientation, so we need to sort each edge individually. - actual = sorted((min(u, v), max(u, v)) for u, v in edges) - expected = [(u, v) for u, v, d in self.minimum_spanning_edgelist] - assert_edges_equal(actual, expected) - - def test_nan_weights(self): - # Edge weights NaN never appear in the spanning tree. see #2164 - G = self.G - G.add_edge(0, 12, weight=float('nan')) - edges = nx.minimum_spanning_edges(G, algorithm=self.algo, - data=False, ignore_nan=True) - actual = sorted((min(u, v), max(u, v)) for u, v in edges) - expected = [(u, v) for u, v, d in self.minimum_spanning_edgelist] - assert_edges_equal(actual, expected) - # Now test for raising exception - edges = nx.minimum_spanning_edges(G, algorithm=self.algo, - data=False, ignore_nan=False) - with pytest.raises(ValueError): - list(edges) - # test default for ignore_nan as False - edges = nx.minimum_spanning_edges(G, algorithm=self.algo, data=False) - with pytest.raises(ValueError): - list(edges) - - def test_nan_weights_order(self): - # now try again with a nan edge at the beginning of G.nodes - edges = [(0, 1, 7), (0, 3, 5), (1, 2, 8), (1, 3, 9), (1, 4, 7), - (2, 4, 5), (3, 4, 15), (3, 5, 6), (4, 5, 8), (4, 6, 9), - (5, 6, 11)] - G = nx.Graph() - G.add_weighted_edges_from([(u + 1, v + 1, wt) for u, v, wt in edges]) - G.add_edge(0, 7, weight=float('nan')) - edges = nx.minimum_spanning_edges(G, algorithm=self.algo, - data=False, ignore_nan=True) - actual = sorted((min(u, v), max(u, v)) for u, v in edges) - shift = [(u + 1, v + 1) for u, v, d in self.minimum_spanning_edgelist] - assert_edges_equal(actual, shift) - - def test_isolated_node(self): - # now try again with an isolated node - edges = [(0, 1, 7), (0, 3, 5), (1, 2, 8), (1, 3, 9), (1, 4, 7), - (2, 4, 5), (3, 4, 15), (3, 5, 6), (4, 5, 8), (4, 6, 9), - (5, 6, 11)] - G = nx.Graph() - G.add_weighted_edges_from([(u + 1, v + 1, wt) for u, v, wt in edges]) - G.add_node(0) - edges = nx.minimum_spanning_edges(G, algorithm=self.algo, - data=False, ignore_nan=True) - actual = sorted((min(u, v), max(u, v)) for u, v in edges) - shift = [(u + 1, v + 1) for u, v, d in self.minimum_spanning_edgelist] - assert_edges_equal(actual, shift) - - def test_minimum_tree(self): - T = nx.minimum_spanning_tree(self.G, algorithm=self.algo) - actual = sorted(T.edges(data=True)) - assert_edges_equal(actual, self.minimum_spanning_edgelist) - - def test_maximum_tree(self): - T = nx.maximum_spanning_tree(self.G, algorithm=self.algo) - actual = sorted(T.edges(data=True)) - assert_edges_equal(actual, self.maximum_spanning_edgelist) - - def test_disconnected(self): - G = nx.Graph([(0, 1, dict(weight=1)), (2, 3, dict(weight=2))]) - T = nx.minimum_spanning_tree(G, algorithm=self.algo) - assert_nodes_equal(list(T), list(range(4))) - assert_edges_equal(list(T.edges()), [(0, 1), (2, 3)]) - - def test_empty_graph(self): - G = nx.empty_graph(3) - T = nx.minimum_spanning_tree(G, algorithm=self.algo) - assert_nodes_equal(sorted(T), list(range(3))) - assert T.number_of_edges() == 0 - - def test_attributes(self): - G = nx.Graph() - G.add_edge(1, 2, weight=1, color='red', distance=7) - G.add_edge(2, 3, weight=1, color='green', distance=2) - G.add_edge(1, 3, weight=10, color='blue', distance=1) - G.graph['foo'] = 'bar' - T = nx.minimum_spanning_tree(G, algorithm=self.algo) - assert T.graph == G.graph - assert_nodes_equal(T, G) - for u, v in T.edges(): - assert T.adj[u][v] == G.adj[u][v] - - def test_weight_attribute(self): - G = nx.Graph() - G.add_edge(0, 1, weight=1, distance=7) - G.add_edge(0, 2, weight=30, distance=1) - G.add_edge(1, 2, weight=1, distance=1) - G.add_node(3) - T = nx.minimum_spanning_tree(G, algorithm=self.algo, weight='distance') - assert_nodes_equal(sorted(T), list(range(4))) - assert_edges_equal(sorted(T.edges()), [(0, 2), (1, 2)]) - T = nx.maximum_spanning_tree(G, algorithm=self.algo, weight='distance') - assert_nodes_equal(sorted(T), list(range(4))) - assert_edges_equal(sorted(T.edges()), [(0, 1), (0, 2)]) - - -class TestBoruvka(MinimumSpanningTreeTestBase, TestCase): - """Unit tests for computing a minimum (or maximum) spanning tree - using Borůvka's algorithm. - - """ - algorithm = 'boruvka' - - def test_unicode_name(self): - """Tests that using a Unicode string can correctly indicate - Borůvka's algorithm. - - """ - edges = nx.minimum_spanning_edges(self.G, algorithm=u'borůvka') - # Edges from the spanning edges functions don't come in sorted - # orientation, so we need to sort each edge individually. - actual = sorted((min(u, v), max(u, v), d) for u, v, d in edges) - assert_edges_equal(actual, self.minimum_spanning_edgelist) - - -class MultigraphMSTTestBase(MinimumSpanningTreeTestBase): - # Abstract class - - def test_multigraph_keys_min(self): - """Tests that the minimum spanning edges of a multigraph - preserves edge keys. - - """ - G = nx.MultiGraph() - G.add_edge(0, 1, key='a', weight=2) - G.add_edge(0, 1, key='b', weight=1) - min_edges = nx.minimum_spanning_edges - mst_edges = min_edges(G, algorithm=self.algo, data=False) - assert_edges_equal([(0, 1, 'b')], list(mst_edges)) - - def test_multigraph_keys_max(self): - """Tests that the maximum spanning edges of a multigraph - preserves edge keys. - - """ - G = nx.MultiGraph() - G.add_edge(0, 1, key='a', weight=2) - G.add_edge(0, 1, key='b', weight=1) - max_edges = nx.maximum_spanning_edges - mst_edges = max_edges(G, algorithm=self.algo, data=False) - assert_edges_equal([(0, 1, 'a')], list(mst_edges)) - - -class TestKruskal(MultigraphMSTTestBase, TestCase): - """Unit tests for computing a minimum (or maximum) spanning tree - using Kruskal's algorithm. - - """ - algorithm = 'kruskal' - - -class TestPrim(MultigraphMSTTestBase, TestCase): - """Unit tests for computing a minimum (or maximum) spanning tree - using Prim's algorithm. - - """ - algorithm = 'prim' - - def test_multigraph_keys_tree(self): - G = nx.MultiGraph() - G.add_edge(0, 1, key='a', weight=2) - G.add_edge(0, 1, key='b', weight=1) - T = nx.minimum_spanning_tree(G) - assert_edges_equal([(0, 1, 1)], list(T.edges(data='weight'))) - - def test_multigraph_keys_tree_max(self): - G = nx.MultiGraph() - G.add_edge(0, 1, key='a', weight=2) - G.add_edge(0, 1, key='b', weight=1) - T = nx.maximum_spanning_tree(G) - assert_edges_equal([(0, 1, 2)], list(T.edges(data='weight'))) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tree/tests/test_operations.py b/extensions/fablabchemnitz/networkx/algorithms/tree/tests/test_operations.py deleted file mode 100644 index c7175941..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tree/tests/test_operations.py +++ /dev/null @@ -1,46 +0,0 @@ -# test_operations.py - unit tests for the operations module -# -# Copyright 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.algorithms.tree.operations` module. - -""" - -import networkx as nx -from networkx.testing import assert_nodes_equal -from networkx.testing import assert_edges_equal - - -class TestJoin(object): - """Unit tests for the :func:`networkx.tree.join` function.""" - - def test_empty_sequence(self): - """Tests that joining the empty sequence results in the tree - with one node. - - """ - T = nx.join([]) - assert len(T) == 1 - assert T.number_of_edges() == 0 - - def test_single(self): - """Tests that joining just one tree yields a tree with one more - node. - - """ - T = nx.empty_graph(1) - actual = nx.join([(T, 0)]) - expected = nx.path_graph(2) - assert_nodes_equal(list(expected), list(actual)) - assert_edges_equal(list(expected.edges()), list(actual.edges())) - - def test_basic(self): - """Tests for joining multiple subtrees at a root node.""" - trees = [(nx.full_rary_tree(2, 2 ** 2 - 1), 0) for i in range(2)] - actual = nx.join(trees) - expected = nx.full_rary_tree(2, 2 ** 3 - 1) - assert nx.is_isomorphic(actual, expected) diff --git a/extensions/fablabchemnitz/networkx/algorithms/tree/tests/test_recognition.py b/extensions/fablabchemnitz/networkx/algorithms/tree/tests/test_recognition.py deleted file mode 100644 index b6190bef..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/tree/tests/test_recognition.py +++ /dev/null @@ -1,157 +0,0 @@ -import pytest -import networkx as nx - - -class TestTreeRecognition(object): - - graph = nx.Graph - multigraph = nx.MultiGraph - - @classmethod - def setup_class(cls): - - cls.T1 = cls.graph() - - cls.T2 = cls.graph() - cls.T2.add_node(1) - - cls.T3 = cls.graph() - cls.T3.add_nodes_from(range(5)) - edges = [(i, i + 1) for i in range(4)] - cls.T3.add_edges_from(edges) - - cls.T5 = cls.multigraph() - cls.T5.add_nodes_from(range(5)) - edges = [(i, i + 1) for i in range(4)] - cls.T5.add_edges_from(edges) - - cls.T6 = cls.graph() - cls.T6.add_nodes_from([6, 7]) - cls.T6.add_edge(6, 7) - - cls.F1 = nx.compose(cls.T6, cls.T3) - - cls.N4 = cls.graph() - cls.N4.add_node(1) - cls.N4.add_edge(1, 1) - - cls.N5 = cls.graph() - cls.N5.add_nodes_from(range(5)) - - cls.N6 = cls.graph() - cls.N6.add_nodes_from(range(3)) - cls.N6.add_edges_from([(0, 1), (1, 2), (2, 0)]) - - cls.NF1 = nx.compose(cls.T6, cls.N6) - - def test_null_tree(self): - with pytest.raises(nx.NetworkXPointlessConcept): - nx.is_tree(self.graph()) - nx.is_tree(self.multigraph()) - - def test_null_forest(self): - with pytest.raises(nx.NetworkXPointlessConcept): - nx.is_forest(self.graph()) - nx.is_forest(self.multigraph()) - - def test_is_tree(self): - assert nx.is_tree(self.T2) - assert nx.is_tree(self.T3) - assert nx.is_tree(self.T5) - - def test_is_not_tree(self): - assert not nx.is_tree(self.N4) - assert not nx.is_tree(self.N5) - assert not nx.is_tree(self.N6) - - def test_is_forest(self): - assert nx.is_forest(self.T2) - assert nx.is_forest(self.T3) - assert nx.is_forest(self.T5) - assert nx.is_forest(self.F1) - assert nx.is_forest(self.N5) - - def test_is_not_forest(self): - assert not nx.is_forest(self.N4) - assert not nx.is_forest(self.N6) - assert not nx.is_forest(self.NF1) - - -class TestDirectedTreeRecognition(TestTreeRecognition): - graph = nx.DiGraph - multigraph = nx.MultiDiGraph - - -def test_disconnected_graph(): - # https://github.com/networkx/networkx/issues/1144 - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (2, 0), (3, 4)]) - assert not nx.is_tree(G) - - G = nx.DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 0), (3, 4)]) - assert not nx.is_tree(G) - - -def test_dag_nontree(): - G = nx.DiGraph() - G.add_edges_from([(0, 1), (0, 2), (1, 2)]) - assert not nx.is_tree(G) - assert nx.is_directed_acyclic_graph(G) - - -def test_multicycle(): - G = nx.MultiDiGraph() - G.add_edges_from([(0, 1), (0, 1)]) - assert not nx.is_tree(G) - assert nx.is_directed_acyclic_graph(G) - - -def test_emptybranch(): - G = nx.DiGraph() - G.add_nodes_from(range(10)) - assert nx.is_branching(G) - assert not nx.is_arborescence(G) - - -def test_path(): - G = nx.DiGraph() - nx.add_path(G, range(5)) - assert nx.is_branching(G) - assert nx.is_arborescence(G) - - -def test_notbranching1(): - # Acyclic violation. - G = nx.MultiDiGraph() - G.add_nodes_from(range(10)) - G.add_edges_from([(0, 1), (1, 0)]) - assert not nx.is_branching(G) - assert not nx.is_arborescence(G) - - -def test_notbranching2(): - # In-degree violation. - G = nx.MultiDiGraph() - G.add_nodes_from(range(10)) - G.add_edges_from([(0, 1), (0, 2), (3, 2)]) - assert not nx.is_branching(G) - assert not nx.is_arborescence(G) - - -def test_notarborescence1(): - # Not an arborescence due to not spanning. - G = nx.MultiDiGraph() - G.add_nodes_from(range(10)) - G.add_edges_from([(0, 1), (0, 2), (1, 3), (5, 6)]) - assert nx.is_branching(G) - assert not nx.is_arborescence(G) - - -def test_notarborescence2(): - # Not an arborescence due to in-degree violation. - G = nx.MultiDiGraph() - nx.add_path(G, range(5)) - G.add_edge(6, 4) - assert not nx.is_branching(G) - assert not nx.is_arborescence(G) diff --git a/extensions/fablabchemnitz/networkx/algorithms/triads.py b/extensions/fablabchemnitz/networkx/algorithms/triads.py deleted file mode 100644 index 2d5dc842..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/triads.py +++ /dev/null @@ -1,115 +0,0 @@ -# triads.py - functions for analyzing triads of a graph -# -# Copyright 2015 NetworkX developers. -# Copyright 2011 Reya Group -# Copyright 2011 Alex Levenson -# Copyright 2011 Diederik van Liere -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Functions for analyzing triads of a graph.""" - -from networkx.utils import not_implemented_for - -__author__ = '\n'.join(['Alex Levenson (alex@isnontinvain.com)', - 'Diederik van Liere (diederik.vanliere@rotman.utoronto.ca)']) - -__all__ = ['triadic_census'] - -#: The integer codes representing each type of triad. -#: -#: Triads that are the same up to symmetry have the same code. -TRICODES = (1, 2, 2, 3, 2, 4, 6, 8, 2, 6, 5, 7, 3, 8, 7, 11, 2, 6, 4, 8, 5, 9, - 9, 13, 6, 10, 9, 14, 7, 14, 12, 15, 2, 5, 6, 7, 6, 9, 10, 14, 4, 9, - 9, 12, 8, 13, 14, 15, 3, 7, 8, 11, 7, 12, 14, 15, 8, 14, 13, 15, - 11, 15, 15, 16) - -#: The names of each type of triad. The order of the elements is -#: important: it corresponds to the tricodes given in :data:`TRICODES`. -TRIAD_NAMES = ('003', '012', '102', '021D', '021U', '021C', '111D', '111U', - '030T', '030C', '201', '120D', '120U', '120C', '210', '300') - - -#: A dictionary mapping triad code to triad name. -TRICODE_TO_NAME = {i: TRIAD_NAMES[code - 1] for i, code in enumerate(TRICODES)} - - -def _tricode(G, v, u, w): - """Returns the integer code of the given triad. - - This is some fancy magic that comes from Batagelj and Mrvar's paper. It - treats each edge joining a pair of `v`, `u`, and `w` as a bit in - the binary representation of an integer. - - """ - combos = ((v, u, 1), (u, v, 2), (v, w, 4), (w, v, 8), (u, w, 16), - (w, u, 32)) - return sum(x for u, v, x in combos if v in G[u]) - - -@not_implemented_for('undirected') -def triadic_census(G): - """Determines the triadic census of a directed graph. - - The triadic census is a count of how many of the 16 possible types of - triads are present in a directed graph. - - Parameters - ---------- - G : digraph - A NetworkX DiGraph - - Returns - ------- - census : dict - Dictionary with triad names as keys and number of occurrences as values. - - Notes - ----- - This algorithm has complexity $O(m)$ where $m$ is the number of edges in - the graph. - - See also - -------- - triad_graph - - References - ---------- - .. [1] Vladimir Batagelj and Andrej Mrvar, A subquadratic triad census - algorithm for large sparse networks with small maximum degree, - University of Ljubljana, - http://vlado.fmf.uni-lj.si/pub/networks/doc/triads/triads.pdf - - """ - # Initialize the count for each triad to be zero. - census = {name: 0 for name in TRIAD_NAMES} - n = len(G) - # m = dict(zip(G, range(n))) - m = {v: i for i, v in enumerate(G)} - for v in G: - vnbrs = set(G.pred[v]) | set(G.succ[v]) - for u in vnbrs: - if m[u] <= m[v]: - continue - neighbors = (vnbrs | set(G.succ[u]) | set(G.pred[u])) - {u, v} - # Calculate dyadic triads instead of counting them. - if v in G[u] and u in G[v]: - census['102'] += n - len(neighbors) - 2 - else: - census['012'] += n - len(neighbors) - 2 - # Count connected triads. - for w in neighbors: - if m[u] < m[w] or (m[v] < m[w] < m[u] and - v not in G.pred[w] and - v not in G.succ[w]): - code = _tricode(G, v, u, w) - census[TRICODE_TO_NAME[code]] += 1 - - # null triads = total number of possible triads - all found triads - # - # Use integer division here, since we know this formula guarantees an - # integral value. - census['003'] = ((n * (n - 1) * (n - 2)) // 6) - sum(census.values()) - return census diff --git a/extensions/fablabchemnitz/networkx/algorithms/vitality.py b/extensions/fablabchemnitz/networkx/algorithms/vitality.py deleted file mode 100644 index cdf57bd8..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/vitality.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (C) 2010 by -# Aric Hagberg (hagberg@lanl.gov) -# Renato Fabbri -# Copyright (C) 2012 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# Copyright (C) 2016-2019 by NetworkX developers. -# -# All rights reserved. -# BSD license. -""" -Vitality measures. -""" -from functools import partial - -import networkx as nx - -__all__ = ['closeness_vitality'] - - -def closeness_vitality(G, node=None, weight=None, wiener_index=None): - """Returns the closeness vitality for nodes in the graph. - - The *closeness vitality* of a node, defined in Section 3.6.2 of [1], - is the change in the sum of distances between all node pairs when - excluding that node. - - Parameters - ---------- - G : NetworkX graph - A strongly-connected graph. - - weight : string - The name of the edge attribute used as weight. This is passed - directly to the :func:`~networkx.wiener_index` function. - - node : object - If specified, only the closeness vitality for this node will be - returned. Otherwise, a dictionary mapping each node to its - closeness vitality will be returned. - - Other parameters - ---------------- - wiener_index : number - If you have already computed the Wiener index of the graph - `G`, you can provide that value here. Otherwise, it will be - computed for you. - - Returns - ------- - dictionary or float - If `node` is None, this function returns a dictionary - with nodes as keys and closeness vitality as the - value. Otherwise, it returns only the closeness vitality for the - specified `node`. - - The closeness vitality of a node may be negative infinity if - removing that node would disconnect the graph. - - Examples - -------- - >>> G = nx.cycle_graph(3) - >>> nx.closeness_vitality(G) - {0: 2.0, 1: 2.0, 2: 2.0} - - See Also - -------- - closeness_centrality - - References - ---------- - .. [1] Ulrik Brandes, Thomas Erlebach (eds.). - *Network Analysis: Methodological Foundations*. - Springer, 2005. - - - """ - if wiener_index is None: - wiener_index = nx.wiener_index(G, weight=weight) - if node is not None: - after = nx.wiener_index(G.subgraph(set(G) - {node}), weight=weight) - return wiener_index - after - vitality = partial(closeness_vitality, G, weight=weight, - wiener_index=wiener_index) - # TODO This can be trivially parallelized. - return {v: vitality(node=v) for v in G} diff --git a/extensions/fablabchemnitz/networkx/algorithms/voronoi.py b/extensions/fablabchemnitz/networkx/algorithms/voronoi.py deleted file mode 100644 index 41725d61..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/voronoi.py +++ /dev/null @@ -1,93 +0,0 @@ -# voronoi.py - functions for computing the Voronoi partition of a graph -# -# Copyright 2016-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Functions for computing the Voronoi cells of a graph.""" -import networkx as nx -from networkx.utils import groups - -__all__ = ['voronoi_cells'] - - -def voronoi_cells(G, center_nodes, weight='weight'): - """Returns the Voronoi cells centered at `center_nodes` with respect - to the shortest-path distance metric. - - If *C* is a set of nodes in the graph and *c* is an element of *C*, - the *Voronoi cell* centered at a node *c* is the set of all nodes - *v* that are closer to *c* than to any other center node in *C* with - respect to the shortest-path distance metric. [1]_ - - For directed graphs, this will compute the "outward" Voronoi cells, - as defined in [1]_, in which distance is measured from the center - nodes to the target node. For the "inward" Voronoi cells, use the - :meth:`DiGraph.reverse` method to reverse the orientation of the - edges before invoking this function on the directed graph. - - Parameters - ---------- - G : NetworkX graph - - center_nodes : set - A nonempty set of nodes in the graph `G` that represent the - center of the Voronoi cells. - - weight : string or function - The edge attribute (or an arbitrary function) representing the - weight of an edge. This keyword argument is as described in the - documentation for :func:`~networkx.multi_source_dijkstra_path`, - for example. - - Returns - ------- - dictionary - A mapping from center node to set of all nodes in the graph - closer to that center node than to any other center node. The - keys of the dictionary are the element of `center_nodes`, and - the values of the dictionary form a partition of the nodes of - `G`. - - Examples - -------- - To get only the partition of the graph induced by the Voronoi cells, - take the collection of all values in the returned dictionary:: - - >>> G = nx.path_graph(6) - >>> center_nodes = {0, 3} - >>> cells = nx.voronoi_cells(G, center_nodes) - >>> partition = set(map(frozenset, cells.values())) - >>> sorted(map(sorted, partition)) - [[0, 1], [2, 3, 4, 5]] - - Raises - ------ - ValueError - If `center_nodes` is empty. - - References - ---------- - .. [1] Erwig, Martin. (2000), - "The graph Voronoi diagram with applications." - *Networks*, 36: 156--163. - 3.0.CO;2-L> - - """ - # Determine the shortest paths from any one of the center nodes to - # every node in the graph. - # - # This raises `ValueError` if `center_nodes` is an empty set. - paths = nx.multi_source_dijkstra_path(G, center_nodes, weight=weight) - # Determine the center node from which the shortest path originates. - nearest = {v: p[0] for v, p in paths.items()} - # Get the mapping from center node to all nodes closer to it than to - # any other center node. - cells = groups(nearest) - # We collect all unreachable nodes under a special key, if there are any. - unreachable = set(G) - set(nearest) - if unreachable: - cells['unreachable'] = unreachable - return cells diff --git a/extensions/fablabchemnitz/networkx/algorithms/wiener.py b/extensions/fablabchemnitz/networkx/algorithms/wiener.py deleted file mode 100644 index 8aac8df5..00000000 --- a/extensions/fablabchemnitz/networkx/algorithms/wiener.py +++ /dev/null @@ -1,85 +0,0 @@ -# wiener.py - functions related to the Wiener index of a graph -# -# Copyright 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Functions related to the Wiener index of a graph.""" - -from itertools import chain - -from .components import is_connected -from .components import is_strongly_connected -from .shortest_paths import shortest_path_length as spl - -__all__ = ['wiener_index'] - -#: Rename the :func:`chain.from_iterable` function for the sake of -#: brevity. -chaini = chain.from_iterable - - -def wiener_index(G, weight=None): - """Returns the Wiener index of the given graph. - - The *Wiener index* of a graph is the sum of the shortest-path - distances between each pair of reachable nodes. For pairs of nodes - in undirected graphs, only one orientation of the pair is counted. - - Parameters - ---------- - G : NetworkX graph - - weight : object - The edge attribute to use as distance when computing - shortest-path distances. This is passed directly to the - :func:`networkx.shortest_path_length` function. - - Returns - ------- - float - The Wiener index of the graph `G`. - - Raises - ------ - NetworkXError - If the graph `G` is not connected. - - Notes - ----- - If a pair of nodes is not reachable, the distance is assumed to be - infinity. This means that for graphs that are not - strongly-connected, this function returns ``inf``. - - The Wiener index is not usually defined for directed graphs, however - this function uses the natural generalization of the Wiener index to - directed graphs. - - Examples - -------- - The Wiener index of the (unweighted) complete graph on *n* nodes - equals the number of pairs of the *n* nodes, since each pair of - nodes is at distance one:: - - >>> import networkx as nx - >>> n = 10 - >>> G = nx.complete_graph(n) - >>> nx.wiener_index(G) == n * (n - 1) / 2 - True - - Graphs that are not strongly-connected have infinite Wiener index:: - - >>> G = nx.empty_graph(2) - >>> nx.wiener_index(G) - inf - - """ - is_directed = G.is_directed() - if (is_directed and not is_strongly_connected(G)) or \ - (not is_directed and not is_connected(G)): - return float('inf') - total = sum(chaini(p.values() for v, p in spl(G, weight=weight))) - # Need to account for double counting pairs of nodes in undirected graphs. - return total if is_directed else total / 2 diff --git a/extensions/fablabchemnitz/networkx/classes/__init__.py b/extensions/fablabchemnitz/networkx/classes/__init__.py deleted file mode 100644 index af26fd3f..00000000 --- a/extensions/fablabchemnitz/networkx/classes/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from .graph import Graph -from .digraph import DiGraph -from .multigraph import MultiGraph -from .multidigraph import MultiDiGraph -from .ordered import * - -from .function import * - -import networkx.classes.filters - -import networkx.classes.coreviews -import networkx.classes.graphviews -import networkx.classes.reportviews diff --git a/extensions/fablabchemnitz/networkx/classes/coreviews.py b/extensions/fablabchemnitz/networkx/classes/coreviews.py deleted file mode 100644 index 76e40031..00000000 --- a/extensions/fablabchemnitz/networkx/classes/coreviews.py +++ /dev/null @@ -1,410 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg (hagberg@lanl.gov), -# Pieter Swart (swart@lanl.gov), -# Dan Schult(dschult@colgate.edu) -""" -""" -from collections.abc import Mapping -import networkx as nx - -__all__ = ['AtlasView', 'AdjacencyView', 'MultiAdjacencyView', - 'UnionAtlas', 'UnionAdjacency', - 'UnionMultiInner', 'UnionMultiAdjacency', - 'FilterAtlas', 'FilterAdjacency', - 'FilterMultiInner', 'FilterMultiAdjacency', - ] - - -class AtlasView(Mapping): - """An AtlasView is a Read-only Mapping of Mappings. - - It is a View into a dict-of-dict data structure. - The inner level of dict is read-write. But the - outer level is read-only. - - See Also - ======== - AdjacencyView - View into dict-of-dict-of-dict - MultiAdjacencyView - View into dict-of-dict-of-dict-of-dict - """ - __slots__ = ('_atlas',) - - def __getstate__(self): - return {'_atlas': self._atlas} - - def __setstate__(self, state): - self._atlas = state['_atlas'] - - def __init__(self, d): - self._atlas = d - - def __len__(self): - return len(self._atlas) - - def __iter__(self): - return iter(self._atlas) - - def __getitem__(self, key): - return self._atlas[key] - - def copy(self): - return {n: self[n].copy() for n in self._atlas} - - def __str__(self): - return str(self._atlas) # {nbr: self[nbr] for nbr in self}) - - def __repr__(self): - return '%s(%r)' % (self.__class__.__name__, self._atlas) - - -class AdjacencyView(AtlasView): - """An AdjacencyView is a Read-only Map of Maps of Maps. - - It is a View into a dict-of-dict-of-dict data structure. - The inner level of dict is read-write. But the - outer levels are read-only. - - See Also - ======== - AtlasView - View into dict-of-dict - MultiAdjacencyView - View into dict-of-dict-of-dict-of-dict - """ - __slots__ = () # Still uses AtlasView slots names _atlas - - def __getitem__(self, name): - return AtlasView(self._atlas[name]) - - def copy(self): - return {n: self[n].copy() for n in self._atlas} - - -class MultiAdjacencyView(AdjacencyView): - """An MultiAdjacencyView is a Read-only Map of Maps of Maps of Maps. - - It is a View into a dict-of-dict-of-dict-of-dict data structure. - The inner level of dict is read-write. But the - outer levels are read-only. - - See Also - ======== - AtlasView - View into dict-of-dict - AdjacencyView - View into dict-of-dict-of-dict - """ - __slots__ = () # Still uses AtlasView slots names _atlas - - def __getitem__(self, name): - return AdjacencyView(self._atlas[name]) - - def copy(self): - return {n: self[n].copy() for n in self._atlas} - - -class UnionAtlas(Mapping): - """A read-only union of two atlases (dict-of-dict). - - The two dict-of-dicts represent the inner dict of - an Adjacency: `G.succ[node]` and `G.pred[node]`. - The inner level of dict of both hold attribute key:value - pairs and is read-write. But the outer level is read-only. - - See Also - ======== - UnionAdjacency - View into dict-of-dict-of-dict - UnionMultiAdjacency - View into dict-of-dict-of-dict-of-dict - """ - __slots__ = ('_succ', '_pred') - - def __getstate__(self): - return {'_succ': self._succ, '_pred': self._pred} - - def __setstate__(self, state): - self._succ = state['_succ'] - self._pred = state['_pred'] - - def __init__(self, succ, pred): - self._succ = succ - self._pred = pred - - def __len__(self): - return len(self._succ) + len(self._pred) - - def __iter__(self): - return iter(set(self._succ.keys()) | set(self._pred.keys())) - - def __getitem__(self, key): - try: - return self._succ[key] - except KeyError: - return self._pred[key] - - def copy(self): - result = {nbr: dd.copy() for nbr, dd in self._succ.items()} - for nbr, dd in self._pred.items(): - if nbr in result: - result[nbr].update(dd) - else: - result[nbr] = dd.copy() - return result - - def __str__(self): - return str({nbr: self[nbr] for nbr in self}) - - def __repr__(self): - return '%s(%r, %r)' % (self.__class__.__name__, self._succ, self._pred) - - -class UnionAdjacency(Mapping): - """A read-only union of dict Adjacencies as a Map of Maps of Maps. - - The two input dict-of-dict-of-dicts represent the union of - `G.succ` and `G.pred`. Return values are UnionAtlas - The inner level of dict is read-write. But the - middle and outer levels are read-only. - - succ : a dict-of-dict-of-dict {node: nbrdict} - pred : a dict-of-dict-of-dict {node: nbrdict} - The keys for the two dicts should be the same - - See Also - ======== - UnionAtlas - View into dict-of-dict - UnionMultiAdjacency - View into dict-of-dict-of-dict-of-dict - """ - __slots__ = ('_succ', '_pred') - - def __getstate__(self): - return {'_succ': self._succ, '_pred': self._pred} - - def __setstate__(self, state): - self._succ = state['_succ'] - self._pred = state['_pred'] - - def __init__(self, succ, pred): - # keys must be the same for two input dicts - assert(len(set(succ.keys()) ^ set(pred.keys())) == 0) - self._succ = succ - self._pred = pred - - def __len__(self): - return len(self._succ) # length of each dict should be the same - - def __iter__(self): - return iter(self._succ) - - def __getitem__(self, nbr): - return UnionAtlas(self._succ[nbr], self._pred[nbr]) - - def copy(self): - return {n: self[n].copy() for n in self._succ} - - def __str__(self): - return str({nbr: self[nbr] for nbr in self}) - - def __repr__(self): - return '%s(%r, %r)' % (self.__class__.__name__, self._succ, self._pred) - - -class UnionMultiInner(UnionAtlas): - """A read-only union of two inner dicts of MultiAdjacencies. - - The two input dict-of-dict-of-dicts represent the union of - `G.succ[node]` and `G.pred[node]` for MultiDiGraphs. - Return values are UnionAtlas. - The inner level of dict is read-write. But the outer levels are read-only. - - See Also - ======== - UnionAtlas - View into dict-of-dict - UnionAdjacency - View into dict-of-dict-of-dict - UnionMultiAdjacency - View into dict-of-dict-of-dict-of-dict - """ - __slots__ = () # Still uses UnionAtlas slots names _succ, _pred - - def __getitem__(self, node): - in_succ = node in self._succ - in_pred = node in self._pred - if in_succ: - if in_pred: - return UnionAtlas(self._succ[node], self._pred[node]) - return UnionAtlas(self._succ[node], {}) - return UnionAtlas({}, self._pred[node]) - - def copy(self): - nodes = set(self._succ.keys()) | set(self._pred.keys()) - return {n: self[n].copy() for n in nodes} - - -class UnionMultiAdjacency(UnionAdjacency): - """A read-only union of two dict MultiAdjacencies. - - The two input dict-of-dict-of-dict-of-dicts represent the union of - `G.succ` and `G.pred` for MultiDiGraphs. Return values are UnionAdjacency. - The inner level of dict is read-write. But the outer levels are read-only. - - See Also - ======== - UnionAtlas - View into dict-of-dict - UnionMultiInner - View into dict-of-dict-of-dict - """ - __slots__ = () # Still uses UnionAdjacency slots names _succ, _pred - - def __getitem__(self, node): - return UnionMultiInner(self._succ[node], self._pred[node]) - - -class FilterAtlas(Mapping): # nodedict, nbrdict, keydict - def __init__(self, d, NODE_OK): - self._atlas = d - self.NODE_OK = NODE_OK - - def __len__(self): - return sum(1 for n in self) - - def __iter__(self): - try: # check that NODE_OK has attr 'nodes' - node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas) - except AttributeError: - node_ok_shorter = False - if node_ok_shorter: - return (n for n in self.NODE_OK.nodes if n in self._atlas) - return (n for n in self._atlas if self.NODE_OK(n)) - - def __getitem__(self, key): - if key in self._atlas and self.NODE_OK(key): - return self._atlas[key] - raise KeyError("Key {} not found".format(key)) - - def copy(self): - try: # check that NODE_OK has attr 'nodes' - node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas) - except AttributeError: - node_ok_shorter = False - if node_ok_shorter: - return {u: self._atlas[u] for u in self.NODE_OK.nodes - if u in self._atlas} - return {u: d for u, d in self._atlas.items() - if self.NODE_OK(u)} - - def __str__(self): - return str({nbr: self[nbr] for nbr in self}) - - def __repr__(self): - return '%s(%r, %r)' % (self.__class__.__name__, self._atlas, - self.NODE_OK) - - -class FilterAdjacency(Mapping): # edgedict - def __init__(self, d, NODE_OK, EDGE_OK): - self._atlas = d - self.NODE_OK = NODE_OK - self.EDGE_OK = EDGE_OK - - def __len__(self): - return sum(1 for n in self) - - def __iter__(self): - try: # check that NODE_OK has attr 'nodes' - node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas) - except AttributeError: - node_ok_shorter = False - if node_ok_shorter: - return (n for n in self.NODE_OK.nodes if n in self._atlas) - return (n for n in self._atlas if self.NODE_OK(n)) - - def __getitem__(self, node): - if node in self._atlas and self.NODE_OK(node): - def new_node_ok(nbr): - return self.NODE_OK(nbr) and self.EDGE_OK(node, nbr) - return FilterAtlas(self._atlas[node], new_node_ok) - raise KeyError("Key {} not found".format(node)) - - def copy(self): - try: # check that NODE_OK has attr 'nodes' - node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas) - except AttributeError: - node_ok_shorter = False - if node_ok_shorter: - return {u: {v: d for v, d in self._atlas[u].items() - if self.NODE_OK(v) if self.EDGE_OK(u, v)} - for u in self.NODE_OK.nodes if u in self._atlas} - return {u: {v: d for v, d in nbrs.items() if self.NODE_OK(v) - if self.EDGE_OK(u, v)} - for u, nbrs in self._atlas.items() - if self.NODE_OK(u)} - - def __str__(self): - return str({nbr: self[nbr] for nbr in self}) - - def __repr__(self): - return '%s(%r, %r, %r)' % (self.__class__.__name__, self._atlas, - self.NODE_OK, self.EDGE_OK) - - -class FilterMultiInner(FilterAdjacency): # muliedge_seconddict - def __iter__(self): - try: # check that NODE_OK has attr 'nodes' - node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas) - except AttributeError: - node_ok_shorter = False - if node_ok_shorter: - my_nodes = (n for n in self.NODE_OK.nodes if n in self._atlas) - else: - my_nodes = (n for n in self._atlas if self.NODE_OK(n)) - for n in my_nodes: - some_keys_ok = False - for key in self._atlas[n]: - if self.EDGE_OK(n, key): - some_keys_ok = True - break - if some_keys_ok is True: - yield n - - def __getitem__(self, nbr): - if nbr in self._atlas and self.NODE_OK(nbr): - def new_node_ok(key): - return self.EDGE_OK(nbr, key) - return FilterAtlas(self._atlas[nbr], new_node_ok) - raise KeyError("Key {} not found".format(nbr)) - - def copy(self): - try: # check that NODE_OK has attr 'nodes' - node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas) - except AttributeError: - node_ok_shorter = False - if node_ok_shorter: - return {v: {k: d for k, d in self._atlas[v].items() - if self.EDGE_OK(v, k)} - for v in self.NODE_OK.nodes if v in self._atlas} - return {v: {k: d for k, d in nbrs.items() if self.EDGE_OK(v, k)} - for v, nbrs in self._atlas.items() if self.NODE_OK(v)} - - -class FilterMultiAdjacency(FilterAdjacency): # multiedgedict - def __getitem__(self, node): - if node in self._atlas and self.NODE_OK(node): - def edge_ok(nbr, key): - return self.NODE_OK(nbr) and self.EDGE_OK(node, nbr, key) - return FilterMultiInner(self._atlas[node], self.NODE_OK, edge_ok) - raise KeyError("Key {} not found".format(node)) - - def copy(self): - try: # check that NODE_OK has attr 'nodes' - node_ok_shorter = 2 * len(self.NODE_OK.nodes) < len(self._atlas) - except AttributeError: - node_ok_shorter = False - if node_ok_shorter: - my_nodes = self.NODE_OK.nodes - return {u: {v: {k: d for k, d in kd.items() - if self.EDGE_OK(u, v, k)} - for v, kd in self._atlas[u].items() if v in my_nodes} - for u in my_nodes if u in self._atlas} - return {u: {v: {k: d for k, d in kd.items() - if self.EDGE_OK(u, v, k)} - for v, kd in nbrs.items() if self.NODE_OK(v)} - for u, nbrs in self._atlas.items() if self.NODE_OK(u)} diff --git a/extensions/fablabchemnitz/networkx/classes/digraph.py b/extensions/fablabchemnitz/networkx/classes/digraph.py deleted file mode 100644 index 07e9c524..00000000 --- a/extensions/fablabchemnitz/networkx/classes/digraph.py +++ /dev/null @@ -1,1201 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg -# Dan Schult -# Pieter Swart -"""Base class for directed graphs.""" -from copy import deepcopy - -import networkx as nx -from networkx.classes.graph import Graph -from networkx.classes.coreviews import AdjacencyView -from networkx.classes.reportviews import OutEdgeView, InEdgeView, \ - DiDegreeView, InDegreeView, OutDegreeView -from networkx.exception import NetworkXError -import networkx.convert as convert - - -class DiGraph(Graph): - """ - Base class for directed graphs. - - A DiGraph stores nodes and edges with optional data, or attributes. - - DiGraphs hold directed edges. Self loops are allowed but multiple - (parallel) edges are not. - - Nodes can be arbitrary (hashable) Python objects with optional - key/value attributes. By convention `None` is not used as a node. - - Edges are represented as links between nodes with optional - key/value attributes. - - Parameters - ---------- - incoming_graph_data : input graph (optional, default: None) - Data to initialize graph. If None (default) an empty - graph is created. The data can be any format that is supported - by the to_networkx_graph() function, currently including edge list, - dict of dicts, dict of lists, NetworkX graph, NumPy matrix - or 2d ndarray, SciPy sparse matrix, or PyGraphviz graph. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - Graph - MultiGraph - MultiDiGraph - OrderedDiGraph - - Examples - -------- - Create an empty graph structure (a "null graph") with no nodes and - no edges. - - >>> G = nx.DiGraph() - - G can be grown in several ways. - - **Nodes:** - - Add one node at a time: - - >>> G.add_node(1) - - Add the nodes from any container (a list, dict, set or - even the lines from a file or the nodes from another graph). - - >>> G.add_nodes_from([2, 3]) - >>> G.add_nodes_from(range(100, 110)) - >>> H = nx.path_graph(10) - >>> G.add_nodes_from(H) - - In addition to strings and integers any hashable Python object - (except None) can represent a node, e.g. a customized node object, - or even another Graph. - - >>> G.add_node(H) - - **Edges:** - - G can also be grown by adding edges. - - Add one edge, - - >>> G.add_edge(1, 2) - - a list of edges, - - >>> G.add_edges_from([(1, 2), (1, 3)]) - - or a collection of edges, - - >>> G.add_edges_from(H.edges) - - If some edges connect nodes not yet in the graph, the nodes - are added automatically. There are no errors when adding - nodes or edges that already exist. - - **Attributes:** - - Each graph, node, and edge can hold key/value attribute pairs - in an associated attribute dictionary (the keys must be hashable). - By default these are empty, but can be added or changed using - add_edge, add_node or direct manipulation of the attribute - dictionaries named graph, node and edge respectively. - - >>> G = nx.DiGraph(day="Friday") - >>> G.graph - {'day': 'Friday'} - - Add node attributes using add_node(), add_nodes_from() or G.nodes - - >>> G.add_node(1, time='5pm') - >>> G.add_nodes_from([3], time='2pm') - >>> G.nodes[1] - {'time': '5pm'} - >>> G.nodes[1]['room'] = 714 - >>> del G.nodes[1]['room'] # remove attribute - >>> list(G.nodes(data=True)) - [(1, {'time': '5pm'}), (3, {'time': '2pm'})] - - Add edge attributes using add_edge(), add_edges_from(), subscript - notation, or G.edges. - - >>> G.add_edge(1, 2, weight=4.7 ) - >>> G.add_edges_from([(3, 4), (4, 5)], color='red') - >>> G.add_edges_from([(1, 2, {'color':'blue'}), (2, 3, {'weight':8})]) - >>> G[1][2]['weight'] = 4.7 - >>> G.edges[1, 2]['weight'] = 4 - - Warning: we protect the graph data structure by making `G.edges[1, 2]` a - read-only dict-like structure. However, you can assign to attributes - in e.g. `G.edges[1, 2]`. Thus, use 2 sets of brackets to add/change - data attributes: `G.edges[1, 2]['weight'] = 4` - (For multigraphs: `MG.edges[u, v, key][name] = value`). - - **Shortcuts:** - - Many common graph features allow python syntax to speed reporting. - - >>> 1 in G # check if node in graph - True - >>> [n for n in G if n < 3] # iterate through nodes - [1, 2] - >>> len(G) # number of nodes in graph - 5 - - Often the best way to traverse all edges of a graph is via the neighbors. - The neighbors are reported as an adjacency-dict `G.adj` or `G.adjacency()` - - >>> for n, nbrsdict in G.adjacency(): - ... for nbr, eattr in nbrsdict.items(): - ... if 'weight' in eattr: - ... # Do something useful with the edges - ... pass - - But the edges reporting object is often more convenient: - - >>> for u, v, weight in G.edges(data='weight'): - ... if weight is not None: - ... # Do something useful with the edges - ... pass - - **Reporting:** - - Simple graph information is obtained using object-attributes and methods. - Reporting usually provides views instead of containers to reduce memory - usage. The views update as the graph is updated similarly to dict-views. - The objects `nodes, `edges` and `adj` provide access to data attributes - via lookup (e.g. `nodes[n], `edges[u, v]`, `adj[u][v]`) and iteration - (e.g. `nodes.items()`, `nodes.data('color')`, - `nodes.data('color', default='blue')` and similarly for `edges`) - Views exist for `nodes`, `edges`, `neighbors()`/`adj` and `degree`. - - For details on these and other miscellaneous methods, see below. - - **Subclasses (Advanced):** - - The Graph class uses a dict-of-dict-of-dict data structure. - The outer dict (node_dict) holds adjacency information keyed by node. - The next dict (adjlist_dict) represents the adjacency information and holds - edge data keyed by neighbor. The inner dict (edge_attr_dict) represents - the edge data and holds edge attribute values keyed by attribute names. - - Each of these three dicts can be replaced in a subclass by a user defined - dict-like object. In general, the dict-like features should be - maintained but extra features can be added. To replace one of the - dicts create a new graph class by changing the class(!) variable - holding the factory for that dict-like structure. The variable names are - node_dict_factory, node_attr_dict_factory, adjlist_inner_dict_factory, - adjlist_outer_dict_factory, edge_attr_dict_factory and graph_attr_dict_factory. - - node_dict_factory : function, (default: dict) - Factory function to be used to create the dict containing node - attributes, keyed by node id. - It should require no arguments and return a dict-like object - - node_attr_dict_factory: function, (default: dict) - Factory function to be used to create the node attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object - - adjlist_outer_dict_factory : function, (default: dict) - Factory function to be used to create the outer-most dict - in the data structure that holds adjacency info keyed by node. - It should require no arguments and return a dict-like object. - - adjlist_inner_dict_factory : function, optional (default: dict) - Factory function to be used to create the adjacency list - dict which holds edge data keyed by neighbor. - It should require no arguments and return a dict-like object - - edge_attr_dict_factory : function, optional (default: dict) - Factory function to be used to create the edge attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - graph_attr_dict_factory : function, (default: dict) - Factory function to be used to create the graph attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - Typically, if your extension doesn't impact the data structure all - methods will inherited without issue except: `to_directed/to_undirected`. - By default these methods create a DiGraph/Graph class and you probably - want them to create your extension of a DiGraph/Graph. To facilitate - this we define two class variables that you can set in your subclass. - - to_directed_class : callable, (default: DiGraph or MultiDiGraph) - Class to create a new graph structure in the `to_directed` method. - If `None`, a NetworkX class (DiGraph or MultiDiGraph) is used. - - to_undirected_class : callable, (default: Graph or MultiGraph) - Class to create a new graph structure in the `to_undirected` method. - If `None`, a NetworkX class (Graph or MultiGraph) is used. - - Examples - -------- - - Create a low memory graph class that effectively disallows edge - attributes by using a single attribute dict for all edges. - This reduces the memory used, but you lose edge attributes. - - >>> class ThinGraph(nx.Graph): - ... all_edge_dict = {'weight': 1} - ... def single_edge_dict(self): - ... return self.all_edge_dict - ... edge_attr_dict_factory = single_edge_dict - >>> G = ThinGraph() - >>> G.add_edge(2, 1) - >>> G[2][1] - {'weight': 1} - >>> G.add_edge(2, 2) - >>> G[2][1] is G[2][2] - True - - - Please see :mod:`~networkx.classes.ordered` for more examples of - creating graph subclasses by overwriting the base class `dict` with - a dictionary-like object. - """ - - def __init__(self, incoming_graph_data=None, **attr): - """Initialize a graph with edges, name, or graph attributes. - - Parameters - ---------- - incoming_graph_data : input graph (optional, default: None) - Data to initialize graph. If None (default) an empty - graph is created. The data can be an edge list, or any - NetworkX graph object. If the corresponding optional Python - packages are installed the data can also be a NumPy matrix - or 2d ndarray, a SciPy sparse matrix, or a PyGraphviz graph. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - convert - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G = nx.Graph(name='my graph') - >>> e = [(1, 2), (2, 3), (3, 4)] # list of edges - >>> G = nx.Graph(e) - - Arbitrary graph attribute pairs (key=value) may be assigned - - >>> G = nx.Graph(e, day="Friday") - >>> G.graph - {'day': 'Friday'} - - """ - self.graph_attr_dict_factory = self.graph_attr_dict_factory - self.node_dict_factory = self.node_dict_factory - self.node_attr_dict_factory = self.node_attr_dict_factory - self.adjlist_outer_dict_factory = self.adjlist_outer_dict_factory - self.adjlist_inner_dict_factory = self.adjlist_inner_dict_factory - self.edge_attr_dict_factory = self.edge_attr_dict_factory - - self.graph = self.graph_attr_dict_factory() # dictionary for graph attributes - self._node = self.node_dict_factory() # dictionary for node attr - # We store two adjacency lists: - # the predecessors of node n are stored in the dict self._pred - # the successors of node n are stored in the dict self._succ=self._adj - self._adj = self.adjlist_outer_dict_factory() # empty adjacency dict - self._pred = self.adjlist_outer_dict_factory() # predecessor - self._succ = self._adj # successor - - # attempt to load graph with data - if incoming_graph_data is not None: - convert.to_networkx_graph(incoming_graph_data, create_using=self) - # load graph attributes (must be after convert) - self.graph.update(attr) - - @property - def adj(self): - """Graph adjacency object holding the neighbors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edge-data-dict. So `G.adj[3][2]['color'] = 'blue'` sets - the color of the edge `(3, 2)` to `"blue"`. - - Iterating over G.adj behaves like a dict. Useful idioms include - `for nbr, datadict in G.adj[n].items():`. - - The neighbor information is also provided by subscripting the graph. - So `for nbr, foovalue in G[node].data('foo', default=1):` works. - - For directed graphs, `G.adj` holds outgoing (successor) info. - """ - return AdjacencyView(self._succ) - - @property - def succ(self): - """Graph adjacency object holding the successors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edge-data-dict. So `G.succ[3][2]['color'] = 'blue'` sets - the color of the edge `(3, 2)` to `"blue"`. - - Iterating over G.succ behaves like a dict. Useful idioms include - `for nbr, datadict in G.succ[n].items():`. A data-view not provided - by dicts also exists: `for nbr, foovalue in G.succ[node].data('foo'):` - and a default can be set via a `default` argument to the `data` method. - - The neighbor information is also provided by subscripting the graph. - So `for nbr, foovalue in G[node].data('foo', default=1):` works. - - For directed graphs, `G.adj` is identical to `G.succ`. - """ - return AdjacencyView(self._succ) - - @property - def pred(self): - """Graph adjacency object holding the predecessors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edge-data-dict. So `G.pred[2][3]['color'] = 'blue'` sets - the color of the edge `(3, 2)` to `"blue"`. - - Iterating over G.pred behaves like a dict. Useful idioms include - `for nbr, datadict in G.pred[n].items():`. A data-view not provided - by dicts also exists: `for nbr, foovalue in G.pred[node].data('foo'):` - A default can be set via a `default` argument to the `data` method. - """ - return AdjacencyView(self._pred) - - def add_node(self, node_for_adding, **attr): - """Add a single node `node_for_adding` and update node attributes. - - Parameters - ---------- - node_for_adding : node - A node can be any hashable Python object except None. - attr : keyword arguments, optional - Set or change node attributes using key=value. - - See Also - -------- - add_nodes_from - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_node(1) - >>> G.add_node('Hello') - >>> K3 = nx.Graph([(0, 1), (1, 2), (2, 0)]) - >>> G.add_node(K3) - >>> G.number_of_nodes() - 3 - - Use keywords set/change node attributes: - - >>> G.add_node(1, size=10) - >>> G.add_node(3, weight=0.4, UTM=('13S', 382871, 3972649)) - - Notes - ----- - A hashable object is one that can be used as a key in a Python - dictionary. This includes strings, numbers, tuples of strings - and numbers, etc. - - On many platforms hashable items also include mutables such as - NetworkX Graphs, though one should be careful that the hash - doesn't change on mutables. - """ - if node_for_adding not in self._succ: - self._succ[node_for_adding] = self.adjlist_inner_dict_factory() - self._pred[node_for_adding] = self.adjlist_inner_dict_factory() - attr_dict = self._node[node_for_adding] = self.node_attr_dict_factory() - attr_dict.update(attr) - else: # update attr even if node already exists - self._node[node_for_adding].update(attr) - - def add_nodes_from(self, nodes_for_adding, **attr): - """Add multiple nodes. - - Parameters - ---------- - nodes_for_adding : iterable container - A container of nodes (list, dict, set, etc.). - OR - A container of (node, attribute dict) tuples. - Node attributes are updated using the attribute dict. - attr : keyword arguments, optional (default= no attributes) - Update attributes for all nodes in nodes. - Node attributes specified in nodes as a tuple take - precedence over attributes specified via keyword arguments. - - See Also - -------- - add_node - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_nodes_from('Hello') - >>> K3 = nx.Graph([(0, 1), (1, 2), (2, 0)]) - >>> G.add_nodes_from(K3) - >>> sorted(G.nodes(), key=str) - [0, 1, 2, 'H', 'e', 'l', 'o'] - - Use keywords to update specific node attributes for every node. - - >>> G.add_nodes_from([1, 2], size=10) - >>> G.add_nodes_from([3, 4], weight=0.4) - - Use (node, attrdict) tuples to update attributes for specific nodes. - - >>> G.add_nodes_from([(1, dict(size=11)), (2, {'color':'blue'})]) - >>> G.nodes[1]['size'] - 11 - >>> H = nx.Graph() - >>> H.add_nodes_from(G.nodes(data=True)) - >>> H.nodes[1]['size'] - 11 - - """ - for n in nodes_for_adding: - # keep all this inside try/except because - # CPython throws TypeError on n not in self._succ, - # while pre-2.7.5 ironpython throws on self._succ[n] - try: - if n not in self._succ: - self._succ[n] = self.adjlist_inner_dict_factory() - self._pred[n] = self.adjlist_inner_dict_factory() - attr_dict = self._node[n] = self.node_attr_dict_factory() - attr_dict.update(attr) - else: - self._node[n].update(attr) - except TypeError: - nn, ndict = n - if nn not in self._succ: - self._succ[nn] = self.adjlist_inner_dict_factory() - self._pred[nn] = self.adjlist_inner_dict_factory() - newdict = attr.copy() - newdict.update(ndict) - attr_dict = self._node[nn] = self.node_attr_dict_factory() - attr_dict.update(newdict) - else: - olddict = self._node[nn] - olddict.update(attr) - olddict.update(ndict) - - def remove_node(self, n): - """Remove node n. - - Removes the node n and all adjacent edges. - Attempting to remove a non-existent node will raise an exception. - - Parameters - ---------- - n : node - A node in the graph - - Raises - ------- - NetworkXError - If n is not in the graph. - - See Also - -------- - remove_nodes_from - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> list(G.edges) - [(0, 1), (1, 2)] - >>> G.remove_node(1) - >>> list(G.edges) - [] - - """ - try: - nbrs = self._succ[n] - del self._node[n] - except KeyError: # NetworkXError if n not in self - raise NetworkXError("The node %s is not in the digraph." % (n,)) - for u in nbrs: - del self._pred[u][n] # remove all edges n-u in digraph - del self._succ[n] # remove node from succ - for u in self._pred[n]: - del self._succ[u][n] # remove all edges n-u in digraph - del self._pred[n] # remove node from pred - - def remove_nodes_from(self, nodes): - """Remove multiple nodes. - - Parameters - ---------- - nodes : iterable container - A container of nodes (list, dict, set, etc.). If a node - in the container is not in the graph it is silently ignored. - - See Also - -------- - remove_node - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> e = list(G.nodes) - >>> e - [0, 1, 2] - >>> G.remove_nodes_from(e) - >>> list(G.nodes) - [] - - """ - for n in nodes: - try: - succs = self._succ[n] - del self._node[n] - for u in succs: - del self._pred[u][n] # remove all edges n-u in digraph - del self._succ[n] # now remove node - for u in self._pred[n]: - del self._succ[u][n] # remove all edges n-u in digraph - del self._pred[n] # now remove node - except KeyError: - pass # silent failure on remove - - def add_edge(self, u_of_edge, v_of_edge, **attr): - """Add an edge between u and v. - - The nodes u and v will be automatically added if they are - not already in the graph. - - Edge attributes can be specified with keywords or by directly - accessing the edge's attribute dictionary. See examples below. - - Parameters - ---------- - u, v : nodes - Nodes can be, for example, strings or numbers. - Nodes must be hashable (and not None) Python objects. - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - See Also - -------- - add_edges_from : add a collection of edges - - Notes - ----- - Adding an edge that already exists updates the edge data. - - Many NetworkX algorithms designed for weighted graphs use - an edge attribute (by default `weight`) to hold a numerical value. - - Examples - -------- - The following all add the edge e=(1, 2) to graph G: - - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> e = (1, 2) - >>> G.add_edge(1, 2) # explicit two-node form - >>> G.add_edge(*e) # single edge as tuple of two nodes - >>> G.add_edges_from( [(1, 2)] ) # add edges from iterable container - - Associate data to edges using keywords: - - >>> G.add_edge(1, 2, weight=3) - >>> G.add_edge(1, 3, weight=7, capacity=15, length=342.7) - - For non-string attribute keys, use subscript notation. - - >>> G.add_edge(1, 2) - >>> G[1][2].update({0: 5}) - >>> G.edges[1, 2].update({0: 5}) - """ - u, v = u_of_edge, v_of_edge - # add nodes - if u not in self._succ: - self._succ[u] = self.adjlist_inner_dict_factory() - self._pred[u] = self.adjlist_inner_dict_factory() - self._node[u] = self.node_attr_dict_factory() - if v not in self._succ: - self._succ[v] = self.adjlist_inner_dict_factory() - self._pred[v] = self.adjlist_inner_dict_factory() - self._node[v] = self.node_attr_dict_factory() - # add the edge - datadict = self._adj[u].get(v, self.edge_attr_dict_factory()) - datadict.update(attr) - self._succ[u][v] = datadict - self._pred[v][u] = datadict - - def add_edges_from(self, ebunch_to_add, **attr): - """Add all the edges in ebunch_to_add. - - Parameters - ---------- - ebunch_to_add : container of edges - Each edge given in the container will be added to the - graph. The edges must be given as 2-tuples (u, v) or - 3-tuples (u, v, d) where d is a dictionary containing edge data. - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - See Also - -------- - add_edge : add a single edge - add_weighted_edges_from : convenient way to add weighted edges - - Notes - ----- - Adding the same edge twice has no effect but any edge data - will be updated when each duplicate edge is added. - - Edge attributes specified in an ebunch take precedence over - attributes specified via keyword arguments. - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edges_from([(0, 1), (1, 2)]) # using a list of edge tuples - >>> e = zip(range(0, 3), range(1, 4)) - >>> G.add_edges_from(e) # Add the path graph 0-1-2-3 - - Associate data to edges - - >>> G.add_edges_from([(1, 2), (2, 3)], weight=3) - >>> G.add_edges_from([(3, 4), (1, 4)], label='WN2898') - """ - for e in ebunch_to_add: - ne = len(e) - if ne == 3: - u, v, dd = e - elif ne == 2: - u, v = e - dd = {} - else: - raise NetworkXError( - "Edge tuple %s must be a 2-tuple or 3-tuple." % (e,)) - if u not in self._succ: - self._succ[u] = self.adjlist_inner_dict_factory() - self._pred[u] = self.adjlist_inner_dict_factory() - self._node[u] = self.node_attr_dict_factory() - if v not in self._succ: - self._succ[v] = self.adjlist_inner_dict_factory() - self._pred[v] = self.adjlist_inner_dict_factory() - self._node[v] = self.node_attr_dict_factory() - datadict = self._adj[u].get(v, self.edge_attr_dict_factory()) - datadict.update(attr) - datadict.update(dd) - self._succ[u][v] = datadict - self._pred[v][u] = datadict - - def remove_edge(self, u, v): - """Remove the edge between u and v. - - Parameters - ---------- - u, v : nodes - Remove the edge between nodes u and v. - - Raises - ------ - NetworkXError - If there is not an edge between u and v. - - See Also - -------- - remove_edges_from : remove a collection of edges - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, etc - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.remove_edge(0, 1) - >>> e = (1, 2) - >>> G.remove_edge(*e) # unpacks e from an edge tuple - >>> e = (2, 3, {'weight':7}) # an edge with attribute data - >>> G.remove_edge(*e[:2]) # select first part of edge tuple - """ - try: - del self._succ[u][v] - del self._pred[v][u] - except KeyError: - raise NetworkXError("The edge %s-%s not in graph." % (u, v)) - - def remove_edges_from(self, ebunch): - """Remove all edges specified in ebunch. - - Parameters - ---------- - ebunch: list or container of edge tuples - Each edge given in the list or container will be removed - from the graph. The edges can be: - - - 2-tuples (u, v) edge between u and v. - - 3-tuples (u, v, k) where k is ignored. - - See Also - -------- - remove_edge : remove a single edge - - Notes - ----- - Will fail silently if an edge in ebunch is not in the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> ebunch = [(1, 2), (2, 3)] - >>> G.remove_edges_from(ebunch) - """ - for e in ebunch: - u, v = e[:2] # ignore edge data - if u in self._succ and v in self._succ[u]: - del self._succ[u][v] - del self._pred[v][u] - - def has_successor(self, u, v): - """Returns True if node u has successor v. - - This is true if graph has the edge u->v. - """ - return (u in self._succ and v in self._succ[u]) - - def has_predecessor(self, u, v): - """Returns True if node u has predecessor v. - - This is true if graph has the edge u<-v. - """ - return (u in self._pred and v in self._pred[u]) - - def successors(self, n): - """Returns an iterator over successor nodes of n. - - A successor of n is a node m such that there exists a directed - edge from n to m. - - Parameters - ---------- - n : node - A node in the graph - - Raises - ------- - NetworkXError - If n is not in the graph. - - See Also - -------- - predecessors - - Notes - ----- - neighbors() and successors() are the same. - """ - try: - return iter(self._succ[n]) - except KeyError: - raise NetworkXError("The node %s is not in the digraph." % (n,)) - - # digraph definitions - neighbors = successors - - def predecessors(self, n): - """Returns an iterator over predecessor nodes of n. - - A predecessor of n is a node m such that there exists a directed - edge from m to n. - - Parameters - ---------- - n : node - A node in the graph - - Raises - ------- - NetworkXError - If n is not in the graph. - - See Also - -------- - successors - """ - try: - return iter(self._pred[n]) - except KeyError: - raise NetworkXError("The node %s is not in the digraph." % (n,)) - - @property - def edges(self): - """An OutEdgeView of the DiGraph as G.edges or G.edges(). - - edges(self, nbunch=None, data=False, default=None) - - The OutEdgeView provides set-like operations on the edge-tuples - as well as edge attribute lookup. When called, it also provides - an EdgeDataView object which allows control of access to edge - attributes (but does not provide set-like operations). - Hence, `G.edges[u, v]['color']` provides the value of the color - attribute for edge `(u, v)` while - `for (u, v, c) in G.edges.data('color', default='red'):` - iterates through all the edges yielding the color attribute - with default `'red'` if no color attribute exists. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - data : string or bool, optional (default=False) - The edge attribute returned in 3-tuple (u, v, ddict[data]). - If True, return edge attribute dict in 3-tuple (u, v, ddict). - If False, return 2-tuple (u, v). - default : value, optional (default=None) - Value used for edges that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - edges : OutEdgeView - A view of edge attributes, usually it iterates over (u, v) - or (u, v, d) tuples of edges, but can also be used for - attribute lookup as `edges[u, v]['foo']`. - - See Also - -------- - in_edges, out_edges - - Notes - ----- - Nodes in nbunch that are not in the graph will be (quietly) ignored. - For directed graphs this returns the out-edges. - - Examples - -------- - >>> G = nx.DiGraph() # or MultiDiGraph, etc - >>> nx.add_path(G, [0, 1, 2]) - >>> G.add_edge(2, 3, weight=5) - >>> [e for e in G.edges] - [(0, 1), (1, 2), (2, 3)] - >>> G.edges.data() # default data is {} (empty dict) - OutEdgeDataView([(0, 1, {}), (1, 2, {}), (2, 3, {'weight': 5})]) - >>> G.edges.data('weight', default=1) - OutEdgeDataView([(0, 1, 1), (1, 2, 1), (2, 3, 5)]) - >>> G.edges([0, 2]) # only edges incident to these nodes - OutEdgeDataView([(0, 1), (2, 3)]) - >>> G.edges(0) # only edges incident to a single node (use G.adj[0]?) - OutEdgeDataView([(0, 1)]) - - """ - return OutEdgeView(self) - - # alias out_edges to edges - out_edges = edges - - @property - def in_edges(self): - """An InEdgeView of the Graph as G.in_edges or G.in_edges(). - - in_edges(self, nbunch=None, data=False, default=None): - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - data : string or bool, optional (default=False) - The edge attribute returned in 3-tuple (u, v, ddict[data]). - If True, return edge attribute dict in 3-tuple (u, v, ddict). - If False, return 2-tuple (u, v). - default : value, optional (default=None) - Value used for edges that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - in_edges : InEdgeView - A view of edge attributes, usually it iterates over (u, v) - or (u, v, d) tuples of edges, but can also be used for - attribute lookup as `edges[u, v]['foo']`. - - See Also - -------- - edges - """ - return InEdgeView(self) - - @property - def degree(self): - """A DegreeView for the Graph as G.degree or G.degree(). - - The node degree is the number of edges adjacent to the node. - The weighted node degree is the sum of the edge weights for - edges incident to that node. - - This object provides an iterator for (node, degree) as well as - lookup for the degree for a single node. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - If a single node is requested - deg : int - Degree of the node - - OR if multiple nodes are requested - nd_iter : iterator - The iterator returns two-tuples of (node, degree). - - See Also - -------- - in_degree, out_degree - - Examples - -------- - >>> G = nx.DiGraph() # or MultiDiGraph - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.degree(0) # node 0 with degree 1 - 1 - >>> list(G.degree([0, 1, 2])) - [(0, 1), (1, 2), (2, 2)] - - """ - return DiDegreeView(self) - - @property - def in_degree(self): - """An InDegreeView for (node, in_degree) or in_degree for single node. - - The node in_degree is the number of edges pointing to the node. - The weighted node degree is the sum of the edge weights for - edges incident to that node. - - This object provides an iteration over (node, in_degree) as well as - lookup for the degree for a single node. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - If a single node is requested - deg : int - In-degree of the node - - OR if multiple nodes are requested - nd_iter : iterator - The iterator returns two-tuples of (node, in-degree). - - See Also - -------- - degree, out_degree - - Examples - -------- - >>> G = nx.DiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.in_degree(0) # node 0 with degree 0 - 0 - >>> list(G.in_degree([0, 1, 2])) - [(0, 0), (1, 1), (2, 1)] - - """ - return InDegreeView(self) - - @property - def out_degree(self): - """An OutDegreeView for (node, out_degree) - - The node out_degree is the number of edges pointing out of the node. - The weighted node degree is the sum of the edge weights for - edges incident to that node. - - This object provides an iterator over (node, out_degree) as well as - lookup for the degree for a single node. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - If a single node is requested - deg : int - Out-degree of the node - - OR if multiple nodes are requested - nd_iter : iterator - The iterator returns two-tuples of (node, out-degree). - - See Also - -------- - degree, in_degree - - Examples - -------- - >>> G = nx.DiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.out_degree(0) # node 0 with degree 1 - 1 - >>> list(G.out_degree([0, 1, 2])) - [(0, 1), (1, 1), (2, 1)] - - """ - return OutDegreeView(self) - - def clear(self): - """Remove all nodes and edges from the graph. - - This also removes the name, and all graph, node, and edge attributes. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.clear() - >>> list(G.nodes) - [] - >>> list(G.edges) - [] - """ - self._succ.clear() - self._pred.clear() - self._node.clear() - self.graph.clear() - - def is_multigraph(self): - """Returns True if graph is a multigraph, False otherwise.""" - return False - - def is_directed(self): - """Returns True if graph is directed, False otherwise.""" - return True - - def to_undirected(self, reciprocal=False, as_view=False): - """Returns an undirected representation of the digraph. - - Parameters - ---------- - reciprocal : bool (optional) - If True only keep edges that appear in both directions - in the original digraph. - as_view : bool (optional, default=False) - If True return an undirected view of the original directed graph. - - Returns - ------- - G : Graph - An undirected graph with the same name and nodes and - with edge (u, v, data) if either (u, v, data) or (v, u, data) - is in the digraph. If both edges exist in digraph and - their edge data is different, only one edge is created - with an arbitrary choice of which edge data to use. - You must check and correct for this manually if desired. - - See Also - -------- - Graph, copy, add_edge, add_edges_from - - Notes - ----- - If edges in both directions (u, v) and (v, u) exist in the - graph, attributes for the new undirected edge will be a combination of - the attributes of the directed edges. The edge data is updated - in the (arbitrary) order that the edges are encountered. For - more customized control of the edge attributes use add_edge(). - - This returns a "deepcopy" of the edge, node, and - graph attributes which attempts to completely copy - all of the data and references. - - This is in contrast to the similar G=DiGraph(D) which returns a - shallow copy of the data. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/2/library/copy.html. - - Warning: If you have subclassed DiGraph to use dict-like objects - in the data structure, those changes do not transfer to the - Graph created by this method. - - Examples - -------- - >>> G = nx.path_graph(2) # or MultiGraph, etc - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1), (1, 0)] - >>> G2 = H.to_undirected() - >>> list(G2.edges) - [(0, 1)] - """ - graph_class = self.to_undirected_class() - if as_view is True: - return nx.graphviews.generic_graph_view(self, Graph) - # deepcopy when not a view - G = Graph() - G.graph.update(deepcopy(self.graph)) - G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) - if reciprocal is True: - G.add_edges_from((u, v, deepcopy(d)) - for u, nbrs in self._adj.items() - for v, d in nbrs.items() - if v in self._pred[u]) - else: - G.add_edges_from((u, v, deepcopy(d)) - for u, nbrs in self._adj.items() - for v, d in nbrs.items()) - return G - - def reverse(self, copy=True): - """Returns the reverse of the graph. - - The reverse is a graph with the same nodes and edges - but with the directions of the edges reversed. - - Parameters - ---------- - copy : bool optional (default=True) - If True, return a new DiGraph holding the reversed edges. - If False, the reverse graph is created using a view of - the original graph. - """ - if copy: - H = self.__class__() - H.graph.update(deepcopy(self.graph)) - H.add_nodes_from((n, deepcopy(d)) for n, d in self.nodes.items()) - H.add_edges_from((v, u, deepcopy(d)) for u, v, d - in self.edges(data=True)) - return H - return nx.graphviews.reverse_view(self) diff --git a/extensions/fablabchemnitz/networkx/classes/filters.py b/extensions/fablabchemnitz/networkx/classes/filters.py deleted file mode 100644 index ee992090..00000000 --- a/extensions/fablabchemnitz/networkx/classes/filters.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Author: Aric Hagberg (hagberg@lanl.gov), -# Pieter Swart (swart@lanl.gov), -# Dan Schult(dschult@colgate.edu) -"""Filter factories to hide or show sets of nodes and edges. - -These filters return the function used when creating `SubGraph`. -""" -__all__ = ['no_filter', 'hide_nodes', - 'hide_edges', 'hide_multiedges', - 'hide_diedges', 'hide_multidiedges', - 'show_nodes', - 'show_edges', 'show_multiedges', - 'show_diedges', 'show_multidiedges', - ] - - -def no_filter(*items): - return True - - -def hide_nodes(nodes): - nodes = set(nodes) - return lambda node: node not in nodes - - -def hide_diedges(edges): - edges = {(u, v) for u, v in edges} - return lambda u, v: (u, v) not in edges - - -def hide_edges(edges): - alledges = set(edges) | {(v, u) for (u, v) in edges} - return lambda u, v: (u, v) not in alledges - - -def hide_multidiedges(edges): - edges = {(u, v, k) for u, v, k in edges} - return lambda u, v, k: (u, v, k) not in edges - - -def hide_multiedges(edges): - alledges = set(edges) | {(v, u, k) for (u, v, k) in edges} - return lambda u, v, k: (u, v, k) not in alledges - - -# write show_nodes as a class to make SubGraph pickleable -class show_nodes(object): - def __init__(self, nodes): - self.nodes = set(nodes) - - def __call__(self, node): - return node in self.nodes - - -def show_diedges(edges): - edges = {(u, v) for u, v in edges} - return lambda u, v: (u, v) in edges - - -def show_edges(edges): - alledges = set(edges) | {(v, u) for (u, v) in edges} - return lambda u, v: (u, v) in alledges - - -def show_multidiedges(edges): - edges = {(u, v, k) for u, v, k in edges} - return lambda u, v, k: (u, v, k) in edges - - -def show_multiedges(edges): - alledges = set(edges) | {(v, u, k) for (u, v, k) in edges} - return lambda u, v, k: (u, v, k) in alledges diff --git a/extensions/fablabchemnitz/networkx/classes/function.py b/extensions/fablabchemnitz/networkx/classes/function.py deleted file mode 100644 index 9764db5d..00000000 --- a/extensions/fablabchemnitz/networkx/classes/function.py +++ /dev/null @@ -1,1192 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg -# Pieter Swart -# Dan Schult -"""Functional interface to graph methods and assorted utilities. -""" - -from collections import Counter -from itertools import chain -try: - from itertools import zip_longest -except ImportError: - from itertools import izip_longest as zip_longest - -import networkx as nx -from networkx.utils import pairwise, not_implemented_for - -from networkx.classes.graphviews import subgraph_view, reverse_view - -__all__ = ['nodes', 'edges', 'degree', 'degree_histogram', 'neighbors', - 'number_of_nodes', 'number_of_edges', 'density', - 'is_directed', 'info', 'freeze', 'is_frozen', - 'subgraph', 'subgraph_view', 'induced_subgraph', 'reverse_view', - 'edge_subgraph', 'restricted_view', - 'to_directed', 'to_undirected', - 'add_star', 'add_path', 'add_cycle', - 'create_empty_copy', 'set_node_attributes', - 'get_node_attributes', 'set_edge_attributes', - 'get_edge_attributes', 'all_neighbors', 'non_neighbors', - 'non_edges', 'common_neighbors', 'is_weighted', - 'is_negatively_weighted', 'is_empty', - 'selfloop_edges', 'nodes_with_selfloops', 'number_of_selfloops', - ] - - -def nodes(G): - """Returns an iterator over the graph nodes.""" - return G.nodes() - - -def edges(G, nbunch=None): - """Returns an edge view of edges incident to nodes in nbunch. - - Return all edges if nbunch is unspecified or nbunch=None. - - For digraphs, edges=out_edges - """ - return G.edges(nbunch) - - -def degree(G, nbunch=None, weight=None): - """Returns a degree view of single node or of nbunch of nodes. - If nbunch is omitted, then return degrees of *all* nodes. - """ - return G.degree(nbunch, weight) - - -def neighbors(G, n): - """Returns a list of nodes connected to node n. """ - return G.neighbors(n) - - -def number_of_nodes(G): - """Returns the number of nodes in the graph.""" - return G.number_of_nodes() - - -def number_of_edges(G): - """Returns the number of edges in the graph. """ - return G.number_of_edges() - - -def density(G): - r"""Returns the density of a graph. - - The density for undirected graphs is - - .. math:: - - d = \frac{2m}{n(n-1)}, - - and for directed graphs is - - .. math:: - - d = \frac{m}{n(n-1)}, - - where `n` is the number of nodes and `m` is the number of edges in `G`. - - Notes - ----- - The density is 0 for a graph without edges and 1 for a complete graph. - The density of multigraphs can be higher than 1. - - Self loops are counted in the total number of edges so graphs with self - loops can have density higher than 1. - """ - n = number_of_nodes(G) - m = number_of_edges(G) - if m == 0 or n <= 1: - return 0 - d = m / (n * (n - 1)) - if not G.is_directed(): - d *= 2 - return d - - -def degree_histogram(G): - """Returns a list of the frequency of each degree value. - - Parameters - ---------- - G : Networkx graph - A graph - - Returns - ------- - hist : list - A list of frequencies of degrees. - The degree values are the index in the list. - - Notes - ----- - Note: the bins are width one, hence len(list) can be large - (Order(number_of_edges)) - """ - counts = Counter(d for n, d in G.degree()) - return [counts.get(i, 0) for i in range(max(counts) + 1)] - - -def is_directed(G): - """ Return True if graph is directed.""" - return G.is_directed() - - -def frozen(*args, **kwargs): - """Dummy method for raising errors when trying to modify frozen graphs""" - raise nx.NetworkXError("Frozen graph can't be modified") - - -def freeze(G): - """Modify graph to prevent further change by adding or removing - nodes or edges. - - Node and edge data can still be modified. - - Parameters - ---------- - G : graph - A NetworkX graph - - Examples - -------- - >>> G = nx.path_graph(4) - >>> G = nx.freeze(G) - >>> try: - ... G.add_edge(4, 5) - ... except nx.NetworkXError as e: - ... print(str(e)) - Frozen graph can't be modified - - Notes - ----- - To "unfreeze" a graph you must make a copy by creating a new graph object: - - >>> graph = nx.path_graph(4) - >>> frozen_graph = nx.freeze(graph) - >>> unfrozen_graph = nx.Graph(frozen_graph) - >>> nx.is_frozen(unfrozen_graph) - False - - See Also - -------- - is_frozen - """ - G.add_node = frozen - G.add_nodes_from = frozen - G.remove_node = frozen - G.remove_nodes_from = frozen - G.add_edge = frozen - G.add_edges_from = frozen - G.add_weighted_edges_from = frozen - G.remove_edge = frozen - G.remove_edges_from = frozen - G.clear = frozen - G.frozen = True - return G - - -def is_frozen(G): - """Returns True if graph is frozen. - - Parameters - ---------- - G : graph - A NetworkX graph - - See Also - -------- - freeze - """ - try: - return G.frozen - except AttributeError: - return False - - -def add_star(G_to_add_to, nodes_for_star, **attr): - """Add a star to Graph G_to_add_to. - - The first node in `nodes_for_star` is the middle of the star. - It is connected to all other nodes. - - Parameters - ---------- - G_to_add_to : graph - A NetworkX graph - nodes_for_star : iterable container - A container of nodes. - attr : keyword arguments, optional (default= no attributes) - Attributes to add to every edge in star. - - See Also - -------- - add_path, add_cycle - - Examples - -------- - >>> G = nx.Graph() - >>> nx.add_star(G, [0, 1, 2, 3]) - >>> nx.add_star(G, [10, 11, 12], weight=2) - """ - nlist = iter(nodes_for_star) - try: - v = next(nlist) - except StopIteration: - return - G_to_add_to.add_node(v) - edges = ((v, n) for n in nlist) - G_to_add_to.add_edges_from(edges, **attr) - - -def add_path(G_to_add_to, nodes_for_path, **attr): - """Add a path to the Graph G_to_add_to. - - Parameters - ---------- - G_to_add_to : graph - A NetworkX graph - nodes_for_path : iterable container - A container of nodes. A path will be constructed from - the nodes (in order) and added to the graph. - attr : keyword arguments, optional (default= no attributes) - Attributes to add to every edge in path. - - See Also - -------- - add_star, add_cycle - - Examples - -------- - >>> G = nx.Graph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> nx.add_path(G, [10, 11, 12], weight=7) - """ - nlist = iter(nodes_for_path) - try: - first_node = next(nlist) - except StopIteration: - return - G_to_add_to.add_node(first_node) - G_to_add_to.add_edges_from(pairwise(chain((first_node,), nlist)), **attr) - - -def add_cycle(G_to_add_to, nodes_for_cycle, **attr): - """Add a cycle to the Graph G_to_add_to. - - Parameters - ---------- - G_to_add_to : graph - A NetworkX graph - nodes_for_cycle: iterable container - A container of nodes. A cycle will be constructed from - the nodes (in order) and added to the graph. - attr : keyword arguments, optional (default= no attributes) - Attributes to add to every edge in cycle. - - See Also - -------- - add_path, add_star - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> nx.add_cycle(G, [0, 1, 2, 3]) - >>> nx.add_cycle(G, [10, 11, 12], weight=7) - """ - nlist = iter(nodes_for_cycle) - try: - first_node = next(nlist) - except StopIteration: - return - G_to_add_to.add_node(first_node) - G_to_add_to.add_edges_from(pairwise(chain((first_node,), nlist), cyclic=True), **attr) - - -def subgraph(G, nbunch): - """Returns the subgraph induced on nodes in nbunch. - - Parameters - ---------- - G : graph - A NetworkX graph - - nbunch : list, iterable - A container of nodes that will be iterated through once (thus - it should be an iterator or be iterable). Each element of the - container should be a valid node type: any hashable type except - None. If nbunch is None, return all edges data in the graph. - Nodes in nbunch that are not in the graph will be (quietly) - ignored. - - Notes - ----- - subgraph(G) calls G.subgraph() - """ - return G.subgraph(nbunch) - - -def induced_subgraph(G, nbunch): - """Returns a SubGraph view of `G` showing only nodes in nbunch. - - The induced subgraph of a graph on a set of nodes N is the - graph with nodes N and edges from G which have both ends in N. - - Parameters - ---------- - G : NetworkX Graph - nbunch : node, container of nodes or None (for all nodes) - - Returns - ------- - subgraph : SubGraph View - A read-only view of the subgraph in `G` induced by the nodes. - Changes to the graph `G` will be reflected in the view. - - Notes - ----- - To create a mutable subgraph with its own copies of nodes - edges and attributes use `subgraph.copy()` or `Graph(subgraph)` - - For an inplace reduction of a graph to a subgraph you can remove nodes: - `G.remove_nodes_from(n in G if n not in set(nbunch))` - - If you are going to compute subgraphs of your subgraphs you could - end up with a chain of views that can be very slow once the chain - has about 15 views in it. If they are all induced subgraphs, you - can short-cut the chain by making them all subgraphs of the original - graph. The graph class method `G.subgraph` does this when `G` is - a subgraph. In contrast, this function allows you to choose to build - chains or not, as you wish. The returned subgraph is a view on `G`. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> H = G.subgraph([0, 1, 2]) - >>> list(H.edges) - [(0, 1), (1, 2)] - """ - induced_nodes = nx.filters.show_nodes(G.nbunch_iter(nbunch)) - return nx.graphviews.subgraph_view(G, induced_nodes) - - -def edge_subgraph(G, edges): - """Returns a view of the subgraph induced by the specified edges. - - The induced subgraph contains each edge in `edges` and each - node incident to any of those edges. - - Parameters - ---------- - G : NetworkX Graph - edges : iterable - An iterable of edges. Edges not present in `G` are ignored. - - Returns - ------- - subgraph : SubGraph View - A read-only edge-induced subgraph of `G`. - Changes to `G` are reflected in the view. - - Notes - ----- - To create a mutable subgraph with its own copies of nodes - edges and attributes use `subgraph.copy()` or `Graph(subgraph)` - - If you create a subgraph of a subgraph recursively you can end up - with a chain of subgraphs that becomes very slow with about 15 - nested subgraph views. Luckily the edge_subgraph filter nests - nicely so you can use the original graph as G in this function - to avoid chains. We do not rule out chains programmatically so - that odd cases like an `edge_subgraph` of a `restricted_view` - can be created. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.path_graph(5) - >>> H = G.edge_subgraph([(0, 1), (3, 4)]) - >>> list(H.nodes) - [0, 1, 3, 4] - >>> list(H.edges) - [(0, 1), (3, 4)] - """ - nxf = nx.filters - edges = set(edges) - nodes = set() - for e in edges: - nodes.update(e[:2]) - induced_nodes = nxf.show_nodes(nodes) - if G.is_multigraph(): - if G.is_directed(): - induced_edges = nxf.show_multidiedges(edges) - else: - induced_edges = nxf.show_multiedges(edges) - else: - if G.is_directed(): - induced_edges = nxf.show_diedges(edges) - else: - induced_edges = nxf.show_edges(edges) - return nx.graphviews.subgraph_view(G, induced_nodes, induced_edges) - - -def restricted_view(G, nodes, edges): - """Returns a view of `G` with hidden nodes and edges. - - The resulting subgraph filters out node `nodes` and edges `edges`. - Filtered out nodes also filter out any of their edges. - - Parameters - ---------- - G : NetworkX Graph - nodes : iterable - An iterable of nodes. Nodes not present in `G` are ignored. - edges : iterable - An iterable of edges. Edges not present in `G` are ignored. - - Returns - ------- - subgraph : SubGraph View - A read-only restricted view of `G` filtering out nodes and edges. - Changes to `G` are reflected in the view. - - Notes - ----- - To create a mutable subgraph with its own copies of nodes - edges and attributes use `subgraph.copy()` or `Graph(subgraph)` - - If you create a subgraph of a subgraph recursively you may end up - with a chain of subgraph views. Such chains can get quite slow - for lengths near 15. To avoid long chains, try to make your subgraph - based on the original graph. We do not rule out chains programmatically - so that odd cases like an `edge_subgraph` of a `restricted_view` - can be created. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.path_graph(5) - >>> H = nx.restricted_view(G, [0], [(1, 2), (3, 4)]) - >>> list(H.nodes) - [1, 2, 3, 4] - >>> list(H.edges) - [(2, 3)] - """ - nxf = nx.filters - hide_nodes = nxf.hide_nodes(nodes) - if G.is_multigraph(): - if G.is_directed(): - hide_edges = nxf.hide_multidiedges(edges) - else: - hide_edges = nxf.hide_multiedges(edges) - else: - if G.is_directed(): - hide_edges = nxf.hide_diedges(edges) - else: - hide_edges = nxf.hide_edges(edges) - return nx.graphviews.subgraph_view(G, hide_nodes, hide_edges) - - -def to_directed(graph): - """Returns a directed view of the graph `graph`. - - Identical to graph.to_directed(as_view=True) - Note that graph.to_directed defaults to `as_view=False` - while this function always provides a view. - """ - return graph.to_directed(as_view=True) - - -def to_undirected(graph): - """Returns an undirected view of the graph `graph`. - - Identical to graph.to_undirected(as_view=True) - Note that graph.to_undirected defaults to `as_view=False` - while this function always provides a view. - """ - return graph.to_undirected(as_view=True) - - -def create_empty_copy(G, with_data=True): - """Returns a copy of the graph G with all of the edges removed. - - Parameters - ---------- - G : graph - A NetworkX graph - - with_data : bool (default=True) - Propagate Graph and Nodes data to the new graph. - - See Also - ----- - empty_graph - - """ - H = G.__class__() - H.add_nodes_from(G.nodes(data=with_data)) - if with_data: - H.graph.update(G.graph) - return H - - -def info(G, n=None): - """Print short summary of information for the graph G or the node n. - - Parameters - ---------- - G : Networkx graph - A graph - n : node (any hashable) - A node in the graph G - """ - info = '' # append this all to a string - if n is None: - info += "Name: %s\n" % G.name - type_name = [type(G).__name__] - info += "Type: %s\n" % ",".join(type_name) - info += "Number of nodes: %d\n" % G.number_of_nodes() - info += "Number of edges: %d\n" % G.number_of_edges() - nnodes = G.number_of_nodes() - if len(G) > 0: - if G.is_directed(): - deg = sum(d for n, d in G.in_degree()) / float(nnodes) - info += "Average in degree: %8.4f\n" % deg - deg = sum(d for n, d in G.out_degree()) / float(nnodes) - info += "Average out degree: %8.4f" % deg - else: - s = sum(dict(G.degree()).values()) - info += "Average degree: %8.4f" % (float(s) / float(nnodes)) - - else: - if n not in G: - raise nx.NetworkXError("node %s not in graph" % (n,)) - info += "Node % s has the following properties:\n" % n - info += "Degree: %d\n" % G.degree(n) - info += "Neighbors: " - info += ' '.join(str(nbr) for nbr in G.neighbors(n)) - return info - - -def set_node_attributes(G, values, name=None): - """Sets node attributes from a given value or dictionary of values. - - .. Warning:: The call order of arguments `values` and `name` - switched between v1.x & v2.x. - - Parameters - ---------- - G : NetworkX Graph - - values : scalar value, dict-like - What the node attribute should be set to. If `values` is - not a dictionary, then it is treated as a single attribute value - that is then applied to every node in `G`. This means that if - you provide a mutable object, like a list, updates to that object - will be reflected in the node attribute for every node. - The attribute name will be `name`. - - If `values` is a dict or a dict of dict, it should be keyed - by node to either an attribute value or a dict of attribute key/value - pairs used to update the node's attributes. - - name : string (optional, default=None) - Name of the node attribute to set if values is a scalar. - - Examples - -------- - After computing some property of the nodes of a graph, you may want - to assign a node attribute to store the value of that property for - each node:: - - >>> G = nx.path_graph(3) - >>> bb = nx.betweenness_centrality(G) - >>> isinstance(bb, dict) - True - >>> nx.set_node_attributes(G, bb, 'betweenness') - >>> G.nodes[1]['betweenness'] - 1.0 - - If you provide a list as the second argument, updates to the list - will be reflected in the node attribute for each node:: - - >>> G = nx.path_graph(3) - >>> labels = [] - >>> nx.set_node_attributes(G, labels, 'labels') - >>> labels.append('foo') - >>> G.nodes[0]['labels'] - ['foo'] - >>> G.nodes[1]['labels'] - ['foo'] - >>> G.nodes[2]['labels'] - ['foo'] - - If you provide a dictionary of dictionaries as the second argument, - the outer dictionary is assumed to be keyed by node to an inner - dictionary of node attributes for that node:: - - >>> G = nx.path_graph(3) - >>> attrs = {0: {'attr1': 20, 'attr2': 'nothing'}, 1: {'attr2': 3}} - >>> nx.set_node_attributes(G, attrs) - >>> G.nodes[0]['attr1'] - 20 - >>> G.nodes[0]['attr2'] - 'nothing' - >>> G.nodes[1]['attr2'] - 3 - >>> G.nodes[2] - {} - - """ - # Set node attributes based on type of `values` - if name is not None: # `values` must not be a dict of dict - try: # `values` is a dict - for n, v in values.items(): - try: - G.nodes[n][name] = values[n] - except KeyError: - pass - except AttributeError: # `values` is a constant - for n in G: - G.nodes[n][name] = values - else: # `values` must be dict of dict - for n, d in values.items(): - try: - G.nodes[n].update(d) - except KeyError: - pass - - -def get_node_attributes(G, name): - """Get node attributes from graph - - Parameters - ---------- - G : NetworkX Graph - - name : string - Attribute name - - Returns - ------- - Dictionary of attributes keyed by node. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_nodes_from([1, 2, 3], color='red') - >>> color = nx.get_node_attributes(G, 'color') - >>> color[1] - 'red' - """ - return {n: d[name] for n, d in G.nodes.items() if name in d} - - -def set_edge_attributes(G, values, name=None): - """Sets edge attributes from a given value or dictionary of values. - - .. Warning:: The call order of arguments `values` and `name` - switched between v1.x & v2.x. - - Parameters - ---------- - G : NetworkX Graph - - values : scalar value, dict-like - What the edge attribute should be set to. If `values` is - not a dictionary, then it is treated as a single attribute value - that is then applied to every edge in `G`. This means that if - you provide a mutable object, like a list, updates to that object - will be reflected in the edge attribute for each edge. The attribute - name will be `name`. - - If `values` is a dict or a dict of dict, it should be keyed - by edge tuple to either an attribute value or a dict of attribute - key/value pairs used to update the edge's attributes. - For multigraphs, the edge tuples must be of the form ``(u, v, key)``, - where `u` and `v` are nodes and `key` is the edge key. - For non-multigraphs, the keys must be tuples of the form ``(u, v)``. - - name : string (optional, default=None) - Name of the edge attribute to set if values is a scalar. - - Examples - -------- - After computing some property of the edges of a graph, you may want - to assign a edge attribute to store the value of that property for - each edge:: - - >>> G = nx.path_graph(3) - >>> bb = nx.edge_betweenness_centrality(G, normalized=False) - >>> nx.set_edge_attributes(G, bb, 'betweenness') - >>> G.edges[1, 2]['betweenness'] - 2.0 - - If you provide a list as the second argument, updates to the list - will be reflected in the edge attribute for each edge:: - - >>> labels = [] - >>> nx.set_edge_attributes(G, labels, 'labels') - >>> labels.append('foo') - >>> G.edges[0, 1]['labels'] - ['foo'] - >>> G.edges[1, 2]['labels'] - ['foo'] - - If you provide a dictionary of dictionaries as the second argument, - the entire dictionary will be used to update edge attributes:: - - >>> G = nx.path_graph(3) - >>> attrs = {(0, 1): {'attr1': 20, 'attr2': 'nothing'}, - ... (1, 2): {'attr2': 3}} - >>> nx.set_edge_attributes(G, attrs) - >>> G[0][1]['attr1'] - 20 - >>> G[0][1]['attr2'] - 'nothing' - >>> G[1][2]['attr2'] - 3 - - """ - if name is not None: - # `values` does not contain attribute names - try: - # if `values` is a dict using `.items()` => {edge: value} - if G.is_multigraph(): - for (u, v, key), value in values.items(): - try: - G[u][v][key][name] = value - except KeyError: - pass - else: - for (u, v), value in values.items(): - try: - G[u][v][name] = value - except KeyError: - pass - except AttributeError: - # treat `values` as a constant - for u, v, data in G.edges(data=True): - data[name] = values - else: - # `values` consists of doct-of-dict {edge: {attr: value}} shape - if G.is_multigraph(): - for (u, v, key), d in values.items(): - try: - G[u][v][key].update(d) - except KeyError: - pass - else: - for (u, v), d in values.items(): - try: - G[u][v].update(d) - except KeyError: - pass - - -def get_edge_attributes(G, name): - """Get edge attributes from graph - - Parameters - ---------- - G : NetworkX Graph - - name : string - Attribute name - - Returns - ------- - Dictionary of attributes keyed by edge. For (di)graphs, the keys are - 2-tuples of the form: (u, v). For multi(di)graphs, the keys are 3-tuples of - the form: (u, v, key). - - Examples - -------- - >>> G = nx.Graph() - >>> nx.add_path(G, [1, 2, 3], color='red') - >>> color = nx.get_edge_attributes(G, 'color') - >>> color[(1, 2)] - 'red' - """ - if G.is_multigraph(): - edges = G.edges(keys=True, data=True) - else: - edges = G.edges(data=True) - return {x[:-1]: x[-1][name] for x in edges if name in x[-1]} - - -def all_neighbors(graph, node): - """Returns all of the neighbors of a node in the graph. - - If the graph is directed returns predecessors as well as successors. - - Parameters - ---------- - graph : NetworkX graph - Graph to find neighbors. - - node : node - The node whose neighbors will be returned. - - Returns - ------- - neighbors : iterator - Iterator of neighbors - """ - if graph.is_directed(): - values = chain(graph.predecessors(node), graph.successors(node)) - else: - values = graph.neighbors(node) - return values - - -def non_neighbors(graph, node): - """Returns the non-neighbors of the node in the graph. - - Parameters - ---------- - graph : NetworkX graph - Graph to find neighbors. - - node : node - The node whose neighbors will be returned. - - Returns - ------- - non_neighbors : iterator - Iterator of nodes in the graph that are not neighbors of the node. - """ - nbors = set(neighbors(graph, node)) | {node} - return (nnode for nnode in graph if nnode not in nbors) - - -def non_edges(graph): - """Returns the non-existent edges in the graph. - - Parameters - ---------- - graph : NetworkX graph. - Graph to find non-existent edges. - - Returns - ------- - non_edges : iterator - Iterator of edges that are not in the graph. - """ - if graph.is_directed(): - for u in graph: - for v in non_neighbors(graph, u): - yield (u, v) - else: - nodes = set(graph) - while nodes: - u = nodes.pop() - for v in nodes - set(graph[u]): - yield (u, v) - - -@not_implemented_for('directed') -def common_neighbors(G, u, v): - """Returns the common neighbors of two nodes in a graph. - - Parameters - ---------- - G : graph - A NetworkX undirected graph. - - u, v : nodes - Nodes in the graph. - - Returns - ------- - cnbors : iterator - Iterator of common neighbors of u and v in the graph. - - Raises - ------ - NetworkXError - If u or v is not a node in the graph. - - Examples - -------- - >>> G = nx.complete_graph(5) - >>> sorted(nx.common_neighbors(G, 0, 1)) - [2, 3, 4] - """ - if u not in G: - raise nx.NetworkXError('u is not in the graph.') - if v not in G: - raise nx.NetworkXError('v is not in the graph.') - - # Return a generator explicitly instead of yielding so that the above - # checks are executed eagerly. - return (w for w in G[u] if w in G[v] and w not in (u, v)) - - -def is_weighted(G, edge=None, weight='weight'): - """Returns True if `G` has weighted edges. - - Parameters - ---------- - G : graph - A NetworkX graph. - - edge : tuple, optional - A 2-tuple specifying the only edge in `G` that will be tested. If - None, then every edge in `G` is tested. - - weight: string, optional - The attribute name used to query for edge weights. - - Returns - ------- - bool - A boolean signifying if `G`, or the specified edge, is weighted. - - Raises - ------ - NetworkXError - If the specified edge does not exist. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.is_weighted(G) - False - >>> nx.is_weighted(G, (2, 3)) - False - - >>> G = nx.DiGraph() - >>> G.add_edge(1, 2, weight=1) - >>> nx.is_weighted(G) - True - - """ - if edge is not None: - data = G.get_edge_data(*edge) - if data is None: - msg = 'Edge {!r} does not exist.'.format(edge) - raise nx.NetworkXError(msg) - return weight in data - - if is_empty(G): - # Special handling required since: all([]) == True - return False - - return all(weight in data for u, v, data in G.edges(data=True)) - - -def is_negatively_weighted(G, edge=None, weight='weight'): - """Returns True if `G` has negatively weighted edges. - - Parameters - ---------- - G : graph - A NetworkX graph. - - edge : tuple, optional - A 2-tuple specifying the only edge in `G` that will be tested. If - None, then every edge in `G` is tested. - - weight: string, optional - The attribute name used to query for edge weights. - - Returns - ------- - bool - A boolean signifying if `G`, or the specified edge, is negatively - weighted. - - Raises - ------ - NetworkXError - If the specified edge does not exist. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_edges_from([(1, 3), (2, 4), (2, 6)]) - >>> G.add_edge(1, 2, weight=4) - >>> nx.is_negatively_weighted(G, (1, 2)) - False - >>> G[2][4]['weight'] = -2 - >>> nx.is_negatively_weighted(G) - True - >>> G = nx.DiGraph() - >>> edges = [('0', '3', 3), ('0', '1', -5), ('1', '0', -2)] - >>> G.add_weighted_edges_from(edges) - >>> nx.is_negatively_weighted(G) - True - - """ - if edge is not None: - data = G.get_edge_data(*edge) - if data is None: - msg = 'Edge {!r} does not exist.'.format(edge) - raise nx.NetworkXError(msg) - return weight in data and data[weight] < 0 - - return any(weight in data and data[weight] < 0 - for u, v, data in G.edges(data=True)) - - -def is_empty(G): - """Returns True if `G` has no edges. - - Parameters - ---------- - G : graph - A NetworkX graph. - - Returns - ------- - bool - True if `G` has no edges, and False otherwise. - - Notes - ----- - An empty graph can have nodes but not edges. The empty graph with zero - nodes is known as the null graph. This is an $O(n)$ operation where n - is the number of nodes in the graph. - - """ - return not any(G.adj.values()) - - -def nodes_with_selfloops(G): - """Returns an iterator over nodes with self loops. - - A node with a self loop has an edge with both ends adjacent - to that node. - - Returns - ------- - nodelist : iterator - A iterator over nodes with self loops. - - See Also - -------- - selfloop_edges, number_of_selfloops - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edge(1, 1) - >>> G.add_edge(1, 2) - >>> list(nx.nodes_with_selfloops(G)) - [1] - - """ - return (n for n, nbrs in G.adj.items() if n in nbrs) - - -def selfloop_edges(G, data=False, keys=False, default=None): - """Returns an iterator over selfloop edges. - - A selfloop edge has the same node at both ends. - - Parameters - ---------- - data : string or bool, optional (default=False) - Return selfloop edges as two tuples (u, v) (data=False) - or three-tuples (u, v, datadict) (data=True) - or three-tuples (u, v, datavalue) (data='attrname') - keys : bool, optional (default=False) - If True, return edge keys with each edge. - default : value, optional (default=None) - Value used for edges that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - edgeiter : iterator over edge tuples - An iterator over all selfloop edges. - - See Also - -------- - nodes_with_selfloops, number_of_selfloops - - Examples - -------- - >>> G = nx.MultiGraph() # or Graph, DiGraph, MultiDiGraph, etc - >>> ekey = G.add_edge(1, 1) - >>> ekey = G.add_edge(1, 2) - >>> list(nx.selfloop_edges(G)) - [(1, 1)] - >>> list(nx.selfloop_edges(G, data=True)) - [(1, 1, {})] - >>> list(nx.selfloop_edges(G, keys=True)) - [(1, 1, 0)] - >>> list(nx.selfloop_edges(G, keys=True, data=True)) - [(1, 1, 0, {})] - """ - if data is True: - if G.is_multigraph(): - if keys is True: - return ((n, n, k, d) - for n, nbrs in G.adj.items() - if n in nbrs for k, d in nbrs[n].items()) - else: - return ((n, n, d) - for n, nbrs in G.adj.items() - if n in nbrs for d in nbrs[n].values()) - else: - return ((n, n, nbrs[n]) for n, nbrs in G.adj.items() if n in nbrs) - elif data is not False: - if G.is_multigraph(): - if keys is True: - return ((n, n, k, d.get(data, default)) - for n, nbrs in G.adj.items() - if n in nbrs for k, d in nbrs[n].items()) - else: - return ((n, n, d.get(data, default)) - for n, nbrs in G.adj.items() - if n in nbrs for d in nbrs[n].values()) - else: - return ((n, n, nbrs[n].get(data, default)) - for n, nbrs in G.adj.items() if n in nbrs) - else: - if G.is_multigraph(): - if keys is True: - return ((n, n, k) - for n, nbrs in G.adj.items() - if n in nbrs for k in nbrs[n]) - else: - return ((n, n) - for n, nbrs in G.adj.items() - if n in nbrs for d in nbrs[n].values()) - else: - return ((n, n) for n, nbrs in G.adj.items() if n in nbrs) - - -def number_of_selfloops(G): - """Returns the number of selfloop edges. - - A selfloop edge has the same node at both ends. - - Returns - ------- - nloops : int - The number of selfloops. - - See Also - -------- - nodes_with_selfloops, selfloop_edges - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edge(1, 1) - >>> G.add_edge(1, 2) - >>> nx.number_of_selfloops(G) - 1 - """ - return sum(1 for _ in nx.selfloop_edges(G)) diff --git a/extensions/fablabchemnitz/networkx/classes/graph.py b/extensions/fablabchemnitz/networkx/classes/graph.py deleted file mode 100644 index b31eff7b..00000000 --- a/extensions/fablabchemnitz/networkx/classes/graph.py +++ /dev/null @@ -1,1890 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Author: Aric Hagberg (hagberg@lanl.gov), -# Pieter Swart (swart@lanl.gov), -# Dan Schult(dschult@colgate.edu) -"""Base class for undirected graphs. - -The Graph class allows any hashable object as a node -and can associate key/value attribute pairs with each undirected edge. - -Self-loops are allowed but multiple edges are not (see MultiGraph). - -For directed graphs see DiGraph and MultiDiGraph. -""" -import warnings -from copy import deepcopy -from collections.abc import Mapping - -import networkx as nx -from networkx.classes.coreviews import AtlasView, AdjacencyView -from networkx.classes.reportviews import NodeView, EdgeView, DegreeView -from networkx.exception import NetworkXError -import networkx.convert as convert -from networkx.utils import pairwise - - -class Graph(object): - """ - Base class for undirected graphs. - - A Graph stores nodes and edges with optional data, or attributes. - - Graphs hold undirected edges. Self loops are allowed but multiple - (parallel) edges are not. - - Nodes can be arbitrary (hashable) Python objects with optional - key/value attributes. By convention `None` is not used as a node. - - Edges are represented as links between nodes with optional - key/value attributes. - - Parameters - ---------- - incoming_graph_data : input graph (optional, default: None) - Data to initialize graph. If None (default) an empty - graph is created. The data can be any format that is supported - by the to_networkx_graph() function, currently including edge list, - dict of dicts, dict of lists, NetworkX graph, NumPy matrix - or 2d ndarray, SciPy sparse matrix, or PyGraphviz graph. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - DiGraph - MultiGraph - MultiDiGraph - OrderedGraph - - Examples - -------- - Create an empty graph structure (a "null graph") with no nodes and - no edges. - - >>> G = nx.Graph() - - G can be grown in several ways. - - **Nodes:** - - Add one node at a time: - - >>> G.add_node(1) - - Add the nodes from any container (a list, dict, set or - even the lines from a file or the nodes from another graph). - - >>> G.add_nodes_from([2, 3]) - >>> G.add_nodes_from(range(100, 110)) - >>> H = nx.path_graph(10) - >>> G.add_nodes_from(H) - - In addition to strings and integers any hashable Python object - (except None) can represent a node, e.g. a customized node object, - or even another Graph. - - >>> G.add_node(H) - - **Edges:** - - G can also be grown by adding edges. - - Add one edge, - - >>> G.add_edge(1, 2) - - a list of edges, - - >>> G.add_edges_from([(1, 2), (1, 3)]) - - or a collection of edges, - - >>> G.add_edges_from(H.edges) - - If some edges connect nodes not yet in the graph, the nodes - are added automatically. There are no errors when adding - nodes or edges that already exist. - - **Attributes:** - - Each graph, node, and edge can hold key/value attribute pairs - in an associated attribute dictionary (the keys must be hashable). - By default these are empty, but can be added or changed using - add_edge, add_node or direct manipulation of the attribute - dictionaries named graph, node and edge respectively. - - >>> G = nx.Graph(day="Friday") - >>> G.graph - {'day': 'Friday'} - - Add node attributes using add_node(), add_nodes_from() or G.nodes - - >>> G.add_node(1, time='5pm') - >>> G.add_nodes_from([3], time='2pm') - >>> G.nodes[1] - {'time': '5pm'} - >>> G.nodes[1]['room'] = 714 # node must exist already to use G.nodes - >>> del G.nodes[1]['room'] # remove attribute - >>> list(G.nodes(data=True)) - [(1, {'time': '5pm'}), (3, {'time': '2pm'})] - - Add edge attributes using add_edge(), add_edges_from(), subscript - notation, or G.edges. - - >>> G.add_edge(1, 2, weight=4.7 ) - >>> G.add_edges_from([(3, 4), (4, 5)], color='red') - >>> G.add_edges_from([(1, 2, {'color': 'blue'}), (2, 3, {'weight': 8})]) - >>> G[1][2]['weight'] = 4.7 - >>> G.edges[1, 2]['weight'] = 4 - - Warning: we protect the graph data structure by making `G.edges` a - read-only dict-like structure. However, you can assign to attributes - in e.g. `G.edges[1, 2]`. Thus, use 2 sets of brackets to add/change - data attributes: `G.edges[1, 2]['weight'] = 4` - (For multigraphs: `MG.edges[u, v, key][name] = value`). - - **Shortcuts:** - - Many common graph features allow python syntax to speed reporting. - - >>> 1 in G # check if node in graph - True - >>> [n for n in G if n < 3] # iterate through nodes - [1, 2] - >>> len(G) # number of nodes in graph - 5 - - Often the best way to traverse all edges of a graph is via the neighbors. - The neighbors are reported as an adjacency-dict `G.adj` or `G.adjacency()` - - >>> for n, nbrsdict in G.adjacency(): - ... for nbr, eattr in nbrsdict.items(): - ... if 'weight' in eattr: - ... # Do something useful with the edges - ... pass - - But the edges() method is often more convenient: - - >>> for u, v, weight in G.edges.data('weight'): - ... if weight is not None: - ... # Do something useful with the edges - ... pass - - **Reporting:** - - Simple graph information is obtained using object-attributes and methods. - Reporting typically provides views instead of containers to reduce memory - usage. The views update as the graph is updated similarly to dict-views. - The objects `nodes, `edges` and `adj` provide access to data attributes - via lookup (e.g. `nodes[n], `edges[u, v]`, `adj[u][v]`) and iteration - (e.g. `nodes.items()`, `nodes.data('color')`, - `nodes.data('color', default='blue')` and similarly for `edges`) - Views exist for `nodes`, `edges`, `neighbors()`/`adj` and `degree`. - - For details on these and other miscellaneous methods, see below. - - **Subclasses (Advanced):** - - The Graph class uses a dict-of-dict-of-dict data structure. - The outer dict (node_dict) holds adjacency information keyed by node. - The next dict (adjlist_dict) represents the adjacency information and holds - edge data keyed by neighbor. The inner dict (edge_attr_dict) represents - the edge data and holds edge attribute values keyed by attribute names. - - Each of these three dicts can be replaced in a subclass by a user defined - dict-like object. In general, the dict-like features should be - maintained but extra features can be added. To replace one of the - dicts create a new graph class by changing the class(!) variable - holding the factory for that dict-like structure. The variable names are - node_dict_factory, node_attr_dict_factory, adjlist_inner_dict_factory, - adjlist_outer_dict_factory, edge_attr_dict_factory and graph_attr_dict_factory. - - node_dict_factory : function, (default: dict) - Factory function to be used to create the dict containing node - attributes, keyed by node id. - It should require no arguments and return a dict-like object - - node_attr_dict_factory: function, (default: dict) - Factory function to be used to create the node attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object - - adjlist_outer_dict_factory : function, (default: dict) - Factory function to be used to create the outer-most dict - in the data structure that holds adjacency info keyed by node. - It should require no arguments and return a dict-like object. - - adjlist_inner_dict_factory : function, (default: dict) - Factory function to be used to create the adjacency list - dict which holds edge data keyed by neighbor. - It should require no arguments and return a dict-like object - - edge_attr_dict_factory : function, (default: dict) - Factory function to be used to create the edge attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - graph_attr_dict_factory : function, (default: dict) - Factory function to be used to create the graph attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - Typically, if your extension doesn't impact the data structure all - methods will inherit without issue except: `to_directed/to_undirected`. - By default these methods create a DiGraph/Graph class and you probably - want them to create your extension of a DiGraph/Graph. To facilitate - this we define two class variables that you can set in your subclass. - - to_directed_class : callable, (default: DiGraph or MultiDiGraph) - Class to create a new graph structure in the `to_directed` method. - If `None`, a NetworkX class (DiGraph or MultiDiGraph) is used. - - to_undirected_class : callable, (default: Graph or MultiGraph) - Class to create a new graph structure in the `to_undirected` method. - If `None`, a NetworkX class (Graph or MultiGraph) is used. - - Examples - -------- - - Create a low memory graph class that effectively disallows edge - attributes by using a single attribute dict for all edges. - This reduces the memory used, but you lose edge attributes. - - >>> class ThinGraph(nx.Graph): - ... all_edge_dict = {'weight': 1} - ... def single_edge_dict(self): - ... return self.all_edge_dict - ... edge_attr_dict_factory = single_edge_dict - >>> G = ThinGraph() - >>> G.add_edge(2, 1) - >>> G[2][1] - {'weight': 1} - >>> G.add_edge(2, 2) - >>> G[2][1] is G[2][2] - True - - Please see :mod:`~networkx.classes.ordered` for more examples of - creating graph subclasses by overwriting the base class `dict` with - a dictionary-like object. - """ - node_dict_factory = dict - node_attr_dict_factory = dict - adjlist_outer_dict_factory = dict - adjlist_inner_dict_factory = dict - edge_attr_dict_factory = dict - graph_attr_dict_factory = dict - - def to_directed_class(self): - """Returns the class to use for empty directed copies. - - If you subclass the base classes, use this to designate - what directed class to use for `to_directed()` copies. - """ - return nx.DiGraph - - def to_undirected_class(self): - """Returns the class to use for empty undirected copies. - - If you subclass the base classes, use this to designate - what directed class to use for `to_directed()` copies. - """ - return Graph - - def __init__(self, incoming_graph_data=None, **attr): - """Initialize a graph with edges, name, or graph attributes. - - Parameters - ---------- - incoming_graph_data : input graph (optional, default: None) - Data to initialize graph. If None (default) an empty - graph is created. The data can be an edge list, or any - NetworkX graph object. If the corresponding optional Python - packages are installed the data can also be a NumPy matrix - or 2d ndarray, a SciPy sparse matrix, or a PyGraphviz graph. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - convert - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G = nx.Graph(name='my graph') - >>> e = [(1, 2), (2, 3), (3, 4)] # list of edges - >>> G = nx.Graph(e) - - Arbitrary graph attribute pairs (key=value) may be assigned - - >>> G = nx.Graph(e, day="Friday") - >>> G.graph - {'day': 'Friday'} - - """ - self.graph_attr_dict_factory = self.graph_attr_dict_factory - self.node_dict_factory = self.node_dict_factory - self.node_attr_dict_factory = self.node_attr_dict_factory - self.adjlist_outer_dict_factory = self.adjlist_outer_dict_factory - self.adjlist_inner_dict_factory = self.adjlist_inner_dict_factory - self.edge_attr_dict_factory = self.edge_attr_dict_factory - - self.graph = self.graph_attr_dict_factory() # dictionary for graph attributes - self._node = self.node_dict_factory() # empty node attribute dict - self._adj = self.adjlist_outer_dict_factory() # empty adjacency dict - # attempt to load graph with data - if incoming_graph_data is not None: - convert.to_networkx_graph(incoming_graph_data, create_using=self) - # load graph attributes (must be after convert) - self.graph.update(attr) - - @property - def adj(self): - """Graph adjacency object holding the neighbors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edge-data-dict. So `G.adj[3][2]['color'] = 'blue'` sets - the color of the edge `(3, 2)` to `"blue"`. - - Iterating over G.adj behaves like a dict. Useful idioms include - `for nbr, datadict in G.adj[n].items():`. - - The neighbor information is also provided by subscripting the graph. - So `for nbr, foovalue in G[node].data('foo', default=1):` works. - - For directed graphs, `G.adj` holds outgoing (successor) info. - """ - return AdjacencyView(self._adj) - - @property - def name(self): - """String identifier of the graph. - - This graph attribute appears in the attribute dict G.graph - keyed by the string `"name"`. as well as an attribute (technically - a property) `G.name`. This is entirely user controlled. - """ - return self.graph.get('name', '') - - @name.setter - def name(self, s): - self.graph['name'] = s - - def __str__(self): - """Returns the graph name. - - Returns - ------- - name : string - The name of the graph. - - Examples - -------- - >>> G = nx.Graph(name='foo') - >>> str(G) - 'foo' - """ - return self.name - - def __iter__(self): - """Iterate over the nodes. Use: 'for n in G'. - - Returns - ------- - niter : iterator - An iterator over all nodes in the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> [n for n in G] - [0, 1, 2, 3] - >>> list(G) - [0, 1, 2, 3] - """ - return iter(self._node) - - def __contains__(self, n): - """Returns True if n is a node, False otherwise. Use: 'n in G'. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> 1 in G - True - """ - try: - return n in self._node - except TypeError: - return False - - def __len__(self): - """Returns the number of nodes in the graph. Use: 'len(G)'. - - Returns - ------- - nnodes : int - The number of nodes in the graph. - - See Also - -------- - number_of_nodes, order which are identical - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> len(G) - 4 - - """ - return len(self._node) - - def __getitem__(self, n): - """Returns a dict of neighbors of node n. Use: 'G[n]'. - - Parameters - ---------- - n : node - A node in the graph. - - Returns - ------- - adj_dict : dictionary - The adjacency dictionary for nodes connected to n. - - Notes - ----- - G[n] is the same as G.adj[n] and similar to G.neighbors(n) - (which is an iterator over G.adj[n]) - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G[0] - AtlasView({1: {}}) - """ - return self.adj[n] - - def add_node(self, node_for_adding, **attr): - """Add a single node `node_for_adding` and update node attributes. - - Parameters - ---------- - node_for_adding : node - A node can be any hashable Python object except None. - attr : keyword arguments, optional - Set or change node attributes using key=value. - - See Also - -------- - add_nodes_from - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_node(1) - >>> G.add_node('Hello') - >>> K3 = nx.Graph([(0, 1), (1, 2), (2, 0)]) - >>> G.add_node(K3) - >>> G.number_of_nodes() - 3 - - Use keywords set/change node attributes: - - >>> G.add_node(1, size=10) - >>> G.add_node(3, weight=0.4, UTM=('13S', 382871, 3972649)) - - Notes - ----- - A hashable object is one that can be used as a key in a Python - dictionary. This includes strings, numbers, tuples of strings - and numbers, etc. - - On many platforms hashable items also include mutables such as - NetworkX Graphs, though one should be careful that the hash - doesn't change on mutables. - """ - if node_for_adding not in self._node: - self._adj[node_for_adding] = self.adjlist_inner_dict_factory() - attr_dict = self._node[node_for_adding] = self.node_attr_dict_factory() - attr_dict.update(attr) - else: # update attr even if node already exists - self._node[node_for_adding].update(attr) - - def add_nodes_from(self, nodes_for_adding, **attr): - """Add multiple nodes. - - Parameters - ---------- - nodes_for_adding : iterable container - A container of nodes (list, dict, set, etc.). - OR - A container of (node, attribute dict) tuples. - Node attributes are updated using the attribute dict. - attr : keyword arguments, optional (default= no attributes) - Update attributes for all nodes in nodes. - Node attributes specified in nodes as a tuple take - precedence over attributes specified via keyword arguments. - - See Also - -------- - add_node - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_nodes_from('Hello') - >>> K3 = nx.Graph([(0, 1), (1, 2), (2, 0)]) - >>> G.add_nodes_from(K3) - >>> sorted(G.nodes(), key=str) - [0, 1, 2, 'H', 'e', 'l', 'o'] - - Use keywords to update specific node attributes for every node. - - >>> G.add_nodes_from([1, 2], size=10) - >>> G.add_nodes_from([3, 4], weight=0.4) - - Use (node, attrdict) tuples to update attributes for specific nodes. - - >>> G.add_nodes_from([(1, dict(size=11)), (2, {'color':'blue'})]) - >>> G.nodes[1]['size'] - 11 - >>> H = nx.Graph() - >>> H.add_nodes_from(G.nodes(data=True)) - >>> H.nodes[1]['size'] - 11 - - """ - for n in nodes_for_adding: - # keep all this inside try/except because - # CPython throws TypeError on n not in self._node, - # while pre-2.7.5 ironpython throws on self._adj[n] - try: - if n not in self._node: - self._adj[n] = self.adjlist_inner_dict_factory() - attr_dict = self._node[n] = self.node_attr_dict_factory() - attr_dict.update(attr) - else: - self._node[n].update(attr) - except TypeError: - nn, ndict = n - if nn not in self._node: - self._adj[nn] = self.adjlist_inner_dict_factory() - newdict = attr.copy() - newdict.update(ndict) - attr_dict = self._node[nn] = self.node_attr_dict_factory() - attr_dict.update(newdict) - else: - olddict = self._node[nn] - olddict.update(attr) - olddict.update(ndict) - - def remove_node(self, n): - """Remove node n. - - Removes the node n and all adjacent edges. - Attempting to remove a non-existent node will raise an exception. - - Parameters - ---------- - n : node - A node in the graph - - Raises - ------- - NetworkXError - If n is not in the graph. - - See Also - -------- - remove_nodes_from - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> list(G.edges) - [(0, 1), (1, 2)] - >>> G.remove_node(1) - >>> list(G.edges) - [] - - """ - adj = self._adj - try: - nbrs = list(adj[n]) # list handles self-loops (allows mutation) - del self._node[n] - except KeyError: # NetworkXError if n not in self - raise NetworkXError("The node %s is not in the graph." % (n,)) - for u in nbrs: - del adj[u][n] # remove all edges n-u in graph - del adj[n] # now remove node - - def remove_nodes_from(self, nodes): - """Remove multiple nodes. - - Parameters - ---------- - nodes : iterable container - A container of nodes (list, dict, set, etc.). If a node - in the container is not in the graph it is silently - ignored. - - See Also - -------- - remove_node - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> e = list(G.nodes) - >>> e - [0, 1, 2] - >>> G.remove_nodes_from(e) - >>> list(G.nodes) - [] - - """ - adj = self._adj - for n in nodes: - try: - del self._node[n] - for u in list(adj[n]): # list handles self-loops - del adj[u][n] # (allows mutation of dict in loop) - del adj[n] - except KeyError: - pass - - @property - def nodes(self): - """A NodeView of the Graph as G.nodes or G.nodes(). - - Can be used as `G.nodes` for data lookup and for set-like operations. - Can also be used as `G.nodes(data='color', default=None)` to return a - NodeDataView which reports specific node data but no set operations. - It presents a dict-like interface as well with `G.nodes.items()` - iterating over `(node, nodedata)` 2-tuples and `G.nodes[3]['foo']` - providing the value of the `foo` attribute for node `3`. In addition, - a view `G.nodes.data('foo')` provides a dict-like interface to the - `foo` attribute of each node. `G.nodes.data('foo', default=1)` - provides a default for nodes that do not have attribute `foo`. - - Parameters - ---------- - data : string or bool, optional (default=False) - The node attribute returned in 2-tuple (n, ddict[data]). - If True, return entire node attribute dict as (n, ddict). - If False, return just the nodes n. - - default : value, optional (default=None) - Value used for nodes that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - NodeView - Allows set-like operations over the nodes as well as node - attribute dict lookup and calling to get a NodeDataView. - A NodeDataView iterates over `(n, data)` and has no set operations. - A NodeView iterates over `n` and includes set operations. - - When called, if data is False, an iterator over nodes. - Otherwise an iterator of 2-tuples (node, attribute value) - where the attribute is specified in `data`. - If data is True then the attribute becomes the - entire data dictionary. - - Notes - ----- - If your node data is not needed, it is simpler and equivalent - to use the expression ``for n in G``, or ``list(G)``. - - Examples - -------- - There are two simple ways of getting a list of all nodes in the graph: - - >>> G = nx.path_graph(3) - >>> list(G.nodes) - [0, 1, 2] - >>> list(G) - [0, 1, 2] - - To get the node data along with the nodes: - - >>> G.add_node(1, time='5pm') - >>> G.nodes[0]['foo'] = 'bar' - >>> list(G.nodes(data=True)) - [(0, {'foo': 'bar'}), (1, {'time': '5pm'}), (2, {})] - >>> list(G.nodes.data()) - [(0, {'foo': 'bar'}), (1, {'time': '5pm'}), (2, {})] - - >>> list(G.nodes(data='foo')) - [(0, 'bar'), (1, None), (2, None)] - >>> list(G.nodes.data('foo')) - [(0, 'bar'), (1, None), (2, None)] - - >>> list(G.nodes(data='time')) - [(0, None), (1, '5pm'), (2, None)] - >>> list(G.nodes.data('time')) - [(0, None), (1, '5pm'), (2, None)] - - >>> list(G.nodes(data='time', default='Not Available')) - [(0, 'Not Available'), (1, '5pm'), (2, 'Not Available')] - >>> list(G.nodes.data('time', default='Not Available')) - [(0, 'Not Available'), (1, '5pm'), (2, 'Not Available')] - - If some of your nodes have an attribute and the rest are assumed - to have a default attribute value you can create a dictionary - from node/attribute pairs using the `default` keyword argument - to guarantee the value is never None:: - - >>> G = nx.Graph() - >>> G.add_node(0) - >>> G.add_node(1, weight=2) - >>> G.add_node(2, weight=3) - >>> dict(G.nodes(data='weight', default=1)) - {0: 1, 1: 2, 2: 3} - - """ - nodes = NodeView(self) - # Lazy View creation: overload the (class) property on the instance - # Then future G.nodes use the existing View - # setattr doesn't work because attribute already exists - self.__dict__['nodes'] = nodes - return nodes - - def number_of_nodes(self): - """Returns the number of nodes in the graph. - - Returns - ------- - nnodes : int - The number of nodes in the graph. - - See Also - -------- - order, __len__ which are identical - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.number_of_nodes() - 3 - """ - return len(self._node) - - def order(self): - """Returns the number of nodes in the graph. - - Returns - ------- - nnodes : int - The number of nodes in the graph. - - See Also - -------- - number_of_nodes, __len__ which are identical - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.order() - 3 - """ - return len(self._node) - - def has_node(self, n): - """Returns True if the graph contains the node n. - - Identical to `n in G` - - Parameters - ---------- - n : node - - Examples - -------- - >>> G = nx.path_graph(3) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.has_node(0) - True - - It is more readable and simpler to use - - >>> 0 in G - True - - """ - try: - return n in self._node - except TypeError: - return False - - def add_edge(self, u_of_edge, v_of_edge, **attr): - """Add an edge between u and v. - - The nodes u and v will be automatically added if they are - not already in the graph. - - Edge attributes can be specified with keywords or by directly - accessing the edge's attribute dictionary. See examples below. - - Parameters - ---------- - u, v : nodes - Nodes can be, for example, strings or numbers. - Nodes must be hashable (and not None) Python objects. - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - See Also - -------- - add_edges_from : add a collection of edges - - Notes - ----- - Adding an edge that already exists updates the edge data. - - Many NetworkX algorithms designed for weighted graphs use - an edge attribute (by default `weight`) to hold a numerical value. - - Examples - -------- - The following all add the edge e=(1, 2) to graph G: - - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> e = (1, 2) - >>> G.add_edge(1, 2) # explicit two-node form - >>> G.add_edge(*e) # single edge as tuple of two nodes - >>> G.add_edges_from([(1, 2)]) # add edges from iterable container - - Associate data to edges using keywords: - - >>> G.add_edge(1, 2, weight=3) - >>> G.add_edge(1, 3, weight=7, capacity=15, length=342.7) - - For non-string attribute keys, use subscript notation. - - >>> G.add_edge(1, 2) - >>> G[1][2].update({0: 5}) - >>> G.edges[1, 2].update({0: 5}) - """ - u, v = u_of_edge, v_of_edge - # add nodes - if u not in self._node: - self._adj[u] = self.adjlist_inner_dict_factory() - self._node[u] = self.node_attr_dict_factory() - if v not in self._node: - self._adj[v] = self.adjlist_inner_dict_factory() - self._node[v] = self.node_attr_dict_factory() - # add the edge - datadict = self._adj[u].get(v, self.edge_attr_dict_factory()) - datadict.update(attr) - self._adj[u][v] = datadict - self._adj[v][u] = datadict - - def add_edges_from(self, ebunch_to_add, **attr): - """Add all the edges in ebunch_to_add. - - Parameters - ---------- - ebunch_to_add : container of edges - Each edge given in the container will be added to the - graph. The edges must be given as as 2-tuples (u, v) or - 3-tuples (u, v, d) where d is a dictionary containing edge data. - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - See Also - -------- - add_edge : add a single edge - add_weighted_edges_from : convenient way to add weighted edges - - Notes - ----- - Adding the same edge twice has no effect but any edge data - will be updated when each duplicate edge is added. - - Edge attributes specified in an ebunch take precedence over - attributes specified via keyword arguments. - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edges_from([(0, 1), (1, 2)]) # using a list of edge tuples - >>> e = zip(range(0, 3), range(1, 4)) - >>> G.add_edges_from(e) # Add the path graph 0-1-2-3 - - Associate data to edges - - >>> G.add_edges_from([(1, 2), (2, 3)], weight=3) - >>> G.add_edges_from([(3, 4), (1, 4)], label='WN2898') - """ - for e in ebunch_to_add: - ne = len(e) - if ne == 3: - u, v, dd = e - elif ne == 2: - u, v = e - dd = {} # doesn't need edge_attr_dict_factory - else: - raise NetworkXError( - "Edge tuple %s must be a 2-tuple or 3-tuple." % (e,)) - if u not in self._node: - self._adj[u] = self.adjlist_inner_dict_factory() - self._node[u] = self.node_attr_dict_factory() - if v not in self._node: - self._adj[v] = self.adjlist_inner_dict_factory() - self._node[v] = self.node_attr_dict_factory() - datadict = self._adj[u].get(v, self.edge_attr_dict_factory()) - datadict.update(attr) - datadict.update(dd) - self._adj[u][v] = datadict - self._adj[v][u] = datadict - - def add_weighted_edges_from(self, ebunch_to_add, weight='weight', **attr): - """Add weighted edges in `ebunch_to_add` with specified weight attr - - Parameters - ---------- - ebunch_to_add : container of edges - Each edge given in the list or container will be added - to the graph. The edges must be given as 3-tuples (u, v, w) - where w is a number. - weight : string, optional (default= 'weight') - The attribute name for the edge weights to be added. - attr : keyword arguments, optional (default= no attributes) - Edge attributes to add/update for all edges. - - See Also - -------- - add_edge : add a single edge - add_edges_from : add multiple edges - - Notes - ----- - Adding the same edge twice for Graph/DiGraph simply updates - the edge data. For MultiGraph/MultiDiGraph, duplicate edges - are stored. - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_weighted_edges_from([(0, 1, 3.0), (1, 2, 7.5)]) - """ - self.add_edges_from(((u, v, {weight: d}) for u, v, d in ebunch_to_add), - **attr) - - def remove_edge(self, u, v): - """Remove the edge between u and v. - - Parameters - ---------- - u, v : nodes - Remove the edge between nodes u and v. - - Raises - ------ - NetworkXError - If there is not an edge between u and v. - - See Also - -------- - remove_edges_from : remove a collection of edges - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, etc - >>> G.remove_edge(0, 1) - >>> e = (1, 2) - >>> G.remove_edge(*e) # unpacks e from an edge tuple - >>> e = (2, 3, {'weight':7}) # an edge with attribute data - >>> G.remove_edge(*e[:2]) # select first part of edge tuple - """ - try: - del self._adj[u][v] - if u != v: # self-loop needs only one entry removed - del self._adj[v][u] - except KeyError: - raise NetworkXError("The edge %s-%s is not in the graph" % (u, v)) - - def remove_edges_from(self, ebunch): - """Remove all edges specified in ebunch. - - Parameters - ---------- - ebunch: list or container of edge tuples - Each edge given in the list or container will be removed - from the graph. The edges can be: - - - 2-tuples (u, v) edge between u and v. - - 3-tuples (u, v, k) where k is ignored. - - See Also - -------- - remove_edge : remove a single edge - - Notes - ----- - Will fail silently if an edge in ebunch is not in the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> ebunch=[(1, 2), (2, 3)] - >>> G.remove_edges_from(ebunch) - """ - adj = self._adj - for e in ebunch: - u, v = e[:2] # ignore edge data if present - if u in adj and v in adj[u]: - del adj[u][v] - if u != v: # self loop needs only one entry removed - del adj[v][u] - - def update(self, edges=None, nodes=None): - """Update the graph using nodes/edges/graphs as input. - - Like dict.update, this method takes a graph as input, adding the - graph's nodes and edges to this graph. It can also take two inputs: - edges and nodes. Finally it can take either edges or nodes. - To specify only nodes the keyword `nodes` must be used. - - The collections of edges and nodes are treated similarly to - the add_edges_from/add_nodes_from methods. When iterated, they - should yield 2-tuples (u, v) or 3-tuples (u, v, datadict). - - Parameters - ---------- - edges : Graph object, collection of edges, or None - The first parameter can be a graph or some edges. If it has - attributes `nodes` and `edges`, then it is taken to be a - Graph-like object and those attributes are used as collections - of nodes and edges to be added to the graph. - If the first parameter does not have those attributes, it is - treated as a collection of edges and added to the graph. - If the first argument is None, no edges are added. - nodes : collection of nodes, or None - The second parameter is treated as a collection of nodes - to be added to the graph unless it is None. - If `edges is None` and `nodes is None` an exception is raised. - If the first parameter is a Graph, then `nodes` is ignored. - - Examples - -------- - >>> G = nx.path_graph(5) - >>> G.update(nx.complete_graph(range(4,10))) - >>> from itertools import combinations - >>> edges = ((u, v, {'power': u * v}) - ... for u, v in combinations(range(10, 20), 2) - ... if u * v < 225) - >>> nodes = [1000] # for singleton, use a container - >>> G.update(edges, nodes) - - Notes - ----- - It you want to update the graph using an adjacency structure - it is straightforward to obtain the edges/nodes from adjacency. - The following examples provide common cases, your adjacency may - be slightly different and require tweaks of these examples. - - >>> # dict-of-set/list/tuple - >>> adj = {1: {2, 3}, 2: {1, 3}, 3: {1, 2}} - >>> e = [(u, v) for u, nbrs in adj.items() for v in nbrs] - >>> G.update(edges=e, nodes=adj) - - >>> DG = nx.DiGraph() - >>> # dict-of-dict-of-attribute - >>> adj = {1: {2: 1.3, 3: 0.7}, 2: {1: 1.4}, 3: {1: 0.7}} - >>> e = [(u, v, {'weight': d}) for u, nbrs in adj.items() - ... for v, d in nbrs.items()] - >>> DG.update(edges=e, nodes=adj) - - >>> # dict-of-dict-of-dict - >>> adj = {1: {2: {'weight': 1.3}, 3: {'color': 0.7, 'weight':1.2}}} - >>> e = [(u, v, {'weight': d}) for u, nbrs in adj.items() - ... for v, d in nbrs.items()] - >>> DG.update(edges=e, nodes=adj) - - >>> # predecessor adjacency (dict-of-set) - >>> pred = {1: {2, 3}, 2: {3}, 3: {3}} - >>> e = [(v, u) for u, nbrs in pred.items() for v in nbrs] - - >>> # MultiGraph dict-of-dict-of-dict-of-attribute - >>> MDG = nx.MultiDiGraph() - >>> adj = {1: {2: {0: {'weight': 1.3}, 1: {'weight': 1.2}}}, - ... 3: {2: {0: {'weight': 0.7}}}} - >>> e = [(u, v, ekey, d) for u, nbrs in adj.items() - ... for v, keydict in nbrs.items() - ... for ekey, d in keydict.items()] - >>> MDG.update(edges=e) - - See Also - -------- - add_edges_from: add multiple edges to a graph - add_nodes_from: add multiple nodes to a graph - """ - if edges is not None: - if nodes is not None: - self.add_nodes_from(nodes) - self.add_edges_from(edges) - else: - # check if edges is a Graph object - try: - graph_nodes = edges.nodes - graph_edges = edges.edges - except AttributeError: - # edge not Graph-like - self.add_edges_from(edges) - else: # edges is Graph-like - self.add_nodes_from(graph_nodes.data()) - self.add_edges_from(graph_edges.data()) - self.graph.update(edges.graph) - elif nodes is not None: - self.add_nodes_from(nodes) - else: - raise NetworkXError("update needs nodes or edges input") - - def has_edge(self, u, v): - """Returns True if the edge (u, v) is in the graph. - - This is the same as `v in G[u]` without KeyError exceptions. - - Parameters - ---------- - u, v : nodes - Nodes can be, for example, strings or numbers. - Nodes must be hashable (and not None) Python objects. - - Returns - ------- - edge_ind : bool - True if edge is in the graph, False otherwise. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.has_edge(0, 1) # using two nodes - True - >>> e = (0, 1) - >>> G.has_edge(*e) # e is a 2-tuple (u, v) - True - >>> e = (0, 1, {'weight':7}) - >>> G.has_edge(*e[:2]) # e is a 3-tuple (u, v, data_dictionary) - True - - The following syntax are equivalent: - - >>> G.has_edge(0, 1) - True - >>> 1 in G[0] # though this gives KeyError if 0 not in G - True - - """ - try: - return v in self._adj[u] - except KeyError: - return False - - def neighbors(self, n): - """Returns an iterator over all neighbors of node n. - - This is identical to `iter(G[n])` - - Parameters - ---------- - n : node - A node in the graph - - Returns - ------- - neighbors : iterator - An iterator over all neighbors of node n - - Raises - ------ - NetworkXError - If the node n is not in the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> [n for n in G.neighbors(0)] - [1] - - Notes - ----- - It is usually more convenient (and faster) to access the - adjacency dictionary as ``G[n]``: - - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edge('a', 'b', weight=7) - >>> G['a'] - AtlasView({'b': {'weight': 7}}) - >>> G = nx.path_graph(4) - >>> [n for n in G[0]] - [1] - """ - try: - return iter(self._adj[n]) - except KeyError: - raise NetworkXError("The node %s is not in the graph." % (n,)) - - @property - def edges(self): - """An EdgeView of the Graph as G.edges or G.edges(). - - edges(self, nbunch=None, data=False, default=None) - - The EdgeView provides set-like operations on the edge-tuples - as well as edge attribute lookup. When called, it also provides - an EdgeDataView object which allows control of access to edge - attributes (but does not provide set-like operations). - Hence, `G.edges[u, v]['color']` provides the value of the color - attribute for edge `(u, v)` while - `for (u, v, c) in G.edges.data('color', default='red'):` - iterates through all the edges yielding the color attribute - with default `'red'` if no color attribute exists. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - data : string or bool, optional (default=False) - The edge attribute returned in 3-tuple (u, v, ddict[data]). - If True, return edge attribute dict in 3-tuple (u, v, ddict). - If False, return 2-tuple (u, v). - default : value, optional (default=None) - Value used for edges that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - edges : EdgeView - A view of edge attributes, usually it iterates over (u, v) - or (u, v, d) tuples of edges, but can also be used for - attribute lookup as `edges[u, v]['foo']`. - - Notes - ----- - Nodes in nbunch that are not in the graph will be (quietly) ignored. - For directed graphs this returns the out-edges. - - Examples - -------- - >>> G = nx.path_graph(3) # or MultiGraph, etc - >>> G.add_edge(2, 3, weight=5) - >>> [e for e in G.edges] - [(0, 1), (1, 2), (2, 3)] - >>> G.edges.data() # default data is {} (empty dict) - EdgeDataView([(0, 1, {}), (1, 2, {}), (2, 3, {'weight': 5})]) - >>> G.edges.data('weight', default=1) - EdgeDataView([(0, 1, 1), (1, 2, 1), (2, 3, 5)]) - >>> G.edges([0, 3]) # only edges incident to these nodes - EdgeDataView([(0, 1), (3, 2)]) - >>> G.edges(0) # only edges incident to a single node (use G.adj[0]?) - EdgeDataView([(0, 1)]) - """ - return EdgeView(self) - - def get_edge_data(self, u, v, default=None): - """Returns the attribute dictionary associated with edge (u, v). - - This is identical to `G[u][v]` except the default is returned - instead of an exception if the edge doesn't exist. - - Parameters - ---------- - u, v : nodes - default: any Python object (default=None) - Value to return if the edge (u, v) is not found. - - Returns - ------- - edge_dict : dictionary - The edge attribute dictionary. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G[0][1] - {} - - Warning: Assigning to `G[u][v]` is not permitted. - But it is safe to assign attributes `G[u][v]['foo']` - - >>> G[0][1]['weight'] = 7 - >>> G[0][1]['weight'] - 7 - >>> G[1][0]['weight'] - 7 - - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.get_edge_data(0, 1) # default edge data is {} - {} - >>> e = (0, 1) - >>> G.get_edge_data(*e) # tuple form - {} - >>> G.get_edge_data('a', 'b', default=0) # edge not in graph, return 0 - 0 - """ - try: - return self._adj[u][v] - except KeyError: - return default - - def adjacency(self): - """Returns an iterator over (node, adjacency dict) tuples for all nodes. - - For directed graphs, only outgoing neighbors/adjacencies are included. - - Returns - ------- - adj_iter : iterator - An iterator over (node, adjacency dictionary) for all nodes in - the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> [(n, nbrdict) for n, nbrdict in G.adjacency()] - [(0, {1: {}}), (1, {0: {}, 2: {}}), (2, {1: {}, 3: {}}), (3, {2: {}})] - - """ - return iter(self._adj.items()) - - @property - def degree(self): - """A DegreeView for the Graph as G.degree or G.degree(). - - The node degree is the number of edges adjacent to the node. - The weighted node degree is the sum of the edge weights for - edges incident to that node. - - This object provides an iterator for (node, degree) as well as - lookup for the degree for a single node. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - If a single node is requested - deg : int - Degree of the node - - OR if multiple nodes are requested - nd_view : A DegreeView object capable of iterating (node, degree) pairs - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.degree[0] # node 0 has degree 1 - 1 - >>> list(G.degree([0, 1, 2])) - [(0, 1), (1, 2), (2, 2)] - """ - return DegreeView(self) - - def clear(self): - """Remove all nodes and edges from the graph. - - This also removes the name, and all graph, node, and edge attributes. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.clear() - >>> list(G.nodes) - [] - >>> list(G.edges) - [] - - """ - self._adj.clear() - self._node.clear() - self.graph.clear() - - def is_multigraph(self): - """Returns True if graph is a multigraph, False otherwise.""" - return False - - def is_directed(self): - """Returns True if graph is directed, False otherwise.""" - return False - - def copy(self, as_view=False): - """Returns a copy of the graph. - - The copy method by default returns an independent shallow copy - of the graph and attributes. That is, if an attribute is a - container, that container is shared by the original an the copy. - Use Python's `copy.deepcopy` for new containers. - - If `as_view` is True then a view is returned instead of a copy. - - Notes - ----- - All copies reproduce the graph structure, but data attributes - may be handled in different ways. There are four types of copies - of a graph that people might want. - - Deepcopy -- A "deepcopy" copies the graph structure as well as - all data attributes and any objects they might contain. - The entire graph object is new so that changes in the copy - do not affect the original object. (see Python's copy.deepcopy) - - Data Reference (Shallow) -- For a shallow copy the graph structure - is copied but the edge, node and graph attribute dicts are - references to those in the original graph. This saves - time and memory but could cause confusion if you change an attribute - in one graph and it changes the attribute in the other. - NetworkX does not provide this level of shallow copy. - - Independent Shallow -- This copy creates new independent attribute - dicts and then does a shallow copy of the attributes. That is, any - attributes that are containers are shared between the new graph - and the original. This is exactly what `dict.copy()` provides. - You can obtain this style copy using: - - >>> G = nx.path_graph(5) - >>> H = G.copy() - >>> H = G.copy(as_view=False) - >>> H = nx.Graph(G) - >>> H = G.__class__(G) - - Fresh Data -- For fresh data, the graph structure is copied while - new empty data attribute dicts are created. The resulting graph - is independent of the original and it has no edge, node or graph - attributes. Fresh copies are not enabled. Instead use: - - >>> H = G.__class__() - >>> H.add_nodes_from(G) - >>> H.add_edges_from(G.edges) - - View -- Inspired by dict-views, graph-views act like read-only - versions of the original graph, providing a copy of the original - structure without requiring any memory for copying the information. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/2/library/copy.html. - - Parameters - ---------- - as_view : bool, optional (default=False) - If True, the returned graph-view provides a read-only view - of the original graph without actually copying any data. - - Returns - ------- - G : Graph - A copy of the graph. - - See Also - -------- - to_directed: return a directed copy of the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> H = G.copy() - - """ - if as_view is True: - return nx.graphviews.generic_graph_view(self) - G = self.__class__() - G.graph.update(self.graph) - G.add_nodes_from((n, d.copy()) for n, d in self._node.items()) - G.add_edges_from((u, v, datadict.copy()) - for u, nbrs in self._adj.items() - for v, datadict in nbrs.items()) - return G - - def to_directed(self, as_view=False): - """Returns a directed representation of the graph. - - Returns - ------- - G : DiGraph - A directed graph with the same name, same nodes, and with - each edge (u, v, data) replaced by two directed edges - (u, v, data) and (v, u, data). - - Notes - ----- - This returns a "deepcopy" of the edge, node, and - graph attributes which attempts to completely copy - all of the data and references. - - This is in contrast to the similar D=DiGraph(G) which returns a - shallow copy of the data. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/2/library/copy.html. - - Warning: If you have subclassed Graph to use dict-like objects - in the data structure, those changes do not transfer to the - DiGraph created by this method. - - Examples - -------- - >>> G = nx.Graph() # or MultiGraph, etc - >>> G.add_edge(0, 1) - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1), (1, 0)] - - If already directed, return a (deep) copy - - >>> G = nx.DiGraph() # or MultiDiGraph, etc - >>> G.add_edge(0, 1) - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1)] - """ - graph_class = self.to_directed_class() - if as_view is True: - return nx.graphviews.generic_graph_view(self, graph_class) - # deepcopy when not a view - G = graph_class() - G.graph.update(deepcopy(self.graph)) - G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) - G.add_edges_from((u, v, deepcopy(data)) - for u, nbrs in self._adj.items() - for v, data in nbrs.items()) - return G - - def to_undirected(self, as_view=False): - """Returns an undirected copy of the graph. - - Parameters - ---------- - as_view : bool (optional, default=False) - If True return a view of the original undirected graph. - - Returns - ------- - G : Graph/MultiGraph - A deepcopy of the graph. - - See Also - -------- - Graph, copy, add_edge, add_edges_from - - Notes - ----- - This returns a "deepcopy" of the edge, node, and - graph attributes which attempts to completely copy - all of the data and references. - - This is in contrast to the similar `G = nx.DiGraph(D)` which returns a - shallow copy of the data. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/2/library/copy.html. - - Warning: If you have subclassed DiGraph to use dict-like objects - in the data structure, those changes do not transfer to the - Graph created by this method. - - Examples - -------- - >>> G = nx.path_graph(2) # or MultiGraph, etc - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1), (1, 0)] - >>> G2 = H.to_undirected() - >>> list(G2.edges) - [(0, 1)] - """ - graph_class = self.to_undirected_class() - if as_view is True: - return nx.graphviews.generic_graph_view(self, graph_class) - # deepcopy when not a view - G = graph_class() - G.graph.update(deepcopy(self.graph)) - G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) - G.add_edges_from((u, v, deepcopy(d)) - for u, nbrs in self._adj.items() - for v, d in nbrs.items()) - return G - - def subgraph(self, nodes): - """Returns a SubGraph view of the subgraph induced on `nodes`. - - The induced subgraph of the graph contains the nodes in `nodes` - and the edges between those nodes. - - Parameters - ---------- - nodes : list, iterable - A container of nodes which will be iterated through once. - - Returns - ------- - G : SubGraph View - A subgraph view of the graph. The graph structure cannot be - changed but node/edge attributes can and are shared with the - original graph. - - Notes - ----- - The graph, edge and node attributes are shared with the original graph. - Changes to the graph structure is ruled out by the view, but changes - to attributes are reflected in the original graph. - - To create a subgraph with its own copy of the edge/node attributes use: - G.subgraph(nodes).copy() - - For an inplace reduction of a graph to a subgraph you can remove nodes: - G.remove_nodes_from([n for n in G if n not in set(nodes)]) - - Subgraph views are sometimes NOT what you want. In most cases where - you want to do more than simply look at the induced edges, it makes - more sense to just create the subgraph as its own graph with code like: - - :: - - # Create a subgraph SG based on a (possibly multigraph) G - SG = G.__class__() - SG.add_nodes_from((n, G.nodes[n]) for n in largest_wcc) - if SG.is_multigraph: - SG.add_edges_from((n, nbr, key, d) - for n, nbrs in G.adj.items() if n in largest_wcc - for nbr, keydict in nbrs.items() if nbr in largest_wcc - for key, d in keydict.items()) - else: - SG.add_edges_from((n, nbr, d) - for n, nbrs in G.adj.items() if n in largest_wcc - for nbr, d in nbrs.items() if nbr in largest_wcc) - SG.graph.update(G.graph) - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> H = G.subgraph([0, 1, 2]) - >>> list(H.edges) - [(0, 1), (1, 2)] - """ - induced_nodes = nx.filters.show_nodes(self.nbunch_iter(nodes)) - # if already a subgraph, don't make a chain - subgraph = nx.graphviews.subgraph_view - if hasattr(self, '_NODE_OK'): - return subgraph(self._graph, induced_nodes, self._EDGE_OK) - return subgraph(self, induced_nodes) - - def edge_subgraph(self, edges): - """Returns the subgraph induced by the specified edges. - - The induced subgraph contains each edge in `edges` and each - node incident to any one of those edges. - - Parameters - ---------- - edges : iterable - An iterable of edges in this graph. - - Returns - ------- - G : Graph - An edge-induced subgraph of this graph with the same edge - attributes. - - Notes - ----- - The graph, edge, and node attributes in the returned subgraph - view are references to the corresponding attributes in the original - graph. The view is read-only. - - To create a full graph version of the subgraph with its own copy - of the edge or node attributes, use:: - - >>> G.edge_subgraph(edges).copy() # doctest: +SKIP - - Examples - -------- - >>> G = nx.path_graph(5) - >>> H = G.edge_subgraph([(0, 1), (3, 4)]) - >>> list(H.nodes) - [0, 1, 3, 4] - >>> list(H.edges) - [(0, 1), (3, 4)] - - """ - return nx.edge_subgraph(self, edges) - - def size(self, weight=None): - """Returns the number of edges or total of all edge weights. - - Parameters - ---------- - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - - Returns - ------- - size : numeric - The number of edges or - (if weight keyword is provided) the total weight sum. - - If weight is None, returns an int. Otherwise a float - (or more general numeric if the weights are more general). - - See Also - -------- - number_of_edges - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.size() - 3 - - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edge('a', 'b', weight=2) - >>> G.add_edge('b', 'c', weight=4) - >>> G.size() - 2 - >>> G.size(weight='weight') - 6.0 - """ - s = sum(d for v, d in self.degree(weight=weight)) - # If `weight` is None, the sum of the degrees is guaranteed to be - # even, so we can perform integer division and hence return an - # integer. Otherwise, the sum of the weighted degrees is not - # guaranteed to be an integer, so we perform "real" division. - return s // 2 if weight is None else s / 2 - - def number_of_edges(self, u=None, v=None): - """Returns the number of edges between two nodes. - - Parameters - ---------- - u, v : nodes, optional (default=all edges) - If u and v are specified, return the number of edges between - u and v. Otherwise return the total number of all edges. - - Returns - ------- - nedges : int - The number of edges in the graph. If nodes `u` and `v` are - specified return the number of edges between those nodes. If - the graph is directed, this only returns the number of edges - from `u` to `v`. - - See Also - -------- - size - - Examples - -------- - For undirected graphs, this method counts the total number of - edges in the graph: - - >>> G = nx.path_graph(4) - >>> G.number_of_edges() - 3 - - If you specify two nodes, this counts the total number of edges - joining the two nodes: - - >>> G.number_of_edges(0, 1) - 1 - - For directed graphs, this method can count the total number of - directed edges from `u` to `v`: - - >>> G = nx.DiGraph() - >>> G.add_edge(0, 1) - >>> G.add_edge(1, 0) - >>> G.number_of_edges(0, 1) - 1 - - """ - if u is None: - return int(self.size()) - if v in self._adj[u]: - return 1 - return 0 - - def nbunch_iter(self, nbunch=None): - """Returns an iterator over nodes contained in nbunch that are - also in the graph. - - The nodes in nbunch are checked for membership in the graph - and if not are silently ignored. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - Returns - ------- - niter : iterator - An iterator over nodes in nbunch that are also in the graph. - If nbunch is None, iterate over all nodes in the graph. - - Raises - ------ - NetworkXError - If nbunch is not a node or or sequence of nodes. - If a node in nbunch is not hashable. - - See Also - -------- - Graph.__iter__ - - Notes - ----- - When nbunch is an iterator, the returned iterator yields values - directly from nbunch, becoming exhausted when nbunch is exhausted. - - To test whether nbunch is a single node, one can use - "if nbunch in self:", even after processing with this routine. - - If nbunch is not a node or a (possibly empty) sequence/iterator - or None, a :exc:`NetworkXError` is raised. Also, if any object in - nbunch is not hashable, a :exc:`NetworkXError` is raised. - """ - if nbunch is None: # include all nodes via iterator - bunch = iter(self._adj) - elif nbunch in self: # if nbunch is a single node - bunch = iter([nbunch]) - else: # if nbunch is a sequence of nodes - def bunch_iter(nlist, adj): - try: - for n in nlist: - if n in adj: - yield n - except TypeError as e: - message = e.args[0] - # capture error for non-sequence/iterator nbunch. - if 'iter' in message: - msg = "nbunch is not a node or a sequence of nodes." - raise NetworkXError(msg) - # capture error for unhashable node. - elif 'hashable' in message: - msg = "Node {} in sequence nbunch is not a valid node." - raise NetworkXError(msg.format(n)) - else: - raise - bunch = bunch_iter(nbunch, self._adj) - return bunch diff --git a/extensions/fablabchemnitz/networkx/classes/graphviews.py b/extensions/fablabchemnitz/networkx/classes/graphviews.py deleted file mode 100644 index ba7d8378..00000000 --- a/extensions/fablabchemnitz/networkx/classes/graphviews.py +++ /dev/null @@ -1,217 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Author: Aric Hagberg (hagberg@lanl.gov), -# Pieter Swart (swart@lanl.gov), -# Dan Schult(dschult@colgate.edu) -"""View of Graphs as SubGraph, Reverse, Directed, Undirected. - -In some algorithms it is convenient to temporarily morph -a graph to exclude some nodes or edges. It should be better -to do that via a view than to remove and then re-add. -In other algorithms it is convenient to temporarily morph -a graph to reverse directed edges, or treat a directed graph -as undirected, etc. This module provides those graph views. - -The resulting views are essentially read-only graphs that -report data from the orignal graph object. We provide an -attribute G._graph which points to the underlying graph object. - -Note: Since graphviews look like graphs, one can end up with -view-of-view-of-view chains. Be careful with chains because -they become very slow with about 15 nested views. -For the common simple case of node induced subgraphs created -from the graph class, we short-cut the chain by returning a -subgraph of the original graph directly rather than a subgraph -of a subgraph. We are careful not to disrupt any edge filter in -the middle subgraph. In general, determining how to short-cut -the chain is tricky and much harder with restricted_views than -with induced subgraphs. -Often it is easiest to use .copy() to avoid chains. -""" -from networkx.classes.coreviews import UnionAdjacency, UnionMultiAdjacency, \ - FilterAtlas, FilterAdjacency, FilterMultiAdjacency -from networkx.classes.filters import no_filter -from networkx.exception import NetworkXError -from networkx.utils import not_implemented_for - -import networkx as nx - -__all__ = ['generic_graph_view', 'subgraph_view', 'reverse_view'] - - -def generic_graph_view(G, create_using=None): - if create_using is None: - newG = G.__class__() - else: - newG = nx.empty_graph(0, create_using) - if G.is_multigraph() != newG.is_multigraph(): - raise NetworkXError("Multigraph for G must agree with create_using") - newG = nx.freeze(newG) - - # create view by assigning attributes from G - newG._graph = G - newG.graph = G.graph - - newG._node = G._node - if newG.is_directed(): - if G.is_directed(): - newG._succ = G._succ - newG._pred = G._pred - newG._adj = G._succ - else: - newG._succ = G._adj - newG._pred = G._adj - newG._adj = G._adj - elif G.is_directed(): - if G.is_multigraph(): - newG._adj = UnionMultiAdjacency(G._succ, G._pred) - else: - newG._adj = UnionAdjacency(G._succ, G._pred) - else: - newG._adj = G._adj - return newG - - -def subgraph_view(G, filter_node=no_filter, filter_edge=no_filter): - """ View of `G` applying a filter on nodes and edges. - - `subgraph_view` provides a read-only view of the input graph that excludes - nodes and edges based on the outcome of two filter functions `filter_node` - and `filter_edge`. - - The `filter_node` function takes one argument --- the node --- and returns - `True` if the node should be included in the subgraph, and `False` if it - should not be included. - - The `filter_edge` function takes two arguments --- the nodes describing an - edge --- and returns `True` if the edge should be included in the subgraph, - and `False` if it should not be included. - - Both node and edge filter functions are called on graph elements as they - are queried, meaning there is no up-front cost to creating the view. - - Parameters - ---------- - G : networkx.Graph - A directed/undirected graph/multigraph - - filter_node : callable, optional - A function taking a node as input, which returns `True` if the node - should appear in the view. - - filter_edge : callable, optional - A function taking as input the two nodes describing an edge, which - returns `True` if the edge should appear in the view. - - Returns - ------- - graph : networkx.Graph - A read-only graph view of the input graph. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.path_graph(6) - - Filter functions operate on the node, and return `True` if the node should - appear in the view: - - >>> def filter_node(n1): - ... return n1 != 5 - ... - >>> view = nx.subgraph_view( - ... G, - ... filter_node=filter_node - ... ) - >>> view.nodes() - NodeView((0, 1, 2, 3, 4)) - - We can use a closure pattern to filter graph elements based on additional - data --- for example, filtering on edge data attached to the graph: - - >>> G[3][4]['cross_me'] = False - >>> def filter_edge(n1, n2): - ... return G[n1][n2].get('cross_me', True) - ... - >>> view = nx.subgraph_view( - ... G, - ... filter_edge=filter_edge - ... ) - >>> view.edges() - EdgeView([(0, 1), (1, 2), (2, 3), (4, 5)]) - - >>> view = nx.subgraph_view( - ... G, - ... filter_node=filter_node, - ... filter_edge=filter_edge, - ... ) - >>> view.nodes() - NodeView((0, 1, 2, 3, 4)) - >>> view.edges() - EdgeView([(0, 1), (1, 2), (2, 3)]) - """ - newG = nx.freeze(G.__class__()) - newG._NODE_OK = filter_node - newG._EDGE_OK = filter_edge - - # create view by assigning attributes from G - newG._graph = G - newG.graph = G.graph - - newG._node = FilterAtlas(G._node, filter_node) - if G.is_multigraph(): - Adj = FilterMultiAdjacency - - def reverse_edge(u, v, k): return filter_edge(v, u, k) - else: - Adj = FilterAdjacency - - def reverse_edge(u, v): return filter_edge(v, u) - if G.is_directed(): - newG._succ = Adj(G._succ, filter_node, filter_edge) - newG._pred = Adj(G._pred, filter_node, reverse_edge) - newG._adj = newG._succ - else: - newG._adj = Adj(G._adj, filter_node, filter_edge) - return newG - - -@not_implemented_for('undirected') -def reverse_view(G): - """ View of `G` with edge directions reversed - - `reverse_view` returns a read-only view of the input graph where - edge directions are reversed. - - Identical to digraph.reverse(copy=False) - - Parameters - ---------- - G : networkx.DiGraph - - Returns - ------- - graph : networkx.DiGraph - - Examples - -------- - >>> import networkx as nx - >>> G = nx.DiGraph() - >>> G.add_edge(1, 2) - >>> G.add_edge(2, 3) - >>> G.edges() - OutEdgeView([(1, 2), (2, 3)]) - - >>> view = nx.reverse_view(G) - >>> view.edges() - OutEdgeView([(2, 1), (3, 2)]) - """ - newG = generic_graph_view(G) - newG._succ, newG._pred = G._pred, G._succ - newG._adj = newG._succ - return newG diff --git a/extensions/fablabchemnitz/networkx/classes/multidigraph.py b/extensions/fablabchemnitz/networkx/classes/multidigraph.py deleted file mode 100644 index ca13f690..00000000 --- a/extensions/fablabchemnitz/networkx/classes/multidigraph.py +++ /dev/null @@ -1,871 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg -# Dan Schult -# Pieter Swart -"""Base class for MultiDiGraph.""" -from copy import deepcopy - -import networkx as nx -from networkx.classes.graph import Graph # for doctests -from networkx.classes.digraph import DiGraph -from networkx.classes.multigraph import MultiGraph -from networkx.classes.coreviews import MultiAdjacencyView -from networkx.classes.reportviews import OutMultiEdgeView, InMultiEdgeView, \ - DiMultiDegreeView, OutMultiDegreeView, InMultiDegreeView -from networkx.exception import NetworkXError - - -class MultiDiGraph(MultiGraph, DiGraph): - """A directed graph class that can store multiedges. - - Multiedges are multiple edges between two nodes. Each edge - can hold optional data or attributes. - - A MultiDiGraph holds directed edges. Self loops are allowed. - - Nodes can be arbitrary (hashable) Python objects with optional - key/value attributes. By convention `None` is not used as a node. - - Edges are represented as links between nodes with optional - key/value attributes. - - Parameters - ---------- - incoming_graph_data : input graph (optional, default: None) - Data to initialize graph. If None (default) an empty - graph is created. The data can be any format that is supported - by the to_networkx_graph() function, currently including edge list, - dict of dicts, dict of lists, NetworkX graph, NumPy matrix - or 2d ndarray, SciPy sparse matrix, or PyGraphviz graph. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - Graph - DiGraph - MultiGraph - OrderedMultiDiGraph - - Examples - -------- - Create an empty graph structure (a "null graph") with no nodes and - no edges. - - >>> G = nx.MultiDiGraph() - - G can be grown in several ways. - - **Nodes:** - - Add one node at a time: - - >>> G.add_node(1) - - Add the nodes from any container (a list, dict, set or - even the lines from a file or the nodes from another graph). - - >>> G.add_nodes_from([2, 3]) - >>> G.add_nodes_from(range(100, 110)) - >>> H = nx.path_graph(10) - >>> G.add_nodes_from(H) - - In addition to strings and integers any hashable Python object - (except None) can represent a node, e.g. a customized node object, - or even another Graph. - - >>> G.add_node(H) - - **Edges:** - - G can also be grown by adding edges. - - Add one edge, - - >>> key = G.add_edge(1, 2) - - a list of edges, - - >>> keys = G.add_edges_from([(1, 2), (1, 3)]) - - or a collection of edges, - - >>> keys = G.add_edges_from(H.edges) - - If some edges connect nodes not yet in the graph, the nodes - are added automatically. If an edge already exists, an additional - edge is created and stored using a key to identify the edge. - By default the key is the lowest unused integer. - - >>> keys = G.add_edges_from([(4,5,dict(route=282)), (4,5,dict(route=37))]) - >>> G[4] - AdjacencyView({5: {0: {}, 1: {'route': 282}, 2: {'route': 37}}}) - - **Attributes:** - - Each graph, node, and edge can hold key/value attribute pairs - in an associated attribute dictionary (the keys must be hashable). - By default these are empty, but can be added or changed using - add_edge, add_node or direct manipulation of the attribute - dictionaries named graph, node and edge respectively. - - >>> G = nx.MultiDiGraph(day="Friday") - >>> G.graph - {'day': 'Friday'} - - Add node attributes using add_node(), add_nodes_from() or G.nodes - - >>> G.add_node(1, time='5pm') - >>> G.add_nodes_from([3], time='2pm') - >>> G.nodes[1] - {'time': '5pm'} - >>> G.nodes[1]['room'] = 714 - >>> del G.nodes[1]['room'] # remove attribute - >>> list(G.nodes(data=True)) - [(1, {'time': '5pm'}), (3, {'time': '2pm'})] - - Add edge attributes using add_edge(), add_edges_from(), subscript - notation, or G.edges. - - >>> key = G.add_edge(1, 2, weight=4.7 ) - >>> keys = G.add_edges_from([(3, 4), (4, 5)], color='red') - >>> keys = G.add_edges_from([(1,2,{'color':'blue'}), (2,3,{'weight':8})]) - >>> G[1][2][0]['weight'] = 4.7 - >>> G.edges[1, 2, 0]['weight'] = 4 - - Warning: we protect the graph data structure by making `G.edges[1, 2]` a - read-only dict-like structure. However, you can assign to attributes - in e.g. `G.edges[1, 2]`. Thus, use 2 sets of brackets to add/change - data attributes: `G.edges[1, 2]['weight'] = 4` - (For multigraphs: `MG.edges[u, v, key][name] = value`). - - **Shortcuts:** - - Many common graph features allow python syntax to speed reporting. - - >>> 1 in G # check if node in graph - True - >>> [n for n in G if n<3] # iterate through nodes - [1, 2] - >>> len(G) # number of nodes in graph - 5 - >>> G[1] # adjacency dict-like view keyed by neighbor to edge attributes - AdjacencyView({2: {0: {'weight': 4}, 1: {'color': 'blue'}}}) - - Often the best way to traverse all edges of a graph is via the neighbors. - The neighbors are available as an adjacency-view `G.adj` object or via - the method `G.adjacency()`. - - >>> for n, nbrsdict in G.adjacency(): - ... for nbr, keydict in nbrsdict.items(): - ... for key, eattr in keydict.items(): - ... if 'weight' in eattr: - ... # Do something useful with the edges - ... pass - - But the edges() method is often more convenient: - - >>> for u, v, keys, weight in G.edges(data='weight', keys=True): - ... if weight is not None: - ... # Do something useful with the edges - ... pass - - **Reporting:** - - Simple graph information is obtained using methods and object-attributes. - Reporting usually provides views instead of containers to reduce memory - usage. The views update as the graph is updated similarly to dict-views. - The objects `nodes, `edges` and `adj` provide access to data attributes - via lookup (e.g. `nodes[n], `edges[u, v]`, `adj[u][v]`) and iteration - (e.g. `nodes.items()`, `nodes.data('color')`, - `nodes.data('color', default='blue')` and similarly for `edges`) - Views exist for `nodes`, `edges`, `neighbors()`/`adj` and `degree`. - - For details on these and other miscellaneous methods, see below. - - **Subclasses (Advanced):** - - The MultiDiGraph class uses a dict-of-dict-of-dict-of-dict structure. - The outer dict (node_dict) holds adjacency information keyed by node. - The next dict (adjlist_dict) represents the adjacency information and holds - edge_key dicts keyed by neighbor. The edge_key dict holds each edge_attr - dict keyed by edge key. The inner dict (edge_attr_dict) represents - the edge data and holds edge attribute values keyed by attribute names. - - Each of these four dicts in the dict-of-dict-of-dict-of-dict - structure can be replaced by a user defined dict-like object. - In general, the dict-like features should be maintained but - extra features can be added. To replace one of the dicts create - a new graph class by changing the class(!) variable holding the - factory for that dict-like structure. The variable names are - node_dict_factory, node_attr_dict_factory, adjlist_inner_dict_factory, - adjlist_outer_dict_factory, edge_key_dict_factory, edge_attr_dict_factory - and graph_attr_dict_factory. - - node_dict_factory : function, (default: dict) - Factory function to be used to create the dict containing node - attributes, keyed by node id. - It should require no arguments and return a dict-like object - - node_attr_dict_factory: function, (default: dict) - Factory function to be used to create the node attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object - - adjlist_outer_dict_factory : function, (default: dict) - Factory function to be used to create the outer-most dict - in the data structure that holds adjacency info keyed by node. - It should require no arguments and return a dict-like object. - - adjlist_inner_dict_factory : function, (default: dict) - Factory function to be used to create the adjacency list - dict which holds multiedge key dicts keyed by neighbor. - It should require no arguments and return a dict-like object. - - edge_key_dict_factory : function, (default: dict) - Factory function to be used to create the edge key dict - which holds edge data keyed by edge key. - It should require no arguments and return a dict-like object. - - edge_attr_dict_factory : function, (default: dict) - Factory function to be used to create the edge attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - graph_attr_dict_factory : function, (default: dict) - Factory function to be used to create the graph attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - Typically, if your extension doesn't impact the data structure all - methods will inherited without issue except: `to_directed/to_undirected`. - By default these methods create a DiGraph/Graph class and you probably - want them to create your extension of a DiGraph/Graph. To facilitate - this we define two class variables that you can set in your subclass. - - to_directed_class : callable, (default: DiGraph or MultiDiGraph) - Class to create a new graph structure in the `to_directed` method. - If `None`, a NetworkX class (DiGraph or MultiDiGraph) is used. - - to_undirected_class : callable, (default: Graph or MultiGraph) - Class to create a new graph structure in the `to_undirected` method. - If `None`, a NetworkX class (Graph or MultiGraph) is used. - - Examples - -------- - - Please see :mod:`~networkx.classes.ordered` for examples of - creating graph subclasses by overwriting the base class `dict` with - a dictionary-like object. - """ - # node_dict_factory = dict # already assigned in Graph - # adjlist_outer_dict_factory = dict - # adjlist_inner_dict_factory = dict - edge_key_dict_factory = dict - # edge_attr_dict_factory = dict - - def __init__(self, incoming_graph_data=None, **attr): - """Initialize a graph with edges, name, or graph attributes. - - Parameters - ---------- - incoming_graph_data : input graph - Data to initialize graph. If incoming_graph_data=None (default) - an empty graph is created. The data can be an edge list, or any - NetworkX graph object. If the corresponding optional Python - packages are installed the data can also be a NumPy matrix - or 2d ndarray, a SciPy sparse matrix, or a PyGraphviz graph. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - convert - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G = nx.Graph(name='my graph') - >>> e = [(1, 2), (2, 3), (3, 4)] # list of edges - >>> G = nx.Graph(e) - - Arbitrary graph attribute pairs (key=value) may be assigned - - >>> G = nx.Graph(e, day="Friday") - >>> G.graph - {'day': 'Friday'} - - """ - self.edge_key_dict_factory = self.edge_key_dict_factory - DiGraph.__init__(self, incoming_graph_data, **attr) - - @property - def adj(self): - """Graph adjacency object holding the neighbors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edgekey-dict. So `G.adj[3][2][0]['color'] = 'blue'` sets - the color of the edge `(3, 2, 0)` to `"blue"`. - - Iterating over G.adj behaves like a dict. Useful idioms include - `for nbr, datadict in G.adj[n].items():`. - - The neighbor information is also provided by subscripting the graph. - So `for nbr, foovalue in G[node].data('foo', default=1):` works. - - For directed graphs, `G.adj` holds outgoing (successor) info. - """ - return MultiAdjacencyView(self._succ) - - @property - def succ(self): - """Graph adjacency object holding the successors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edgekey-dict. So `G.adj[3][2][0]['color'] = 'blue'` sets - the color of the edge `(3, 2, 0)` to `"blue"`. - - Iterating over G.adj behaves like a dict. Useful idioms include - `for nbr, datadict in G.adj[n].items():`. - - The neighbor information is also provided by subscripting the graph. - So `for nbr, foovalue in G[node].data('foo', default=1):` works. - - For directed graphs, `G.succ` is identical to `G.adj`. - """ - return MultiAdjacencyView(self._succ) - - @property - def pred(self): - """Graph adjacency object holding the predecessors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edgekey-dict. So `G.adj[3][2][0]['color'] = 'blue'` sets - the color of the edge `(3, 2, 0)` to `"blue"`. - - Iterating over G.adj behaves like a dict. Useful idioms include - `for nbr, datadict in G.adj[n].items():`. - """ - return MultiAdjacencyView(self._pred) - - def add_edge(self, u_for_edge, v_for_edge, key=None, **attr): - """Add an edge between u and v. - - The nodes u and v will be automatically added if they are - not already in the graph. - - Edge attributes can be specified with keywords or by directly - accessing the edge's attribute dictionary. See examples below. - - Parameters - ---------- - u_for_edge, v_for_edge : nodes - Nodes can be, for example, strings or numbers. - Nodes must be hashable (and not None) Python objects. - key : hashable identifier, optional (default=lowest unused integer) - Used to distinguish multiedges between a pair of nodes. - attr_dict : dictionary, optional (default= no attributes) - Dictionary of edge attributes. Key/value pairs will - update existing data associated with the edge. - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - Returns - ------- - The edge key assigned to the edge. - - See Also - -------- - add_edges_from : add a collection of edges - - Notes - ----- - To replace/update edge data, use the optional key argument - to identify a unique edge. Otherwise a new edge will be created. - - NetworkX algorithms designed for weighted graphs cannot use - multigraphs directly because it is not clear how to handle - multiedge weights. Convert to Graph using edge attribute - 'weight' to enable weighted graph algorithms. - - Default keys are generated using the method `new_edge_key()`. - This method can be overridden by subclassing the base class and - providing a custom `new_edge_key()` method. - - Examples - -------- - The following all add the edge e=(1, 2) to graph G: - - >>> G = nx.MultiDiGraph() - >>> e = (1, 2) - >>> key = G.add_edge(1, 2) # explicit two-node form - >>> G.add_edge(*e) # single edge as tuple of two nodes - 1 - >>> G.add_edges_from( [(1, 2)] ) # add edges from iterable container - [2] - - Associate data to edges using keywords: - - >>> key = G.add_edge(1, 2, weight=3) - >>> key = G.add_edge(1, 2, key=0, weight=4) # update data for key=0 - >>> key = G.add_edge(1, 3, weight=7, capacity=15, length=342.7) - - For non-string attribute keys, use subscript notation. - - >>> ekey = G.add_edge(1, 2) - >>> G[1][2][0].update({0: 5}) - >>> G.edges[1, 2, 0].update({0: 5}) - """ - u, v = u_for_edge, v_for_edge - # add nodes - if u not in self._succ: - self._succ[u] = self.adjlist_inner_dict_factory() - self._pred[u] = self.adjlist_inner_dict_factory() - self._node[u] = self.node_attr_dict_factory() - if v not in self._succ: - self._succ[v] = self.adjlist_inner_dict_factory() - self._pred[v] = self.adjlist_inner_dict_factory() - self._node[v] = self.node_attr_dict_factory() - if key is None: - key = self.new_edge_key(u, v) - if v in self._succ[u]: - keydict = self._adj[u][v] - datadict = keydict.get(key, self.edge_key_dict_factory()) - datadict.update(attr) - keydict[key] = datadict - else: - # selfloops work this way without special treatment - datadict = self.edge_attr_dict_factory() - datadict.update(attr) - keydict = self.edge_key_dict_factory() - keydict[key] = datadict - self._succ[u][v] = keydict - self._pred[v][u] = keydict - return key - - def remove_edge(self, u, v, key=None): - """Remove an edge between u and v. - - Parameters - ---------- - u, v : nodes - Remove an edge between nodes u and v. - key : hashable identifier, optional (default=None) - Used to distinguish multiple edges between a pair of nodes. - If None remove a single (arbitrary) edge between u and v. - - Raises - ------ - NetworkXError - If there is not an edge between u and v, or - if there is no edge with the specified key. - - See Also - -------- - remove_edges_from : remove a collection of edges - - Examples - -------- - >>> G = nx.MultiDiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.remove_edge(0, 1) - >>> e = (1, 2) - >>> G.remove_edge(*e) # unpacks e from an edge tuple - - For multiple edges - - >>> G = nx.MultiDiGraph() - >>> G.add_edges_from([(1, 2), (1, 2), (1, 2)]) # key_list returned - [0, 1, 2] - >>> G.remove_edge(1, 2) # remove a single (arbitrary) edge - - For edges with keys - - >>> G = nx.MultiDiGraph() - >>> G.add_edge(1, 2, key='first') - 'first' - >>> G.add_edge(1, 2, key='second') - 'second' - >>> G.remove_edge(1, 2, key='second') - - """ - try: - d = self._adj[u][v] - except KeyError: - raise NetworkXError( - "The edge %s-%s is not in the graph." % (u, v)) - # remove the edge with specified data - if key is None: - d.popitem() - else: - try: - del d[key] - except KeyError: - msg = "The edge %s-%s with key %s is not in the graph." - raise NetworkXError(msg % (u, v, key)) - if len(d) == 0: - # remove the key entries if last edge - del self._succ[u][v] - del self._pred[v][u] - - @property - def edges(self): - """An OutMultiEdgeView of the Graph as G.edges or G.edges(). - - edges(self, nbunch=None, data=False, keys=False, default=None) - - The OutMultiEdgeView provides set-like operations on the edge-tuples - as well as edge attribute lookup. When called, it also provides - an EdgeDataView object which allows control of access to edge - attributes (but does not provide set-like operations). - Hence, `G.edges[u, v]['color']` provides the value of the color - attribute for edge `(u, v)` while - `for (u, v, c) in G.edges(data='color', default='red'):` - iterates through all the edges yielding the color attribute - with default `'red'` if no color attribute exists. - - Edges are returned as tuples with optional data and keys - in the order (node, neighbor, key, data). - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - data : string or bool, optional (default=False) - The edge attribute returned in 3-tuple (u, v, ddict[data]). - If True, return edge attribute dict in 3-tuple (u, v, ddict). - If False, return 2-tuple (u, v). - keys : bool, optional (default=False) - If True, return edge keys with each edge. - default : value, optional (default=None) - Value used for edges that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - edges : EdgeView - A view of edge attributes, usually it iterates over (u, v) - (u, v, k) or (u, v, k, d) tuples of edges, but can also be - used for attribute lookup as `edges[u, v, k]['foo']`. - - Notes - ----- - Nodes in nbunch that are not in the graph will be (quietly) ignored. - For directed graphs this returns the out-edges. - - Examples - -------- - >>> G = nx.MultiDiGraph() - >>> nx.add_path(G, [0, 1, 2]) - >>> key = G.add_edge(2, 3, weight=5) - >>> [e for e in G.edges()] - [(0, 1), (1, 2), (2, 3)] - >>> list(G.edges(data=True)) # default data is {} (empty dict) - [(0, 1, {}), (1, 2, {}), (2, 3, {'weight': 5})] - >>> list(G.edges(data='weight', default=1)) - [(0, 1, 1), (1, 2, 1), (2, 3, 5)] - >>> list(G.edges(keys=True)) # default keys are integers - [(0, 1, 0), (1, 2, 0), (2, 3, 0)] - >>> list(G.edges(data=True, keys=True)) - [(0, 1, 0, {}), (1, 2, 0, {}), (2, 3, 0, {'weight': 5})] - >>> list(G.edges(data='weight', default=1, keys=True)) - [(0, 1, 0, 1), (1, 2, 0, 1), (2, 3, 0, 5)] - >>> list(G.edges([0, 2])) - [(0, 1), (2, 3)] - >>> list(G.edges(0)) - [(0, 1)] - - See Also - -------- - in_edges, out_edges - """ - return OutMultiEdgeView(self) - - # alias out_edges to edges - out_edges = edges - - @property - def in_edges(self): - """An InMultiEdgeView of the Graph as G.in_edges or G.in_edges(). - - in_edges(self, nbunch=None, data=False, keys=False, default=None) - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - data : string or bool, optional (default=False) - The edge attribute returned in 3-tuple (u, v, ddict[data]). - If True, return edge attribute dict in 3-tuple (u, v, ddict). - If False, return 2-tuple (u, v). - keys : bool, optional (default=False) - If True, return edge keys with each edge. - default : value, optional (default=None) - Value used for edges that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - in_edges : InMultiEdgeView - A view of edge attributes, usually it iterates over (u, v) - or (u, v, k) or (u, v, k, d) tuples of edges, but can also be - used for attribute lookup as `edges[u, v, k]['foo']`. - - See Also - -------- - edges - """ - return InMultiEdgeView(self) - - @property - def degree(self): - """A DegreeView for the Graph as G.degree or G.degree(). - - The node degree is the number of edges adjacent to the node. - The weighted node degree is the sum of the edge weights for - edges incident to that node. - - This object provides an iterator for (node, degree) as well as - lookup for the degree for a single node. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - If a single nodes is requested - deg : int - Degree of the node - - OR if multiple nodes are requested - nd_iter : iterator - The iterator returns two-tuples of (node, degree). - - See Also - -------- - out_degree, in_degree - - Examples - -------- - >>> G = nx.MultiDiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.degree(0) # node 0 with degree 1 - 1 - >>> list(G.degree([0, 1, 2])) - [(0, 1), (1, 2), (2, 2)] - - """ - return DiMultiDegreeView(self) - - @property - def in_degree(self): - """A DegreeView for (node, in_degree) or in_degree for single node. - - The node in-degree is the number of edges pointing in to the node. - The weighted node degree is the sum of the edge weights for - edges incident to that node. - - This object provides an iterator for (node, degree) as well as - lookup for the degree for a single node. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - If a single node is requested - deg : int - Degree of the node - - OR if multiple nodes are requested - nd_iter : iterator - The iterator returns two-tuples of (node, in-degree). - - See Also - -------- - degree, out_degree - - Examples - -------- - >>> G = nx.MultiDiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.in_degree(0) # node 0 with degree 0 - 0 - >>> list(G.in_degree([0, 1, 2])) - [(0, 0), (1, 1), (2, 1)] - - """ - return InMultiDegreeView(self) - - @property - def out_degree(self): - """Returns an iterator for (node, out-degree) or out-degree for single node. - - out_degree(self, nbunch=None, weight=None) - - The node out-degree is the number of edges pointing out of the node. - This function returns the out-degree for a single node or an iterator - for a bunch of nodes or if nothing is passed as argument. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights. - - Returns - ------- - If a single node is requested - deg : int - Degree of the node - - OR if multiple nodes are requested - nd_iter : iterator - The iterator returns two-tuples of (node, out-degree). - - See Also - -------- - degree, in_degree - - Examples - -------- - >>> G = nx.MultiDiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.out_degree(0) # node 0 with degree 1 - 1 - >>> list(G.out_degree([0, 1, 2])) - [(0, 1), (1, 1), (2, 1)] - - """ - return OutMultiDegreeView(self) - - def is_multigraph(self): - """Returns True if graph is a multigraph, False otherwise.""" - return True - - def is_directed(self): - """Returns True if graph is directed, False otherwise.""" - return True - - def to_undirected(self, reciprocal=False, as_view=False): - """Returns an undirected representation of the digraph. - - Parameters - ---------- - reciprocal : bool (optional) - If True only keep edges that appear in both directions - in the original digraph. - as_view : bool (optional, default=False) - If True return an undirected view of the original directed graph. - - Returns - ------- - G : MultiGraph - An undirected graph with the same name and nodes and - with edge (u, v, data) if either (u, v, data) or (v, u, data) - is in the digraph. If both edges exist in digraph and - their edge data is different, only one edge is created - with an arbitrary choice of which edge data to use. - You must check and correct for this manually if desired. - - See Also - -------- - MultiGraph, copy, add_edge, add_edges_from - - Notes - ----- - This returns a "deepcopy" of the edge, node, and - graph attributes which attempts to completely copy - all of the data and references. - - This is in contrast to the similar D=MultiiGraph(G) which - returns a shallow copy of the data. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/2/library/copy.html. - - Warning: If you have subclassed MultiDiGraph to use dict-like - objects in the data structure, those changes do not transfer - to the MultiGraph created by this method. - - Examples - -------- - >>> G = nx.path_graph(2) # or MultiGraph, etc - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1), (1, 0)] - >>> G2 = H.to_undirected() - >>> list(G2.edges) - [(0, 1)] - """ - graph_class = self.to_undirected_class() - if as_view is True: - return nx.graphviews.generic_graph_view(self, graph_class) - # deepcopy when not a view - G = graph_class() - G.graph.update(deepcopy(self.graph)) - G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) - if reciprocal is True: - G.add_edges_from((u, v, key, deepcopy(data)) - for u, nbrs in self._adj.items() - for v, keydict in nbrs.items() - for key, data in keydict.items() - if v in self._pred[u] and key in self._pred[u][v]) - else: - G.add_edges_from((u, v, key, deepcopy(data)) - for u, nbrs in self._adj.items() - for v, keydict in nbrs.items() - for key, data in keydict.items()) - return G - - def reverse(self, copy=True): - """Returns the reverse of the graph. - - The reverse is a graph with the same nodes and edges - but with the directions of the edges reversed. - - Parameters - ---------- - copy : bool optional (default=True) - If True, return a new DiGraph holding the reversed edges. - If False, the reverse graph is created using a view of - the original graph. - """ - if copy: - H = self.__class__() - H.graph.update(deepcopy(self.graph)) - H.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) - H.add_edges_from((v, u, k, deepcopy(d)) for u, v, k, d - in self.edges(keys=True, data=True)) - return H - return nx.graphviews.reverse_view(self) diff --git a/extensions/fablabchemnitz/networkx/classes/multigraph.py b/extensions/fablabchemnitz/networkx/classes/multigraph.py deleted file mode 100644 index edbf1d04..00000000 --- a/extensions/fablabchemnitz/networkx/classes/multigraph.py +++ /dev/null @@ -1,1139 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg -# Dan Schult -# Pieter Swart -"""Base class for MultiGraph.""" -from copy import deepcopy - -import networkx as nx -from networkx.classes.graph import Graph -from networkx.classes.coreviews import MultiAdjacencyView -from networkx.classes.reportviews import MultiEdgeView, MultiDegreeView -from networkx import NetworkXError -from networkx.utils import iterable - - -class MultiGraph(Graph): - """ - An undirected graph class that can store multiedges. - - Multiedges are multiple edges between two nodes. Each edge - can hold optional data or attributes. - - A MultiGraph holds undirected edges. Self loops are allowed. - - Nodes can be arbitrary (hashable) Python objects with optional - key/value attributes. By convention `None` is not used as a node. - - Edges are represented as links between nodes with optional - key/value attributes. - - Parameters - ---------- - incoming_graph_data : input graph (optional, default: None) - Data to initialize graph. If None (default) an empty - graph is created. The data can be any format that is supported - by the to_networkx_graph() function, currently including edge list, - dict of dicts, dict of lists, NetworkX graph, NumPy matrix - or 2d ndarray, SciPy sparse matrix, or PyGraphviz graph. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - Graph - DiGraph - MultiDiGraph - OrderedMultiGraph - - Examples - -------- - Create an empty graph structure (a "null graph") with no nodes and - no edges. - - >>> G = nx.MultiGraph() - - G can be grown in several ways. - - **Nodes:** - - Add one node at a time: - - >>> G.add_node(1) - - Add the nodes from any container (a list, dict, set or - even the lines from a file or the nodes from another graph). - - >>> G.add_nodes_from([2, 3]) - >>> G.add_nodes_from(range(100, 110)) - >>> H = nx.path_graph(10) - >>> G.add_nodes_from(H) - - In addition to strings and integers any hashable Python object - (except None) can represent a node, e.g. a customized node object, - or even another Graph. - - >>> G.add_node(H) - - **Edges:** - - G can also be grown by adding edges. - - Add one edge, - - >>> key = G.add_edge(1, 2) - - a list of edges, - - >>> keys = G.add_edges_from([(1, 2), (1, 3)]) - - or a collection of edges, - - >>> keys = G.add_edges_from(H.edges) - - If some edges connect nodes not yet in the graph, the nodes - are added automatically. If an edge already exists, an additional - edge is created and stored using a key to identify the edge. - By default the key is the lowest unused integer. - - >>> keys = G.add_edges_from([(4,5,{'route':28}), (4,5,{'route':37})]) - >>> G[4] - AdjacencyView({3: {0: {}}, 5: {0: {}, 1: {'route': 28}, 2: {'route': 37}}}) - - **Attributes:** - - Each graph, node, and edge can hold key/value attribute pairs - in an associated attribute dictionary (the keys must be hashable). - By default these are empty, but can be added or changed using - add_edge, add_node or direct manipulation of the attribute - dictionaries named graph, node and edge respectively. - - >>> G = nx.MultiGraph(day="Friday") - >>> G.graph - {'day': 'Friday'} - - Add node attributes using add_node(), add_nodes_from() or G.nodes - - >>> G.add_node(1, time='5pm') - >>> G.add_nodes_from([3], time='2pm') - >>> G.nodes[1] - {'time': '5pm'} - >>> G.nodes[1]['room'] = 714 - >>> del G.nodes[1]['room'] # remove attribute - >>> list(G.nodes(data=True)) - [(1, {'time': '5pm'}), (3, {'time': '2pm'})] - - Add edge attributes using add_edge(), add_edges_from(), subscript - notation, or G.edges. - - >>> key = G.add_edge(1, 2, weight=4.7 ) - >>> keys = G.add_edges_from([(3, 4), (4, 5)], color='red') - >>> keys = G.add_edges_from([(1,2,{'color':'blue'}), (2,3,{'weight':8})]) - >>> G[1][2][0]['weight'] = 4.7 - >>> G.edges[1, 2, 0]['weight'] = 4 - - Warning: we protect the graph data structure by making `G.edges[1, 2]` a - read-only dict-like structure. However, you can assign to attributes - in e.g. `G.edges[1, 2]`. Thus, use 2 sets of brackets to add/change - data attributes: `G.edges[1, 2]['weight'] = 4` - (For multigraphs: `MG.edges[u, v, key][name] = value`). - - **Shortcuts:** - - Many common graph features allow python syntax to speed reporting. - - >>> 1 in G # check if node in graph - True - >>> [n for n in G if n<3] # iterate through nodes - [1, 2] - >>> len(G) # number of nodes in graph - 5 - >>> G[1] # adjacency dict-like view keyed by neighbor to edge attributes - AdjacencyView({2: {0: {'weight': 4}, 1: {'color': 'blue'}}}) - - Often the best way to traverse all edges of a graph is via the neighbors. - The neighbors are reported as an adjacency-dict `G.adj` or `G.adjacency()`. - - >>> for n, nbrsdict in G.adjacency(): - ... for nbr, keydict in nbrsdict.items(): - ... for key, eattr in keydict.items(): - ... if 'weight' in eattr: - ... # Do something useful with the edges - ... pass - - But the edges() method is often more convenient: - - >>> for u, v, keys, weight in G.edges(data='weight', keys=True): - ... if weight is not None: - ... # Do something useful with the edges - ... pass - - **Reporting:** - - Simple graph information is obtained using methods and object-attributes. - Reporting usually provides views instead of containers to reduce memory - usage. The views update as the graph is updated similarly to dict-views. - The objects `nodes, `edges` and `adj` provide access to data attributes - via lookup (e.g. `nodes[n], `edges[u, v]`, `adj[u][v]`) and iteration - (e.g. `nodes.items()`, `nodes.data('color')`, - `nodes.data('color', default='blue')` and similarly for `edges`) - Views exist for `nodes`, `edges`, `neighbors()`/`adj` and `degree`. - - For details on these and other miscellaneous methods, see below. - - **Subclasses (Advanced):** - - The MultiGraph class uses a dict-of-dict-of-dict-of-dict data structure. - The outer dict (node_dict) holds adjacency information keyed by node. - The next dict (adjlist_dict) represents the adjacency information and holds - edge_key dicts keyed by neighbor. The edge_key dict holds each edge_attr - dict keyed by edge key. The inner dict (edge_attr_dict) represents - the edge data and holds edge attribute values keyed by attribute names. - - Each of these four dicts in the dict-of-dict-of-dict-of-dict - structure can be replaced by a user defined dict-like object. - In general, the dict-like features should be maintained but - extra features can be added. To replace one of the dicts create - a new graph class by changing the class(!) variable holding the - factory for that dict-like structure. The variable names are - node_dict_factory, node_attr_dict_factory, adjlist_inner_dict_factory, - adjlist_outer_dict_factory, edge_key_dict_factory, edge_attr_dict_factory - and graph_attr_dict_factory. - - node_dict_factory : function, (default: dict) - Factory function to be used to create the dict containing node - attributes, keyed by node id. - It should require no arguments and return a dict-like object - - node_attr_dict_factory: function, (default: dict) - Factory function to be used to create the node attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object - - adjlist_outer_dict_factory : function, (default: dict) - Factory function to be used to create the outer-most dict - in the data structure that holds adjacency info keyed by node. - It should require no arguments and return a dict-like object. - - adjlist_inner_dict_factory : function, (default: dict) - Factory function to be used to create the adjacency list - dict which holds multiedge key dicts keyed by neighbor. - It should require no arguments and return a dict-like object. - - edge_key_dict_factory : function, (default: dict) - Factory function to be used to create the edge key dict - which holds edge data keyed by edge key. - It should require no arguments and return a dict-like object. - - edge_attr_dict_factory : function, (default: dict) - Factory function to be used to create the edge attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - graph_attr_dict_factory : function, (default: dict) - Factory function to be used to create the graph attribute - dict which holds attribute values keyed by attribute name. - It should require no arguments and return a dict-like object. - - Typically, if your extension doesn't impact the data structure all - methods will inherited without issue except: `to_directed/to_undirected`. - By default these methods create a DiGraph/Graph class and you probably - want them to create your extension of a DiGraph/Graph. To facilitate - this we define two class variables that you can set in your subclass. - - to_directed_class : callable, (default: DiGraph or MultiDiGraph) - Class to create a new graph structure in the `to_directed` method. - If `None`, a NetworkX class (DiGraph or MultiDiGraph) is used. - - to_undirected_class : callable, (default: Graph or MultiGraph) - Class to create a new graph structure in the `to_undirected` method. - If `None`, a NetworkX class (Graph or MultiGraph) is used. - - Examples - -------- - - Please see :mod:`~networkx.classes.ordered` for examples of - creating graph subclasses by overwriting the base class `dict` with - a dictionary-like object. - """ - # node_dict_factory = dict # already assigned in Graph - # adjlist_outer_dict_factory = dict - # adjlist_inner_dict_factory = dict - edge_key_dict_factory = dict - # edge_attr_dict_factory = dict - - def to_directed_class(self): - """Returns the class to use for empty directed copies. - - If you subclass the base classes, use this to designate - what directed class to use for `to_directed()` copies. - """ - return nx.MultiDiGraph - - def to_undirected_class(self): - """Returns the class to use for empty undirected copies. - - If you subclass the base classes, use this to designate - what directed class to use for `to_directed()` copies. - """ - return MultiGraph - - def __init__(self, incoming_graph_data=None, **attr): - """Initialize a graph with edges, name, or graph attributes. - - Parameters - ---------- - incoming_graph_data : input graph - Data to initialize graph. If incoming_graph_data=None (default) - an empty graph is created. The data can be an edge list, or any - NetworkX graph object. If the corresponding optional Python - packages are installed the data can also be a NumPy matrix - or 2d ndarray, a SciPy sparse matrix, or a PyGraphviz graph. - - attr : keyword arguments, optional (default= no attributes) - Attributes to add to graph as key=value pairs. - - See Also - -------- - convert - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G = nx.Graph(name='my graph') - >>> e = [(1, 2), (2, 3), (3, 4)] # list of edges - >>> G = nx.Graph(e) - - Arbitrary graph attribute pairs (key=value) may be assigned - - >>> G = nx.Graph(e, day="Friday") - >>> G.graph - {'day': 'Friday'} - - """ - self.edge_key_dict_factory = self.edge_key_dict_factory - Graph.__init__(self, incoming_graph_data, **attr) - - @property - def adj(self): - """Graph adjacency object holding the neighbors of each node. - - This object is a read-only dict-like structure with node keys - and neighbor-dict values. The neighbor-dict is keyed by neighbor - to the edgekey-data-dict. So `G.adj[3][2][0]['color'] = 'blue'` sets - the color of the edge `(3, 2, 0)` to `"blue"`. - - Iterating over G.adj behaves like a dict. Useful idioms include - `for nbr, nbrdict in G.adj[n].items():`. - - The neighbor information is also provided by subscripting the graph. - So `for nbr, foovalue in G[node].data('foo', default=1):` works. - - For directed graphs, `G.adj` holds outgoing (successor) info. - """ - return MultiAdjacencyView(self._adj) - - def new_edge_key(self, u, v): - """Returns an unused key for edges between nodes `u` and `v`. - - The nodes `u` and `v` do not need to be already in the graph. - - Notes - ----- - In the standard MultiGraph class the new key is the number of existing - edges between `u` and `v` (increased if necessary to ensure unused). - The first edge will have key 0, then 1, etc. If an edge is removed - further new_edge_keys may not be in this order. - - Parameters - ---------- - u, v : nodes - - Returns - ------- - key : int - """ - try: - keydict = self._adj[u][v] - except KeyError: - return 0 - key = len(keydict) - while key in keydict: - key += 1 - return key - - def add_edge(self, u_for_edge, v_for_edge, key=None, **attr): - """Add an edge between u and v. - - The nodes u and v will be automatically added if they are - not already in the graph. - - Edge attributes can be specified with keywords or by directly - accessing the edge's attribute dictionary. See examples below. - - Parameters - ---------- - u_for_edge, v_for_edge : nodes - Nodes can be, for example, strings or numbers. - Nodes must be hashable (and not None) Python objects. - key : hashable identifier, optional (default=lowest unused integer) - Used to distinguish multiedges between a pair of nodes. - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - Returns - ------- - The edge key assigned to the edge. - - See Also - -------- - add_edges_from : add a collection of edges - - Notes - ----- - To replace/update edge data, use the optional key argument - to identify a unique edge. Otherwise a new edge will be created. - - NetworkX algorithms designed for weighted graphs cannot use - multigraphs directly because it is not clear how to handle - multiedge weights. Convert to Graph using edge attribute - 'weight' to enable weighted graph algorithms. - - Default keys are generated using the method `new_edge_key()`. - This method can be overridden by subclassing the base class and - providing a custom `new_edge_key()` method. - - Examples - -------- - The following all add the edge e=(1, 2) to graph G: - - >>> G = nx.MultiGraph() - >>> e = (1, 2) - >>> ekey = G.add_edge(1, 2) # explicit two-node form - >>> G.add_edge(*e) # single edge as tuple of two nodes - 1 - >>> G.add_edges_from( [(1, 2)] ) # add edges from iterable container - [2] - - Associate data to edges using keywords: - - >>> ekey = G.add_edge(1, 2, weight=3) - >>> ekey = G.add_edge(1, 2, key=0, weight=4) # update data for key=0 - >>> ekey = G.add_edge(1, 3, weight=7, capacity=15, length=342.7) - - For non-string attribute keys, use subscript notation. - - >>> ekey = G.add_edge(1, 2) - >>> G[1][2][0].update({0: 5}) - >>> G.edges[1, 2, 0].update({0: 5}) - """ - u, v = u_for_edge, v_for_edge - # add nodes - if u not in self._adj: - self._adj[u] = self.adjlist_inner_dict_factory() - self._node[u] = self.node_attr_dict_factory() - if v not in self._adj: - self._adj[v] = self.adjlist_inner_dict_factory() - self._node[v] = self.node_attr_dict_factory() - if key is None: - key = self.new_edge_key(u, v) - if v in self._adj[u]: - keydict = self._adj[u][v] - datadict = keydict.get(key, self.edge_attr_dict_factory()) - datadict.update(attr) - keydict[key] = datadict - else: - # selfloops work this way without special treatment - datadict = self.edge_attr_dict_factory() - datadict.update(attr) - keydict = self.edge_key_dict_factory() - keydict[key] = datadict - self._adj[u][v] = keydict - self._adj[v][u] = keydict - return key - - def add_edges_from(self, ebunch_to_add, **attr): - """Add all the edges in ebunch_to_add. - - Parameters - ---------- - ebunch_to_add : container of edges - Each edge given in the container will be added to the - graph. The edges can be: - - - 2-tuples (u, v) or - - 3-tuples (u, v, d) for an edge data dict d, or - - 3-tuples (u, v, k) for not iterable key k, or - - 4-tuples (u, v, k, d) for an edge with data and key k - - attr : keyword arguments, optional - Edge data (or labels or objects) can be assigned using - keyword arguments. - - Returns - ------- - A list of edge keys assigned to the edges in `ebunch`. - - See Also - -------- - add_edge : add a single edge - add_weighted_edges_from : convenient way to add weighted edges - - Notes - ----- - Adding the same edge twice has no effect but any edge data - will be updated when each duplicate edge is added. - - Edge attributes specified in an ebunch take precedence over - attributes specified via keyword arguments. - - Default keys are generated using the method ``new_edge_key()``. - This method can be overridden by subclassing the base class and - providing a custom ``new_edge_key()`` method. - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> G.add_edges_from([(0, 1), (1, 2)]) # using a list of edge tuples - >>> e = zip(range(0, 3), range(1, 4)) - >>> G.add_edges_from(e) # Add the path graph 0-1-2-3 - - Associate data to edges - - >>> G.add_edges_from([(1, 2), (2, 3)], weight=3) - >>> G.add_edges_from([(3, 4), (1, 4)], label='WN2898') - """ - keylist = [] - for e in ebunch_to_add: - ne = len(e) - if ne == 4: - u, v, key, dd = e - elif ne == 3: - u, v, dd = e - key = None - elif ne == 2: - u, v = e - dd = {} - key = None - else: - msg = "Edge tuple {} must be a 2-tuple, 3-tuple or 4-tuple." - raise NetworkXError(msg.format(e)) - ddd = {} - ddd.update(attr) - try: - ddd.update(dd) - except: - if ne != 3: - raise - key = dd - key = self.add_edge(u, v, key) - self[u][v][key].update(ddd) - keylist.append(key) - return keylist - - def remove_edge(self, u, v, key=None): - """Remove an edge between u and v. - - Parameters - ---------- - u, v : nodes - Remove an edge between nodes u and v. - key : hashable identifier, optional (default=None) - Used to distinguish multiple edges between a pair of nodes. - If None remove a single (arbitrary) edge between u and v. - - Raises - ------ - NetworkXError - If there is not an edge between u and v, or - if there is no edge with the specified key. - - See Also - -------- - remove_edges_from : remove a collection of edges - - Examples - -------- - >>> G = nx.MultiGraph() - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.remove_edge(0, 1) - >>> e = (1, 2) - >>> G.remove_edge(*e) # unpacks e from an edge tuple - - For multiple edges - - >>> G = nx.MultiGraph() # or MultiDiGraph, etc - >>> G.add_edges_from([(1, 2), (1, 2), (1, 2)]) # key_list returned - [0, 1, 2] - >>> G.remove_edge(1, 2) # remove a single (arbitrary) edge - - For edges with keys - - >>> G = nx.MultiGraph() # or MultiDiGraph, etc - >>> G.add_edge(1, 2, key='first') - 'first' - >>> G.add_edge(1, 2, key='second') - 'second' - >>> G.remove_edge(1, 2, key='second') - - """ - try: - d = self._adj[u][v] - except KeyError: - raise NetworkXError( - "The edge %s-%s is not in the graph." % (u, v)) - # remove the edge with specified data - if key is None: - d.popitem() - else: - try: - del d[key] - except KeyError: - msg = "The edge %s-%s with key %s is not in the graph." - raise NetworkXError(msg % (u, v, key)) - if len(d) == 0: - # remove the key entries if last edge - del self._adj[u][v] - if u != v: # check for selfloop - del self._adj[v][u] - - def remove_edges_from(self, ebunch): - """Remove all edges specified in ebunch. - - Parameters - ---------- - ebunch: list or container of edge tuples - Each edge given in the list or container will be removed - from the graph. The edges can be: - - - 2-tuples (u, v) All edges between u and v are removed. - - 3-tuples (u, v, key) The edge identified by key is removed. - - 4-tuples (u, v, key, data) where data is ignored. - - See Also - -------- - remove_edge : remove a single edge - - Notes - ----- - Will fail silently if an edge in ebunch is not in the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> ebunch=[(1, 2), (2, 3)] - >>> G.remove_edges_from(ebunch) - - Removing multiple copies of edges - - >>> G = nx.MultiGraph() - >>> keys = G.add_edges_from([(1, 2), (1, 2), (1, 2)]) - >>> G.remove_edges_from([(1, 2), (1, 2)]) - >>> list(G.edges()) - [(1, 2)] - >>> G.remove_edges_from([(1, 2), (1, 2)]) # silently ignore extra copy - >>> list(G.edges) # now empty graph - [] - """ - for e in ebunch: - try: - self.remove_edge(*e[:3]) - except NetworkXError: - pass - - def has_edge(self, u, v, key=None): - """Returns True if the graph has an edge between nodes u and v. - - This is the same as `v in G[u] or key in G[u][v]` - without KeyError exceptions. - - Parameters - ---------- - u, v : nodes - Nodes can be, for example, strings or numbers. - - key : hashable identifier, optional (default=None) - If specified return True only if the edge with - key is found. - - Returns - ------- - edge_ind : bool - True if edge is in the graph, False otherwise. - - Examples - -------- - Can be called either using two nodes u, v, an edge tuple (u, v), - or an edge tuple (u, v, key). - - >>> G = nx.MultiGraph() # or MultiDiGraph - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.has_edge(0, 1) # using two nodes - True - >>> e = (0, 1) - >>> G.has_edge(*e) # e is a 2-tuple (u, v) - True - >>> G.add_edge(0, 1, key='a') - 'a' - >>> G.has_edge(0, 1, key='a') # specify key - True - >>> e=(0, 1, 'a') - >>> G.has_edge(*e) # e is a 3-tuple (u, v, 'a') - True - - The following syntax are equivalent: - - >>> G.has_edge(0, 1) - True - >>> 1 in G[0] # though this gives :exc:`KeyError` if 0 not in G - True - - """ - try: - if key is None: - return v in self._adj[u] - else: - return key in self._adj[u][v] - except KeyError: - return False - - @property - def edges(self): - """Returns an iterator over the edges. - - edges(self, nbunch=None, data=False, keys=False, default=None) - - The EdgeView provides set-like operations on the edge-tuples - as well as edge attribute lookup. When called, it also provides - an EdgeDataView object which allows control of access to edge - attributes (but does not provide set-like operations). - Hence, `G.edges[u, v]['color']` provides the value of the color - attribute for edge `(u, v)` while - `for (u, v, c) in G.edges(data='color', default='red'):` - iterates through all the edges yielding the color attribute. - - Edges are returned as tuples with optional data and keys - in the order (node, neighbor, key, data). - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - data : string or bool, optional (default=False) - The edge attribute returned in 3-tuple (u, v, ddict[data]). - If True, return edge attribute dict in 3-tuple (u, v, ddict). - If False, return 2-tuple (u, v). - keys : bool, optional (default=False) - If True, return edge keys with each edge. - default : value, optional (default=None) - Value used for edges that don't have the requested attribute. - Only relevant if data is not True or False. - - Returns - ------- - edges : MultiEdgeView - A view of edge attributes, usually it iterates over (u, v) - (u, v, k) or (u, v, k, d) tuples of edges, but can also be - used for attribute lookup as `edges[u, v, k]['foo']`. - - Notes - ----- - Nodes in nbunch that are not in the graph will be (quietly) ignored. - For directed graphs this returns the out-edges. - - Examples - -------- - >>> G = nx.MultiGraph() # or MultiDiGraph - >>> nx.add_path(G, [0, 1, 2]) - >>> key = G.add_edge(2, 3, weight=5) - >>> [e for e in G.edges()] - [(0, 1), (1, 2), (2, 3)] - >>> G.edges.data() # default data is {} (empty dict) - MultiEdgeDataView([(0, 1, {}), (1, 2, {}), (2, 3, {'weight': 5})]) - >>> G.edges.data('weight', default=1) - MultiEdgeDataView([(0, 1, 1), (1, 2, 1), (2, 3, 5)]) - >>> G.edges(keys=True) # default keys are integers - MultiEdgeView([(0, 1, 0), (1, 2, 0), (2, 3, 0)]) - >>> G.edges.data(keys=True) - MultiEdgeDataView([(0, 1, 0, {}), (1, 2, 0, {}), (2, 3, 0, {'weight': 5})]) - >>> G.edges.data('weight', default=1, keys=True) - MultiEdgeDataView([(0, 1, 0, 1), (1, 2, 0, 1), (2, 3, 0, 5)]) - >>> G.edges([0, 3]) - MultiEdgeDataView([(0, 1), (3, 2)]) - >>> G.edges(0) - MultiEdgeDataView([(0, 1)]) - """ - return MultiEdgeView(self) - - def get_edge_data(self, u, v, key=None, default=None): - """Returns the attribute dictionary associated with edge (u, v). - - This is identical to `G[u][v][key]` except the default is returned - instead of an exception is the edge doesn't exist. - - Parameters - ---------- - u, v : nodes - - default : any Python object (default=None) - Value to return if the edge (u, v) is not found. - - key : hashable identifier, optional (default=None) - Return data only for the edge with specified key. - - Returns - ------- - edge_dict : dictionary - The edge attribute dictionary. - - Examples - -------- - >>> G = nx.MultiGraph() # or MultiDiGraph - >>> key = G.add_edge(0, 1, key='a', weight=7) - >>> G[0][1]['a'] # key='a' - {'weight': 7} - >>> G.edges[0, 1, 'a'] # key='a' - {'weight': 7} - - Warning: we protect the graph data structure by making - `G.edges` and `G[1][2]` read-only dict-like structures. - However, you can assign values to attributes in e.g. - `G.edges[1, 2, 'a']` or `G[1][2]['a']` using an additional - bracket as shown next. You need to specify all edge info - to assign to the edge data associated with an edge. - - >>> G[0][1]['a']['weight'] = 10 - >>> G.edges[0, 1, 'a']['weight'] = 10 - >>> G[0][1]['a']['weight'] - 10 - >>> G.edges[1, 0, 'a']['weight'] - 10 - - >>> G = nx.MultiGraph() # or MultiDiGraph - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.get_edge_data(0, 1) - {0: {}} - >>> e = (0, 1) - >>> G.get_edge_data(*e) # tuple form - {0: {}} - >>> G.get_edge_data('a', 'b', default=0) # edge not in graph, return 0 - 0 - """ - try: - if key is None: - return self._adj[u][v] - else: - return self._adj[u][v][key] - except KeyError: - return default - - @property - def degree(self): - """A DegreeView for the Graph as G.degree or G.degree(). - - The node degree is the number of edges adjacent to the node. - The weighted node degree is the sum of the edge weights for - edges incident to that node. - - This object provides an iterator for (node, degree) as well as - lookup for the degree for a single node. - - Parameters - ---------- - nbunch : single node, container, or all nodes (default= all nodes) - The view will only report edges incident to these nodes. - - weight : string or None, optional (default=None) - The name of an edge attribute that holds the numerical value used - as a weight. If None, then each edge has weight 1. - The degree is the sum of the edge weights adjacent to the node. - - Returns - ------- - If a single node is requested - deg : int - Degree of the node, if a single node is passed as argument. - - OR if multiple nodes are requested - nd_iter : iterator - The iterator returns two-tuples of (node, degree). - - Examples - -------- - >>> G = nx.Graph() # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> nx.add_path(G, [0, 1, 2, 3]) - >>> G.degree(0) # node 0 with degree 1 - 1 - >>> list(G.degree([0, 1])) - [(0, 1), (1, 2)] - - """ - return MultiDegreeView(self) - - def is_multigraph(self): - """Returns True if graph is a multigraph, False otherwise.""" - return True - - def is_directed(self): - """Returns True if graph is directed, False otherwise.""" - return False - - def copy(self, as_view=False): - """Returns a copy of the graph. - - The copy method by default returns an independent shallow copy - of the graph and attributes. That is, if an attribute is a - container, that container is shared by the original an the copy. - Use Python's `copy.deepcopy` for new containers. - - If `as_view` is True then a view is returned instead of a copy. - - Notes - ----- - All copies reproduce the graph structure, but data attributes - may be handled in different ways. There are four types of copies - of a graph that people might want. - - Deepcopy -- A "deepcopy" copies the graph structure as well as - all data attributes and any objects they might contain. - The entire graph object is new so that changes in the copy - do not affect the original object. (see Python's copy.deepcopy) - - Data Reference (Shallow) -- For a shallow copy the graph structure - is copied but the edge, node and graph attribute dicts are - references to those in the original graph. This saves - time and memory but could cause confusion if you change an attribute - in one graph and it changes the attribute in the other. - NetworkX does not provide this level of shallow copy. - - Independent Shallow -- This copy creates new independent attribute - dicts and then does a shallow copy of the attributes. That is, any - attributes that are containers are shared between the new graph - and the original. This is exactly what `dict.copy()` provides. - You can obtain this style copy using: - - >>> G = nx.path_graph(5) - >>> H = G.copy() - >>> H = G.copy(as_view=False) - >>> H = nx.Graph(G) - >>> H = G.__class__(G) - - Fresh Data -- For fresh data, the graph structure is copied while - new empty data attribute dicts are created. The resulting graph - is independent of the original and it has no edge, node or graph - attributes. Fresh copies are not enabled. Instead use: - - >>> H = G.__class__() - >>> H.add_nodes_from(G) - >>> H.add_edges_from(G.edges) - - View -- Inspired by dict-views, graph-views act like read-only - versions of the original graph, providing a copy of the original - structure without requiring any memory for copying the information. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/2/library/copy.html. - - Parameters - ---------- - as_view : bool, optional (default=False) - If True, the returned graph-view provides a read-only view - of the original graph without actually copying any data. - - Returns - ------- - G : Graph - A copy of the graph. - - See Also - -------- - to_directed: return a directed copy of the graph. - - Examples - -------- - >>> G = nx.path_graph(4) # or DiGraph, MultiGraph, MultiDiGraph, etc - >>> H = G.copy() - - """ - if as_view is True: - return nx.graphviews.generic_graph_view(self) - G = self.__class__() - G.graph.update(self.graph) - G.add_nodes_from((n, d.copy()) for n, d in self._node.items()) - G.add_edges_from((u, v, key, datadict.copy()) - for u, nbrs in self._adj.items() - for v, keydict in nbrs.items() - for key, datadict in keydict.items()) - return G - - def to_directed(self, as_view=False): - """Returns a directed representation of the graph. - - Returns - ------- - G : MultiDiGraph - A directed graph with the same name, same nodes, and with - each edge (u, v, data) replaced by two directed edges - (u, v, data) and (v, u, data). - - Notes - ----- - This returns a "deepcopy" of the edge, node, and - graph attributes which attempts to completely copy - all of the data and references. - - This is in contrast to the similar D=DiGraph(G) which returns a - shallow copy of the data. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/2/library/copy.html. - - Warning: If you have subclassed MultiGraph to use dict-like objects - in the data structure, those changes do not transfer to the - MultiDiGraph created by this method. - - Examples - -------- - >>> G = nx.Graph() # or MultiGraph, etc - >>> G.add_edge(0, 1) - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1), (1, 0)] - - If already directed, return a (deep) copy - - >>> G = nx.DiGraph() # or MultiDiGraph, etc - >>> G.add_edge(0, 1) - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1)] - """ - graph_class = self.to_directed_class() - if as_view is True: - return nx.graphviews.generic_graph_view(self, graph_class) - # deepcopy when not a view - G = graph_class() - G.graph.update(deepcopy(self.graph)) - G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) - G.add_edges_from((u, v, key, deepcopy(datadict)) - for u, nbrs in self.adj.items() - for v, keydict in nbrs.items() - for key, datadict in keydict.items()) - return G - - def to_undirected(self, as_view=False): - """Returns an undirected copy of the graph. - - Returns - ------- - G : Graph/MultiGraph - A deepcopy of the graph. - - See Also - -------- - copy, add_edge, add_edges_from - - Notes - ----- - This returns a "deepcopy" of the edge, node, and - graph attributes which attempts to completely copy - all of the data and references. - - This is in contrast to the similar `G = nx.MultiGraph(D)` - which returns a shallow copy of the data. - - See the Python copy module for more information on shallow - and deep copies, https://docs.python.org/2/library/copy.html. - - Warning: If you have subclassed MultiiGraph to use dict-like - objects in the data structure, those changes do not transfer - to the MultiGraph created by this method. - - Examples - -------- - >>> G = nx.path_graph(2) # or MultiGraph, etc - >>> H = G.to_directed() - >>> list(H.edges) - [(0, 1), (1, 0)] - >>> G2 = H.to_undirected() - >>> list(G2.edges) - [(0, 1)] - """ - graph_class = self.to_undirected_class() - if as_view is True: - return nx.graphviews.generic_graph_view(self, graph_class) - # deepcopy when not a view - G = graph_class() - G.graph.update(deepcopy(self.graph)) - G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) - G.add_edges_from((u, v, key, deepcopy(datadict)) - for u, nbrs in self._adj.items() - for v, keydict in nbrs.items() - for key, datadict in keydict.items()) - return G - - def number_of_edges(self, u=None, v=None): - """Returns the number of edges between two nodes. - - Parameters - ---------- - u, v : nodes, optional (Gefault=all edges) - If u and v are specified, return the number of edges between - u and v. Otherwise return the total number of all edges. - - Returns - ------- - nedges : int - The number of edges in the graph. If nodes `u` and `v` are - specified return the number of edges between those nodes. If - the graph is directed, this only returns the number of edges - from `u` to `v`. - - See Also - -------- - size - - Examples - -------- - For undirected multigraphs, this method counts the total number - of edges in the graph:: - - >>> G = nx.MultiGraph() - >>> G.add_edges_from([(0, 1), (0, 1), (1, 2)]) - [0, 1, 0] - >>> G.number_of_edges() - 3 - - If you specify two nodes, this counts the total number of edges - joining the two nodes:: - - >>> G.number_of_edges(0, 1) - 2 - - For directed multigraphs, this method can count the total number - of directed edges from `u` to `v`:: - - >>> G = nx.MultiDiGraph() - >>> G.add_edges_from([(0, 1), (0, 1), (1, 0)]) - [0, 1, 0] - >>> G.number_of_edges(0, 1) - 2 - >>> G.number_of_edges(1, 0) - 1 - - """ - if u is None: - return self.size() - try: - edgedata = self._adj[u][v] - except KeyError: - return 0 # no such edge - return len(edgedata) diff --git a/extensions/fablabchemnitz/networkx/classes/ordered.py b/extensions/fablabchemnitz/networkx/classes/ordered.py deleted file mode 100644 index ba8e6d78..00000000 --- a/extensions/fablabchemnitz/networkx/classes/ordered.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -Consistently ordered variants of the default base classes. -Note that if you are using Python 3.6+, you shouldn't need these classes -because the dicts in Python 3.6+ are ordered. -Note also that there are many differing expectations for the word "ordered" -and that these classes may not provide the order you expect. -The intent here is to give a consistent order not a particular order. - -The Ordered (Di/Multi/MultiDi) Graphs give a consistent order for reporting of -nodes and edges. The order of node reporting agrees with node adding, but for -edges, the order is not necessarily the order that the edges were added. - -In general, you should use the default (i.e., unordered) graph classes. -However, there are times (e.g., when testing) when you may need the -order preserved. - -Special care is required when using subgraphs of the Ordered classes. -The order of nodes in the subclass is not necessarily the same order -as the original class. In general it is probably better to avoid using -subgraphs and replace with code similar to: - -.. code-block:: python - - # instead of SG = G.subgraph(ordered_nodes) - SG=nx.OrderedGraph() - SG.add_nodes_from(ordered_nodes) - SG.add_edges_from((u, v) for (u, v) in G.edges() if u in SG if v in SG) - -""" -from collections import OrderedDict - -from .graph import Graph -from .multigraph import MultiGraph -from .digraph import DiGraph -from .multidigraph import MultiDiGraph - -__all__ = [] - -__all__.extend([ - 'OrderedGraph', - 'OrderedDiGraph', - 'OrderedMultiGraph', - 'OrderedMultiDiGraph', -]) - - -class OrderedGraph(Graph): - """Consistently ordered variant of :class:`~networkx.Graph`.""" - node_dict_factory = OrderedDict - adjlist_outer_dict_factory = OrderedDict - adjlist_inner_dict_factory = OrderedDict - edge_attr_dict_factory = OrderedDict - - -class OrderedDiGraph(DiGraph): - """Consistently ordered variant of :class:`~networkx.DiGraph`.""" - node_dict_factory = OrderedDict - adjlist_outer_dict_factory = OrderedDict - adjlist_inner_dict_factory = OrderedDict - edge_attr_dict_factory = OrderedDict - - -class OrderedMultiGraph(MultiGraph): - """Consistently ordered variant of :class:`~networkx.MultiGraph`.""" - node_dict_factory = OrderedDict - adjlist_outer_dict_factory = OrderedDict - adjlist_inner_dict_factory = OrderedDict - edge_key_dict_factory = OrderedDict - edge_attr_dict_factory = OrderedDict - - -class OrderedMultiDiGraph(MultiDiGraph): - """Consistently ordered variant of :class:`~networkx.MultiDiGraph`.""" - node_dict_factory = OrderedDict - adjlist_outer_dict_factory = OrderedDict - adjlist_inner_dict_factory = OrderedDict - edge_key_dict_factory = OrderedDict - edge_attr_dict_factory = OrderedDict diff --git a/extensions/fablabchemnitz/networkx/classes/reportviews.py b/extensions/fablabchemnitz/networkx/classes/reportviews.py deleted file mode 100644 index c80e20c3..00000000 --- a/extensions/fablabchemnitz/networkx/classes/reportviews.py +++ /dev/null @@ -1,1178 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg (hagberg@lanl.gov), -# Pieter Swart (swart@lanl.gov), -# Dan Schult(dschult@colgate.edu) -""" -View Classes provide node, edge and degree "views" of a graph. - -Views for nodes, edges and degree are provided for all base graph classes. -A view means a read-only object that is quick to create, automatically -updated when the graph changes, and provides basic access like `n in V`, -`for n in V`, `V[n]` and sometimes set operations. - -The views are read-only iterable containers that are updated as the -graph is updated. As with dicts, the graph should not be updated -while iterating through the view. Views can be iterated multiple times. - -Edge and Node views also allow data attribute lookup. -The resulting attribute dict is writable as `G.edges[3, 4]['color']='red'` -Degree views allow lookup of degree values for single nodes. -Weighted degree is supported with the `weight` argument. - -NodeView -======== - - `V = G.nodes` (or `V = G.nodes()`) allows `len(V)`, `n in V`, set - operations e.g. "G.nodes & H.nodes", and `dd = G.nodes[n]`, where - `dd` is the node data dict. Iteration is over the nodes by default. - -NodeDataView -============ - - To iterate over (node, data) pairs, use arguments to `G.nodes()` - to create a DataView e.g. `DV = G.nodes(data='color', default='red')`. - The DataView iterates as `for n, color in DV` and allows - `(n, 'red') in DV`. Using `DV = G.nodes(data=True)`, the DataViews - use the full datadict in writeable form also allowing contain testing as - `(n, {'color': 'red'}) in VD`. DataViews allow set operations when - data attributes are hashable. - -DegreeView -========== - - `V = G.degree` allows iteration over (node, degree) pairs as well - as lookup: `deg=V[n]`. There are many flavors of DegreeView - for In/Out/Directed/Multi. For Directed Graphs, `G.degree` - counts both in and out going edges. `G.out_degree` and - `G.in_degree` count only specific directions. - Weighted degree using edge data attributes is provide via - `V = G.degree(weight='attr_name')` where any string with the - attribute name can be used. `weight=None` is the default. - No set operations are implemented for degrees, use NodeView. - - The argument `nbunch` restricts iteration to nodes in nbunch. - The DegreeView can still lookup any node even if nbunch is specified. - -EdgeView -======== - - `V = G.edges` or `V = G.edges()` allows iteration over edges as well as - `e in V`, set operations and edge data lookup `dd = G.edges[2, 3]`. - Iteration is over 2-tuples `(u, v)` for Graph/DiGraph. For multigraphs - edges 3-tuples `(u, v, key)` are the default but 2-tuples can be obtained - via `V = G.edges(keys=False)`. - - Set operations for directed graphs treat the edges as a set of 2-tuples. - For undirected graphs, 2-tuples are not a unique representation of edges. - So long as the set being compared to contains unique representations - of its edges, the set operations will act as expected. If the other - set contains both `(0, 1)` and `(1, 0)` however, the result of set - operations may contain both representations of the same edge. - -EdgeDataView -============ - - Edge data can be reported using an EdgeDataView typically created - by calling an EdgeView: `DV = G.edges(data='weight', default=1)`. - The EdgeDataView allows iteration over edge tuples, membership checking - but no set operations. - - Iteration depends on `data` and `default` and for multigraph `keys` - If `data is False` (the default) then iterate over 2-tuples `(u, v)`. - If `data is True` iterate over 3-tuples `(u, v, datadict)`. - Otherwise iterate over `(u, v, datadict.get(data, default))`. - For Multigraphs, if `keys is True`, replace `u, v` with `u, v, key` - to create 3-tuples and 4-tuples. - - The argument `nbunch` restricts edges to those incident to nodes in nbunch. -""" -from collections.abc import Mapping, Set, Iterable -import networkx as nx - -__all__ = ['NodeView', 'NodeDataView', - 'EdgeView', 'OutEdgeView', 'InEdgeView', - 'EdgeDataView', 'OutEdgeDataView', 'InEdgeDataView', - 'MultiEdgeView', 'OutMultiEdgeView', 'InMultiEdgeView', - 'MultiEdgeDataView', 'OutMultiEdgeDataView', 'InMultiEdgeDataView', - 'DegreeView', 'DiDegreeView', 'InDegreeView', 'OutDegreeView', - 'MultiDegreeView', 'DiMultiDegreeView', - 'InMultiDegreeView', 'OutMultiDegreeView'] - - -# NodeViews -class NodeView(Mapping, Set): - """A NodeView class to act as G.nodes for a NetworkX Graph - - Set operations act on the nodes without considering data. - Iteration is over nodes. Node data can be looked up like a dict. - Use NodeDataView to iterate over node data or to specify a data - attribute for lookup. NodeDataView is created by calling the NodeView. - - Parameters - ---------- - graph : NetworkX graph-like class - - Examples - -------- - >>> G = nx.path_graph(3) - >>> NV = G.nodes() - >>> 2 in NV - True - >>> for n in NV: print(n) - 0 - 1 - 2 - >>> assert(NV & {1, 2, 3} == {1, 2}) - - >>> G.add_node(2, color='blue') - >>> NV[2] - {'color': 'blue'} - >>> G.add_node(8, color='red') - >>> NDV = G.nodes(data=True) - >>> (2, NV[2]) in NDV - True - >>> for n, dd in NDV: print((n, dd.get('color', 'aqua'))) - (0, 'aqua') - (1, 'aqua') - (2, 'blue') - (8, 'red') - >>> NDV[2] == NV[2] - True - - >>> NVdata = G.nodes(data='color', default='aqua') - >>> (2, NVdata[2]) in NVdata - True - >>> for n, dd in NVdata: print((n, dd)) - (0, 'aqua') - (1, 'aqua') - (2, 'blue') - (8, 'red') - >>> NVdata[2] == NV[2] # NVdata gets 'color', NV gets datadict - False - """ - __slots__ = '_nodes', - - def __getstate__(self): - return {'_nodes': self._nodes} - - def __setstate__(self, state): - self._nodes = state['_nodes'] - - def __init__(self, graph): - self._nodes = graph._node - - # Mapping methods - def __len__(self): - return len(self._nodes) - - def __iter__(self): - return iter(self._nodes) - - def __getitem__(self, n): - return self._nodes[n] - - # Set methods - def __contains__(self, n): - return n in self._nodes - - @classmethod - def _from_iterable(cls, it): - return set(it) - - # DataView method - def __call__(self, data=False, default=None): - if data is False: - return self - return NodeDataView(self._nodes, data, default) - - def data(self, data=True, default=None): - if data is False: - return self - return NodeDataView(self._nodes, data, default) - - def __str__(self): - return str(list(self)) - - def __repr__(self): - return '%s(%r)' % (self.__class__.__name__, tuple(self)) - - -class NodeDataView(Set): - """A DataView class for nodes of a NetworkX Graph - - The main use for this class is to iterate through node-data pairs. - The data can be the entire data-dictionary for each node, or it - can be a specific attribute (with default) for each node. - Set operations are enabled with NodeDataView, but don't work in - cases where the data is not hashable. Use with caution. - Typically, set operations on nodes use NodeView, not NodeDataView. - That is, they use `G.nodes` instead of `G.nodes(data='foo')`. - - Parameters - ========== - graph : NetworkX graph-like class - data : bool or string (default=False) - default : object (default=None) - """ - __slots__ = ('_nodes', '_data', '_default') - - def __getstate__(self): - return {'_nodes': self._nodes, - '_data': self._data, - '_default': self._default} - - def __setstate__(self, state): - self._nodes = state['_nodes'] - self._data = state['_data'] - self._default = state['_default'] - - def __init__(self, nodedict, data=False, default=None): - self._nodes = nodedict - self._data = data - self._default = default - - @classmethod - def _from_iterable(cls, it): - try: - return set(it) - except TypeError as err: - if "unhashable" in str(err): - msg = " : Could be b/c data=True or your values are unhashable" - raise TypeError(str(err) + msg) - raise - - def __len__(self): - return len(self._nodes) - - def __iter__(self): - data = self._data - if data is False: - return iter(self._nodes) - if data is True: - return iter(self._nodes.items()) - return ((n, dd[data] if data in dd else self._default) - for n, dd in self._nodes.items()) - - def __contains__(self, n): - try: - node_in = n in self._nodes - except TypeError: - n, d = n - return n in self._nodes and self[n] == d - if node_in is True: - return node_in - try: - n, d = n - except (TypeError, ValueError): - return False - return n in self._nodes and self[n] == d - - def __getitem__(self, n): - ddict = self._nodes[n] - data = self._data - if data is False or data is True: - return ddict - return ddict[data] if data in ddict else self._default - - def __str__(self): - return str(list(self)) - - def __repr__(self): - if self._data is False: - return '%s(%r)' % (self.__class__.__name__, tuple(self)) - if self._data is True: - return '%s(%r)' % (self.__class__.__name__, dict(self)) - return '%s(%r, data=%r)' % \ - (self.__class__.__name__, dict(self), self._data) - - -# DegreeViews -class DiDegreeView(object): - """A View class for degree of nodes in a NetworkX Graph - - The functionality is like dict.items() with (node, degree) pairs. - Additional functionality includes read-only lookup of node degree, - and calling with optional features nbunch (for only a subset of nodes) - and weight (use edge weights to compute degree). - - Parameters - ========== - graph : NetworkX graph-like class - nbunch : node, container of nodes, or None meaning all nodes (default=None) - weight : bool or string (default=None) - - Notes - ----- - DegreeView can still lookup any node even if nbunch is specified. - - Examples - -------- - >>> G = nx.path_graph(3) - >>> DV = G.degree() - >>> assert(DV[2] == 1) - >>> assert(sum(deg for n, deg in DV) == 4) - - >>> DVweight = G.degree(weight="span") - >>> G.add_edge(1, 2, span=34) - >>> DVweight[2] - 34 - >>> DVweight[0] # default edge weight is 1 - 1 - >>> sum(span for n, span in DVweight) # sum weighted degrees - 70 - - >>> DVnbunch = G.degree(nbunch=(1, 2)) - >>> assert(len(list(DVnbunch)) == 2) # iteration over nbunch only - """ - - def __init__(self, G, nbunch=None, weight=None): - self._graph = G - self._succ = G._succ if hasattr(G, "_succ") else G._adj - self._pred = G._pred if hasattr(G, "_pred") else G._adj - self._nodes = self._succ if nbunch is None \ - else list(G.nbunch_iter(nbunch)) - self._weight = weight - - def __call__(self, nbunch=None, weight=None): - if nbunch is None: - if weight == self._weight: - return self - return self.__class__(self._graph, None, weight) - try: - if nbunch in self._nodes: - if weight == self._weight: - return self[nbunch] - return self.__class__(self._graph, None, weight)[nbunch] - except TypeError: - pass - return self.__class__(self._graph, nbunch, weight) - - def __getitem__(self, n): - weight = self._weight - succs = self._succ[n] - preds = self._pred[n] - if weight is None: - return len(succs) + len(preds) - return sum(dd.get(weight, 1) for dd in succs.values()) + \ - sum(dd.get(weight, 1) for dd in preds.values()) - - def __iter__(self): - weight = self._weight - if weight is None: - for n in self._nodes: - succs = self._succ[n] - preds = self._pred[n] - yield (n, len(succs) + len(preds)) - else: - for n in self._nodes: - succs = self._succ[n] - preds = self._pred[n] - deg = sum(dd.get(weight, 1) for dd in succs.values()) \ - + sum(dd.get(weight, 1) for dd in preds.values()) - yield (n, deg) - - def __len__(self): - return len(self._nodes) - - def __str__(self): - return str(list(self)) - - def __repr__(self): - return '%s(%r)' % (self.__class__.__name__, dict(self)) - - -class DegreeView(DiDegreeView): - """A DegreeView class to act as G.degree for a NetworkX Graph - - Typical usage focuses on iteration over `(node, degree)` pairs. - The degree is by default the number of edges incident to the node. - Optional argument `weight` enables weighted degree using the edge - attribute named in the `weight` argument. Reporting and iteration - can also be restricted to a subset of nodes using `nbunch`. - - Additional functionality include node lookup so that `G.degree[n]` - reported the (possibly weighted) degree of node `n`. Calling the - view creates a view with different arguments `nbunch` or `weight`. - - Parameters - ========== - graph : NetworkX graph-like class - nbunch : node, container of nodes, or None meaning all nodes (default=None) - weight : string or None (default=None) - - Notes - ----- - DegreeView can still lookup any node even if nbunch is specified. - - Examples - -------- - >>> G = nx.path_graph(3) - >>> DV = G.degree() - >>> assert(DV[2] == 1) - >>> assert(G.degree[2] == 1) - >>> assert(sum(deg for n, deg in DV) == 4) - - >>> DVweight = G.degree(weight="span") - >>> G.add_edge(1, 2, span=34) - >>> DVweight[2] - 34 - >>> DVweight[0] # default edge weight is 1 - 1 - >>> sum(span for n, span in DVweight) # sum weighted degrees - 70 - - >>> DVnbunch = G.degree(nbunch=(1, 2)) - >>> assert(len(list(DVnbunch)) == 2) # iteration over nbunch only - """ - - def __getitem__(self, n): - weight = self._weight - nbrs = self._succ[n] - if weight is None: - return len(nbrs) + (n in nbrs) - return sum(dd.get(weight, 1) for dd in nbrs.values()) + \ - (n in nbrs and nbrs[n].get(weight, 1)) - - def __iter__(self): - weight = self._weight - if weight is None: - for n in self._nodes: - nbrs = self._succ[n] - yield (n, len(nbrs) + (n in nbrs)) - else: - for n in self._nodes: - nbrs = self._succ[n] - deg = sum(dd.get(weight, 1) for dd in nbrs.values()) + \ - (n in nbrs and nbrs[n].get(weight, 1)) - yield (n, deg) - - -class OutDegreeView(DiDegreeView): - """A DegreeView class to report out_degree for a DiGraph; See DegreeView""" - - def __getitem__(self, n): - weight = self._weight - nbrs = self._succ[n] - if self._weight is None: - return len(nbrs) - return sum(dd.get(self._weight, 1) for dd in nbrs.values()) - - def __iter__(self): - weight = self._weight - if weight is None: - for n in self._nodes: - succs = self._succ[n] - yield (n, len(succs)) - else: - for n in self._nodes: - succs = self._succ[n] - deg = sum(dd.get(weight, 1) for dd in succs.values()) - yield (n, deg) - - -class InDegreeView(DiDegreeView): - """A DegreeView class to report in_degree for a DiGraph; See DegreeView""" - - def __getitem__(self, n): - weight = self._weight - nbrs = self._pred[n] - if weight is None: - return len(nbrs) - return sum(dd.get(weight, 1) for dd in nbrs.values()) - - def __iter__(self): - weight = self._weight - if weight is None: - for n in self._nodes: - preds = self._pred[n] - yield (n, len(preds)) - else: - for n in self._nodes: - preds = self._pred[n] - deg = sum(dd.get(weight, 1) for dd in preds.values()) - yield (n, deg) - - -class MultiDegreeView(DiDegreeView): - """A DegreeView class for undirected multigraphs; See DegreeView""" - - def __getitem__(self, n): - weight = self._weight - nbrs = self._succ[n] - if weight is None: - return sum(len(keys) for keys in nbrs.values()) + \ - (n in nbrs and len(nbrs[n])) - # edge weighted graph - degree is sum of nbr edge weights - deg = sum(d.get(weight, 1) for key_dict in nbrs.values() - for d in key_dict.values()) - if n in nbrs: - deg += sum(d.get(weight, 1) for d in nbrs[n].values()) - return deg - - def __iter__(self): - weight = self._weight - if weight is None: - for n in self._nodes: - nbrs = self._succ[n] - deg = sum(len(keys) for keys in nbrs.values()) + \ - (n in nbrs and len(nbrs[n])) - yield (n, deg) - else: - for n in self._nodes: - nbrs = self._succ[n] - deg = sum(d.get(weight, 1) for key_dict in nbrs.values() - for d in key_dict.values()) - if n in nbrs: - deg += sum(d.get(weight, 1) for d in nbrs[n].values()) - yield (n, deg) - - -class DiMultiDegreeView(DiDegreeView): - """A DegreeView class for MultiDiGraph; See DegreeView""" - - def __getitem__(self, n): - weight = self._weight - succs = self._succ[n] - preds = self._pred[n] - if weight is None: - return sum(len(keys) for keys in succs.values()) + \ - sum(len(keys) for keys in preds.values()) - # edge weighted graph - degree is sum of nbr edge weights - deg = sum(d.get(weight, 1) for key_dict in succs.values() - for d in key_dict.values()) + \ - sum(d.get(weight, 1) for key_dict in preds.values() - for d in key_dict.values()) - return deg - - def __iter__(self): - weight = self._weight - if weight is None: - for n in self._nodes: - succs = self._succ[n] - preds = self._pred[n] - deg = sum(len(keys) for keys in succs.values()) + \ - sum(len(keys) for keys in preds.values()) - yield (n, deg) - else: - for n in self._nodes: - succs = self._succ[n] - preds = self._pred[n] - deg = sum(d.get(weight, 1) for key_dict in succs.values() - for d in key_dict.values()) + \ - sum(d.get(weight, 1) for key_dict in preds.values() - for d in key_dict.values()) - yield (n, deg) - - -class InMultiDegreeView(DiDegreeView): - """A DegreeView class for inward degree of MultiDiGraph; See DegreeView""" - - def __getitem__(self, n): - weight = self._weight - nbrs = self._pred[n] - if weight is None: - return sum(len(data) for data in nbrs.values()) - # edge weighted graph - degree is sum of nbr edge weights - return sum(d.get(weight, 1) for key_dict in nbrs.values() - for d in key_dict.values()) - - def __iter__(self): - weight = self._weight - if weight is None: - for n in self._nodes: - nbrs = self._pred[n] - deg = sum(len(data) for data in nbrs.values()) - yield (n, deg) - else: - for n in self._nodes: - nbrs = self._pred[n] - deg = sum(d.get(weight, 1) for key_dict in nbrs.values() - for d in key_dict.values()) - yield (n, deg) - - -class OutMultiDegreeView(DiDegreeView): - """A DegreeView class for outward degree of MultiDiGraph; See DegreeView""" - - def __getitem__(self, n): - weight = self._weight - nbrs = self._succ[n] - if weight is None: - return sum(len(data) for data in nbrs.values()) - # edge weighted graph - degree is sum of nbr edge weights - return sum(d.get(weight, 1) for key_dict in nbrs.values() - for d in key_dict.values()) - - def __iter__(self): - weight = self._weight - if weight is None: - for n in self._nodes: - nbrs = self._succ[n] - deg = sum(len(data) for data in nbrs.values()) - yield (n, deg) - else: - for n in self._nodes: - nbrs = self._succ[n] - deg = sum(d.get(weight, 1) for key_dict in nbrs.values() - for d in key_dict.values()) - yield (n, deg) - - -# EdgeDataViews -class OutEdgeDataView(object): - """EdgeDataView for outward edges of DiGraph; See EdgeDataView""" - __slots__ = ('_viewer', '_nbunch', '_data', '_default', - '_adjdict', '_nodes_nbrs', '_report') - - def __getstate__(self): - return {'viewer': self._viewer, - 'nbunch': self._nbunch, - 'data': self._data, - 'default': self._default} - - def __setstate__(self, state): - self.__init__(**state) - - def __init__(self, viewer, nbunch=None, data=False, default=None): - self._viewer = viewer - adjdict = self._adjdict = viewer._adjdict - if nbunch is None: - self._nodes_nbrs = adjdict.items - else: - nbunch = list(viewer._graph.nbunch_iter(nbunch)) - self._nodes_nbrs = lambda: [(n, adjdict[n]) for n in nbunch] - self._nbunch = nbunch - self._data = data - self._default = default - # Set _report based on data and default - if data is True: - self._report = lambda n, nbr, dd: (n, nbr, dd) - elif data is False: - self._report = lambda n, nbr, dd: (n, nbr) - else: # data is attribute name - self._report = lambda n, nbr, dd: \ - (n, nbr, dd[data]) if data in dd else (n, nbr, default) - - def __len__(self): - return sum(len(nbrs) for n, nbrs in self._nodes_nbrs()) - - def __iter__(self): - return (self._report(n, nbr, dd) for n, nbrs in self._nodes_nbrs() - for nbr, dd in nbrs.items()) - - def __contains__(self, e): - try: - u, v = e[:2] - ddict = self._adjdict[u][v] - except KeyError: - return False - return e == self._report(u, v, ddict) - - def __str__(self): - return str(list(self)) - - def __repr__(self): - return '%s(%r)' % (self.__class__.__name__, list(self)) - - -class EdgeDataView(OutEdgeDataView): - """A EdgeDataView class for edges of Graph - - This view is primarily used to iterate over the edges reporting - edges as node-tuples with edge data optionally reported. The - argument `nbunch` allows restriction to edges incident to nodes - in that container/singleton. The default (nbunch=None) - reports all edges. The arguments `data` and `default` control - what edge data is reported. The default `data is False` reports - only node-tuples for each edge. If `data is True` the entire edge - data dict is returned. Otherwise `data` is assumed to hold the name - of the edge attribute to report with default `default` if that - edge attribute is not present. - - Parameters - ---------- - nbunch : container of nodes, node or None (default None) - data : False, True or string (default False) - default : default value (default None) - - Examples - -------- - >>> G = nx.path_graph(3) - >>> G.add_edge(1, 2, foo='bar') - >>> list(G.edges(data='foo', default='biz')) - [(0, 1, 'biz'), (1, 2, 'bar')] - >>> assert((0, 1, 'biz') in G.edges(data='foo', default='biz')) - """ - __slots__ = () - - def __len__(self): - return sum(1 for e in self) - - def __iter__(self): - seen = {} - for n, nbrs in self._nodes_nbrs(): - for nbr, dd in nbrs.items(): - if nbr not in seen: - yield self._report(n, nbr, dd) - seen[n] = 1 - del seen - - def __contains__(self, e): - try: - u, v = e[:2] - ddict = self._adjdict[u][v] - except KeyError: - try: - ddict = self._adjdict[v][u] - except KeyError: - return False - return e == self._report(u, v, ddict) - - -class InEdgeDataView(OutEdgeDataView): - """An EdgeDataView class for outward edges of DiGraph; See EdgeDataView""" - __slots__ = () - - def __iter__(self): - return (self._report(nbr, n, dd) for n, nbrs in self._nodes_nbrs() - for nbr, dd in nbrs.items()) - - def __contains__(self, e): - try: - u, v = e[:2] - ddict = self._adjdict[v][u] - except KeyError: - return False - return e == self._report(u, v, ddict) - - -class OutMultiEdgeDataView(OutEdgeDataView): - """An EdgeDataView for outward edges of MultiDiGraph; See EdgeDataView""" - __slots__ = ('keys',) - - def __getstate__(self): - return {'viewer': self._viewer, - 'nbunch': self._nbunch, - 'keys': self.keys, - 'data': self._data, - 'default': self._default} - - def __setstate__(self, state): - self.__init__(**state) - - def __init__(self, viewer, nbunch=None, - data=False, keys=False, default=None): - self._viewer = viewer - adjdict = self._adjdict = viewer._adjdict - self.keys = keys - if nbunch is None: - self._nodes_nbrs = adjdict.items - else: - nbunch = list(viewer._graph.nbunch_iter(nbunch)) - self._nodes_nbrs = lambda: [(n, adjdict[n]) for n in nbunch] - self._nbunch = nbunch - self._data = data - self._default = default - # Set _report based on data and default - if data is True: - if keys is True: - self._report = lambda n, nbr, k, dd: (n, nbr, k, dd) - else: - self._report = lambda n, nbr, k, dd: (n, nbr, dd) - elif data is False: - if keys is True: - self._report = lambda n, nbr, k, dd: (n, nbr, k) - else: - self._report = lambda n, nbr, k, dd: (n, nbr) - else: # data is attribute name - if keys is True: - self._report = lambda n, nbr, k, dd: (n, nbr, k, dd[data]) \ - if data in dd else (n, nbr, k, default) - else: - self._report = lambda n, nbr, k, dd: (n, nbr, dd[data]) \ - if data in dd else (n, nbr, default) - - def __len__(self): - return sum(1 for e in self) - - def __iter__(self): - return (self._report(n, nbr, k, dd) for n, nbrs in self._nodes_nbrs() - for nbr, kd in nbrs.items() for k, dd in kd.items()) - - def __contains__(self, e): - u, v = e[:2] - try: - kdict = self._adjdict[u][v] - except KeyError: - return False - if self.keys is True: - k = e[2] - try: - dd = kdict[k] - except KeyError: - return False - return e == self._report(u, v, k, dd) - for k, dd in kdict.items(): - if e == self._report(u, v, k, dd): - return True - return False - - -class MultiEdgeDataView(OutMultiEdgeDataView): - """An EdgeDataView class for edges of MultiGraph; See EdgeDataView""" - __slots__ = () - - def __iter__(self): - seen = {} - for n, nbrs in self._nodes_nbrs(): - for nbr, kd in nbrs.items(): - if nbr not in seen: - for k, dd in kd.items(): - yield self._report(n, nbr, k, dd) - seen[n] = 1 - del seen - - def __contains__(self, e): - u, v = e[:2] - try: - kdict = self._adjdict[u][v] - except KeyError: - try: - kdict = self._adjdict[v][u] - except KeyError: - return False - if self.keys is True: - k = e[2] - try: - dd = kdict[k] - except KeyError: - return False - return e == self._report(u, v, k, dd) - for k, dd in kdict.items(): - if e == self._report(u, v, k, dd): - return True - return False - - -class InMultiEdgeDataView(OutMultiEdgeDataView): - """An EdgeDataView for inward edges of MultiDiGraph; See EdgeDataView""" - __slots__ = () - - def __iter__(self): - return (self._report(nbr, n, k, dd) for n, nbrs in self._nodes_nbrs() - for nbr, kd in nbrs.items() for k, dd in kd.items()) - - def __contains__(self, e): - u, v = e[:2] - try: - kdict = self._adjdict[v][u] - except KeyError: - return False - if self.keys is True: - k = e[2] - dd = kdict[k] - return e == self._report(u, v, k, dd) - for k, dd in kdict.items(): - if e == self._report(u, v, k, dd): - return True - return False - - -# EdgeViews have set operations and no data reported -class OutEdgeView(Set, Mapping): - """A EdgeView class for outward edges of a DiGraph""" - __slots__ = ('_adjdict', '_graph', '_nodes_nbrs') - - def __getstate__(self): - return {'_graph': self._graph} - - def __setstate__(self, state): - self._graph = G = state['_graph'] - self._adjdict = G._succ if hasattr(G, "succ") else G._adj - self._nodes_nbrs = self._adjdict.items - - @classmethod - def _from_iterable(cls, it): - return set(it) - - dataview = OutEdgeDataView - - def __init__(self, G): - self._graph = G - self._adjdict = G._succ if hasattr(G, "succ") else G._adj - self._nodes_nbrs = self._adjdict.items - - # Set methods - def __len__(self): - return sum(len(nbrs) for n, nbrs in self._nodes_nbrs()) - - def __iter__(self): - for n, nbrs in self._nodes_nbrs(): - for nbr in nbrs: - yield (n, nbr) - - def __contains__(self, e): - try: - u, v = e - return v in self._adjdict[u] - except KeyError: - return False - - # Mapping Methods - def __getitem__(self, e): - u, v = e - return self._adjdict[u][v] - - # EdgeDataView methods - def __call__(self, nbunch=None, data=False, default=None): - if nbunch is None and data is False: - return self - return self.dataview(self, nbunch, data, default) - - def data(self, data=True, default=None, nbunch=None): - if nbunch is None and data is False: - return self - return self.dataview(self, nbunch, data, default) - - # String Methods - def __str__(self): - return str(list(self)) - - def __repr__(self): - return "{0.__class__.__name__}({1!r})".format(self, list(self)) - - -class EdgeView(OutEdgeView): - """A EdgeView class for edges of a Graph - - This densely packed View allows iteration over edges, data lookup - like a dict and set operations on edges represented by node-tuples. - In addition, edge data can be controlled by calling this object - possibly creating an EdgeDataView. Typically edges are iterated over - and reported as `(u, v)` node tuples or `(u, v, key)` node/key tuples - for multigraphs. Those edge representations can also be using to - lookup the data dict for any edge. Set operations also are available - where those tuples are the elements of the set. - Calling this object with optional arguments `data`, `default` and `keys` - controls the form of the tuple (see EdgeDataView). Optional argument - `nbunch` allows restriction to edges only involving certain nodes. - - If `data is False` (the default) then iterate over 2-tuples `(u, v)`. - If `data is True` iterate over 3-tuples `(u, v, datadict)`. - Otherwise iterate over `(u, v, datadict.get(data, default))`. - For Multigraphs, if `keys is True`, replace `u, v` with `u, v, key` above. - - Parameters - ========== - graph : NetworkX graph-like class - nbunch : (default= all nodes in graph) only report edges with these nodes - keys : (only for MultiGraph. default=False) report edge key in tuple - data : bool or string (default=False) see above - default : object (default=None) - - Examples - ======== - >>> G = nx.path_graph(4) - >>> EV = G.edges() - >>> (2, 3) in EV - True - >>> for u, v in EV: print((u, v)) - (0, 1) - (1, 2) - (2, 3) - >>> assert(EV & {(1, 2), (3, 4)} == {(1, 2)}) - - >>> EVdata = G.edges(data='color', default='aqua') - >>> G.add_edge(2, 3, color='blue') - >>> assert((2, 3, 'blue') in EVdata) - >>> for u, v, c in EVdata: print("({}, {}) has color: {}".format(u, v, c)) - (0, 1) has color: aqua - (1, 2) has color: aqua - (2, 3) has color: blue - - >>> EVnbunch = G.edges(nbunch=2) - >>> assert((2, 3) in EVnbunch) - >>> assert((0, 1) in EVnbunch) # nbunch is ignored in __contains__ - >>> for u, v in EVnbunch: assert(u == 2 or v == 2) - - >>> MG = nx.path_graph(4, create_using=nx.MultiGraph) - >>> EVmulti = MG.edges(keys=True) - >>> (2, 3, 0) in EVmulti - True - >>> (2, 3) in EVmulti # 2-tuples work even when keys is True - True - >>> key = MG.add_edge(2, 3) - >>> for u, v, k in EVmulti: print((u, v, k)) - (0, 1, 0) - (1, 2, 0) - (2, 3, 0) - (2, 3, 1) - """ - __slots__ = () - - dataview = EdgeDataView - - def __len__(self): - num_nbrs = (len(nbrs) + (n in nbrs) for n, nbrs in self._nodes_nbrs()) - return sum(num_nbrs) // 2 - - def __iter__(self): - seen = {} - for n, nbrs in self._nodes_nbrs(): - for nbr in list(nbrs): - if nbr not in seen: - yield (n, nbr) - seen[n] = 1 - del seen - - def __contains__(self, e): - try: - u, v = e[:2] - return v in self._adjdict[u] or u in self._adjdict[v] - except (KeyError, ValueError): - return False - - -class InEdgeView(OutEdgeView): - """A EdgeView class for inward edges of a DiGraph""" - __slots__ = () - - def __setstate__(self, state): - self._graph = G = state['_graph'] - self._adjdict = G._pred if hasattr(G, "pred") else G._adj - self._nodes_nbrs = self._adjdict.items - - dataview = InEdgeDataView - - def __init__(self, G): - self._graph = G - self._adjdict = G._pred if hasattr(G, "pred") else G._adj - self._nodes_nbrs = self._adjdict.items - - def __iter__(self): - for n, nbrs in self._nodes_nbrs(): - for nbr in nbrs: - yield (nbr, n) - - def __contains__(self, e): - try: - u, v = e - return u in self._adjdict[v] - except KeyError: - return False - - def __getitem__(self, e): - u, v = e - return self._adjdict[v][u] - - -class OutMultiEdgeView(OutEdgeView): - """A EdgeView class for outward edges of a MultiDiGraph""" - __slots__ = () - - dataview = OutMultiEdgeDataView - - def __len__(self): - return sum(len(kdict) for n, nbrs in self._nodes_nbrs() - for nbr, kdict in nbrs.items()) - - def __iter__(self): - for n, nbrs in self._nodes_nbrs(): - for nbr, kdict in nbrs.items(): - for key in kdict: - yield (n, nbr, key) - - def __contains__(self, e): - N = len(e) - if N == 3: - u, v, k = e - elif N == 2: - u, v = e - k = 0 - else: - raise ValueError("MultiEdge must have length 2 or 3") - try: - return k in self._adjdict[u][v] - except KeyError: - return False - - def __getitem__(self, e): - u, v, k = e - return self._adjdict[u][v][k] - - def __call__(self, nbunch=None, data=False, keys=False, default=None): - if nbunch is None and data is False and keys is True: - return self - return self.dataview(self, nbunch, data, keys, default) - - def data(self, data=True, keys=False, default=None, nbunch=None): - if nbunch is None and data is False and keys is True: - return self - return self.dataview(self, nbunch, data, keys, default) - - -class MultiEdgeView(OutMultiEdgeView): - """A EdgeView class for edges of a MultiGraph""" - __slots__ = () - - dataview = MultiEdgeDataView - - def __len__(self): - return sum(1 for e in self) - - def __iter__(self): - seen = {} - for n, nbrs in self._nodes_nbrs(): - for nbr, kd in nbrs.items(): - if nbr not in seen: - for k, dd in kd.items(): - yield (n, nbr, k) - seen[n] = 1 - del seen - - -class InMultiEdgeView(OutMultiEdgeView): - """A EdgeView class for inward edges of a MultiDiGraph""" - __slots__ = () - - def __setstate__(self, state): - self._graph = G = state['_graph'] - self._adjdict = G._pred if hasattr(G, "pred") else G._adj - self._nodes_nbrs = self._adjdict.items - - dataview = InMultiEdgeDataView - - def __init__(self, G): - self._graph = G - self._adjdict = G._pred if hasattr(G, "pred") else G._adj - self._nodes_nbrs = self._adjdict.items - - def __iter__(self): - for n, nbrs in self._nodes_nbrs(): - for nbr, kdict in nbrs.items(): - for key in kdict: - yield (nbr, n, key) - - def __contains__(self, e): - N = len(e) - if N == 3: - u, v, k = e - elif N == 2: - u, v = e - k = 0 - else: - raise ValueError("MultiEdge must have length 2 or 3") - try: - return k in self._adjdict[v][u] - except KeyError: - return False - - def __getitem__(self, e): - u, v, k = e - return self._adjdict[v][u][k] diff --git a/extensions/fablabchemnitz/networkx/classes/tests/__init__.py b/extensions/fablabchemnitz/networkx/classes/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/classes/tests/historical_tests.py b/extensions/fablabchemnitz/networkx/classes/tests/historical_tests.py deleted file mode 100644 index 82373763..00000000 --- a/extensions/fablabchemnitz/networkx/classes/tests/historical_tests.py +++ /dev/null @@ -1,434 +0,0 @@ -#!/usr/bin/env python -"""Original NetworkX graph tests""" -import pytest -import networkx as nx -from networkx import convert_node_labels_to_integers as cnlti -from networkx.testing import * - - -class HistoricalTests(object): - - @classmethod - def setup_class(cls): - cls.null = nx.null_graph() - cls.P1 = cnlti(nx.path_graph(1), first_label=1) - cls.P3 = cnlti(nx.path_graph(3), first_label=1) - cls.P10 = cnlti(nx.path_graph(10), first_label=1) - cls.K1 = cnlti(nx.complete_graph(1), first_label=1) - cls.K3 = cnlti(nx.complete_graph(3), first_label=1) - cls.K4 = cnlti(nx.complete_graph(4), first_label=1) - cls.K5 = cnlti(nx.complete_graph(5), first_label=1) - cls.K10 = cnlti(nx.complete_graph(10), first_label=1) - cls.G = nx.Graph - - def test_name(self): - G = self.G(name="test") - assert str(G) == 'test' - assert G.name == 'test' - H = self.G() - assert H.name == '' - - # Nodes - - def test_add_remove_node(self): - G = self.G() - G.add_node('A') - assert G.has_node('A') - G.remove_node('A') - assert not G.has_node('A') - - def test_nonhashable_node(self): - # Test if a non-hashable object is in the Graph. A python dict will - # raise a TypeError, but for a Graph class a simple False should be - # returned (see Graph __contains__). If it cannot be a node then it is - # not a node. - G = self.G() - assert not G.has_node(['A']) - assert not G.has_node({'A': 1}) - - def test_add_nodes_from(self): - G = self.G() - G.add_nodes_from(list("ABCDEFGHIJKL")) - assert G.has_node("L") - G.remove_nodes_from(['H', 'I', 'J', 'K', 'L']) - G.add_nodes_from([1, 2, 3, 4]) - assert (sorted(G.nodes(), key=str) == - [1, 2, 3, 4, 'A', 'B', 'C', 'D', 'E', 'F', 'G']) - # test __iter__ - assert (sorted(G, key=str) == - [1, 2, 3, 4, 'A', 'B', 'C', 'D', 'E', 'F', 'G']) - - def test_contains(self): - G = self.G() - G.add_node('A') - assert 'A' in G - assert not [] in G # never raise a Key or TypeError in this test - assert not {1: 1} in G - - def test_add_remove(self): - # Test add_node and remove_node acting for various nbunch - G = self.G() - G.add_node('m') - assert G.has_node('m') - G.add_node('m') # no complaints - pytest.raises(nx.NetworkXError, G.remove_node, 'j') - G.remove_node('m') - assert list(G) == [] - - def test_nbunch_is_list(self): - G = self.G() - G.add_nodes_from(list("ABCD")) - G.add_nodes_from(self.P3) # add nbunch of nodes (nbunch=Graph) - assert (sorted(G.nodes(), key=str) == - [1, 2, 3, 'A', 'B', 'C', 'D']) - G.remove_nodes_from(self.P3) # remove nbunch of nodes (nbunch=Graph) - assert (sorted(G.nodes(), key=str) == - ['A', 'B', 'C', 'D']) - - def test_nbunch_is_set(self): - G = self.G() - nbunch = set("ABCDEFGHIJKL") - G.add_nodes_from(nbunch) - assert G.has_node("L") - - def test_nbunch_dict(self): - # nbunch is a dict with nodes as keys - G = self.G() - nbunch = set("ABCDEFGHIJKL") - G.add_nodes_from(nbunch) - nbunch = {'I': "foo", 'J': 2, 'K': True, 'L': "spam"} - G.remove_nodes_from(nbunch) - assert sorted(G.nodes(), key=str), ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] - - def test_nbunch_iterator(self): - G = self.G() - G.add_nodes_from(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']) - n_iter = self.P3.nodes() - G.add_nodes_from(n_iter) - assert (sorted(G.nodes(), key=str) == - [1, 2, 3, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']) - n_iter = self.P3.nodes() # rebuild same iterator - G.remove_nodes_from(n_iter) # remove nbunch of nodes (nbunch=iterator) - assert (sorted(G.nodes(), key=str) == - ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']) - - def test_nbunch_graph(self): - G = self.G() - G.add_nodes_from(['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']) - nbunch = self.K3 - G.add_nodes_from(nbunch) - assert sorted(G.nodes(), key=str), [1, 2, 3, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'] - - # Edges - - def test_add_edge(self): - G = self.G() - pytest.raises(TypeError, G.add_edge, 'A') - - G.add_edge('A', 'B') # testing add_edge() - G.add_edge('A', 'B') # should fail silently - assert G.has_edge('A', 'B') - assert not G.has_edge('A', 'C') - assert G.has_edge(*('A', 'B')) - if G.is_directed(): - assert not G.has_edge('B', 'A') - else: - # G is undirected, so B->A is an edge - assert G.has_edge('B', 'A') - - G.add_edge('A', 'C') # test directedness - G.add_edge('C', 'A') - G.remove_edge('C', 'A') - if G.is_directed(): - assert G.has_edge('A', 'C') - else: - assert not G.has_edge('A', 'C') - assert not G.has_edge('C', 'A') - - def test_self_loop(self): - G = self.G() - G.add_edge('A', 'A') # test self loops - assert G.has_edge('A', 'A') - G.remove_edge('A', 'A') - G.add_edge('X', 'X') - assert G.has_node('X') - G.remove_node('X') - G.add_edge('A', 'Z') # should add the node silently - assert G.has_node('Z') - - def test_add_edges_from(self): - G = self.G() - G.add_edges_from([('B', 'C')]) # test add_edges_from() - assert G.has_edge('B', 'C') - if G.is_directed(): - assert not G.has_edge('C', 'B') - else: - assert G.has_edge('C', 'B') # undirected - - G.add_edges_from([('D', 'F'), ('B', 'D')]) - assert G.has_edge('D', 'F') - assert G.has_edge('B', 'D') - - if G.is_directed(): - assert not G.has_edge('D', 'B') - else: - assert G.has_edge('D', 'B') # undirected - - def test_add_edges_from2(self): - G = self.G() - # after failing silently, should add 2nd edge - G.add_edges_from([tuple('IJ'), list('KK'), tuple('JK')]) - assert G.has_edge(*('I', 'J')) - assert G.has_edge(*('K', 'K')) - assert G.has_edge(*('J', 'K')) - if G.is_directed(): - assert not G.has_edge(*('K', 'J')) - else: - assert G.has_edge(*('K', 'J')) - - def test_add_edges_from3(self): - G = self.G() - G.add_edges_from(zip(list('ACD'), list('CDE'))) - assert G.has_edge('D', 'E') - assert not G.has_edge('E', 'C') - - def test_remove_edge(self): - G = self.G() - G.add_nodes_from([1, 2, 3, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']) - - G.add_edges_from(zip(list('MNOP'), list('NOPM'))) - assert G.has_edge('O', 'P') - assert G.has_edge('P', 'M') - G.remove_node('P') # tests remove_node()'s handling of edges. - assert not G.has_edge('P', 'M') - pytest.raises(TypeError, G.remove_edge, 'M') - - G.add_edge('N', 'M') - assert G.has_edge('M', 'N') - G.remove_edge('M', 'N') - assert not G.has_edge('M', 'N') - - # self loop fails silently - G.remove_edges_from([list('HI'), list('DF'), - tuple('KK'), tuple('JK')]) - assert not G.has_edge('H', 'I') - assert not G.has_edge('J', 'K') - G.remove_edges_from([list('IJ'), list('KK'), list('JK')]) - assert not G.has_edge('I', 'J') - G.remove_nodes_from(set('ZEFHIMNO')) - G.add_edge('J', 'K') - - def test_edges_nbunch(self): - # Test G.edges(nbunch) with various forms of nbunch - G = self.G() - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'D'), - ('C', 'B'), ('C', 'D')]) - # node not in nbunch should be quietly ignored - pytest.raises(nx.NetworkXError, G.edges, 6) - assert list(G.edges('Z')) == [] # iterable non-node - # nbunch can be an empty list - assert list(G.edges([])) == [] - if G.is_directed(): - elist = [('A', 'B'), ('A', 'C'), ('B', 'D')] - else: - elist = [('A', 'B'), ('A', 'C'), ('B', 'C'), ('B', 'D')] - # nbunch can be a list - assert_edges_equal(list(G.edges(['A', 'B'])), elist) - # nbunch can be a set - assert_edges_equal(G.edges(set(['A', 'B'])), elist) - # nbunch can be a graph - G1 = self.G() - G1.add_nodes_from('AB') - assert_edges_equal(G.edges(G1), elist) - # nbunch can be a dict with nodes as keys - ndict = {'A': "thing1", 'B': "thing2"} - assert_edges_equal(G.edges(ndict), elist) - # nbunch can be a single node - assert_edges_equal(list(G.edges('A')), [('A', 'B'), ('A', 'C')]) - assert_nodes_equal(sorted(G), ['A', 'B', 'C', 'D']) - - # nbunch can be nothing (whole graph) - assert_edges_equal( - list(G.edges()), - [('A', 'B'), ('A', 'C'), ('B', 'D'), ('C', 'B'), ('C', 'D')] - ) - - def test_degree(self): - G = self.G() - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'D'), - ('C', 'B'), ('C', 'D')]) - assert G.degree('A') == 2 - - # degree of single node in iterable container must return dict - assert list(G.degree(['A'])) == [('A', 2)] - assert sorted(d for n, d in G.degree(['A', 'B'])) == [2, 3] - assert sorted(d for n, d in G.degree()) == [2, 2, 3, 3] - - def test_degree2(self): - H = self.G() - H.add_edges_from([(1, 24), (1, 2)]) - assert sorted(d for n, d in H.degree([1, 24])) == [1, 2] - - def test_degree_graph(self): - P3 = nx.path_graph(3) - P5 = nx.path_graph(5) - # silently ignore nodes not in P3 - assert dict(d for n, d in P3.degree(['A', 'B'])) == {} - # nbunch can be a graph - assert sorted(d for n, d in P5.degree(P3)) == [1, 2, 2] - # nbunch can be a graph that's way too big - assert sorted(d for n, d in P3.degree(P5)) == [1, 1, 2] - assert list(P5.degree([])) == [] - assert dict(P5.degree([])) == {} - - def test_null(self): - null = nx.null_graph() - assert list(null.degree()) == [] - assert dict(null.degree()) == {} - - def test_order_size(self): - G = self.G() - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'D'), - ('C', 'B'), ('C', 'D')]) - assert G.order() == 4 - assert G.size() == 5 - assert G.number_of_edges() == 5 - assert G.number_of_edges('A', 'B') == 1 - assert G.number_of_edges('A', 'D') == 0 - - def test_copy(self): - G = self.G() - H = G.copy() # copy - assert H.adj == G.adj - assert H.name == G.name - assert H != G - - def test_subgraph(self): - G = self.G() - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'D'), - ('C', 'B'), ('C', 'D')]) - SG = G.subgraph(['A', 'B', 'D']) - assert_nodes_equal(list(SG), ['A', 'B', 'D']) - assert_edges_equal(list(SG.edges()), [('A', 'B'), ('B', 'D')]) - - def test_to_directed(self): - G = self.G() - if not G.is_directed(): - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'D'), - ('C', 'B'), ('C', 'D')]) - - DG = G.to_directed() - assert DG != G # directed copy or copy - - assert DG.is_directed() - assert DG.name == G.name - assert DG.adj == G.adj - assert (sorted(DG.out_edges(list('AB'))) == - [('A', 'B'), ('A', 'C'), ('B', 'A'), - ('B', 'C'), ('B', 'D')]) - DG.remove_edge('A', 'B') - assert DG.has_edge('B', 'A') # this removes B-A but not A-B - assert not DG.has_edge('A', 'B') - - def test_to_undirected(self): - G = self.G() - if G.is_directed(): - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'D'), - ('C', 'B'), ('C', 'D')]) - UG = G.to_undirected() # to_undirected - assert UG != G - assert not UG.is_directed() - assert G.is_directed() - assert UG.name == G.name - assert UG.adj != G.adj - assert (sorted(UG.edges(list('AB'))) == - [('A', 'B'), ('A', 'C'), ('B', 'C'), ('B', 'D')]) - assert (sorted(UG.edges(['A', 'B'])) == - [('A', 'B'), ('A', 'C'), ('B', 'C'), ('B', 'D')]) - UG.remove_edge('A', 'B') - assert not UG.has_edge('B', 'A') - assert not UG.has_edge('A', 'B') - - def test_neighbors(self): - G = self.G() - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'D'), - ('C', 'B'), ('C', 'D')]) - G.add_nodes_from('GJK') - assert sorted(G['A']) == ['B', 'C'] - assert sorted(G.neighbors('A')) == ['B', 'C'] - assert sorted(G.neighbors('A')) == ['B', 'C'] - assert sorted(G.neighbors('G')) == [] - pytest.raises(nx.NetworkXError, G.neighbors, 'j') - - def test_iterators(self): - G = self.G() - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'D'), - ('C', 'B'), ('C', 'D')]) - G.add_nodes_from('GJK') - assert (sorted(G.nodes()) == - ['A', 'B', 'C', 'D', 'G', 'J', 'K']) - assert_edges_equal(G.edges(), - [('A', 'B'), ('A', 'C'), ('B', 'D'), ('C', 'B'), ('C', 'D')]) - - assert (sorted([v for k, v in G.degree()]) == - [0, 0, 0, 2, 2, 3, 3]) - assert (sorted(G.degree(), key=str) == - [('A', 2), ('B', 3), ('C', 3), ('D', 2), - ('G', 0), ('J', 0), ('K', 0)]) - assert sorted(G.neighbors('A')) == ['B', 'C'] - pytest.raises(nx.NetworkXError, G.neighbors, 'X') - G.clear() - assert nx.number_of_nodes(G) == 0 - assert nx.number_of_edges(G) == 0 - - def test_null_subgraph(self): - # Subgraph of a null graph is a null graph - nullgraph = nx.null_graph() - G = nx.null_graph() - H = G.subgraph([]) - assert nx.is_isomorphic(H, nullgraph) - - def test_empty_subgraph(self): - # Subgraph of an empty graph is an empty graph. test 1 - nullgraph = nx.null_graph() - E5 = nx.empty_graph(5) - E10 = nx.empty_graph(10) - H = E10.subgraph([]) - assert nx.is_isomorphic(H, nullgraph) - H = E10.subgraph([1, 2, 3, 4, 5]) - assert nx.is_isomorphic(H, E5) - - def test_complete_subgraph(self): - # Subgraph of a complete graph is a complete graph - K1 = nx.complete_graph(1) - K3 = nx.complete_graph(3) - K5 = nx.complete_graph(5) - H = K5.subgraph([1, 2, 3]) - assert nx.is_isomorphic(H, K3) - - def test_subgraph_nbunch(self): - nullgraph = nx.null_graph() - K1 = nx.complete_graph(1) - K3 = nx.complete_graph(3) - K5 = nx.complete_graph(5) - # Test G.subgraph(nbunch), where nbunch is a single node - H = K5.subgraph(1) - assert nx.is_isomorphic(H, K1) - # Test G.subgraph(nbunch), where nbunch is a set - H = K5.subgraph(set([1])) - assert nx.is_isomorphic(H, K1) - # Test G.subgraph(nbunch), where nbunch is an iterator - H = K5.subgraph(iter(K3)) - assert nx.is_isomorphic(H, K3) - # Test G.subgraph(nbunch), where nbunch is another graph - H = K5.subgraph(K3) - assert nx.is_isomorphic(H, K3) - H = K5.subgraph([9]) - assert nx.is_isomorphic(H, nullgraph) - - def test_node_tuple_issue(self): - H = self.G() - # Test error handling of tuple as a node - pytest.raises(nx.NetworkXError, H.remove_node, (1, 2)) - H.remove_nodes_from([(1, 2)]) # no error - pytest.raises(nx.NetworkXError, H.neighbors, (1, 2)) diff --git a/extensions/fablabchemnitz/networkx/classes/tests/test_coreviews.py b/extensions/fablabchemnitz/networkx/classes/tests/test_coreviews.py deleted file mode 100644 index 5dc68f97..00000000 --- a/extensions/fablabchemnitz/networkx/classes/tests/test_coreviews.py +++ /dev/null @@ -1,359 +0,0 @@ -import pytest -import pickle - -import networkx as nx - - -class TestAtlasView(object): - # node->data - def setup(self): - self.d = {0: {'color': 'blue', 'weight': 1.2}, 1: {}, 2: {'color': 1}} - self.av = nx.classes.coreviews.AtlasView(self.d) - - def test_pickle(self): - view = self.av - pview = pickle.loads(pickle.dumps(view, -1)) - assert view == pview - assert view.__slots__ == pview.__slots__ - pview = pickle.loads(pickle.dumps(view)) - assert view == pview - assert view.__slots__ == pview.__slots__ - - def test_len(self): - assert len(self.av) == len(self.d) - - def test_iter(self): - assert list(self.av) == list(self.d) - - def test_getitem(self): - assert self.av[1] is self.d[1] - assert self.av[2]['color'] == 1 - pytest.raises(KeyError, self.av.__getitem__, 3) - - def test_copy(self): - avcopy = self.av.copy() - assert avcopy[0] == self.av[0] - assert avcopy == self.av - assert avcopy[0] is not self.av[0] - assert avcopy is not self.av - avcopy[5] = {} - assert avcopy != self.av - - avcopy[0]['ht'] = 4 - assert avcopy[0] != self.av[0] - self.av[0]['ht'] = 4 - assert avcopy[0] == self.av[0] - del self.av[0]['ht'] - - assert not hasattr(self.av, '__setitem__') - - def test_items(self): - assert sorted(self.av.items()) == sorted(self.d.items()) - - def test_str(self): - out = str(self.d) - assert str(self.av) == out - - def test_repr(self): - out = "AtlasView(" + str(self.d) + ")" - assert repr(self.av) == out - - -class TestAdjacencyView(object): - # node->nbr->data - def setup(self): - dd = {'color': 'blue', 'weight': 1.2} - self.nd = {0: dd, 1: {}, 2: {'color': 1}} - self.adj = {3: self.nd, 0: {3: dd}, 1: {}, 2: {3: {'color': 1}}} - self.adjview = nx.classes.coreviews.AdjacencyView(self.adj) - - def test_pickle(self): - view = self.adjview - pview = pickle.loads(pickle.dumps(view, -1)) - assert view == pview - assert view.__slots__ == pview.__slots__ - - def test_len(self): - assert len(self.adjview) == len(self.adj) - - def test_iter(self): - assert list(self.adjview) == list(self.adj) - - def test_getitem(self): - assert self.adjview[1] is not self.adj[1] - assert self.adjview[3][0] is self.adjview[0][3] - assert self.adjview[2][3]['color'] == 1 - pytest.raises(KeyError, self.adjview.__getitem__, 4) - - def test_copy(self): - avcopy = self.adjview.copy() - assert avcopy[0] == self.adjview[0] - assert avcopy[0] is not self.adjview[0] - - avcopy[2][3]['ht'] = 4 - assert avcopy[2] != self.adjview[2] - self.adjview[2][3]['ht'] = 4 - assert avcopy[2] == self.adjview[2] - del self.adjview[2][3]['ht'] - - assert not hasattr(self.adjview, '__setitem__') - - def test_items(self): - view_items = sorted((n, dict(d)) for n, d in self.adjview.items()) - assert view_items == sorted(self.adj.items()) - - def test_str(self): - out = str(dict(self.adj)) - assert str(self.adjview) == out - - def test_repr(self): - out = self.adjview.__class__.__name__ + "(" + str(self.adj) + ")" - assert repr(self.adjview) == out - - -class TestMultiAdjacencyView(TestAdjacencyView): - # node->nbr->key->data - def setup(self): - dd = {'color': 'blue', 'weight': 1.2} - self.kd = {0: dd, 1: {}, 2: {'color': 1}} - self.nd = {3: self.kd, 0: {3: dd}, 1: {0: {}}, 2: {3: {'color': 1}}} - self.adj = {3: self.nd, 0: {3: {3: dd}}, 1: {}, 2: {3: {8: {}}}} - self.adjview = nx.classes.coreviews.MultiAdjacencyView(self.adj) - - def test_getitem(self): - assert self.adjview[1] is not self.adj[1] - assert self.adjview[3][0][3] is self.adjview[0][3][3] - assert self.adjview[3][2][3]['color'] == 1 - pytest.raises(KeyError, self.adjview.__getitem__, 4) - - def test_copy(self): - avcopy = self.adjview.copy() - assert avcopy[0] == self.adjview[0] - assert avcopy[0] is not self.adjview[0] - - avcopy[2][3][8]['ht'] = 4 - assert avcopy[2] != self.adjview[2] - self.adjview[2][3][8]['ht'] = 4 - assert avcopy[2] == self.adjview[2] - del self.adjview[2][3][8]['ht'] - - assert not hasattr(self.adjview, '__setitem__') - - -class TestUnionAtlas(object): - # node->data - def setup(self): - self.s = {0: {'color': 'blue', 'weight': 1.2}, 1: {}, 2: {'color': 1}} - self.p = {3: {'color': 'blue', 'weight': 1.2}, 4: {}, 2: {'watch': 2}} - self.av = nx.classes.coreviews.UnionAtlas(self.s, self.p) - - def test_pickle(self): - view = self.av - pview = pickle.loads(pickle.dumps(view, -1)) - assert view == pview - assert view.__slots__ == pview.__slots__ - - def test_len(self): - assert len(self.av) == len(self.s) + len(self.p) - - def test_iter(self): - assert set(self.av) == set(self.s) | set(self.p) - - def test_getitem(self): - assert self.av[0] is self.s[0] - assert self.av[4] is self.p[4] - assert self.av[2]['color'] == 1 - pytest.raises(KeyError, self.av[2].__getitem__, 'watch') - pytest.raises(KeyError, self.av.__getitem__, 8) - - def test_copy(self): - avcopy = self.av.copy() - assert avcopy[0] == self.av[0] - assert avcopy[0] is not self.av[0] - assert avcopy is not self.av - avcopy[5] = {} - assert avcopy != self.av - - avcopy[0]['ht'] = 4 - assert avcopy[0] != self.av[0] - self.av[0]['ht'] = 4 - assert avcopy[0] == self.av[0] - del self.av[0]['ht'] - - assert not hasattr(self.av, '__setitem__') - - def test_items(self): - expected = dict(self.p.items()) - expected.update(self.s) - assert sorted(self.av.items()) == sorted(expected.items()) - - def test_str(self): - out = str(dict(self.av)) - assert str(self.av) == out - - def test_repr(self): - out = "{}({}, {})".format(self.av.__class__.__name__, self.s, self.p) - assert repr(self.av) == out - - -class TestUnionAdjacency(object): - # node->nbr->data - def setup(self): - dd = {'color': 'blue', 'weight': 1.2} - self.nd = {0: dd, 1: {}, 2: {'color': 1}} - self.s = {3: self.nd, 0: {}, 1: {}, 2: {3: {'color': 1}}} - self.p = {3: {}, 0: {3: dd}, 1: {0: {}}, 2: {1: {'color': 1}}} - self.adjview = nx.classes.coreviews.UnionAdjacency(self.s, self.p) - - def test_pickle(self): - view = self.adjview - pview = pickle.loads(pickle.dumps(view, -1)) - assert view == pview - assert view.__slots__ == pview.__slots__ - - def test_len(self): - assert len(self.adjview) == len(self.s) - - def test_iter(self): - assert sorted(self.adjview) == sorted(self.s) - - def test_getitem(self): - assert self.adjview[1] is not self.s[1] - assert self.adjview[3][0] is self.adjview[0][3] - assert self.adjview[2][3]['color'] == 1 - pytest.raises(KeyError, self.adjview.__getitem__, 4) - - def test_copy(self): - avcopy = self.adjview.copy() - assert avcopy[0] == self.adjview[0] - assert avcopy[0] is not self.adjview[0] - - avcopy[2][3]['ht'] = 4 - assert avcopy[2] != self.adjview[2] - self.adjview[2][3]['ht'] = 4 - assert avcopy[2] == self.adjview[2] - del self.adjview[2][3]['ht'] - - assert not hasattr(self.adjview, '__setitem__') - - def test_str(self): - out = str(dict(self.adjview)) - assert str(self.adjview) == out - - def test_repr(self): - clsname = self.adjview.__class__.__name__ - out = "{}({}, {})".format(clsname, self.s, self.p) - assert repr(self.adjview) == out - - -class TestUnionMultiInner(TestUnionAdjacency): - # nbr->key->data - def setup(self): - dd = {'color': 'blue', 'weight': 1.2} - self.kd = {7: {}, 'ekey': {}, 9: {'color': 1}} - self.s = {3: self.kd, 0: {7: dd}, 1: {}, 2: {'key': {'color': 1}}} - self.p = {3: {}, 0: {3: dd}, 1: {}, 2: {1: {'span': 2}}} - self.adjview = nx.classes.coreviews.UnionMultiInner(self.s, self.p) - - def test_len(self): - assert len(self.adjview) == len(self.s) + len(self.p) - - def test_getitem(self): - assert self.adjview[1] is not self.s[1] - assert self.adjview[0][7] is self.adjview[0][3] - assert self.adjview[2]['key']['color'] == 1 - assert self.adjview[2][1]['span'] == 2 - pytest.raises(KeyError, self.adjview.__getitem__, 4) - pytest.raises(KeyError, self.adjview[1].__getitem__, 'key') - - def test_copy(self): - avcopy = self.adjview.copy() - assert avcopy[0] == self.adjview[0] - assert avcopy[0] is not self.adjview[0] - - avcopy[2][1]['width'] = 8 - assert avcopy[2] != self.adjview[2] - self.adjview[2][1]['width'] = 8 - assert avcopy[2] == self.adjview[2] - del self.adjview[2][1]['width'] - - assert not hasattr(self.adjview, '__setitem__') - assert hasattr(avcopy, '__setitem__') - - -class TestUnionMultiAdjacency(TestUnionAdjacency): - # node->nbr->key->data - def setup(self): - dd = {'color': 'blue', 'weight': 1.2} - self.kd = {7: {}, 8: {}, 9: {'color': 1}} - self.nd = {3: self.kd, 0: {9: dd}, 1: {8: {}}, 2: {9: {'color': 1}}} - self.s = {3: self.nd, 0: {3: {7: dd}}, 1: {}, 2: {3: {8: {}}}} - self.p = {3: {}, 0: {3: {9: dd}}, 1: {}, 2: {1: {8: {}}}} - self.adjview = nx.classes.coreviews.UnionMultiAdjacency(self.s, self.p) - - def test_getitem(self): - assert self.adjview[1] is not self.s[1] - assert self.adjview[3][0][9] is self.adjview[0][3][9] - assert self.adjview[3][2][9]['color'] == 1 - pytest.raises(KeyError, self.adjview.__getitem__, 4) - - def test_copy(self): - avcopy = self.adjview.copy() - assert avcopy[0] == self.adjview[0] - assert avcopy[0] is not self.adjview[0] - - avcopy[2][3][8]['ht'] = 4 - assert avcopy[2] != self.adjview[2] - self.adjview[2][3][8]['ht'] = 4 - assert avcopy[2] == self.adjview[2] - del self.adjview[2][3][8]['ht'] - - assert not hasattr(self.adjview, '__setitem__') - assert hasattr(avcopy, '__setitem__') - - -class TestFilteredGraphs(object): - def setup(self): - self.Graphs = [nx.Graph, - nx.DiGraph, - nx.MultiGraph, - nx.MultiDiGraph] - self.SubGraphs = [nx.graphviews.subgraph_view] * 4 - - def test_hide_show_nodes(self): - for Graph, SubGraph in zip(self.Graphs, self.SubGraphs): - G = nx.path_graph(4, Graph) - SG = G.subgraph([2, 3]) - RG = SubGraph(G, nx.filters.hide_nodes([0, 1])) - assert SG.nodes == RG.nodes - assert SG.edges == RG.edges - SGC = SG.copy() - RGC = RG.copy() - assert SGC.nodes == RGC.nodes - assert SGC.edges == RGC.edges - - def test_str_repr(self): - for Graph, SubGraph in zip(self.Graphs, self.SubGraphs): - G = nx.path_graph(4, Graph) - SG = G.subgraph([2, 3]) - RG = SubGraph(G, nx.filters.hide_nodes([0, 1])) - str(SG.adj) - str(RG.adj) - repr(SG.adj) - repr(RG.adj) - str(SG.adj[2]) - str(RG.adj[2]) - repr(SG.adj[2]) - repr(RG.adj[2]) - - def test_copy(self): - for Graph, SubGraph in zip(self.Graphs, self.SubGraphs): - G = nx.path_graph(4, Graph) - SG = G.subgraph([2, 3]) - RG = SubGraph(G, nx.filters.hide_nodes([0, 1])) - assert G.adj.copy() == G.adj - assert G.adj[2].copy() == G.adj[2] - assert SG.adj.copy() == SG.adj - assert SG.adj[2].copy() == SG.adj[2] - assert RG.adj.copy() == RG.adj - assert RG.adj[2].copy() == RG.adj[2] diff --git a/extensions/fablabchemnitz/networkx/classes/tests/test_digraph.py b/extensions/fablabchemnitz/networkx/classes/tests/test_digraph.py deleted file mode 100644 index 4c418001..00000000 --- a/extensions/fablabchemnitz/networkx/classes/tests/test_digraph.py +++ /dev/null @@ -1,277 +0,0 @@ -#!/usr/bin/env python - -import pytest - - -import networkx as nx -from networkx.testing import assert_nodes_equal -from .test_graph import BaseGraphTester, BaseAttrGraphTester, TestGraph -from .test_graph import TestEdgeSubgraph as TestGraphEdgeSubgraph - - -class BaseDiGraphTester(BaseGraphTester): - def test_has_successor(self): - G = self.K3 - assert G.has_successor(0, 1) == True - assert G.has_successor(0, -1) == False - - def test_successors(self): - G = self.K3 - assert sorted(G.successors(0)) == [1, 2] - with pytest.raises(nx.NetworkXError): - G.successors(-1) - - def test_has_predecessor(self): - G = self.K3 - assert G.has_predecessor(0, 1) == True - assert G.has_predecessor(0, -1) == False - - def test_predecessors(self): - G = self.K3 - assert sorted(G.predecessors(0)) == [1, 2] - with pytest.raises(nx.NetworkXError): - G.predecessors(-1) - - def test_edges(self): - G = self.K3 - assert sorted(G.edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] - assert sorted(G.edges(0)) == [(0, 1), (0, 2)] - assert sorted(G.edges([0, 1])) == [(0, 1), (0, 2), (1, 0), (1, 2)] - with pytest.raises(nx.NetworkXError): - G.edges(-1) - - def test_edges_data(self): - G = self.K3 - all_edges = [(0, 1, {}), (0, 2, {}), (1, 0, {}), (1, 2, {}), (2, 0, {}), (2, 1, {})] - assert sorted(G.edges(data=True)) == all_edges - assert sorted(G.edges(0, data=True)) == all_edges[:2] - assert sorted(G.edges([0, 1], data=True)) == all_edges[:4] - with pytest.raises(nx.NetworkXError): - G.edges(-1, True) - - def test_out_edges(self): - G = self.K3 - assert sorted(G.out_edges()) == [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] - assert sorted(G.out_edges(0)) == [(0, 1), (0, 2)] - with pytest.raises(nx.NetworkXError): - G.out_edges(-1) - - def test_out_edges_dir(self): - G = self.P3 - assert sorted(G.out_edges()) == [(0, 1), (1, 2)] - assert sorted(G.out_edges(0)) == [(0, 1)] - assert sorted(G.out_edges(2)) == [] - - def test_out_edges_data(self): - G = nx.DiGraph([(0, 1, {'data': 0}), (1, 0, {})]) - assert sorted(G.out_edges(data=True)) == [(0, 1, {'data': 0}), (1, 0, {})] - assert sorted(G.out_edges(0, data=True)) == [(0, 1, {'data': 0})] - assert sorted(G.out_edges(data='data')) == [(0, 1, 0), (1, 0, None)] - assert sorted(G.out_edges(0, data='data')) == [(0, 1, 0)] - - def test_in_edges_dir(self): - G = self.P3 - assert sorted(G.in_edges()) == [(0, 1), (1, 2)] - assert sorted(G.in_edges(0)) == [] - assert sorted(G.in_edges(2)) == [(1, 2)] - - def test_in_edges_data(self): - G = nx.DiGraph([(0, 1, {'data': 0}), (1, 0, {})]) - assert sorted(G.in_edges(data=True)) == [(0, 1, {'data': 0}), (1, 0, {})] - assert sorted(G.in_edges(1, data=True)) == [(0, 1, {'data': 0})] - assert sorted(G.in_edges(data='data')) == [(0, 1, 0), (1, 0, None)] - assert sorted(G.in_edges(1, data='data')) == [(0, 1, 0)] - - def test_degree(self): - G = self.K3 - assert sorted(G.degree()) == [(0, 4), (1, 4), (2, 4)] - assert dict(G.degree()) == {0: 4, 1: 4, 2: 4} - assert G.degree(0) == 4 - assert list(G.degree(iter([0]))) == [ - (0, 4)] # run through iterator - - def test_in_degree(self): - G = self.K3 - assert sorted(G.in_degree()) == [(0, 2), (1, 2), (2, 2)] - assert dict(G.in_degree()) == {0: 2, 1: 2, 2: 2} - assert G.in_degree(0) == 2 - assert list(G.in_degree(iter([0]))) == [(0, 2)] # run through iterator - - def test_in_degree_weighted(self): - G = self.K3 - G.add_edge(0, 1, weight=0.3, other=1.2) - assert sorted(G.in_degree(weight='weight')) == [(0, 2), (1, 1.3), (2, 2)] - assert dict(G.in_degree(weight='weight')) == {0: 2, 1: 1.3, 2: 2} - assert G.in_degree(1, weight='weight') == 1.3 - assert sorted(G.in_degree(weight='other')) == [(0, 2), (1, 2.2), (2, 2)] - assert dict(G.in_degree(weight='other')) == {0: 2, 1: 2.2, 2: 2} - assert G.in_degree(1, weight='other') == 2.2 - assert list(G.in_degree(iter([1]), weight='other')) == [(1, 2.2)] - - def test_out_degree_weighted(self): - G = self.K3 - G.add_edge(0, 1, weight=0.3, other=1.2) - assert sorted(G.out_degree(weight='weight')) == [(0, 1.3), (1, 2), (2, 2)] - assert dict(G.out_degree(weight='weight')) == {0: 1.3, 1: 2, 2: 2} - assert G.out_degree(0, weight='weight') == 1.3 - assert sorted(G.out_degree(weight='other')) == [(0, 2.2), (1, 2), (2, 2)] - assert dict(G.out_degree(weight='other')) == {0: 2.2, 1: 2, 2: 2} - assert G.out_degree(0, weight='other') == 2.2 - assert list(G.out_degree(iter([0]), weight='other')) == [(0, 2.2)] - - def test_out_degree(self): - G = self.K3 - assert sorted(G.out_degree()) == [(0, 2), (1, 2), (2, 2)] - assert dict(G.out_degree()) == {0: 2, 1: 2, 2: 2} - assert G.out_degree(0) == 2 - assert list(G.out_degree(iter([0]))) == [(0, 2)] - - def test_size(self): - G = self.K3 - assert G.size() == 6 - assert G.number_of_edges() == 6 - - def test_to_undirected_reciprocal(self): - G = self.Graph() - G.add_edge(1, 2) - assert G.to_undirected().has_edge(1, 2) - assert not G.to_undirected(reciprocal=True).has_edge(1, 2) - G.add_edge(2, 1) - assert G.to_undirected(reciprocal=True).has_edge(1, 2) - - def test_reverse_copy(self): - G = nx.DiGraph([(0, 1), (1, 2)]) - R = G.reverse() - assert sorted(R.edges()) == [(1, 0), (2, 1)] - R.remove_edge(1, 0) - assert sorted(R.edges()) == [(2, 1)] - assert sorted(G.edges()) == [(0, 1), (1, 2)] - - def test_reverse_nocopy(self): - G = nx.DiGraph([(0, 1), (1, 2)]) - R = G.reverse(copy=False) - assert sorted(R.edges()) == [(1, 0), (2, 1)] - with pytest.raises(nx.NetworkXError): - R.remove_edge(1, 0) - - def test_reverse_hashable(self): - class Foo(object): - pass - x = Foo() - y = Foo() - G = nx.DiGraph() - G.add_edge(x, y) - assert_nodes_equal(G.nodes(), G.reverse().nodes()) - assert [(y, x)] == list(G.reverse().edges()) - - -class BaseAttrDiGraphTester(BaseDiGraphTester, BaseAttrGraphTester): - pass - - -class TestDiGraph(BaseAttrDiGraphTester, TestGraph): - """Tests specific to dict-of-dict-of-dict digraph data structure""" - - def setup_method(self): - self.Graph = nx.DiGraph - # build dict-of-dict-of-dict K3 - ed1, ed2, ed3, ed4, ed5, ed6 = ({}, {}, {}, {}, {}, {}) - self.k3adj = {0: {1: ed1, 2: ed2}, 1: {0: ed3, 2: ed4}, 2: {0: ed5, 1: ed6}} - self.k3edges = [(0, 1), (0, 2), (1, 2)] - self.k3nodes = [0, 1, 2] - self.K3 = self.Graph() - self.K3._adj = self.K3._succ = self.k3adj - self.K3._pred = {0: {1: ed3, 2: ed5}, 1: {0: ed1, 2: ed6}, 2: {0: ed2, 1: ed4}} - self.K3._node = {} - self.K3._node[0] = {} - self.K3._node[1] = {} - self.K3._node[2] = {} - - ed1, ed2 = ({}, {}) - self.P3 = self.Graph() - self.P3._adj = {0: {1: ed1}, 1: {2: ed2}, 2: {}} - self.P3._succ = self.P3._adj - self.P3._pred = {0: {}, 1: {0: ed1}, 2: {1: ed2}} - self.P3._node = {} - self.P3._node[0] = {} - self.P3._node[1] = {} - self.P3._node[2] = {} - - def test_data_input(self): - G = self.Graph({1: [2], 2: [1]}, name="test") - assert G.name == "test" - assert sorted(G.adj.items()) == [(1, {2: {}}), (2, {1: {}})] - assert sorted(G.succ.items()) == [(1, {2: {}}), (2, {1: {}})] - assert sorted(G.pred.items()) == [(1, {2: {}}), (2, {1: {}})] - - def test_add_edge(self): - G = self.Graph() - G.add_edge(0, 1) - assert G.adj == {0: {1: {}}, 1: {}} - assert G.succ == {0: {1: {}}, 1: {}} - assert G.pred == {0: {}, 1: {0: {}}} - G = self.Graph() - G.add_edge(*(0, 1)) - assert G.adj == {0: {1: {}}, 1: {}} - assert G.succ == {0: {1: {}}, 1: {}} - assert G.pred == {0: {}, 1: {0: {}}} - - def test_add_edges_from(self): - G = self.Graph() - G.add_edges_from([(0, 1), (0, 2, {'data': 3})], data=2) - assert G.adj == {0: {1: {'data': 2}, 2: {'data': 3}}, 1: {}, 2: {}} - assert G.succ == {0: {1: {'data': 2}, 2: {'data': 3}}, 1: {}, 2: {}} - assert G.pred == {0: {}, 1: {0: {'data': 2}}, 2: {0: {'data': 3}}} - - with pytest.raises(nx.NetworkXError): - G.add_edges_from([(0,)]) # too few in tuple - with pytest.raises(nx.NetworkXError): - G.add_edges_from([(0, 1, 2, 3)]) # too many in tuple - with pytest.raises(TypeError): - G.add_edges_from([0]) # not a tuple - - def test_remove_edge(self): - G = self.K3 - G.remove_edge(0, 1) - assert G.succ == {0: {2: {}}, 1: {0: {}, 2: {}}, 2: {0: {}, 1: {}}} - assert G.pred == {0: {1: {}, 2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}} - with pytest.raises(nx.NetworkXError): - G.remove_edge(-1, 0) - - def test_remove_edges_from(self): - G = self.K3 - G.remove_edges_from([(0, 1)]) - assert G.succ == {0: {2: {}}, 1: {0: {}, 2: {}}, 2: {0: {}, 1: {}}} - assert G.pred == {0: {1: {}, 2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}} - G.remove_edges_from([(0, 0)]) # silent fail - - -class TestEdgeSubgraph(TestGraphEdgeSubgraph): - """Unit tests for the :meth:`DiGraph.edge_subgraph` method.""" - - def setup_method(self): - # Create a doubly-linked path graph on five nodes. - G = nx.DiGraph(nx.path_graph(5)) - # Add some node, edge, and graph attributes. - for i in range(5): - G.nodes[i]['name'] = 'node{}'.format(i) - G.edges[0, 1]['name'] = 'edge01' - G.edges[3, 4]['name'] = 'edge34' - G.graph['name'] = 'graph' - # Get the subgraph induced by the first and last edges. - self.G = G - self.H = G.edge_subgraph([(0, 1), (3, 4)]) - - def test_pred_succ(self): - """Test that nodes are added to predecessors and successors. - - For more information, see GitHub issue #2370. - - """ - G = nx.DiGraph() - G.add_edge(0, 1) - H = G.edge_subgraph([(0, 1)]) - assert list(H.predecessors(0)) == [] - assert list(H.successors(0)) == [1] - assert list(H.predecessors(1)) == [0] - assert list(H.successors(1)) == [] diff --git a/extensions/fablabchemnitz/networkx/classes/tests/test_digraph_historical.py b/extensions/fablabchemnitz/networkx/classes/tests/test_digraph_historical.py deleted file mode 100644 index b39ae3cc..00000000 --- a/extensions/fablabchemnitz/networkx/classes/tests/test_digraph_historical.py +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env python -"""Original NetworkX graph tests""" -import pytest -import networkx -import networkx as nx -from networkx.testing.utils import * - -from .historical_tests import HistoricalTests - - -class TestDiGraphHistorical(HistoricalTests): - - @classmethod - def setup_class(cls): - HistoricalTests.setup_class() - cls.G = nx.DiGraph - - def test_in_degree(self): - G = self.G() - G.add_nodes_from('GJK') - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'D'), - ('B', 'C'), ('C', 'D')]) - - assert sorted(d for n, d in G.in_degree()) == [0, 0, 0, 0, 1, 2, 2] - assert (dict(G.in_degree()) == - {'A': 0, 'C': 2, 'B': 1, 'D': 2, 'G': 0, 'K': 0, 'J': 0}) - - def test_out_degree(self): - G = self.G() - G.add_nodes_from('GJK') - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'D'), - ('B', 'C'), ('C', 'D')]) - assert (sorted([v for k, v in G.in_degree()]) == - [0, 0, 0, 0, 1, 2, 2]) - assert (dict(G.out_degree()) == - {'A': 2, 'C': 1, 'B': 2, 'D': 0, 'G': 0, 'K': 0, 'J': 0}) - - def test_degree_digraph(self): - H = nx.DiGraph() - H.add_edges_from([(1, 24), (1, 2)]) - assert sorted(d for n, d in H.in_degree([1, 24])) == [0, 1] - assert sorted(d for n, d in H.out_degree([1, 24])) == [0, 2] - assert sorted(d for n, d in H.degree([1, 24])) == [1, 2] - - def test_neighbors(self): - G = self.G() - G.add_nodes_from('GJK') - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'D'), - ('B', 'C'), ('C', 'D')]) - - assert sorted(G.neighbors('C')) == ['D'] - assert sorted(G['C']) == ['D'] - assert sorted(G.neighbors('A')) == ['B', 'C'] - pytest.raises(nx.NetworkXError, G.neighbors, 'j') - pytest.raises(nx.NetworkXError, G.neighbors, 'j') - - def test_successors(self): - G = self.G() - G.add_nodes_from('GJK') - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'D'), - ('B', 'C'), ('C', 'D')]) - assert sorted(G.successors('A')) == ['B', 'C'] - assert sorted(G.successors('A')) == ['B', 'C'] - assert sorted(G.successors('G')) == [] - assert sorted(G.successors('D')) == [] - assert sorted(G.successors('G')) == [] - pytest.raises(nx.NetworkXError, G.successors, 'j') - pytest.raises(nx.NetworkXError, G.successors, 'j') - - def test_predecessors(self): - G = self.G() - G.add_nodes_from('GJK') - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'D'), - ('B', 'C'), ('C', 'D')]) - assert sorted(G.predecessors('C')) == ['A', 'B'] - assert sorted(G.predecessors('C')) == ['A', 'B'] - assert sorted(G.predecessors('G')) == [] - assert sorted(G.predecessors('A')) == [] - assert sorted(G.predecessors('G')) == [] - assert sorted(G.predecessors('A')) == [] - assert sorted(G.successors('D')) == [] - - pytest.raises(nx.NetworkXError, G.predecessors, 'j') - pytest.raises(nx.NetworkXError, G.predecessors, 'j') - - def test_reverse(self): - G = nx.complete_graph(10) - H = G.to_directed() - HR = H.reverse() - assert nx.is_isomorphic(H, HR) - assert sorted(H.edges()) == sorted(HR.edges()) - - def test_reverse2(self): - H = nx.DiGraph() - foo = [H.add_edge(u, u + 1) for u in range(0, 5)] - HR = H.reverse() - for u in range(0, 5): - assert HR.has_edge(u + 1, u) - - def test_reverse3(self): - H = nx.DiGraph() - H.add_nodes_from([1, 2, 3, 4]) - HR = H.reverse() - assert sorted(HR.nodes()) == [1, 2, 3, 4] diff --git a/extensions/fablabchemnitz/networkx/classes/tests/test_filters.py b/extensions/fablabchemnitz/networkx/classes/tests/test_filters.py deleted file mode 100644 index d5ea8be8..00000000 --- a/extensions/fablabchemnitz/networkx/classes/tests/test_filters.py +++ /dev/null @@ -1,176 +0,0 @@ -import pytest -import networkx as nx - - -class TestFilterFactory(object): - def test_no_filter(self): - nf = nx.filters.no_filter - assert nf() - assert nf(1) - assert nf(2, 1) - - def test_hide_nodes(self): - f = nx.classes.filters.hide_nodes([1, 2, 3]) - assert not f(1) - assert not f(2) - assert not f(3) - assert f(4) - assert f(0) - assert f('a') - pytest.raises(TypeError, f, 1, 2) - pytest.raises(TypeError, f) - - def test_show_nodes(self): - f = nx.classes.filters.show_nodes([1, 2, 3]) - assert f(1) - assert f(2) - assert f(3) - assert not f(4) - assert not f(0) - assert not f('a') - pytest.raises(TypeError, f, 1, 2) - pytest.raises(TypeError, f) - - def test_hide_edges(self): - factory = nx.classes.filters.hide_edges - f = factory([(1, 2), (3, 4)]) - assert not f(1, 2) - assert not f(3, 4) - assert not f(4, 3) - assert f(2, 3) - assert f(0, -1) - assert f('a', 'b') - pytest.raises(TypeError, f, 1, 2, 3) - pytest.raises(TypeError, f, 1) - pytest.raises(TypeError, f) - pytest.raises(TypeError, factory, [1, 2, 3]) - pytest.raises(ValueError, factory, [(1, 2, 3)]) - - def test_show_edges(self): - factory = nx.classes.filters.show_edges - f = factory([(1, 2), (3, 4)]) - assert f(1, 2) - assert f(3, 4) - assert f(4, 3) - assert not f(2, 3) - assert not f(0, -1) - assert not f('a', 'b') - pytest.raises(TypeError, f, 1, 2, 3) - pytest.raises(TypeError, f, 1) - pytest.raises(TypeError, f) - pytest.raises(TypeError, factory, [1, 2, 3]) - pytest.raises(ValueError, factory, [(1, 2, 3)]) - - def test_hide_diedges(self): - factory = nx.classes.filters.hide_diedges - f = factory([(1, 2), (3, 4)]) - assert not f(1, 2) - assert not f(3, 4) - assert f(4, 3) - assert f(2, 3) - assert f(0, -1) - assert f('a', 'b') - pytest.raises(TypeError, f, 1, 2, 3) - pytest.raises(TypeError, f, 1) - pytest.raises(TypeError, f) - pytest.raises(TypeError, factory, [1, 2, 3]) - pytest.raises(ValueError, factory, [(1, 2, 3)]) - - def test_show_diedges(self): - factory = nx.classes.filters.show_diedges - f = factory([(1, 2), (3, 4)]) - assert f(1, 2) - assert f(3, 4) - assert not f(4, 3) - assert not f(2, 3) - assert not f(0, -1) - assert not f('a', 'b') - pytest.raises(TypeError, f, 1, 2, 3) - pytest.raises(TypeError, f, 1) - pytest.raises(TypeError, f) - pytest.raises(TypeError, factory, [1, 2, 3]) - pytest.raises(ValueError, factory, [(1, 2, 3)]) - - def test_hide_multiedges(self): - factory = nx.classes.filters.hide_multiedges - f = factory([(1, 2, 0), (3, 4, 1), (1, 2, 1)]) - assert not f(1, 2, 0) - assert not f(1, 2, 1) - assert f(1, 2, 2) - assert f(3, 4, 0) - assert not f(3, 4, 1) - assert not f(4, 3, 1) - assert f(4, 3, 0) - assert f(2, 3, 0) - assert f(0, -1, 0) - assert f('a', 'b', 0) - pytest.raises(TypeError, f, 1, 2, 3, 4) - pytest.raises(TypeError, f, 1, 2) - pytest.raises(TypeError, f, 1) - pytest.raises(TypeError, f) - pytest.raises(TypeError, factory, [1, 2, 3]) - pytest.raises(ValueError, factory, [(1, 2)]) - pytest.raises(ValueError, factory, [(1, 2, 3, 4)]) - - def test_show_multiedges(self): - factory = nx.classes.filters.show_multiedges - f = factory([(1, 2, 0), (3, 4, 1), (1, 2, 1)]) - assert f(1, 2, 0) - assert f(1, 2, 1) - assert not f(1, 2, 2) - assert not f(3, 4, 0) - assert f(3, 4, 1) - assert f(4, 3, 1) - assert not f(4, 3, 0) - assert not f(2, 3, 0) - assert not f(0, -1, 0) - assert not f('a', 'b', 0) - pytest.raises(TypeError, f, 1, 2, 3, 4) - pytest.raises(TypeError, f, 1, 2) - pytest.raises(TypeError, f, 1) - pytest.raises(TypeError, f) - pytest.raises(TypeError, factory, [1, 2, 3]) - pytest.raises(ValueError, factory, [(1, 2)]) - pytest.raises(ValueError, factory, [(1, 2, 3, 4)]) - - def test_hide_multidiedges(self): - factory = nx.classes.filters.hide_multidiedges - f = factory([(1, 2, 0), (3, 4, 1), (1, 2, 1)]) - assert not f(1, 2, 0) - assert not f(1, 2, 1) - assert f(1, 2, 2) - assert f(3, 4, 0) - assert not f(3, 4, 1) - assert f(4, 3, 1) - assert f(4, 3, 0) - assert f(2, 3, 0) - assert f(0, -1, 0) - assert f('a', 'b', 0) - pytest.raises(TypeError, f, 1, 2, 3, 4) - pytest.raises(TypeError, f, 1, 2) - pytest.raises(TypeError, f, 1) - pytest.raises(TypeError, f) - pytest.raises(TypeError, factory, [1, 2, 3]) - pytest.raises(ValueError, factory, [(1, 2)]) - pytest.raises(ValueError, factory, [(1, 2, 3, 4)]) - - def test_show_multidiedges(self): - factory = nx.classes.filters.show_multidiedges - f = factory([(1, 2, 0), (3, 4, 1), (1, 2, 1)]) - assert f(1, 2, 0) - assert f(1, 2, 1) - assert not f(1, 2, 2) - assert not f(3, 4, 0) - assert f(3, 4, 1) - assert not f(4, 3, 1) - assert not f(4, 3, 0) - assert not f(2, 3, 0) - assert not f(0, -1, 0) - assert not f('a', 'b', 0) - pytest.raises(TypeError, f, 1, 2, 3, 4) - pytest.raises(TypeError, f, 1, 2) - pytest.raises(TypeError, f, 1) - pytest.raises(TypeError, f) - pytest.raises(TypeError, factory, [1, 2, 3]) - pytest.raises(ValueError, factory, [(1, 2)]) - pytest.raises(ValueError, factory, [(1, 2, 3, 4)]) diff --git a/extensions/fablabchemnitz/networkx/classes/tests/test_function.py b/extensions/fablabchemnitz/networkx/classes/tests/test_function.py deleted file mode 100644 index 79e76f75..00000000 --- a/extensions/fablabchemnitz/networkx/classes/tests/test_function.py +++ /dev/null @@ -1,608 +0,0 @@ -#!/usr/bin/env python -import random -import pytest -import networkx as nx -from networkx.testing.utils import * - - -class TestFunction(object): - def setup_method(self): - self.G = nx.Graph({0: [1, 2, 3], 1: [1, 2, 0], 4: []}, name='Test') - self.Gdegree = {0: 3, 1: 2, 2: 2, 3: 1, 4: 0} - self.Gnodes = list(range(5)) - self.Gedges = [(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)] - self.DG = nx.DiGraph({0: [1, 2, 3], 1: [1, 2, 0], 4: []}) - self.DGin_degree = {0: 1, 1: 2, 2: 2, 3: 1, 4: 0} - self.DGout_degree = {0: 3, 1: 3, 2: 0, 3: 0, 4: 0} - self.DGnodes = list(range(5)) - self.DGedges = [(0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2)] - - def test_nodes(self): - assert_nodes_equal(self.G.nodes(), list(nx.nodes(self.G))) - assert_nodes_equal(self.DG.nodes(), list(nx.nodes(self.DG))) - - def test_edges(self): - assert_edges_equal(self.G.edges(), list(nx.edges(self.G))) - assert sorted(self.DG.edges()) == sorted(nx.edges(self.DG)) - assert_edges_equal(self.G.edges(nbunch=[0, 1, 3]), - list(nx.edges(self.G, nbunch=[0, 1, 3]))) - assert (sorted(self.DG.edges(nbunch=[0, 1, 3])) == - sorted(nx.edges(self.DG, nbunch=[0, 1, 3]))) - - def test_degree(self): - assert_edges_equal(self.G.degree(), list(nx.degree(self.G))) - assert sorted(self.DG.degree()) == sorted(nx.degree(self.DG)) - assert_edges_equal(self.G.degree(nbunch=[0, 1]), - list(nx.degree(self.G, nbunch=[0, 1]))) - assert (sorted(self.DG.degree(nbunch=[0, 1])) == - sorted(nx.degree(self.DG, nbunch=[0, 1]))) - assert_edges_equal(self.G.degree(weight='weight'), - list(nx.degree(self.G, weight='weight'))) - assert (sorted(self.DG.degree(weight='weight')) == - sorted(nx.degree(self.DG, weight='weight'))) - - def test_neighbors(self): - assert list(self.G.neighbors(1)) == list(nx.neighbors(self.G, 1)) - assert list(self.DG.neighbors(1)) == list(nx.neighbors(self.DG, 1)) - - def test_number_of_nodes(self): - assert self.G.number_of_nodes() == nx.number_of_nodes(self.G) - assert self.DG.number_of_nodes() == nx.number_of_nodes(self.DG) - - def test_number_of_edges(self): - assert self.G.number_of_edges() == nx.number_of_edges(self.G) - assert self.DG.number_of_edges() == nx.number_of_edges(self.DG) - - def test_is_directed(self): - assert self.G.is_directed() == nx.is_directed(self.G) - assert self.DG.is_directed() == nx.is_directed(self.DG) - - def test_add_star(self): - G = self.G.copy() - nlist = [12, 13, 14, 15] - nx.add_star(G, nlist) - assert_edges_equal(G.edges(nlist), [(12, 13), (12, 14), (12, 15)]) - - G = self.G.copy() - nx.add_star(G, nlist, weight=2.0) - assert_edges_equal(G.edges(nlist, data=True), - [(12, 13, {'weight': 2.}), - (12, 14, {'weight': 2.}), - (12, 15, {'weight': 2.})]) - - G = self.G.copy() - nlist = [12] - nx.add_star(G, nlist) - assert_nodes_equal(G, list(self.G) + nlist) - - G = self.G.copy() - nlist = [] - nx.add_star(G, nlist) - assert_nodes_equal(G.nodes, self.Gnodes) - assert_edges_equal(G.edges, self.G.edges) - - def test_add_path(self): - G = self.G.copy() - nlist = [12, 13, 14, 15] - nx.add_path(G, nlist) - assert_edges_equal(G.edges(nlist), [(12, 13), (13, 14), (14, 15)]) - G = self.G.copy() - nx.add_path(G, nlist, weight=2.0) - assert_edges_equal(G.edges(nlist, data=True), - [(12, 13, {'weight': 2.}), - (13, 14, {'weight': 2.}), - (14, 15, {'weight': 2.})]) - - G = self.G.copy() - nlist = [None] - nx.add_path(G, nlist) - assert_edges_equal(G.edges(nlist), []) - assert_nodes_equal(G, list(self.G) + [None]) - - G = self.G.copy() - nlist = iter([None]) - nx.add_path(G, nlist) - assert_edges_equal(G.edges([None]), []) - assert_nodes_equal(G, list(self.G) + [None]) - - G = self.G.copy() - nlist = [12] - nx.add_path(G, nlist) - assert_edges_equal(G.edges(nlist), []) - assert_nodes_equal(G, list(self.G) + [12]) - - G = self.G.copy() - nlist = iter([12]) - nx.add_path(G, nlist) - assert_edges_equal(G.edges([12]), []) - assert_nodes_equal(G, list(self.G) + [12]) - - G = self.G.copy() - nlist = [] - nx.add_path(G, nlist) - assert_edges_equal(G.edges, self.G.edges) - assert_nodes_equal(G, list(self.G)) - - G = self.G.copy() - nlist = iter([]) - nx.add_path(G, nlist) - assert_edges_equal(G.edges, self.G.edges) - assert_nodes_equal(G, list(self.G)) - - def test_add_cycle(self): - G = self.G.copy() - nlist = [12, 13, 14, 15] - oklists = [[(12, 13), (12, 15), (13, 14), (14, 15)], - [(12, 13), (13, 14), (14, 15), (15, 12)]] - nx.add_cycle(G, nlist) - assert sorted(G.edges(nlist)) in oklists - G = self.G.copy() - oklists = [[(12, 13, {'weight': 1.}), - (12, 15, {'weight': 1.}), - (13, 14, {'weight': 1.}), - (14, 15, {'weight': 1.})], - [(12, 13, {'weight': 1.}), - (13, 14, {'weight': 1.}), - (14, 15, {'weight': 1.}), - (15, 12, {'weight': 1.})]] - nx.add_cycle(G, nlist, weight=1.0) - assert sorted(G.edges(nlist, data=True)) in oklists - - G = self.G.copy() - nlist = [12] - nx.add_cycle(G, nlist) - assert_nodes_equal(G, list(self.G) + nlist) - - G = self.G.copy() - nlist = [] - nx.add_cycle(G, nlist) - assert_nodes_equal(G.nodes, self.Gnodes) - assert_edges_equal(G.edges, self.G.edges) - - def test_subgraph(self): - assert (self.G.subgraph([0, 1, 2, 4]).adj == - nx.subgraph(self.G, [0, 1, 2, 4]).adj) - assert (self.DG.subgraph([0, 1, 2, 4]).adj == - nx.subgraph(self.DG, [0, 1, 2, 4]).adj) - assert (self.G.subgraph([0, 1, 2, 4]).adj == - nx.induced_subgraph(self.G, [0, 1, 2, 4]).adj) - assert (self.DG.subgraph([0, 1, 2, 4]).adj == - nx.induced_subgraph(self.DG, [0, 1, 2, 4]).adj) - # subgraph-subgraph chain is allowed in function interface - H = nx.induced_subgraph(self.G.subgraph([0, 1, 2, 4]), [0, 1, 4]) - assert H._graph is not self.G - assert H.adj == self.G.subgraph([0, 1, 4]).adj - - def test_edge_subgraph(self): - assert (self.G.edge_subgraph([(1, 2), (0, 3)]).adj == - nx.edge_subgraph(self.G, [(1, 2), (0, 3)]).adj) - assert (self.DG.edge_subgraph([(1, 2), (0, 3)]).adj == - nx.edge_subgraph(self.DG, [(1, 2), (0, 3)]).adj) - - def test_restricted_view(self): - H = nx.restricted_view(self.G, [0, 2, 5], [(1, 2), (3, 4)]) - assert set(H.nodes) == {1, 3, 4} - assert set(H.edges) == {(1, 1)} - - def test_create_empty_copy(self): - G = nx.create_empty_copy(self.G, with_data=False) - assert_nodes_equal(G, list(self.G)) - assert G.graph == {} - assert G._node == {}.fromkeys(self.G.nodes(), {}) - assert G._adj == {}.fromkeys(self.G.nodes(), {}) - G = nx.create_empty_copy(self.G) - assert_nodes_equal(G, list(self.G)) - assert G.graph == self.G.graph - assert G._node == self.G._node - assert G._adj == {}.fromkeys(self.G.nodes(), {}) - - def test_degree_histogram(self): - assert nx.degree_histogram(self.G) == [1, 1, 1, 1, 1] - - def test_density(self): - assert nx.density(self.G) == 0.5 - assert nx.density(self.DG) == 0.3 - G = nx.Graph() - G.add_node(1) - assert nx.density(G) == 0.0 - - def test_density_selfloop(self): - G = nx.Graph() - G.add_edge(1, 1) - assert nx.density(G) == 0.0 - G.add_edge(1, 2) - assert nx.density(G) == 2.0 - - def test_freeze(self): - G = nx.freeze(self.G) - assert G.frozen == True - pytest.raises(nx.NetworkXError, G.add_node, 1) - pytest.raises(nx.NetworkXError, G.add_nodes_from, [1]) - pytest.raises(nx.NetworkXError, G.remove_node, 1) - pytest.raises(nx.NetworkXError, G.remove_nodes_from, [1]) - pytest.raises(nx.NetworkXError, G.add_edge, 1, 2) - pytest.raises(nx.NetworkXError, G.add_edges_from, [(1, 2)]) - pytest.raises(nx.NetworkXError, G.remove_edge, 1, 2) - pytest.raises(nx.NetworkXError, G.remove_edges_from, [(1, 2)]) - pytest.raises(nx.NetworkXError, G.clear) - - def test_is_frozen(self): - assert nx.is_frozen(self.G) == False - G = nx.freeze(self.G) - assert G.frozen == nx.is_frozen(self.G) - assert G.frozen == True - - def test_info(self): - G = nx.path_graph(5) - G.name = "path_graph(5)" - info = nx.info(G) - expected_graph_info = '\n'.join(['Name: path_graph(5)', - 'Type: Graph', - 'Number of nodes: 5', - 'Number of edges: 4', - 'Average degree: 1.6000']) - assert info == expected_graph_info - - info = nx.info(G, n=1) - expected_node_info = '\n'.join( - ['Node 1 has the following properties:', - 'Degree: 2', - 'Neighbors: 0 2']) - assert info == expected_node_info - - def test_info_digraph(self): - G = nx.DiGraph(name='path_graph(5)') - nx.add_path(G, [0, 1, 2, 3, 4]) - info = nx.info(G) - expected_graph_info = '\n'.join(['Name: path_graph(5)', - 'Type: DiGraph', - 'Number of nodes: 5', - 'Number of edges: 4', - 'Average in degree: 0.8000', - 'Average out degree: 0.8000']) - assert info == expected_graph_info - - info = nx.info(G, n=1) - expected_node_info = '\n'.join( - ['Node 1 has the following properties:', - 'Degree: 2', - 'Neighbors: 2']) - assert info == expected_node_info - - pytest.raises(nx.NetworkXError, nx.info, G, n=-1) - - def test_neighbors_complete_graph(self): - graph = nx.complete_graph(100) - pop = random.sample(list(graph), 1) - nbors = list(nx.neighbors(graph, pop[0])) - # should be all the other vertices in the graph - assert len(nbors) == len(graph) - 1 - - graph = nx.path_graph(100) - node = random.sample(list(graph), 1)[0] - nbors = list(nx.neighbors(graph, node)) - # should be all the other vertices in the graph - if node != 0 and node != 99: - assert len(nbors) == 2 - else: - assert len(nbors) == 1 - - # create a star graph with 99 outer nodes - graph = nx.star_graph(99) - nbors = list(nx.neighbors(graph, 0)) - assert len(nbors) == 99 - - def test_non_neighbors(self): - graph = nx.complete_graph(100) - pop = random.sample(list(graph), 1) - nbors = list(nx.non_neighbors(graph, pop[0])) - # should be all the other vertices in the graph - assert len(nbors) == 0 - - graph = nx.path_graph(100) - node = random.sample(list(graph), 1)[0] - nbors = list(nx.non_neighbors(graph, node)) - # should be all the other vertices in the graph - if node != 0 and node != 99: - assert len(nbors) == 97 - else: - assert len(nbors) == 98 - - # create a star graph with 99 outer nodes - graph = nx.star_graph(99) - nbors = list(nx.non_neighbors(graph, 0)) - assert len(nbors) == 0 - - # disconnected graph - graph = nx.Graph() - graph.add_nodes_from(range(10)) - nbors = list(nx.non_neighbors(graph, 0)) - assert len(nbors) == 9 - - def test_non_edges(self): - # All possible edges exist - graph = nx.complete_graph(5) - nedges = list(nx.non_edges(graph)) - assert len(nedges) == 0 - - graph = nx.path_graph(4) - expected = [(0, 2), (0, 3), (1, 3)] - nedges = list(nx.non_edges(graph)) - for (u, v) in expected: - assert (u, v) in nedges or (v, u) in nedges - - graph = nx.star_graph(4) - expected = [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - nedges = list(nx.non_edges(graph)) - for (u, v) in expected: - assert (u, v) in nedges or (v, u) in nedges - - # Directed graphs - graph = nx.DiGraph() - graph.add_edges_from([(0, 2), (2, 0), (2, 1)]) - expected = [(0, 1), (1, 0), (1, 2)] - nedges = list(nx.non_edges(graph)) - for e in expected: - assert e in nedges - - def test_is_weighted(self): - G = nx.Graph() - assert not nx.is_weighted(G) - - G = nx.path_graph(4) - assert not nx.is_weighted(G) - assert not nx.is_weighted(G, (2, 3)) - - G.add_node(4) - G.add_edge(3, 4, weight=4) - assert not nx.is_weighted(G) - assert nx.is_weighted(G, (3, 4)) - - G = nx.DiGraph() - G.add_weighted_edges_from([('0', '3', 3), ('0', '1', -5), - ('1', '0', -5), ('0', '2', 2), - ('1', '2', 4), ('2', '3', 1)]) - assert nx.is_weighted(G) - assert nx.is_weighted(G, ('1', '0')) - - G = G.to_undirected() - assert nx.is_weighted(G) - assert nx.is_weighted(G, ('1', '0')) - - pytest.raises(nx.NetworkXError, nx.is_weighted, G, (1, 2)) - - def test_is_negatively_weighted(self): - G = nx.Graph() - assert not nx.is_negatively_weighted(G) - - G.add_node(1) - G.add_nodes_from([2, 3, 4, 5]) - assert not nx.is_negatively_weighted(G) - - G.add_edge(1, 2, weight=4) - assert not nx.is_negatively_weighted(G, (1, 2)) - - G.add_edges_from([(1, 3), (2, 4), (2, 6)]) - G[1][3]['color'] = 'blue' - assert not nx.is_negatively_weighted(G) - assert not nx.is_negatively_weighted(G, (1, 3)) - - G[2][4]['weight'] = -2 - assert nx.is_negatively_weighted(G, (2, 4)) - assert nx.is_negatively_weighted(G) - - G = nx.DiGraph() - G.add_weighted_edges_from([('0', '3', 3), ('0', '1', -5), - ('1', '0', -2), ('0', '2', 2), - ('1', '2', -3), ('2', '3', 1)]) - assert nx.is_negatively_weighted(G) - assert not nx.is_negatively_weighted(G, ('0', '3')) - assert nx.is_negatively_weighted(G, ('1', '0')) - - pytest.raises(nx.NetworkXError, nx.is_negatively_weighted, G, (1, 4)) - - -class TestCommonNeighbors(): - @classmethod - def setup_class(cls): - cls.func = staticmethod(nx.common_neighbors) - - def test_func(G, u, v, expected): - result = sorted(cls.func(G, u, v)) - assert result == expected - cls.test = staticmethod(test_func) - - def test_K5(self): - G = nx.complete_graph(5) - self.test(G, 0, 1, [2, 3, 4]) - - def test_P3(self): - G = nx.path_graph(3) - self.test(G, 0, 2, [1]) - - def test_S4(self): - G = nx.star_graph(4) - self.test(G, 1, 2, [0]) - - def test_digraph(self): - with pytest.raises(nx.NetworkXNotImplemented): - G = nx.DiGraph() - G.add_edges_from([(0, 1), (1, 2)]) - self.func(G, 0, 2) - - def test_nonexistent_nodes(self): - G = nx.complete_graph(5) - pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 5, 4) - pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 4, 5) - pytest.raises(nx.NetworkXError, nx.common_neighbors, G, 5, 6) - - def test_custom1(self): - """Case of no common neighbors.""" - G = nx.Graph() - G.add_nodes_from([0, 1]) - self.test(G, 0, 1, []) - - def test_custom2(self): - """Case of equal nodes.""" - G = nx.complete_graph(4) - self.test(G, 0, 0, [1, 2, 3]) - - -def test_set_node_attributes(): - graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()] - for G in graphs: - # Test single value - G = nx.path_graph(3, create_using=G) - vals = 100 - attr = 'hello' - nx.set_node_attributes(G, vals, attr) - assert G.nodes[0][attr] == vals - assert G.nodes[1][attr] == vals - assert G.nodes[2][attr] == vals - - # Test dictionary - G = nx.path_graph(3, create_using=G) - vals = dict(zip(sorted(G.nodes()), range(len(G)))) - attr = 'hi' - nx.set_node_attributes(G, vals, attr) - assert G.nodes[0][attr] == 0 - assert G.nodes[1][attr] == 1 - assert G.nodes[2][attr] == 2 - - # Test dictionary of dictionaries - G = nx.path_graph(3, create_using=G) - d = {'hi': 0, 'hello': 200} - vals = dict.fromkeys(G.nodes(), d) - vals.pop(0) - nx.set_node_attributes(G, vals) - assert G.nodes[0] == {} - assert G.nodes[1]["hi"] == 0 - assert G.nodes[2]["hello"] == 200 - - -def test_set_edge_attributes(): - graphs = [nx.Graph(), nx.DiGraph()] - for G in graphs: - # Test single value - G = nx.path_graph(3, create_using=G) - attr = 'hello' - vals = 3 - nx.set_edge_attributes(G, vals, attr) - assert G[0][1][attr] == vals - assert G[1][2][attr] == vals - - # Test multiple values - G = nx.path_graph(3, create_using=G) - attr = 'hi' - edges = [(0, 1), (1, 2)] - vals = dict(zip(edges, range(len(edges)))) - nx.set_edge_attributes(G, vals, attr) - assert G[0][1][attr] == 0 - assert G[1][2][attr] == 1 - - # Test dictionary of dictionaries - G = nx.path_graph(3, create_using=G) - d = {'hi': 0, 'hello': 200} - edges = [(0, 1)] - vals = dict.fromkeys(edges, d) - nx.set_edge_attributes(G, vals) - assert G[0][1]['hi'] == 0 - assert G[0][1]['hello'] == 200 - assert G[1][2] == {} - - -def test_set_edge_attributes_multi(): - graphs = [nx.MultiGraph(), nx.MultiDiGraph()] - for G in graphs: - # Test single value - G = nx.path_graph(3, create_using=G) - attr = 'hello' - vals = 3 - nx.set_edge_attributes(G, vals, attr) - assert G[0][1][0][attr] == vals - assert G[1][2][0][attr] == vals - - # Test multiple values - G = nx.path_graph(3, create_using=G) - attr = 'hi' - edges = [(0, 1, 0), (1, 2, 0)] - vals = dict(zip(edges, range(len(edges)))) - nx.set_edge_attributes(G, vals, attr) - assert G[0][1][0][attr] == 0 - assert G[1][2][0][attr] == 1 - - # Test dictionary of dictionaries - G = nx.path_graph(3, create_using=G) - d = {'hi': 0, 'hello': 200} - edges = [(0, 1, 0)] - vals = dict.fromkeys(edges, d) - nx.set_edge_attributes(G, vals) - assert G[0][1][0]['hi'] == 0 - assert G[0][1][0]['hello'] == 200 - assert G[1][2][0] == {} - - -def test_get_node_attributes(): - graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()] - for G in graphs: - G = nx.path_graph(3, create_using=G) - attr = 'hello' - vals = 100 - nx.set_node_attributes(G, vals, attr) - attrs = nx.get_node_attributes(G, attr) - assert attrs[0] == vals - assert attrs[1] == vals - assert attrs[2] == vals - - -def test_get_edge_attributes(): - graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()] - for G in graphs: - G = nx.path_graph(3, create_using=G) - attr = 'hello' - vals = 100 - nx.set_edge_attributes(G, vals, attr) - attrs = nx.get_edge_attributes(G, attr) - - assert len(attrs) == 2 - if G.is_multigraph(): - keys = [(0, 1, 0), (1, 2, 0)] - for u, v, k in keys: - try: - assert attrs[(u, v, k)] == 100 - except KeyError: - assert attrs[(v, u, k)] == 100 - else: - keys = [(0, 1), (1, 2)] - for u, v in keys: - try: - assert attrs[(u, v)] == 100 - except KeyError: - assert attrs[(v, u)] == 100 - - -def test_is_empty(): - graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()] - for G in graphs: - assert nx.is_empty(G) - G.add_nodes_from(range(5)) - assert nx.is_empty(G) - G.add_edges_from([(1, 2), (3, 4)]) - assert not nx.is_empty(G) - - -def test_selfloops(): - graphs = [nx.Graph(), nx.DiGraph(), nx.MultiGraph(), nx.MultiDiGraph()] - for graph in graphs: - G = nx.complete_graph(3, create_using=graph) - G.add_edge(0, 0) - assert_nodes_equal(nx.nodes_with_selfloops(G), [0]) - assert_edges_equal(nx.selfloop_edges(G), [(0, 0)]) - assert_edges_equal(nx.selfloop_edges(G, data=True), [(0, 0, {})]) - assert nx.number_of_selfloops(G) == 1 - # test selfloop attr - G.add_edge(1, 1, weight=2) - assert_edges_equal(nx.selfloop_edges(G, data=True), - [(0, 0, {}), (1, 1, {'weight': 2})]) - assert_edges_equal(nx.selfloop_edges(G, data='weight'), - [(0, 0, None), (1, 1, 2)]) diff --git a/extensions/fablabchemnitz/networkx/classes/tests/test_graph.py b/extensions/fablabchemnitz/networkx/classes/tests/test_graph.py deleted file mode 100644 index 93758c75..00000000 --- a/extensions/fablabchemnitz/networkx/classes/tests/test_graph.py +++ /dev/null @@ -1,761 +0,0 @@ -import pickle -import gc - -import networkx as nx -from networkx.testing.utils import * - -import pytest - - -class BaseGraphTester(object): - """ Tests for data-structure independent graph class features.""" - - def test_contains(self): - G = self.K3 - assert(1 in G) - assert(4 not in G) - assert('b' not in G) - assert([] not in G) # no exception for nonhashable - assert({1: 1} not in G) # no exception for nonhashable - - def test_order(self): - G = self.K3 - assert len(G) == 3 - assert G.order() == 3 - assert G.number_of_nodes() == 3 - - def test_nodes(self): - G = self.K3 - assert sorted(G.nodes()) == self.k3nodes - assert sorted(G.nodes(data=True)) == [(0, {}), (1, {}), (2, {})] - - def test_has_node(self): - G = self.K3 - assert(G.has_node(1)) - assert(not G.has_node(4)) - assert(not G.has_node([])) # no exception for nonhashable - assert(not G.has_node({1: 1})) # no exception for nonhashable - - def test_has_edge(self): - G = self.K3 - assert G.has_edge(0, 1) == True - assert G.has_edge(0, -1) == False - - def test_neighbors(self): - G = self.K3 - assert sorted(G.neighbors(0)) == [1, 2] - with pytest.raises(nx.NetworkXError): - G.neighbors(-1) - - def test_memory_leak(self): - G = self.Graph() - - def count_objects_of_type(_type): - return sum(1 for obj in gc.get_objects() if isinstance(obj, _type)) - - gc.collect() - before = count_objects_of_type(self.Graph) - G.copy() - after = count_objects_of_type(self.Graph) - assert before == after - - # test a subgraph of the base class - class MyGraph(self.Graph): - pass - - gc.collect() - G = MyGraph() - before = count_objects_of_type(MyGraph) - G.copy() - after = count_objects_of_type(MyGraph) - assert before == after - - def test_edges(self): - G = self.K3 - assert_edges_equal(G.edges(), [(0, 1), (0, 2), (1, 2)]) - assert_edges_equal(G.edges(0), [(0, 1), (0, 2)]) - assert_edges_equal(G.edges([0, 1]), [(0, 1), (0, 2), (1, 2)]) - with pytest.raises(nx.NetworkXError): - G.edges(-1) - - def test_weighted_degree(self): - G = self.Graph() - G.add_edge(1, 2, weight=2) - G.add_edge(2, 3, weight=3) - assert (sorted(d for n, d in G.degree(weight='weight')) == - [2, 3, 5]) - assert dict(G.degree(weight='weight')) == {1: 2, 2: 5, 3: 3} - assert G.degree(1, weight='weight') == 2 - assert G.degree([1], weight='weight') == [(1, 2)] - - def test_degree(self): - G = self.K3 - assert sorted(G.degree()) == [(0, 2), (1, 2), (2, 2)] - assert dict(G.degree()) == {0: 2, 1: 2, 2: 2} - assert G.degree(0) == 2 - with pytest.raises(nx.NetworkXError): - G.degree(-1) # node not in graph - - def test_size(self): - G = self.K3 - assert G.size() == 3 - assert G.number_of_edges() == 3 - - def test_nbunch_iter(self): - G = self.K3 - assert_nodes_equal(G.nbunch_iter(), self.k3nodes) # all nodes - assert_nodes_equal(G.nbunch_iter(0), [0]) # single node - assert_nodes_equal(G.nbunch_iter([0, 1]), [0, 1]) # sequence - # sequence with none in graph - assert_nodes_equal(G.nbunch_iter([-1]), []) - # string sequence with none in graph - assert_nodes_equal(G.nbunch_iter("foo"), []) - # node not in graph doesn't get caught upon creation of iterator - bunch = G.nbunch_iter(-1) - # but gets caught when iterator used - with pytest.raises(nx.NetworkXError): - list(bunch) - # unhashable doesn't get caught upon creation of iterator - bunch = G.nbunch_iter([0, 1, 2, {}]) - # but gets caught when iterator hits the unhashable - with pytest.raises(nx.NetworkXError): - list(bunch) - - def test_nbunch_iter_node_format_raise(self): - # Tests that a node that would have failed string formatting - # doesn't cause an error when attempting to raise a - # :exc:`nx.NetworkXError`. - - # For more information, see pull request #1813. - G = self.Graph() - nbunch = [('x', set())] - with pytest.raises(nx.NetworkXError): - list(G.nbunch_iter(nbunch)) - - def test_selfloop_degree(self): - G = self.Graph() - G.add_edge(1, 1) - assert sorted(G.degree()) == [(1, 2)] - assert dict(G.degree()) == {1: 2} - assert G.degree(1) == 2 - assert sorted(G.degree([1])) == [(1, 2)] - assert G.degree(1, weight='weight') == 2 - - def test_selfloops(self): - G = self.K3.copy() - G.add_edge(0, 0) - assert_nodes_equal(nx.nodes_with_selfloops(G), [0]) - assert_edges_equal(nx.selfloop_edges(G), [(0, 0)]) - assert nx.number_of_selfloops(G) == 1 - G.remove_edge(0, 0) - G.add_edge(0, 0) - G.remove_edges_from([(0, 0)]) - G.add_edge(1, 1) - G.remove_node(1) - G.add_edge(0, 0) - G.add_edge(1, 1) - G.remove_nodes_from([0, 1]) - - -class BaseAttrGraphTester(BaseGraphTester): - """ Tests of graph class attribute features.""" - - def test_weighted_degree(self): - G = self.Graph() - G.add_edge(1, 2, weight=2, other=3) - G.add_edge(2, 3, weight=3, other=4) - assert (sorted(d for n, d in G.degree(weight='weight')) == - [2, 3, 5]) - assert dict(G.degree(weight='weight')) == {1: 2, 2: 5, 3: 3} - assert G.degree(1, weight='weight') == 2 - assert_nodes_equal((G.degree([1], weight='weight')), [(1, 2)]) - - assert_nodes_equal((d for n, d in G.degree(weight='other')), [3, 7, 4]) - assert dict(G.degree(weight='other')) == {1: 3, 2: 7, 3: 4} - assert G.degree(1, weight='other') == 3 - assert_edges_equal((G.degree([1], weight='other')), [(1, 3)]) - - def add_attributes(self, G): - G.graph['foo'] = [] - G.nodes[0]['foo'] = [] - G.remove_edge(1, 2) - ll = [] - G.add_edge(1, 2, foo=ll) - G.add_edge(2, 1, foo=ll) - - def test_name(self): - G = self.Graph(name='') - assert G.name == "" - G = self.Graph(name='test') - assert G.__str__() == "test" - assert G.name == "test" - - def test_graph_chain(self): - G = self.Graph([(0, 1), (1, 2)]) - DG = G.to_directed(as_view=True) - SDG = DG.subgraph([0, 1]) - RSDG = SDG.reverse(copy=False) - assert G is DG._graph - assert DG is SDG._graph - assert SDG is RSDG._graph - - def test_copy(self): - G = self.Graph() - G.add_node(0) - G.add_edge(1, 2) - self.add_attributes(G) - # copy edge datadict but any container attr are same - H = G.copy() - self.graphs_equal(H, G) - self.different_attrdict(H, G) - self.shallow_copy_attrdict(H, G) - - def test_class_copy(self): - G = self.Graph() - G.add_node(0) - G.add_edge(1, 2) - self.add_attributes(G) - # copy edge datadict but any container attr are same - H = G.__class__(G) - self.graphs_equal(H, G) - self.different_attrdict(H, G) - self.shallow_copy_attrdict(H, G) - - def test_fresh_copy(self): - G = self.Graph() - G.add_node(0) - G.add_edge(1, 2) - self.add_attributes(G) - # copy graph structure but use fresh datadict - H = G.__class__() - H.add_nodes_from(G) - H.add_edges_from(G.edges()) - assert len(G.nodes[0]) == 1 - ddict = G.adj[1][2][0] if G.is_multigraph() else G.adj[1][2] - assert len(ddict) == 1 - assert len(H.nodes[0]) == 0 - ddict = H.adj[1][2][0] if H.is_multigraph() else H.adj[1][2] - assert len(ddict) == 0 - - def is_deepcopy(self, H, G): - self.graphs_equal(H, G) - self.different_attrdict(H, G) - self.deep_copy_attrdict(H, G) - - def deep_copy_attrdict(self, H, G): - self.deepcopy_graph_attr(H, G) - self.deepcopy_node_attr(H, G) - self.deepcopy_edge_attr(H, G) - - def deepcopy_graph_attr(self, H, G): - assert G.graph['foo'] == H.graph['foo'] - G.graph['foo'].append(1) - assert G.graph['foo'] != H.graph['foo'] - - def deepcopy_node_attr(self, H, G): - assert G.nodes[0]['foo'] == H.nodes[0]['foo'] - G.nodes[0]['foo'].append(1) - assert G.nodes[0]['foo'] != H.nodes[0]['foo'] - - def deepcopy_edge_attr(self, H, G): - assert G[1][2]['foo'] == H[1][2]['foo'] - G[1][2]['foo'].append(1) - assert G[1][2]['foo'] != H[1][2]['foo'] - - def is_shallow_copy(self, H, G): - self.graphs_equal(H, G) - self.shallow_copy_attrdict(H, G) - - def shallow_copy_attrdict(self, H, G): - self.shallow_copy_graph_attr(H, G) - self.shallow_copy_node_attr(H, G) - self.shallow_copy_edge_attr(H, G) - - def shallow_copy_graph_attr(self, H, G): - assert G.graph['foo'] == H.graph['foo'] - G.graph['foo'].append(1) - assert G.graph['foo'] == H.graph['foo'] - - def shallow_copy_node_attr(self, H, G): - assert G.nodes[0]['foo'] == H.nodes[0]['foo'] - G.nodes[0]['foo'].append(1) - assert G.nodes[0]['foo'] == H.nodes[0]['foo'] - - def shallow_copy_edge_attr(self, H, G): - assert G[1][2]['foo'] == H[1][2]['foo'] - G[1][2]['foo'].append(1) - assert G[1][2]['foo'] == H[1][2]['foo'] - - def same_attrdict(self, H, G): - old_foo = H[1][2]['foo'] - H.adj[1][2]['foo'] = 'baz' - assert G.edges == H.edges - H.adj[1][2]['foo'] = old_foo - assert G.edges == H.edges - - old_foo = H.nodes[0]['foo'] - H.nodes[0]['foo'] = 'baz' - assert G.nodes == H.nodes - H.nodes[0]['foo'] = old_foo - assert G.nodes == H.nodes - - def different_attrdict(self, H, G): - old_foo = H[1][2]['foo'] - H.adj[1][2]['foo'] = 'baz' - assert G._adj != H._adj - H.adj[1][2]['foo'] = old_foo - assert G._adj == H._adj - - old_foo = H.nodes[0]['foo'] - H.nodes[0]['foo'] = 'baz' - assert G._node != H._node - H.nodes[0]['foo'] = old_foo - assert G._node == H._node - - def graphs_equal(self, H, G): - assert G._adj == H._adj - assert G._node == H._node - assert G.graph == H.graph - assert G.name == H.name - if not G.is_directed() and not H.is_directed(): - assert H._adj[1][2] is H._adj[2][1] - assert G._adj[1][2] is G._adj[2][1] - else: # at least one is directed - if not G.is_directed(): - G._pred = G._adj - G._succ = G._adj - if not H.is_directed(): - H._pred = H._adj - H._succ = H._adj - assert G._pred == H._pred - assert G._succ == H._succ - assert H._succ[1][2] is H._pred[2][1] - assert G._succ[1][2] is G._pred[2][1] - - def test_graph_attr(self): - G = self.K3 - G.graph['foo'] = 'bar' - assert G.graph['foo'] == 'bar' - del G.graph['foo'] - assert G.graph == {} - H = self.Graph(foo='bar') - assert H.graph['foo'] == 'bar' - - def test_node_attr(self): - G = self.K3 - G.add_node(1, foo='bar') - assert_nodes_equal(G.nodes(), [0, 1, 2]) - assert_nodes_equal(G.nodes(data=True), - [(0, {}), (1, {'foo': 'bar'}), (2, {})]) - G.nodes[1]['foo'] = 'baz' - assert_nodes_equal(G.nodes(data=True), - [(0, {}), (1, {'foo': 'baz'}), (2, {})]) - assert_nodes_equal(G.nodes(data='foo'), - [(0, None), (1, 'baz'), (2, None)]) - assert_nodes_equal(G.nodes(data='foo', default='bar'), - [(0, 'bar'), (1, 'baz'), (2, 'bar')]) - - def test_node_attr2(self): - G = self.K3 - a = {'foo': 'bar'} - G.add_node(3, **a) - assert_nodes_equal(G.nodes(), [0, 1, 2, 3]) - assert_nodes_equal(G.nodes(data=True), - [(0, {}), (1, {}), (2, {}), (3, {'foo': 'bar'})]) - - def test_edge_lookup(self): - G = self.Graph() - G.add_edge(1, 2, foo='bar') - assert_edges_equal(G.edges[1, 2], {'foo': 'bar'}) - - def test_edge_attr(self): - G = self.Graph() - G.add_edge(1, 2, foo='bar') - assert_edges_equal(G.edges(data=True), [(1, 2, {'foo': 'bar'})]) - assert_edges_equal(G.edges(data='foo'), [(1, 2, 'bar')]) - - def test_edge_attr2(self): - G = self.Graph() - G.add_edges_from([(1, 2), (3, 4)], foo='foo') - assert_edges_equal(G.edges(data=True), - [(1, 2, {'foo': 'foo'}), (3, 4, {'foo': 'foo'})]) - assert_edges_equal(G.edges(data='foo'), - [(1, 2, 'foo'), (3, 4, 'foo')]) - - def test_edge_attr3(self): - G = self.Graph() - G.add_edges_from([(1, 2, {'weight': 32}), - (3, 4, {'weight': 64})], foo='foo') - assert_edges_equal(G.edges(data=True), - [(1, 2, {'foo': 'foo', 'weight': 32}), - (3, 4, {'foo': 'foo', 'weight': 64})]) - - G.remove_edges_from([(1, 2), (3, 4)]) - G.add_edge(1, 2, data=7, spam='bar', bar='foo') - assert_edges_equal(G.edges(data=True), - [(1, 2, {'data': 7, 'spam': 'bar', 'bar': 'foo'})]) - - def test_edge_attr4(self): - G = self.Graph() - G.add_edge(1, 2, data=7, spam='bar', bar='foo') - assert_edges_equal(G.edges(data=True), - [(1, 2, {'data': 7, 'spam': 'bar', 'bar': 'foo'})]) - G[1][2]['data'] = 10 # OK to set data like this - assert_edges_equal(G.edges(data=True), - [(1, 2, {'data': 10, 'spam': 'bar', 'bar': 'foo'})]) - - G.adj[1][2]['data'] = 20 - assert_edges_equal(G.edges(data=True), - [(1, 2, {'data': 20, 'spam': 'bar', 'bar': 'foo'})]) - G.edges[1, 2]['data'] = 21 # another spelling, "edge" - assert_edges_equal(G.edges(data=True), - [(1, 2, {'data': 21, 'spam': 'bar', 'bar': 'foo'})]) - G.adj[1][2]['listdata'] = [20, 200] - G.adj[1][2]['weight'] = 20 - dd = {'data': 21, 'spam': 'bar', 'bar': 'foo', - 'listdata': [20, 200], 'weight': 20} - assert_edges_equal(G.edges(data=True), [(1, 2, dd)]) - - def test_to_undirected(self): - G = self.K3 - self.add_attributes(G) - H = nx.Graph(G) - self.is_shallow_copy(H, G) - self.different_attrdict(H, G) - H = G.to_undirected() - self.is_deepcopy(H, G) - - def test_to_directed(self): - G = self.K3 - self.add_attributes(G) - H = nx.DiGraph(G) - self.is_shallow_copy(H, G) - self.different_attrdict(H, G) - H = G.to_directed() - self.is_deepcopy(H, G) - - def test_subgraph(self): - G = self.K3 - self.add_attributes(G) - H = G.subgraph([0, 1, 2, 5]) - self.graphs_equal(H, G) - self.same_attrdict(H, G) - self.shallow_copy_attrdict(H, G) - - H = G.subgraph(0) - assert H.adj == {0: {}} - H = G.subgraph([]) - assert H.adj == {} - assert G.adj != {} - - def test_selfloops_attr(self): - G = self.K3.copy() - G.add_edge(0, 0) - G.add_edge(1, 1, weight=2) - assert_edges_equal(nx.selfloop_edges(G, data=True), - [(0, 0, {}), (1, 1, {'weight': 2})]) - assert_edges_equal(nx.selfloop_edges(G, data='weight'), - [(0, 0, None), (1, 1, 2)]) - - -class TestGraph(BaseAttrGraphTester): - """Tests specific to dict-of-dict-of-dict graph data structure""" - - def setup_method(self): - self.Graph = nx.Graph - # build dict-of-dict-of-dict K3 - ed1, ed2, ed3 = ({}, {}, {}) - self.k3adj = {0: {1: ed1, 2: ed2}, - 1: {0: ed1, 2: ed3}, - 2: {0: ed2, 1: ed3}} - self.k3edges = [(0, 1), (0, 2), (1, 2)] - self.k3nodes = [0, 1, 2] - self.K3 = self.Graph() - self.K3._adj = self.k3adj - self.K3._node = {} - self.K3._node[0] = {} - self.K3._node[1] = {} - self.K3._node[2] = {} - - def test_pickle(self): - G = self.K3 - pg = pickle.loads(pickle.dumps(G, -1)) - self.graphs_equal(pg, G) - pg = pickle.loads(pickle.dumps(G)) - self.graphs_equal(pg, G) - - def test_data_input(self): - G = self.Graph({1: [2], 2: [1]}, name="test") - assert G.name == "test" - assert sorted(G.adj.items()) == [(1, {2: {}}), (2, {1: {}})] - G = self.Graph({1: [2], 2: [1]}, name="test") - assert G.name == "test" - assert sorted(G.adj.items()) == [(1, {2: {}}), (2, {1: {}})] - - def test_adjacency(self): - G = self.K3 - assert (dict(G.adjacency()) == - {0: {1: {}, 2: {}}, 1: {0: {}, 2: {}}, 2: {0: {}, 1: {}}}) - - def test_getitem(self): - G = self.K3 - assert G[0] == {1: {}, 2: {}} - with pytest.raises(KeyError): - G.__getitem__('j') - with pytest.raises(TypeError): - G.__getitem__(['A']) - - def test_add_node(self): - G = self.Graph() - G.add_node(0) - assert G.adj == {0: {}} - # test add attributes - G.add_node(1, c='red') - G.add_node(2, c='blue') - G.add_node(3, c='red') - assert G.nodes[1]['c'] == 'red' - assert G.nodes[2]['c'] == 'blue' - assert G.nodes[3]['c'] == 'red' - # test updating attributes - G.add_node(1, c='blue') - G.add_node(2, c='red') - G.add_node(3, c='blue') - assert G.nodes[1]['c'] == 'blue' - assert G.nodes[2]['c'] == 'red' - assert G.nodes[3]['c'] == 'blue' - - def test_add_nodes_from(self): - G = self.Graph() - G.add_nodes_from([0, 1, 2]) - assert G.adj == {0: {}, 1: {}, 2: {}} - # test add attributes - G.add_nodes_from([0, 1, 2], c='red') - assert G.nodes[0]['c'] == 'red' - assert G.nodes[2]['c'] == 'red' - # test that attribute dicts are not the same - assert(G.nodes[0] is not G.nodes[1]) - # test updating attributes - G.add_nodes_from([0, 1, 2], c='blue') - assert G.nodes[0]['c'] == 'blue' - assert G.nodes[2]['c'] == 'blue' - assert(G.nodes[0] is not G.nodes[1]) - # test tuple input - H = self.Graph() - H.add_nodes_from(G.nodes(data=True)) - assert H.nodes[0]['c'] == 'blue' - assert H.nodes[2]['c'] == 'blue' - assert(H.nodes[0] is not H.nodes[1]) - # specific overrides general - H.add_nodes_from([0, (1, {'c': 'green'}), (3, {'c': 'cyan'})], c='red') - assert H.nodes[0]['c'] == 'red' - assert H.nodes[1]['c'] == 'green' - assert H.nodes[2]['c'] == 'blue' - assert H.nodes[3]['c'] == 'cyan' - - def test_remove_node(self): - G = self.K3 - G.remove_node(0) - assert G.adj == {1: {2: {}}, 2: {1: {}}} - with pytest.raises(nx.NetworkXError): - G.remove_node(-1) - - # generator here to implement list,set,string... - def test_remove_nodes_from(self): - G = self.K3 - G.remove_nodes_from([0, 1]) - assert G.adj == {2: {}} - G.remove_nodes_from([-1]) # silent fail - - def test_add_edge(self): - G = self.Graph() - G.add_edge(0, 1) - assert G.adj == {0: {1: {}}, 1: {0: {}}} - G = self.Graph() - G.add_edge(*(0, 1)) - assert G.adj == {0: {1: {}}, 1: {0: {}}} - - def test_add_edges_from(self): - G = self.Graph() - G.add_edges_from([(0, 1), (0, 2, {'weight': 3})]) - assert G.adj == {0: {1: {}, 2: {'weight': 3}}, 1: {0: {}}, - 2: {0: {'weight': 3}}} - G = self.Graph() - G.add_edges_from([(0, 1), (0, 2, {'weight': 3}), - (1, 2, {'data': 4})], data=2) - assert G.adj == { - 0: {1: {'data': 2}, 2: {'weight': 3, 'data': 2}}, - 1: {0: {'data': 2}, 2: {'data': 4}}, - 2: {0: {'weight': 3, 'data': 2}, 1: {'data': 4}} - } - - with pytest.raises(nx.NetworkXError): - G.add_edges_from([(0,)]) # too few in tuple - with pytest.raises(nx.NetworkXError): - G.add_edges_from([(0, 1, 2, 3)]) # too many in tuple - with pytest.raises(TypeError): - G.add_edges_from([0]) # not a tuple - - def test_remove_edge(self): - G = self.K3 - G.remove_edge(0, 1) - assert G.adj == {0: {2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}} - with pytest.raises(nx.NetworkXError): - G.remove_edge(-1, 0) - - def test_remove_edges_from(self): - G = self.K3 - G.remove_edges_from([(0, 1)]) - assert G.adj == {0: {2: {}}, 1: {2: {}}, 2: {0: {}, 1: {}}} - G.remove_edges_from([(0, 0)]) # silent fail - - def test_clear(self): - G = self.K3 - G.clear() - assert G.adj == {} - - def test_edges_data(self): - G = self.K3 - all_edges = [(0, 1, {}), (0, 2, {}), (1, 2, {})] - assert_edges_equal(G.edges(data=True), all_edges) - assert_edges_equal(G.edges(0, data=True), [(0, 1, {}), (0, 2, {})]) - assert_edges_equal(G.edges([0, 1], data=True), all_edges) - with pytest.raises(nx.NetworkXError): - G.edges(-1, True) - - def test_get_edge_data(self): - G = self.K3 - assert G.get_edge_data(0, 1) == {} - assert G[0][1] == {} - assert G.get_edge_data(10, 20) == None - assert G.get_edge_data(-1, 0) == None - assert G.get_edge_data(-1, 0, default=1) == 1 - - def test_update(self): - # specify both edgees and nodes - G = self.K3.copy() - G.update(nodes=[3, (4, {'size': 2})], - edges=[(4, 5), (6, 7, {'weight': 2})]) - nlist = [(0, {}), (1, {}), (2, {}), (3, {}), - (4, {'size': 2}), (5, {}), (6, {}), (7, {})] - assert sorted(G.nodes.data()) == nlist - if G.is_directed(): - elist = [(0, 1, {}), (0, 2, {}), (1, 0, {}), (1, 2, {}), - (2, 0, {}), (2, 1, {}), - (4, 5, {}), (6, 7, {'weight': 2})] - else: - elist = [(0, 1, {}), (0, 2, {}), (1, 2, {}), - (4, 5, {}), (6, 7, {'weight': 2})] - assert sorted(G.edges.data()) == elist - assert G.graph == {} - - # no keywords -- order is edges, nodes - G = self.K3.copy() - G.update([(4, 5), (6, 7, {'weight': 2})], [3, (4, {'size': 2})]) - assert sorted(G.nodes.data()) == nlist - assert sorted(G.edges.data()) == elist - assert G.graph == {} - - # update using only a graph - G = self.Graph() - G.graph['foo'] = 'bar' - G.add_node(2, data=4) - G.add_edge(0, 1, weight=0.5) - GG = G.copy() - H = self.Graph() - GG.update(H) - assert_graphs_equal(G, GG) - H.update(G) - assert_graphs_equal(H, G) - - # update nodes only - H = self.Graph() - H.update(nodes=[3, 4]) - assert H.nodes ^ {3, 4} == set([]) - assert H.size() == 0 - - # update edges only - H = self.Graph() - H.update(edges=[(3, 4)]) - assert sorted(H.edges.data()) == [(3, 4, {})] - assert H.size() == 1 - - # No inputs -> exception - with pytest.raises(nx.NetworkXError): - nx.Graph().update() - - -class TestEdgeSubgraph(object): - """Unit tests for the :meth:`Graph.edge_subgraph` method.""" - - def setup_method(self): - # Create a path graph on five nodes. - G = nx.path_graph(5) - # Add some node, edge, and graph attributes. - for i in range(5): - G.nodes[i]['name'] = 'node{}'.format(i) - G.edges[0, 1]['name'] = 'edge01' - G.edges[3, 4]['name'] = 'edge34' - G.graph['name'] = 'graph' - # Get the subgraph induced by the first and last edges. - self.G = G - self.H = G.edge_subgraph([(0, 1), (3, 4)]) - - def test_correct_nodes(self): - """Tests that the subgraph has the correct nodes.""" - assert [0, 1, 3, 4] == sorted(self.H.nodes()) - - def test_correct_edges(self): - """Tests that the subgraph has the correct edges.""" - assert ([(0, 1, 'edge01'), (3, 4, 'edge34')] == - sorted(self.H.edges(data='name'))) - - def test_add_node(self): - """Tests that adding a node to the original graph does not - affect the nodes of the subgraph. - - """ - self.G.add_node(5) - assert [0, 1, 3, 4] == sorted(self.H.nodes()) - - def test_remove_node(self): - """Tests that removing a node in the original graph does - affect the nodes of the subgraph. - - """ - self.G.remove_node(0) - assert [1, 3, 4] == sorted(self.H.nodes()) - - def test_node_attr_dict(self): - """Tests that the node attribute dictionary of the two graphs is - the same object. - - """ - for v in self.H: - assert self.G.nodes[v] == self.H.nodes[v] - # Making a change to G should make a change in H and vice versa. - self.G.nodes[0]['name'] = 'foo' - assert self.G.nodes[0] == self.H.nodes[0] - self.H.nodes[1]['name'] = 'bar' - assert self.G.nodes[1] == self.H.nodes[1] - - def test_edge_attr_dict(self): - """Tests that the edge attribute dictionary of the two graphs is - the same object. - - """ - for u, v in self.H.edges(): - assert self.G.edges[u, v] == self.H.edges[u, v] - # Making a change to G should make a change in H and vice versa. - self.G.edges[0, 1]['name'] = 'foo' - assert (self.G.edges[0, 1]['name'] == - self.H.edges[0, 1]['name']) - self.H.edges[3, 4]['name'] = 'bar' - assert (self.G.edges[3, 4]['name'] == - self.H.edges[3, 4]['name']) - - def test_graph_attr_dict(self): - """Tests that the graph attribute dictionary of the two graphs - is the same object. - - """ - assert self.G.graph is self.H.graph diff --git a/extensions/fablabchemnitz/networkx/classes/tests/test_graph_historical.py b/extensions/fablabchemnitz/networkx/classes/tests/test_graph_historical.py deleted file mode 100644 index ccac3050..00000000 --- a/extensions/fablabchemnitz/networkx/classes/tests/test_graph_historical.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python -"""Original NetworkX graph tests""" -import networkx -import networkx as nx - -from .historical_tests import HistoricalTests - - -class TestGraphHistorical(HistoricalTests): - - @classmethod - def setup_class(cls): - HistoricalTests.setup_class() - cls.G = nx.Graph diff --git a/extensions/fablabchemnitz/networkx/classes/tests/test_graphviews.py b/extensions/fablabchemnitz/networkx/classes/tests/test_graphviews.py deleted file mode 100644 index f6c00368..00000000 --- a/extensions/fablabchemnitz/networkx/classes/tests/test_graphviews.py +++ /dev/null @@ -1,325 +0,0 @@ -import pytest - -import networkx as nx -from networkx.testing import assert_edges_equal, assert_nodes_equal - -# Note: SubGraph views are not tested here. They have their own testing file - - -class TestReverseView(object): - def setup(self): - self.G = nx.path_graph(9, create_using=nx.DiGraph()) - self.rv = nx.reverse_view(self.G) - - def test_pickle(self): - import pickle - rv = self.rv - prv = pickle.loads(pickle.dumps(rv, -1)) - assert rv._node == prv._node - assert rv._adj == prv._adj - assert rv.graph == prv.graph - - def test_contains(self): - assert (2, 3) in self.G.edges - assert (3, 2) not in self.G.edges - assert (2, 3) not in self.rv.edges - assert (3, 2) in self.rv.edges - - def test_iter(self): - expected = sorted(tuple(reversed(e)) for e in self.G.edges) - assert sorted(self.rv.edges) == expected - - def test_exceptions(self): - nxg = nx.graphviews - pytest.raises(nx.NetworkXNotImplemented, nxg.reverse_view, nx.Graph()) - - def test_subclass(self): - class MyGraph(nx.DiGraph): - def my_method(self): - return "me" - def to_directed_class(self): - return MyGraph() - - M = MyGraph() - M.add_edge(1, 2) - RM = nx.reverse_view(M) - print("RM class",RM.__class__) - RMC = RM.copy() - print("RMC class",RMC.__class__) - print(RMC.edges) - assert RMC.has_edge(2, 1) - assert RMC.my_method() == "me" - - -class TestMultiReverseView(object): - def setup(self): - self.G = nx.path_graph(9, create_using=nx.MultiDiGraph()) - self.G.add_edge(4, 5) - self.rv = nx.reverse_view(self.G) - - def test_pickle(self): - import pickle - rv = self.rv - prv = pickle.loads(pickle.dumps(rv, -1)) - assert rv._node == prv._node - assert rv._adj == prv._adj - assert rv.graph == prv.graph - - def test_contains(self): - assert (2, 3, 0) in self.G.edges - assert (3, 2, 0) not in self.G.edges - assert (2, 3, 0) not in self.rv.edges - assert (3, 2, 0) in self.rv.edges - assert (5, 4, 1) in self.rv.edges - assert (4, 5, 1) not in self.rv.edges - - def test_iter(self): - expected = sorted((v, u, k) for u, v, k in self.G.edges) - assert sorted(self.rv.edges) == expected - - def test_exceptions(self): - nxg = nx.graphviews - MG = nx.MultiGraph(self.G) - pytest.raises(nx.NetworkXNotImplemented, nxg.reverse_view, MG) - - -class TestToDirected(object): - def setup(self): - self.G = nx.path_graph(9) - self.dv = nx.to_directed(self.G) - self.MG = nx.path_graph(9, create_using=nx.MultiGraph()) - self.Mdv = nx.to_directed(self.MG) - - def test_directed(self): - assert not self.G.is_directed() - assert self.dv.is_directed() - - def test_already_directed(self): - dd = nx.to_directed(self.dv) - Mdd = nx.to_directed(self.Mdv) - assert_edges_equal(dd.edges, self.dv.edges) - assert_edges_equal(Mdd.edges, self.Mdv.edges) - - def test_pickle(self): - import pickle - dv = self.dv - pdv = pickle.loads(pickle.dumps(dv, -1)) - assert dv._node == pdv._node - assert dv._succ == pdv._succ - assert dv._pred == pdv._pred - assert dv.graph == pdv.graph - - def test_contains(self): - assert (2, 3) in self.G.edges - assert (3, 2) in self.G.edges - assert (2, 3) in self.dv.edges - assert (3, 2) in self.dv.edges - - def test_iter(self): - revd = [tuple(reversed(e)) for e in self.G.edges] - expected = sorted(list(self.G.edges) + revd) - assert sorted(self.dv.edges) == expected - - -class TestToUndirected(object): - def setup(self): - self.DG = nx.path_graph(9, create_using=nx.DiGraph()) - self.uv = nx.to_undirected(self.DG) - self.MDG = nx.path_graph(9, create_using=nx.MultiDiGraph()) - self.Muv = nx.to_undirected(self.MDG) - - def test_directed(self): - assert self.DG.is_directed() - assert not self.uv.is_directed() - - def test_already_directed(self): - uu = nx.to_undirected(self.uv) - Muu = nx.to_undirected(self.Muv) - assert_edges_equal(uu.edges, self.uv.edges) - assert_edges_equal(Muu.edges, self.Muv.edges) - - def test_pickle(self): - import pickle - uv = self.uv - puv = pickle.loads(pickle.dumps(uv, -1)) - assert uv._node == puv._node - assert uv._adj == puv._adj - assert uv.graph == puv.graph - assert hasattr(uv, '_graph') - - def test_contains(self): - assert (2, 3) in self.DG.edges - assert (3, 2) not in self.DG.edges - assert (2, 3) in self.uv.edges - assert (3, 2) in self.uv.edges - - def test_iter(self): - expected = sorted(self.DG.edges) - assert sorted(self.uv.edges) == expected - - -class TestChainsOfViews(object): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9) - cls.DG = nx.path_graph(9, create_using=nx.DiGraph()) - cls.MG = nx.path_graph(9, create_using=nx.MultiGraph()) - cls.MDG = nx.path_graph(9, create_using=nx.MultiDiGraph()) - cls.Gv = nx.to_undirected(cls.DG) - cls.DGv = nx.to_directed(cls.G) - cls.MGv = nx.to_undirected(cls.MDG) - cls.MDGv = nx.to_directed(cls.MG) - cls.Rv = cls.DG.reverse() - cls.MRv = cls.MDG.reverse() - cls.graphs = [cls.G, cls.DG, cls.MG, cls.MDG, - cls.Gv, cls.DGv, cls.MGv, cls.MDGv, - cls.Rv, cls.MRv] - for G in cls.graphs: - G.edges, G.nodes, G.degree - - def test_pickle(self): - import pickle - for G in self.graphs: - H = pickle.loads(pickle.dumps(G, -1)) - assert_edges_equal(H.edges, G.edges) - assert_nodes_equal(H.nodes, G.nodes) - - def test_subgraph_of_subgraph(self): - SGv = nx.subgraph(self.G, range(3, 7)) - SDGv = nx.subgraph(self.DG, range(3, 7)) - SMGv = nx.subgraph(self.MG, range(3, 7)) - SMDGv = nx.subgraph(self.MDG, range(3, 7)) - for G in self.graphs + [SGv, SDGv, SMGv, SMDGv]: - SG = nx.induced_subgraph(G, [4, 5, 6]) - assert list(SG) == [4, 5, 6] - SSG = SG.subgraph([6, 7]) - assert list(SSG) == [6] - # subgraph-subgraph chain is short-cut in base class method - assert SSG._graph is G - - def test_restricted_induced_subgraph_chains(self): - """ Test subgraph chains that both restrict and show nodes/edges. - - A restricted_view subgraph should allow induced subgraphs using - G.subgraph that automagically without a chain (meaning the result - is a subgraph view of the original graph not a subgraph-of-subgraph. - """ - hide_nodes = [3, 4, 5] - hide_edges = [(6, 7)] - RG = nx.restricted_view(self.G, hide_nodes, hide_edges) - nodes = [4, 5, 6, 7, 8] - SG = nx.induced_subgraph(RG, nodes) - SSG = RG.subgraph(nodes) - assert RG._graph is self.G - assert SSG._graph is self.G - assert SG._graph is RG - assert_edges_equal(SG.edges, SSG.edges) - # should be same as morphing the graph - CG = self.G.copy() - CG.remove_nodes_from(hide_nodes) - CG.remove_edges_from(hide_edges) - assert_edges_equal(CG.edges(nodes), SSG.edges) - CG.remove_nodes_from([0, 1, 2, 3]) - assert_edges_equal(CG.edges, SSG.edges) - # switch order: subgraph first, then restricted view - SSSG = self.G.subgraph(nodes) - RSG = nx.restricted_view(SSSG, hide_nodes, hide_edges) - assert RSG._graph is not self.G - assert_edges_equal(RSG.edges, CG.edges) - - def test_subgraph_copy(self): - for origG in self.graphs: - G = nx.OrderedGraph(origG) - SG = G.subgraph([4, 5, 6]) - H = SG.copy() - assert type(G) == type(H) - - def test_subgraph_todirected(self): - SG = nx.induced_subgraph(self.G, [4, 5, 6]) - SSG = SG.to_directed() - assert sorted(SSG) == [4, 5, 6] - assert sorted(SSG.edges) == [(4, 5), (5, 4), (5, 6), (6, 5)] - - def test_subgraph_toundirected(self): - SG = nx.induced_subgraph(self.G, [4, 5, 6]) - SSG = SG.to_undirected() - assert list(SSG) == [4, 5, 6] - assert sorted(SSG.edges) == [(4, 5), (5, 6)] - - def test_reverse_subgraph_toundirected(self): - G = self.DG.reverse(copy=False) - SG = G.subgraph([4, 5, 6]) - SSG = SG.to_undirected() - assert list(SSG) == [4, 5, 6] - assert sorted(SSG.edges) == [(4, 5), (5, 6)] - - def test_reverse_reverse_copy(self): - G = self.DG.reverse(copy=False) - H = G.reverse(copy=True) - assert H.nodes == self.DG.nodes - assert H.edges == self.DG.edges - G = self.MDG.reverse(copy=False) - H = G.reverse(copy=True) - assert H.nodes == self.MDG.nodes - assert H.edges == self.MDG.edges - - def test_subgraph_edgesubgraph_toundirected(self): - G = self.G.copy() - SG = G.subgraph([4, 5, 6]) - SSG = SG.edge_subgraph([(4, 5), (5, 4)]) - USSG = SSG.to_undirected() - assert list(USSG) == [4, 5] - assert sorted(USSG.edges) == [(4, 5)] - - def test_copy_subgraph(self): - G = self.G.copy() - SG = G.subgraph([4, 5, 6]) - CSG = SG.copy(as_view=True) - DCSG = SG.copy(as_view=False) - assert hasattr(CSG, '_graph') # is a view - assert not hasattr(DCSG, '_graph') # not a view - - def test_copy_disubgraph(self): - G = self.DG.copy() - SG = G.subgraph([4, 5, 6]) - CSG = SG.copy(as_view=True) - DCSG = SG.copy(as_view=False) - assert hasattr(CSG, '_graph') # is a view - assert not hasattr(DCSG, '_graph') # not a view - - def test_copy_multidisubgraph(self): - G = self.MDG.copy() - SG = G.subgraph([4, 5, 6]) - CSG = SG.copy(as_view=True) - DCSG = SG.copy(as_view=False) - assert hasattr(CSG, '_graph') # is a view - assert not hasattr(DCSG, '_graph') # not a view - - def test_copy_multisubgraph(self): - G = self.MG.copy() - SG = G.subgraph([4, 5, 6]) - CSG = SG.copy(as_view=True) - DCSG = SG.copy(as_view=False) - assert hasattr(CSG, '_graph') # is a view - assert not hasattr(DCSG, '_graph') # not a view - - def test_copy_of_view(self): - G = nx.OrderedMultiGraph(self.MGv) - assert G.__class__.__name__ == 'OrderedMultiGraph' - G = G.copy(as_view=True) - assert G.__class__.__name__ == 'OrderedMultiGraph' - - def test_subclass(self): - class MyGraph(nx.DiGraph): - def my_method(self): - return "me" - def to_directed_class(self): - return MyGraph() - - for origG in self.graphs: - G = MyGraph(origG) - SG = G.subgraph([4, 5, 6]) - H = SG.copy() - assert SG.my_method() == "me" - assert H.my_method() == "me" - assert not 3 in H or 3 in SG diff --git a/extensions/fablabchemnitz/networkx/classes/tests/test_multidigraph.py b/extensions/fablabchemnitz/networkx/classes/tests/test_multidigraph.py deleted file mode 100644 index 11ceca77..00000000 --- a/extensions/fablabchemnitz/networkx/classes/tests/test_multidigraph.py +++ /dev/null @@ -1,359 +0,0 @@ -#!/usr/bin/env python -import pytest -from networkx.testing import assert_edges_equal -import networkx as nx -from .test_multigraph import BaseMultiGraphTester, TestMultiGraph -from .test_multigraph import TestEdgeSubgraph as TestMultiGraphEdgeSubgraph - - -class BaseMultiDiGraphTester(BaseMultiGraphTester): - def test_edges(self): - G = self.K3 - edges = [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)] - assert sorted(G.edges()) == edges - assert sorted(G.edges(0)) == [(0, 1), (0, 2)] - pytest.raises((KeyError, nx.NetworkXError), G.edges, -1) - - def test_edges_data(self): - G = self.K3 - edges = [(0, 1, {}), (0, 2, {}), (1, 0, {}), - (1, 2, {}), (2, 0, {}), (2, 1, {})] - assert sorted(G.edges(data=True)) == edges - assert sorted(G.edges(0, data=True)) == [(0, 1, {}), (0, 2, {})] - pytest.raises((KeyError, nx.NetworkXError), G.neighbors, -1) - - def test_edges_multi(self): - G = self.K3 - assert (sorted(G.edges()) == - [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]) - assert sorted(G.edges(0)) == [(0, 1), (0, 2)] - G.add_edge(0, 1) - assert (sorted(G.edges()) == - [(0, 1), (0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]) - - def test_out_edges(self): - G = self.K3 - assert (sorted(G.out_edges()) == - [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]) - assert sorted(G.out_edges(0)) == [(0, 1), (0, 2)] - pytest.raises((KeyError, nx.NetworkXError), G.out_edges, -1) - assert sorted(G.out_edges(0, keys=True)) == [(0, 1, 0), (0, 2, 0)] - - def test_out_edges_multi(self): - G = self.K3 - assert (sorted(G.out_edges()) == - [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]) - assert sorted(G.out_edges(0)) == [(0, 1), (0, 2)] - G.add_edge(0, 1, 2) - assert (sorted(G.out_edges()) == - [(0, 1), (0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]) - - def test_out_edges_data(self): - G = self.K3 - assert sorted(G.edges(0, data=True)) == [(0, 1, {}), (0, 2, {})] - G.remove_edge(0, 1) - G.add_edge(0, 1, data=1) - assert (sorted(G.edges(0, data=True)) == - [(0, 1, {'data': 1}), (0, 2, {})]) - assert (sorted(G.edges(0, data='data')) == - [(0, 1, 1), (0, 2, None)]) - assert (sorted(G.edges(0, data='data', default=-1)) == - [(0, 1, 1), (0, 2, -1)]) - - def test_in_edges(self): - G = self.K3 - assert (sorted(G.in_edges()) == - [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]) - assert sorted(G.in_edges(0)) == [(1, 0), (2, 0)] - pytest.raises((KeyError, nx.NetworkXError), G.in_edges, -1) - G.add_edge(0, 1, 2) - assert (sorted(G.in_edges()) == - [(0, 1), (0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]) - assert sorted(G.in_edges(0, keys=True)) == [(1, 0, 0), (2, 0, 0)] - - def test_in_edges_no_keys(self): - G = self.K3 - assert (sorted(G.in_edges()) == - [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]) - assert sorted(G.in_edges(0)) == [(1, 0), (2, 0)] - G.add_edge(0, 1, 2) - assert (sorted(G.in_edges()) == - [(0, 1), (0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]) - - assert (sorted(G.in_edges(data=True, keys=False)) == - [(0, 1, {}), (0, 1, {}), (0, 2, {}), (1, 0, {}), - (1, 2, {}), (2, 0, {}), (2, 1, {})]) - - def test_in_edges_data(self): - G = self.K3 - assert (sorted(G.in_edges(0, data=True)) == - [(1, 0, {}), (2, 0, {})]) - G.remove_edge(1, 0) - G.add_edge(1, 0, data=1) - assert (sorted(G.in_edges(0, data=True)) == - [(1, 0, {'data': 1}), (2, 0, {})]) - assert (sorted(G.in_edges(0, data='data')) == - [(1, 0, 1), (2, 0, None)]) - assert (sorted(G.in_edges(0, data='data', default=-1)) == - [(1, 0, 1), (2, 0, -1)]) - - def is_shallow(self, H, G): - # graph - assert G.graph['foo'] == H.graph['foo'] - G.graph['foo'].append(1) - assert G.graph['foo'] == H.graph['foo'] - # node - assert G.nodes[0]['foo'] == H.nodes[0]['foo'] - G.nodes[0]['foo'].append(1) - assert G.nodes[0]['foo'] == H.nodes[0]['foo'] - # edge - assert G[1][2][0]['foo'] == H[1][2][0]['foo'] - G[1][2][0]['foo'].append(1) - assert G[1][2][0]['foo'] == H[1][2][0]['foo'] - - def is_deep(self, H, G): - # graph - assert G.graph['foo'] == H.graph['foo'] - G.graph['foo'].append(1) - assert G.graph['foo'] != H.graph['foo'] - # node - assert G.nodes[0]['foo'] == H.nodes[0]['foo'] - G.nodes[0]['foo'].append(1) - assert G.nodes[0]['foo'] != H.nodes[0]['foo'] - # edge - assert G[1][2][0]['foo'] == H[1][2][0]['foo'] - G[1][2][0]['foo'].append(1) - assert G[1][2][0]['foo'] != H[1][2][0]['foo'] - - def test_to_undirected(self): - # MultiDiGraph -> MultiGraph changes number of edges so it is - # not a copy operation... use is_shallow, not is_shallow_copy - G = self.K3 - self.add_attributes(G) - H = nx.MultiGraph(G) - # self.is_shallow(H,G) - # the result is traversal order dependent so we - # can't use the is_shallow() test here. - try: - assert_edges_equal(H.edges(), [(0, 1), (1, 2), (2, 0)]) - except AssertionError: - assert_edges_equal(H.edges(), [(0, 1), (1, 2), (1, 2), (2, 0)]) - H = G.to_undirected() - self.is_deep(H, G) - - def test_has_successor(self): - G = self.K3 - assert G.has_successor(0, 1) == True - assert G.has_successor(0, -1) == False - - def test_successors(self): - G = self.K3 - assert sorted(G.successors(0)) == [1, 2] - pytest.raises((KeyError, nx.NetworkXError), G.successors, -1) - - def test_has_predecessor(self): - G = self.K3 - assert G.has_predecessor(0, 1) == True - assert G.has_predecessor(0, -1) == False - - def test_predecessors(self): - G = self.K3 - assert sorted(G.predecessors(0)) == [1, 2] - pytest.raises((KeyError, nx.NetworkXError), G.predecessors, -1) - - def test_degree(self): - G = self.K3 - assert sorted(G.degree()) == [(0, 4), (1, 4), (2, 4)] - assert dict(G.degree()) == {0: 4, 1: 4, 2: 4} - assert G.degree(0) == 4 - assert list(G.degree(iter([0]))) == [(0, 4)] - G.add_edge(0, 1, weight=0.3, other=1.2) - assert (sorted(G.degree(weight='weight')) == - [(0, 4.3), (1, 4.3), (2, 4)]) - assert (sorted(G.degree(weight='other')) == - [(0, 5.2), (1, 5.2), (2, 4)]) - - def test_in_degree(self): - G = self.K3 - assert sorted(G.in_degree()) == [(0, 2), (1, 2), (2, 2)] - assert dict(G.in_degree()) == {0: 2, 1: 2, 2: 2} - assert G.in_degree(0) == 2 - assert list(G.in_degree(iter([0]))) == [(0, 2)] - assert G.in_degree(0, weight='weight') == 2 - - def test_out_degree(self): - G = self.K3 - assert sorted(G.out_degree()) == [(0, 2), (1, 2), (2, 2)] - assert dict(G.out_degree()) == {0: 2, 1: 2, 2: 2} - assert G.out_degree(0) == 2 - assert list(G.out_degree(iter([0]))) == [(0, 2)] - assert G.out_degree(0, weight='weight') == 2 - - def test_size(self): - G = self.K3 - assert G.size() == 6 - assert G.number_of_edges() == 6 - G.add_edge(0, 1, weight=0.3, other=1.2) - assert round(G.size(weight='weight'), 2) == 6.3 - assert round(G.size(weight='other'), 2) == 7.2 - - def test_to_undirected_reciprocal(self): - G = self.Graph() - G.add_edge(1, 2) - assert G.to_undirected().has_edge(1, 2) - assert not G.to_undirected(reciprocal=True).has_edge(1, 2) - G.add_edge(2, 1) - assert G.to_undirected(reciprocal=True).has_edge(1, 2) - - def test_reverse_copy(self): - G = nx.MultiDiGraph([(0, 1), (0, 1)]) - R = G.reverse() - assert sorted(R.edges()) == [(1, 0), (1, 0)] - R.remove_edge(1, 0) - assert sorted(R.edges()) == [(1, 0)] - assert sorted(G.edges()) == [(0, 1), (0, 1)] - - def test_reverse_nocopy(self): - G = nx.MultiDiGraph([(0, 1), (0, 1)]) - R = G.reverse(copy=False) - assert sorted(R.edges()) == [(1, 0), (1, 0)] - pytest.raises(nx.NetworkXError, R.remove_edge, 1, 0) - - -class TestMultiDiGraph(BaseMultiDiGraphTester, TestMultiGraph): - def setup_method(self): - self.Graph = nx.MultiDiGraph - # build K3 - self.k3edges = [(0, 1), (0, 2), (1, 2)] - self.k3nodes = [0, 1, 2] - self.K3 = self.Graph() - self.K3._adj = {0: {}, 1: {}, 2: {}} - self.K3._succ = self.K3._adj - self.K3._pred = {0: {}, 1: {}, 2: {}} - for u in self.k3nodes: - for v in self.k3nodes: - if u == v: - continue - d = {0: {}} - self.K3._succ[u][v] = d - self.K3._pred[v][u] = d - self.K3._node = {} - self.K3._node[0] = {} - self.K3._node[1] = {} - self.K3._node[2] = {} - - def test_add_edge(self): - G = self.Graph() - G.add_edge(0, 1) - assert G._adj == {0: {1: {0: {}}}, 1: {}} - assert G._succ == {0: {1: {0: {}}}, 1: {}} - assert G._pred == {0: {}, 1: {0: {0: {}}}} - G = self.Graph() - G.add_edge(*(0, 1)) - assert G._adj == {0: {1: {0: {}}}, 1: {}} - assert G._succ == {0: {1: {0: {}}}, 1: {}} - assert G._pred == {0: {}, 1: {0: {0: {}}}} - - def test_add_edges_from(self): - G = self.Graph() - G.add_edges_from([(0, 1), (0, 1, {'weight': 3})]) - assert G._adj == {0: {1: {0: {}, 1: {'weight': 3}}}, 1: {}} - assert G._succ == {0: {1: {0: {}, 1: {'weight': 3}}}, 1: {}} - assert G._pred == {0: {}, 1: {0: {0: {}, 1: {'weight': 3}}}} - - G.add_edges_from([(0, 1), (0, 1, {'weight': 3})], weight=2) - assert G._succ == {0: {1: {0: {}, - 1: {'weight': 3}, - 2: {'weight': 2}, - 3: {'weight': 3}}}, - 1: {}} - assert G._pred == {0: {}, 1: {0: {0: {}, 1: {'weight': 3}, - 2: {'weight': 2}, - 3: {'weight': 3}}}} - - G = self.Graph() - edges = [(0, 1, {'weight': 3}), (0, 1, (('weight', 2),)), - (0, 1, 5), (0, 1, 's')] - G.add_edges_from(edges) - keydict = {0: {'weight': 3}, 1: {'weight': 2}, 5: {}, 's': {}} - assert G._succ == {0: {1: keydict}, 1: {}} - assert G._pred == {1: {0: keydict}, 0: {}} - - # too few in tuple - pytest.raises(nx.NetworkXError, G.add_edges_from, [(0,)]) - # too many in tuple - pytest.raises(nx.NetworkXError, G.add_edges_from, [(0, 1, 2, 3, 4)]) - # not a tuple - pytest.raises(TypeError, G.add_edges_from, [0]) - - def test_remove_edge(self): - G = self.K3 - G.remove_edge(0, 1) - assert G._succ == {0: {2: {0: {}}}, - 1: {0: {0: {}}, 2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}} - assert G._pred == {0: {1: {0: {}}, 2: {0: {}}}, - 1: {2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}} - pytest.raises((KeyError, nx.NetworkXError), G.remove_edge, -1, 0) - pytest.raises((KeyError, nx.NetworkXError), G.remove_edge, 0, 2, - key=1) - - def test_remove_multiedge(self): - G = self.K3 - G.add_edge(0, 1, key='parallel edge') - G.remove_edge(0, 1, key='parallel edge') - assert G._adj == {0: {1: {0: {}}, 2: {0: {}}}, - 1: {0: {0: {}}, 2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}} - - assert G._succ == {0: {1: {0: {}}, 2: {0: {}}}, - 1: {0: {0: {}}, 2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}} - - assert G._pred == {0: {1: {0: {}}, 2: {0: {}}}, - 1: {0: {0: {}}, 2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}} - G.remove_edge(0, 1) - assert G._succ == {0: {2: {0: {}}}, - 1: {0: {0: {}}, 2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}} - assert G._pred == {0: {1: {0: {}}, 2: {0: {}}}, - 1: {2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}} - pytest.raises((KeyError, nx.NetworkXError), G.remove_edge, -1, 0) - - def test_remove_edges_from(self): - G = self.K3 - G.remove_edges_from([(0, 1)]) - assert G._succ == {0: {2: {0: {}}}, - 1: {0: {0: {}}, 2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}} - assert G._pred == {0: {1: {0: {}}, 2: {0: {}}}, - 1: {2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}} - G.remove_edges_from([(0, 0)]) # silent fail - - -class TestEdgeSubgraph(TestMultiGraphEdgeSubgraph): - """Unit tests for the :meth:`MultiDiGraph.edge_subgraph` method.""" - - def setup_method(self): - # Create a quadruply-linked path graph on five nodes. - G = nx.MultiDiGraph() - nx.add_path(G, range(5)) - nx.add_path(G, range(5)) - nx.add_path(G, reversed(range(5))) - nx.add_path(G, reversed(range(5))) - # Add some node, edge, and graph attributes. - for i in range(5): - G.nodes[i]['name'] = 'node{}'.format(i) - G.adj[0][1][0]['name'] = 'edge010' - G.adj[0][1][1]['name'] = 'edge011' - G.adj[3][4][0]['name'] = 'edge340' - G.adj[3][4][1]['name'] = 'edge341' - G.graph['name'] = 'graph' - # Get the subgraph induced by one of the first edges and one of - # the last edges. - self.G = G - self.H = G.edge_subgraph([(0, 1, 0), (3, 4, 1)]) diff --git a/extensions/fablabchemnitz/networkx/classes/tests/test_multigraph.py b/extensions/fablabchemnitz/networkx/classes/tests/test_multigraph.py deleted file mode 100644 index 13b4f2e0..00000000 --- a/extensions/fablabchemnitz/networkx/classes/tests/test_multigraph.py +++ /dev/null @@ -1,356 +0,0 @@ -#!/usr/bin/env python - -import pytest - -import networkx as nx -from networkx.testing.utils import * - -from .test_graph import BaseAttrGraphTester, TestGraph - - -class BaseMultiGraphTester(BaseAttrGraphTester): - def test_has_edge(self): - G = self.K3 - assert G.has_edge(0, 1) == True - assert G.has_edge(0, -1) == False - assert G.has_edge(0, 1, 0) == True - assert G.has_edge(0, 1, 1) == False - - def test_get_edge_data(self): - G = self.K3 - assert G.get_edge_data(0, 1) == {0: {}} - assert G[0][1] == {0: {}} - assert G[0][1][0] == {} - assert G.get_edge_data(10, 20) == None - assert G.get_edge_data(0, 1, 0) == {} - - def test_adjacency(self): - G = self.K3 - assert (dict(G.adjacency()) == - {0: {1: {0: {}}, 2: {0: {}}}, - 1: {0: {0: {}}, 2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}}) - - def deepcopy_edge_attr(self, H, G): - assert G[1][2][0]['foo'] == H[1][2][0]['foo'] - G[1][2][0]['foo'].append(1) - assert G[1][2][0]['foo'] != H[1][2][0]['foo'] - - def shallow_copy_edge_attr(self, H, G): - assert G[1][2][0]['foo'] == H[1][2][0]['foo'] - G[1][2][0]['foo'].append(1) - assert G[1][2][0]['foo'] == H[1][2][0]['foo'] - - def graphs_equal(self, H, G): - assert G._adj == H._adj - assert G._node == H._node - assert G.graph == H.graph - assert G.name == H.name - if not G.is_directed() and not H.is_directed(): - assert H._adj[1][2][0] is H._adj[2][1][0] - assert G._adj[1][2][0] is G._adj[2][1][0] - else: # at least one is directed - if not G.is_directed(): - G._pred = G._adj - G._succ = G._adj - if not H.is_directed(): - H._pred = H._adj - H._succ = H._adj - assert G._pred == H._pred - assert G._succ == H._succ - assert H._succ[1][2][0] is H._pred[2][1][0] - assert G._succ[1][2][0] is G._pred[2][1][0] - - def same_attrdict(self, H, G): - # same attrdict in the edgedata - old_foo = H[1][2][0]['foo'] - H.adj[1][2][0]['foo'] = 'baz' - assert G._adj == H._adj - H.adj[1][2][0]['foo'] = old_foo - assert G._adj == H._adj - - old_foo = H.nodes[0]['foo'] - H.nodes[0]['foo'] = 'baz' - assert G._node == H._node - H.nodes[0]['foo'] = old_foo - assert G._node == H._node - - def different_attrdict(self, H, G): - # used by graph_equal_but_different - old_foo = H[1][2][0]['foo'] - H.adj[1][2][0]['foo'] = 'baz' - assert G._adj != H._adj - H.adj[1][2][0]['foo'] = old_foo - assert G._adj == H._adj - - old_foo = H.nodes[0]['foo'] - H.nodes[0]['foo'] = 'baz' - assert G._node != H._node - H.nodes[0]['foo'] = old_foo - assert G._node == H._node - - def test_to_undirected(self): - G = self.K3 - self.add_attributes(G) - H = nx.MultiGraph(G) - self.is_shallow_copy(H, G) - H = G.to_undirected() - self.is_deepcopy(H, G) - - def test_to_directed(self): - G = self.K3 - self.add_attributes(G) - H = nx.MultiDiGraph(G) - self.is_shallow_copy(H, G) - H = G.to_directed() - self.is_deepcopy(H, G) - - def test_number_of_edges_selfloops(self): - G = self.K3 - G.add_edge(0, 0) - G.add_edge(0, 0) - G.add_edge(0, 0, key='parallel edge') - G.remove_edge(0, 0, key='parallel edge') - assert G.number_of_edges(0, 0) == 2 - G.remove_edge(0, 0) - assert G.number_of_edges(0, 0) == 1 - - def test_edge_lookup(self): - G = self.Graph() - G.add_edge(1, 2, foo='bar') - G.add_edge(1, 2, 'key', foo='biz') - assert_edges_equal(G.edges[1, 2, 0], {'foo': 'bar'}) - assert_edges_equal(G.edges[1, 2, 'key'], {'foo': 'biz'}) - - def test_edge_attr4(self): - G = self.Graph() - G.add_edge(1, 2, key=0, data=7, spam='bar', bar='foo') - assert_edges_equal(G.edges(data=True), - [(1, 2, {'data': 7, 'spam': 'bar', 'bar': 'foo'})]) - G[1][2][0]['data'] = 10 # OK to set data like this - assert_edges_equal(G.edges(data=True), - [(1, 2, {'data': 10, 'spam': 'bar', 'bar': 'foo'})]) - - G.adj[1][2][0]['data'] = 20 - assert_edges_equal(G.edges(data=True), - [(1, 2, {'data': 20, 'spam': 'bar', 'bar': 'foo'})]) - G.edges[1, 2, 0]['data'] = 21 # another spelling, "edge" - assert_edges_equal(G.edges(data=True), - [(1, 2, {'data': 21, 'spam': 'bar', 'bar': 'foo'})]) - G.adj[1][2][0]['listdata'] = [20, 200] - G.adj[1][2][0]['weight'] = 20 - assert_edges_equal(G.edges(data=True), - [(1, 2, {'data': 21, 'spam': 'bar', 'bar': 'foo', - 'listdata': [20, 200], 'weight':20})]) - - -class TestMultiGraph(BaseMultiGraphTester, TestGraph): - def setup_method(self): - self.Graph = nx.MultiGraph - # build K3 - ed1, ed2, ed3 = ({0: {}}, {0: {}}, {0: {}}) - self.k3adj = {0: {1: ed1, 2: ed2}, - 1: {0: ed1, 2: ed3}, - 2: {0: ed2, 1: ed3}} - self.k3edges = [(0, 1), (0, 2), (1, 2)] - self.k3nodes = [0, 1, 2] - self.K3 = self.Graph() - self.K3._adj = self.k3adj - self.K3._node = {} - self.K3._node[0] = {} - self.K3._node[1] = {} - self.K3._node[2] = {} - - def test_data_input(self): - G = self.Graph({1: [2], 2: [1]}, name="test") - assert G.name == "test" - expected = [(1, {2: {0: {}}}), (2, {1: {0: {}}})] - assert sorted(G.adj.items()) == expected - - def test_getitem(self): - G = self.K3 - assert G[0] == {1: {0: {}}, 2: {0: {}}} - with pytest.raises(KeyError): - G.__getitem__('j') - with pytest.raises(TypeError): - G.__getitem__(['A']) - - def test_remove_node(self): - G = self.K3 - G.remove_node(0) - assert G.adj == {1: {2: {0: {}}}, 2: {1: {0: {}}}} - with pytest.raises(nx.NetworkXError): - G.remove_node(-1) - - def test_add_edge(self): - G = self.Graph() - G.add_edge(0, 1) - assert G.adj == {0: {1: {0: {}}}, 1: {0: {0: {}}}} - G = self.Graph() - G.add_edge(*(0, 1)) - assert G.adj == {0: {1: {0: {}}}, 1: {0: {0: {}}}} - - def test_add_edge_conflicting_key(self): - G = self.Graph() - G.add_edge(0, 1, key=1) - G.add_edge(0, 1) - assert G.number_of_edges() == 2 - G = self.Graph() - G.add_edges_from([(0, 1, 1, {})]) - G.add_edges_from([(0, 1)]) - assert G.number_of_edges() == 2 - - def test_add_edges_from(self): - G = self.Graph() - G.add_edges_from([(0, 1), (0, 1, {'weight': 3})]) - assert G.adj == {0: {1: {0: {}, 1: {'weight': 3}}}, - 1: {0: {0: {}, 1: {'weight': 3}}}} - G.add_edges_from([(0, 1), (0, 1, {'weight': 3})], weight=2) - assert G.adj == {0: {1: {0: {}, 1: {'weight': 3}, - 2: {'weight': 2}, 3: {'weight': 3}}}, - 1: {0: {0: {}, 1: {'weight': 3}, - 2: {'weight': 2}, 3: {'weight': 3}}}} - G = self.Graph() - edges = [(0, 1, {'weight': 3}), (0, 1, (('weight', 2),)), - (0, 1, 5), (0, 1, 's')] - G.add_edges_from(edges) - keydict = {0: {'weight': 3}, 1: {'weight': 2}, 5: {}, 's': {}} - assert G._adj == {0: {1: keydict}, 1: {0: keydict}} - - # too few in tuple - with pytest.raises(nx.NetworkXError): - G.add_edges_from([(0,)]) - # too many in tuple - with pytest.raises(nx.NetworkXError): - G.add_edges_from([(0, 1, 2, 3, 4)]) - # not a tuple - with pytest.raises(TypeError): - G.add_edges_from([0]) - - def test_remove_edge(self): - G = self.K3 - G.remove_edge(0, 1) - assert G.adj == {0: {2: {0: {}}}, - 1: {2: {0: {}}}, - 2: {0: {0: {}}, - 1: {0: {}}}} - - with pytest.raises(nx.NetworkXError): - G.remove_edge(-1, 0) - with pytest.raises(nx.NetworkXError): - G.remove_edge(0, 2, key=1) - - def test_remove_edges_from(self): - G = self.K3.copy() - G.remove_edges_from([(0, 1)]) - kd = {0: {}} - assert G.adj == {0: {2: kd}, 1: {2: kd}, 2: {0: kd, 1: kd}} - G.remove_edges_from([(0, 0)]) # silent fail - self.K3.add_edge(0, 1) - G = self.K3.copy() - G.remove_edges_from(list(G.edges(data=True, keys=True))) - assert G.adj == {0: {}, 1: {}, 2: {}} - G = self.K3.copy() - G.remove_edges_from(list(G.edges(data=False, keys=True))) - assert G.adj == {0: {}, 1: {}, 2: {}} - G = self.K3.copy() - G.remove_edges_from(list(G.edges(data=False, keys=False))) - assert G.adj == {0: {}, 1: {}, 2: {}} - G = self.K3.copy() - G.remove_edges_from([(0, 1, 0), (0, 2, 0, {}), (1, 2)]) - assert G.adj == {0: {1: {1: {}}}, 1: {0: {1: {}}}, 2: {}} - - def test_remove_multiedge(self): - G = self.K3 - G.add_edge(0, 1, key='parallel edge') - G.remove_edge(0, 1, key='parallel edge') - assert G.adj == {0: {1: {0: {}}, 2: {0: {}}}, - 1: {0: {0: {}}, 2: {0: {}}}, - 2: {0: {0: {}}, 1: {0: {}}}} - G.remove_edge(0, 1) - kd = {0: {}} - assert G.adj == {0: {2: kd}, 1: {2: kd}, 2: {0: kd, 1: kd}} - with pytest.raises(nx.NetworkXError): - G.remove_edge(-1, 0) - - -class TestEdgeSubgraph(object): - """Unit tests for the :meth:`MultiGraph.edge_subgraph` method.""" - - def setup_method(self): - # Create a doubly-linked path graph on five nodes. - G = nx.MultiGraph() - nx.add_path(G, range(5)) - nx.add_path(G, range(5)) - # Add some node, edge, and graph attributes. - for i in range(5): - G.nodes[i]['name'] = 'node{}'.format(i) - G.adj[0][1][0]['name'] = 'edge010' - G.adj[0][1][1]['name'] = 'edge011' - G.adj[3][4][0]['name'] = 'edge340' - G.adj[3][4][1]['name'] = 'edge341' - G.graph['name'] = 'graph' - # Get the subgraph induced by one of the first edges and one of - # the last edges. - self.G = G - self.H = G.edge_subgraph([(0, 1, 0), (3, 4, 1)]) - - def test_correct_nodes(self): - """Tests that the subgraph has the correct nodes.""" - assert [0, 1, 3, 4] == sorted(self.H.nodes()) - - def test_correct_edges(self): - """Tests that the subgraph has the correct edges.""" - assert ([(0, 1, 0, 'edge010'), (3, 4, 1, 'edge341')] == - sorted(self.H.edges(keys=True, data='name'))) - - def test_add_node(self): - """Tests that adding a node to the original graph does not - affect the nodes of the subgraph. - - """ - self.G.add_node(5) - assert [0, 1, 3, 4] == sorted(self.H.nodes()) - - def test_remove_node(self): - """Tests that removing a node in the original graph does - affect the nodes of the subgraph. - - """ - self.G.remove_node(0) - assert [1, 3, 4] == sorted(self.H.nodes()) - - def test_node_attr_dict(self): - """Tests that the node attribute dictionary of the two graphs is - the same object. - - """ - for v in self.H: - assert self.G.nodes[v] == self.H.nodes[v] - # Making a change to G should make a change in H and vice versa. - self.G.nodes[0]['name'] = 'foo' - assert self.G.nodes[0] == self.H.nodes[0] - self.H.nodes[1]['name'] = 'bar' - assert self.G.nodes[1] == self.H.nodes[1] - - def test_edge_attr_dict(self): - """Tests that the edge attribute dictionary of the two graphs is - the same object. - - """ - for u, v, k in self.H.edges(keys=True): - assert self.G._adj[u][v][k] == self.H._adj[u][v][k] - # Making a change to G should make a change in H and vice versa. - self.G._adj[0][1][0]['name'] = 'foo' - assert (self.G._adj[0][1][0]['name'] == - self.H._adj[0][1][0]['name']) - self.H._adj[3][4][1]['name'] = 'bar' - assert (self.G._adj[3][4][1]['name'] == - self.H._adj[3][4][1]['name']) - - def test_graph_attr_dict(self): - """Tests that the graph attribute dictionary of the two graphs - is the same object. - - """ - assert self.G.graph is self.H.graph diff --git a/extensions/fablabchemnitz/networkx/classes/tests/test_ordered.py b/extensions/fablabchemnitz/networkx/classes/tests/test_ordered.py deleted file mode 100644 index d505e26c..00000000 --- a/extensions/fablabchemnitz/networkx/classes/tests/test_ordered.py +++ /dev/null @@ -1,40 +0,0 @@ -import networkx as nx - - -class SmokeTestOrdered(object): - # Just test instantiation. - def test_graph(self): - G = nx.OrderedGraph() - - def test_digraph(self): - G = nx.OrderedDiGraph() - - def test_multigraph(self): - G = nx.OrderedMultiGraph() - - def test_multidigraph(self): - G = nx.OrderedMultiDiGraph() - - -class TestOrderedFeatures(object): - @classmethod - def setup_class(cls): - cls.G = nx.OrderedDiGraph() - cls.G.add_nodes_from([1, 2, 3]) - cls.G.add_edges_from([(2, 3), (1, 3)]) - - def test_subgraph_order(self): - G = self.G - G_sub = G.subgraph([1, 2, 3]) - assert list(G.nodes) == list(G_sub.nodes) - assert list(G.edges) == list(G_sub.edges) - assert list(G.pred[3]) == list(G_sub.pred[3]) - assert [2, 1] == list(G_sub.pred[3]) - assert [] == list(G_sub.succ[3]) - - G_sub = nx.induced_subgraph(G, [1, 2, 3]) - assert list(G.nodes) == list(G_sub.nodes) - assert list(G.edges) == list(G_sub.edges) - assert list(G.pred[3]) == list(G_sub.pred[3]) - assert [2, 1] == list(G_sub.pred[3]) - assert [] == list(G_sub.succ[3]) diff --git a/extensions/fablabchemnitz/networkx/classes/tests/test_reportviews.py b/extensions/fablabchemnitz/networkx/classes/tests/test_reportviews.py deleted file mode 100644 index 44817191..00000000 --- a/extensions/fablabchemnitz/networkx/classes/tests/test_reportviews.py +++ /dev/null @@ -1,1150 +0,0 @@ -import pytest - -import networkx as nx - - -# Nodes -class TestNodeView(object): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9) - cls.nv = cls.G.nodes # NodeView(G) - - def test_pickle(self): - import pickle - nv = self.nv - pnv = pickle.loads(pickle.dumps(nv, -1)) - assert nv == pnv - assert nv.__slots__ == pnv.__slots__ - - def test_str(self): - assert str(self.nv) == "[0, 1, 2, 3, 4, 5, 6, 7, 8]" - - def test_repr(self): - assert repr(self.nv) == "NodeView((0, 1, 2, 3, 4, 5, 6, 7, 8))" - - def test_contains(self): - G = self.G.copy() - nv = G.nodes - assert 7 in nv - assert not 9 in nv - G.remove_node(7) - G.add_node(9) - assert not 7 in nv - assert 9 in nv - - def test_getitem(self): - G = self.G.copy() - nv = G.nodes - G.nodes[3]['foo'] = 'bar' - assert nv[7] == {} - assert nv[3] == {'foo': 'bar'} - - def test_iter(self): - nv = self.nv - for i, n in enumerate(nv): - assert i == n - inv = iter(nv) - assert next(inv) == 0 - assert iter(nv) != nv - assert iter(inv) == inv - inv2 = iter(nv) - next(inv2) - assert list(inv) == list(inv2) - # odd case where NodeView calls NodeDataView with data=False - nnv = nv(data=False) - for i, n in enumerate(nnv): - assert i == n - - def test_call(self): - nodes = self.nv - assert nodes is nodes() - assert nodes is not nodes(data=True) - assert nodes is not nodes(data='weight') - - -class TestNodeDataView(object): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9) - cls.nv = cls.G.nodes.data() # NodeDataView(G) - cls.ndv = cls.G.nodes.data(True) - cls.nwv = cls.G.nodes.data('foo') - - def test_viewtype(self): - nv = self.G.nodes - ndvfalse = nv.data(False) - assert nv is ndvfalse - assert nv is not self.ndv - - def test_pickle(self): - import pickle - nv = self.nv - pnv = pickle.loads(pickle.dumps(nv, -1)) - assert nv == pnv - assert nv.__slots__ == pnv.__slots__ - - def test_str(self): - msg = str([(n, {}) for n in range(9)]) - assert str(self.ndv) == msg - - def test_repr(self): - msg = "NodeDataView({0: {}, 1: {}, 2: {}, 3: {}, " + \ - "4: {}, 5: {}, 6: {}, 7: {}, 8: {}})" - assert repr(self.ndv) == msg - - def test_contains(self): - G = self.G.copy() - nv = G.nodes.data() - nwv = G.nodes.data('foo') - G.nodes[3]['foo'] = 'bar' - assert (7, {}) in nv - assert (3, {'foo': 'bar'}) in nv - assert (3, 'bar') in nwv - assert (7, None) in nwv - # default - nwv_def = G.nodes(data='foo', default='biz') - assert (7, 'biz') in nwv_def - assert (3, 'bar') in nwv_def - - def test_getitem(self): - G = self.G.copy() - nv = G.nodes - G.nodes[3]['foo'] = 'bar' - assert nv[3] == {'foo': 'bar'} - # default - nwv_def = G.nodes(data='foo', default='biz') - assert nwv_def[7], 'biz' - assert nwv_def[3] == 'bar' - - def test_iter(self): - G = self.G.copy() - nv = G.nodes.data() - ndv = G.nodes.data(True) - nwv = G.nodes.data('foo') - for i, (n, d) in enumerate(nv): - assert i == n - assert d == {} - inv = iter(nv) - assert next(inv) == (0, {}) - G.nodes[3]['foo'] = 'bar' - # default - for n, d in nv: - if n == 3: - assert d == {'foo': 'bar'} - else: - assert d == {} - # data=True - for n, d in ndv: - if n == 3: - assert d == {'foo': 'bar'} - else: - assert d == {} - # data='foo' - for n, d in nwv: - if n == 3: - assert d == 'bar' - else: - assert d == None - # data='foo', default=1 - for n, d in G.nodes.data('foo', default=1): - if n == 3: - assert d == 'bar' - else: - assert d == 1 - - -def test_nodedataview_unhashable(): - G = nx.path_graph(9) - G.nodes[3]['foo'] = 'bar' - nvs = [G.nodes.data()] - nvs.append(G.nodes.data(True)) - H = G.copy() - H.nodes[4]['foo'] = {1, 2, 3} - nvs.append(H.nodes.data(True)) - # raise unhashable - for nv in nvs: - pytest.raises(TypeError, set, nv) - pytest.raises(TypeError, eval, 'nv | nv', locals()) - # no raise... hashable - Gn = G.nodes.data(False) - set(Gn) - Gn | Gn - Gn = G.nodes.data('foo') - set(Gn) - Gn | Gn - - -class TestNodeViewSetOps(object): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9) - cls.G.nodes[3]['foo'] = 'bar' - cls.nv = cls.G.nodes - - def n_its(self, nodes): - return {node for node in nodes} - - def test_len(self): - G = self.G.copy() - nv = G.nodes - assert len(nv) == 9 - G.remove_node(7) - assert len(nv) == 8 - G.add_node(9) - assert len(nv) == 9 - - def test_and(self): - # print("G & H nodes:", gnv & hnv) - nv = self.nv - some_nodes = self.n_its(range(5, 12)) - assert nv & some_nodes == self.n_its(range(5, 9)) - assert some_nodes & nv == self.n_its(range(5, 9)) - - def test_or(self): - # print("G | H nodes:", gnv | hnv) - nv = self.nv - some_nodes = self.n_its(range(5, 12)) - assert nv | some_nodes == self.n_its(range(12)) - assert some_nodes | nv == self.n_its(range(12)) - - def test_xor(self): - # print("G ^ H nodes:", gnv ^ hnv) - nv = self.nv - some_nodes = self.n_its(range(5, 12)) - nodes = {0, 1, 2, 3, 4, 9, 10, 11} - assert nv ^ some_nodes == self.n_its(nodes) - assert some_nodes ^ nv == self.n_its(nodes) - - def test_sub(self): - # print("G - H nodes:", gnv - hnv) - nv = self.nv - some_nodes = self.n_its(range(5, 12)) - assert nv - some_nodes == self.n_its(range(5)) - assert some_nodes - nv == self.n_its(range(9, 12)) - - -class TestNodeDataViewSetOps(TestNodeViewSetOps): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9) - cls.G.nodes[3]['foo'] = 'bar' - cls.nv = cls.G.nodes.data('foo') - - def n_its(self, nodes): - return {(node, 'bar' if node == 3 else None) for node in nodes} - - -class TestNodeDataViewDefaultSetOps(TestNodeDataViewSetOps): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9) - cls.G.nodes[3]['foo'] = 'bar' - cls.nv = cls.G.nodes.data('foo', default=1) - - def n_its(self, nodes): - return {(node, 'bar' if node == 3 else 1) for node in nodes} - - -# Edges Data View -class TestEdgeDataView(object): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9) - cls.eview = nx.reportviews.EdgeView - - def test_pickle(self): - import pickle - ev = self.eview(self.G)(data=True) - pev = pickle.loads(pickle.dumps(ev, -1)) - assert list(ev) == list(pev) - assert ev.__slots__ == pev.__slots__ - - def modify_edge(self, G, e, **kwds): - G._adj[e[0]][e[1]].update(kwds) - - def test_str(self): - ev = self.eview(self.G)(data=True) - rep = str([(n, n + 1, {}) for n in range(8)]) - assert str(ev) == rep - - def test_repr(self): - ev = self.eview(self.G)(data=True) - rep = "EdgeDataView([(0, 1, {}), (1, 2, {}), " + \ - "(2, 3, {}), (3, 4, {}), " + \ - "(4, 5, {}), (5, 6, {}), " + \ - "(6, 7, {}), (7, 8, {})])" - assert repr(ev) == rep - - def test_iterdata(self): - G = self.G.copy() - evr = self.eview(G) - ev = evr(data=True) - ev_def = evr(data='foo', default=1) - - for u, v, d in ev: - pass - assert d == {} - - for u, v, wt in ev_def: - pass - assert wt == 1 - - self.modify_edge(G, (2, 3), foo='bar') - for e in ev: - assert len(e) == 3 - if set(e[:2]) == {2, 3}: - assert e[2] == {'foo': 'bar'} - checked = True - else: - assert e[2] == {} - assert checked - - for e in ev_def: - assert len(e) == 3 - if set(e[:2]) == {2, 3}: - assert e[2] == 'bar' - checked_wt = True - else: - assert e[2] == 1 - assert checked_wt - - def test_iter(self): - evr = self.eview(self.G) - ev = evr() - for u, v in ev: - pass - iev = iter(ev) - assert next(iev) == (0, 1) - assert iter(ev) != ev - assert iter(iev) == iev - - def test_contains(self): - evr = self.eview(self.G) - ev = evr() - if self.G.is_directed(): - assert (1, 2) in ev and (2, 1) not in ev - else: - assert (1, 2) in ev and (2, 1) in ev - assert not (1, 4) in ev - assert not (1, 90) in ev - assert not (90, 1) in ev - - def test_len(self): - evr = self.eview(self.G) - ev = evr(data='foo') - assert len(ev) == 8 - assert len(evr(1)) == 2 - assert len(evr([1, 2, 3])) == 4 - - assert len(self.G.edges(1)) == 2 - assert len(self.G.edges()) == 8 - assert len(self.G.edges) == 8 - - H = self.G.copy() - H.add_edge(1, 1) - assert len(H.edges(1)) == 3 - assert len(H.edges()) == 9 - assert len(H.edges) == 9 - - -class TestOutEdgeDataView(TestEdgeDataView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, create_using=nx.DiGraph()) - cls.eview = nx.reportviews.OutEdgeView - - def test_repr(self): - ev = self.eview(self.G)(data=True) - rep = "OutEdgeDataView([(0, 1, {}), (1, 2, {}), " + \ - "(2, 3, {}), (3, 4, {}), " + \ - "(4, 5, {}), (5, 6, {}), " + \ - "(6, 7, {}), (7, 8, {})])" - assert repr(ev) == rep - - def test_len(self): - evr = self.eview(self.G) - ev = evr(data='foo') - assert len(ev) == 8 - assert len(evr(1)) == 1 - assert len(evr([1, 2, 3])) == 3 - - assert len(self.G.edges(1)) == 1 - assert len(self.G.edges()) == 8 - assert len(self.G.edges) == 8 - - H = self.G.copy() - H.add_edge(1, 1) - assert len(H.edges(1)) == 2 - assert len(H.edges()) == 9 - assert len(H.edges) == 9 - - -class TestInEdgeDataView(TestOutEdgeDataView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, create_using=nx.DiGraph()) - cls.eview = nx.reportviews.InEdgeView - - def test_repr(self): - ev = self.eview(self.G)(data=True) - rep = "InEdgeDataView([(0, 1, {}), (1, 2, {}), " + \ - "(2, 3, {}), (3, 4, {}), " + \ - "(4, 5, {}), (5, 6, {}), " + \ - "(6, 7, {}), (7, 8, {})])" - assert repr(ev) == rep - - -class TestMultiEdgeDataView(TestEdgeDataView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, create_using=nx.MultiGraph()) - cls.eview = nx.reportviews.MultiEdgeView - - def modify_edge(self, G, e, **kwds): - G._adj[e[0]][e[1]][0].update(kwds) - - def test_repr(self): - ev = self.eview(self.G)(data=True) - rep = "MultiEdgeDataView([(0, 1, {}), (1, 2, {}), " + \ - "(2, 3, {}), (3, 4, {}), " + \ - "(4, 5, {}), (5, 6, {}), " + \ - "(6, 7, {}), (7, 8, {})])" - assert repr(ev) == rep - - -class TestOutMultiEdgeDataView(TestOutEdgeDataView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, create_using=nx.MultiDiGraph()) - cls.eview = nx.reportviews.OutMultiEdgeView - - def modify_edge(self, G, e, **kwds): - G._adj[e[0]][e[1]][0].update(kwds) - - def test_repr(self): - ev = self.eview(self.G)(data=True) - rep = "OutMultiEdgeDataView([(0, 1, {}), (1, 2, {}), " + \ - "(2, 3, {}), (3, 4, {}), " + \ - "(4, 5, {}), (5, 6, {}), " + \ - "(6, 7, {}), (7, 8, {})])" - assert repr(ev) == rep - - -class TestInMultiEdgeDataView(TestOutMultiEdgeDataView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, create_using=nx.MultiDiGraph()) - cls.eview = nx.reportviews.InMultiEdgeView - - def test_repr(self): - ev = self.eview(self.G)(data=True) - rep = "InMultiEdgeDataView([(0, 1, {}), (1, 2, {}), " + \ - "(2, 3, {}), (3, 4, {}), " + \ - "(4, 5, {}), (5, 6, {}), " + \ - "(6, 7, {}), (7, 8, {})])" - assert repr(ev) == rep - - -# Edge Views -class TestEdgeView(object): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9) - cls.eview = nx.reportviews.EdgeView - - def test_pickle(self): - import pickle - ev = self.eview(self.G) - pev = pickle.loads(pickle.dumps(ev, -1)) - assert ev == pev - assert ev.__slots__ == pev.__slots__ - - def modify_edge(self, G, e, **kwds): - G._adj[e[0]][e[1]].update(kwds) - - def test_str(self): - ev = self.eview(self.G) - rep = str([(n, n + 1) for n in range(8)]) - assert str(ev) == rep - - def test_repr(self): - ev = self.eview(self.G) - rep = "EdgeView([(0, 1), (1, 2), (2, 3), (3, 4), " + \ - "(4, 5), (5, 6), (6, 7), (7, 8)])" - assert repr(ev) == rep - - def test_call(self): - ev = self.eview(self.G) - assert id(ev) == id(ev()) - assert id(ev) == id(ev(data=False)) - assert id(ev) != id(ev(data=True)) - assert id(ev) != id(ev(nbunch=1)) - - def test_data(self): - ev = self.eview(self.G) - assert id(ev) != id(ev.data()) - assert id(ev) == id(ev.data(data=False)) - assert id(ev) != id(ev.data(data=True)) - assert id(ev) != id(ev.data(nbunch=1)) - - def test_iter(self): - ev = self.eview(self.G) - for u, v in ev: - pass - iev = iter(ev) - assert next(iev) == (0, 1) - assert iter(ev) != ev - assert iter(iev) == iev - - def test_contains(self): - ev = self.eview(self.G) - edv = ev() - if self.G.is_directed(): - assert (1, 2) in ev and (2, 1) not in ev - assert (1, 2) in edv and (2, 1) not in edv - else: - assert (1, 2) in ev and (2, 1) in ev - assert (1, 2) in edv and (2, 1) in edv - assert not (1, 4) in ev - assert not (1, 4) in edv - # edge not in graph - assert not (1, 90) in ev - assert not (90, 1) in ev - assert not (1, 90) in edv - assert not (90, 1) in edv - - def test_len(self): - ev = self.eview(self.G) - num_ed = 9 if self.G.is_multigraph() else 8 - assert len(ev) == num_ed - - H = self.G.copy() - H.add_edge(1, 1) - assert len(H.edges(1)) == 3 + H.is_multigraph() - H.is_directed() - assert len(H.edges()) == num_ed + 1 - assert len(H.edges) == num_ed + 1 - - def test_and(self): - # print("G & H edges:", gnv & hnv) - ev = self.eview(self.G) - some_edges = {(0, 1), (1, 0), (0, 2)} - if self.G.is_directed(): - assert some_edges & ev, {(0, 1)} - assert ev & some_edges, {(0, 1)} - else: - assert ev & some_edges == {(0, 1), (1, 0)} - assert some_edges & ev == {(0, 1), (1, 0)} - return - - def test_or(self): - # print("G | H edges:", gnv | hnv) - ev = self.eview(self.G) - some_edges = {(0, 1), (1, 0), (0, 2)} - result1 = {(n, n + 1) for n in range(8)} - result1.update(some_edges) - result2 = {(n + 1, n) for n in range(8)} - result2.update(some_edges) - assert (ev | some_edges) in (result1, result2) - assert (some_edges | ev) in (result1, result2) - - def test_xor(self): - # print("G ^ H edges:", gnv ^ hnv) - ev = self.eview(self.G) - some_edges = {(0, 1), (1, 0), (0, 2)} - if self.G.is_directed(): - result = {(n, n + 1) for n in range(1, 8)} - result.update({(1, 0), (0, 2)}) - assert ev ^ some_edges == result - else: - result = {(n, n + 1) for n in range(1, 8)} - result.update({(0, 2)}) - assert ev ^ some_edges == result - return - - def test_sub(self): - # print("G - H edges:", gnv - hnv) - ev = self.eview(self.G) - some_edges = {(0, 1), (1, 0), (0, 2)} - result = {(n, n + 1) for n in range(8)} - result.remove((0, 1)) - assert ev - some_edges, result - - -class TestOutEdgeView(TestEdgeView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, nx.DiGraph()) - cls.eview = nx.reportviews.OutEdgeView - - def test_repr(self): - ev = self.eview(self.G) - rep = "OutEdgeView([(0, 1), (1, 2), (2, 3), (3, 4), " + \ - "(4, 5), (5, 6), (6, 7), (7, 8)])" - assert repr(ev) == rep - - -class TestInEdgeView(TestEdgeView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, nx.DiGraph()) - cls.eview = nx.reportviews.InEdgeView - - def test_repr(self): - ev = self.eview(self.G) - rep = "InEdgeView([(0, 1), (1, 2), (2, 3), (3, 4), " + \ - "(4, 5), (5, 6), (6, 7), (7, 8)])" - assert repr(ev) == rep - - -class TestMultiEdgeView(TestEdgeView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, nx.MultiGraph()) - cls.G.add_edge(1, 2, key=3, foo='bar') - cls.eview = nx.reportviews.MultiEdgeView - - def modify_edge(self, G, e, **kwds): - if len(e) == 2: - e = e + (0,) - G._adj[e[0]][e[1]][e[2]].update(kwds) - - def test_str(self): - ev = self.eview(self.G) - replist = [(n, n + 1, 0) for n in range(8)] - replist.insert(2, (1, 2, 3)) - rep = str(replist) - assert str(ev) == rep - - def test_repr(self): - ev = self.eview(self.G) - rep = "MultiEdgeView([(0, 1, 0), (1, 2, 0), (1, 2, 3), (2, 3, 0), " + \ - "(3, 4, 0), (4, 5, 0), (5, 6, 0), (6, 7, 0), (7, 8, 0)])" - assert repr(ev) == rep - - def test_call(self): - ev = self.eview(self.G) - assert id(ev) == id(ev(keys=True)) - assert id(ev) == id(ev(data=False, keys=True)) - assert id(ev) != id(ev(keys=False)) - assert id(ev) != id(ev(data=True)) - assert id(ev) != id(ev(nbunch=1)) - - def test_data(self): - ev = self.eview(self.G) - assert id(ev) != id(ev.data()) - assert id(ev) == id(ev.data(data=False, keys=True)) - assert id(ev) != id(ev.data(keys=False)) - assert id(ev) != id(ev.data(data=True)) - assert id(ev) != id(ev.data(nbunch=1)) - - def test_iter(self): - ev = self.eview(self.G) - for u, v, k in ev: - pass - iev = iter(ev) - assert next(iev) == (0, 1, 0) - assert iter(ev) != ev - assert iter(iev) == iev - - def test_iterkeys(self): - G = self.G - evr = self.eview(G) - ev = evr(keys=True) - for u, v, k in ev: - pass - assert k == 0 - ev = evr(keys=True, data="foo", default=1) - for u, v, k, wt in ev: - pass - assert wt == 1 - - self.modify_edge(G, (2, 3, 0), foo='bar') - ev = evr(keys=True, data=True) - for e in ev: - assert len(e) == 4 - print('edge:', e) - if set(e[:2]) == {2, 3}: - print(self.G._adj[2][3]) - assert e[2] == 0 - assert e[3] == {'foo': 'bar'} - checked = True - elif set(e[:3]) == {1, 2, 3}: - assert e[2] == 3 - assert e[3] == {'foo': 'bar'} - checked_multi = True - else: - assert e[2] == 0 - assert e[3] == {} - assert checked - assert checked_multi - ev = evr(keys=True, data='foo', default=1) - for e in ev: - if set(e[:2]) == {1, 2} and e[2] == 3: - assert e[3] == 'bar' - if set(e[:2]) == {1, 2} and e[2] == 0: - assert e[3] == 1 - if set(e[:2]) == {2, 3}: - assert e[2] == 0 - assert e[3] == 'bar' - assert len(e) == 4 - checked_wt = True - assert checked_wt - ev = evr(keys=True) - for e in ev: - assert len(e) == 3 - elist = sorted([(i, i + 1, 0) for i in range(8)] + [(1, 2, 3)]) - assert sorted(list(ev)) == elist - # test order of arguments:graph, nbunch, data, keys, default - ev = evr((1, 2), 'foo', True, 1) - for e in ev: - if set(e[:2]) == {1, 2}: - assert e[2] in {0, 3} - if e[2] == 3: - assert e[3] == 'bar' - else: # e[2] == 0 - assert e[3] == 1 - if G.is_directed(): - assert len(list(ev)) == 3 - else: - assert len(list(ev)) == 4 - - def test_or(self): - # print("G | H edges:", gnv | hnv) - ev = self.eview(self.G) - some_edges = {(0, 1, 0), (1, 0, 0), (0, 2, 0)} - result = {(n, n + 1, 0) for n in range(8)} - result.update(some_edges) - result.update({(1, 2, 3)}) - assert ev | some_edges == result - assert some_edges | ev == result - - def test_sub(self): - # print("G - H edges:", gnv - hnv) - ev = self.eview(self.G) - some_edges = {(0, 1, 0), (1, 0, 0), (0, 2, 0)} - result = {(n, n + 1, 0) for n in range(8)} - result.remove((0, 1, 0)) - result.update({(1, 2, 3)}) - assert ev - some_edges, result - assert some_edges - ev, result - - def test_xor(self): - # print("G ^ H edges:", gnv ^ hnv) - ev = self.eview(self.G) - some_edges = {(0, 1, 0), (1, 0, 0), (0, 2, 0)} - if self.G.is_directed(): - result = {(n, n + 1, 0) for n in range(1, 8)} - result.update({(1, 0, 0), (0, 2, 0), (1, 2, 3)}) - assert ev ^ some_edges == result - assert some_edges ^ ev == result - else: - result = {(n, n + 1, 0) for n in range(1, 8)} - result.update({(0, 2, 0), (1, 2, 3)}) - assert ev ^ some_edges == result - assert some_edges ^ ev == result - - def test_and(self): - # print("G & H edges:", gnv & hnv) - ev = self.eview(self.G) - some_edges = {(0, 1, 0), (1, 0, 0), (0, 2, 0)} - if self.G.is_directed(): - assert ev & some_edges == {(0, 1, 0)} - assert some_edges & ev == {(0, 1, 0)} - else: - assert ev & some_edges == {(0, 1, 0), (1, 0, 0)} - assert some_edges & ev == {(0, 1, 0), (1, 0, 0)} - - -class TestOutMultiEdgeView(TestMultiEdgeView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, nx.MultiDiGraph()) - cls.G.add_edge(1, 2, key=3, foo='bar') - cls.eview = nx.reportviews.OutMultiEdgeView - - def modify_edge(self, G, e, **kwds): - if len(e) == 2: - e = e + (0,) - G._adj[e[0]][e[1]][e[2]].update(kwds) - - def test_repr(self): - ev = self.eview(self.G) - rep = "OutMultiEdgeView([(0, 1, 0), (1, 2, 0), (1, 2, 3), (2, 3, 0),"\ - + " (3, 4, 0), (4, 5, 0), (5, 6, 0), (6, 7, 0), (7, 8, 0)])" - assert repr(ev) == rep - - -class TestInMultiEdgeView(TestMultiEdgeView): - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, nx.MultiDiGraph()) - cls.G.add_edge(1, 2, key=3, foo='bar') - cls.eview = nx.reportviews.InMultiEdgeView - - def modify_edge(self, G, e, **kwds): - if len(e) == 2: - e = e + (0,) - G._adj[e[0]][e[1]][e[2]].update(kwds) - - def test_repr(self): - ev = self.eview(self.G) - rep = "InMultiEdgeView([(0, 1, 0), (1, 2, 0), (1, 2, 3), (2, 3, 0), "\ - + "(3, 4, 0), (4, 5, 0), (5, 6, 0), (6, 7, 0), (7, 8, 0)])" - assert repr(ev) == rep - - -# Degrees -class TestDegreeView(object): - GRAPH = nx.Graph - dview = nx.reportviews.DegreeView - - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(6, cls.GRAPH()) - cls.G.add_edge(1, 3, foo=2) - cls.G.add_edge(1, 3, foo=3) - - def test_pickle(self): - import pickle - deg = self.G.degree - pdeg = pickle.loads(pickle.dumps(deg, -1)) - assert dict(deg) == dict(pdeg) - - def test_str(self): - dv = self.dview(self.G) - rep = str([(0, 1), (1, 3), (2, 2), (3, 3), (4, 2), (5, 1)]) - assert str(dv) == rep - dv = self.G.degree() - assert str(dv) == rep - - def test_repr(self): - dv = self.dview(self.G) - rep = "DegreeView({0: 1, 1: 3, 2: 2, 3: 3, 4: 2, 5: 1})" - assert repr(dv) == rep - - def test_iter(self): - dv = self.dview(self.G) - for n, d in dv: - pass - idv = iter(dv) - assert iter(dv) != dv - assert iter(idv) == idv - assert next(idv) == (0, dv[0]) - assert next(idv) == (1, dv[1]) - # weighted - dv = self.dview(self.G, weight='foo') - for n, d in dv: - pass - idv = iter(dv) - assert iter(dv) != dv - assert iter(idv) == idv - assert next(idv) == (0, dv[0]) - assert next(idv) == (1, dv[1]) - - def test_nbunch(self): - dv = self.dview(self.G) - dvn = dv(0) - assert dvn == 1 - dvn = dv([2, 3]) - assert sorted(dvn) == [(2, 2), (3, 3)] - - def test_getitem(self): - dv = self.dview(self.G) - assert dv[0] == 1 - assert dv[1] == 3 - assert dv[2] == 2 - assert dv[3] == 3 - dv = self.dview(self.G, weight='foo') - assert dv[0] == 1 - assert dv[1] == 5 - assert dv[2] == 2 - assert dv[3] == 5 - - def test_weight(self): - dv = self.dview(self.G) - dvw = dv(0, weight='foo') - assert dvw == 1 - dvw = dv(1, weight='foo') - assert dvw == 5 - dvw = dv([2, 3], weight='foo') - assert sorted(dvw) == [(2, 2), (3, 5)] - dvd = dict(dv(weight='foo')) - assert dvd[0] == 1 - assert dvd[1] == 5 - assert dvd[2] == 2 - assert dvd[3] == 5 - - def test_len(self): - dv = self.dview(self.G) - assert len(dv) == 6 - - -class TestDiDegreeView(TestDegreeView): - GRAPH = nx.DiGraph - dview = nx.reportviews.DiDegreeView - - def test_repr(self): - dv = self.G.degree() - rep = "DiDegreeView({0: 1, 1: 3, 2: 2, 3: 3, 4: 2, 5: 1})" - assert repr(dv) == rep - - -class TestOutDegreeView(TestDegreeView): - GRAPH = nx.DiGraph - dview = nx.reportviews.OutDegreeView - - def test_str(self): - dv = self.dview(self.G) - rep = str([(0, 1), (1, 2), (2, 1), (3, 1), (4, 1), (5, 0)]) - assert str(dv) == rep - dv = self.G.out_degree() - assert str(dv) == rep - - def test_repr(self): - dv = self.G.out_degree() - rep = "OutDegreeView({0: 1, 1: 2, 2: 1, 3: 1, 4: 1, 5: 0})" - assert repr(dv) == rep - - def test_nbunch(self): - dv = self.dview(self.G) - dvn = dv(0) - assert dvn == 1 - dvn = dv([2, 3]) - assert sorted(dvn) == [(2, 1), (3, 1)] - - def test_getitem(self): - dv = self.dview(self.G) - assert dv[0] == 1 - assert dv[1] == 2 - assert dv[2] == 1 - assert dv[3] == 1 - dv = self.dview(self.G, weight='foo') - assert dv[0] == 1 - assert dv[1] == 4 - assert dv[2] == 1 - assert dv[3] == 1 - - def test_weight(self): - dv = self.dview(self.G) - dvw = dv(0, weight='foo') - assert dvw == 1 - dvw = dv(1, weight='foo') - assert dvw == 4 - dvw = dv([2, 3], weight='foo') - assert sorted(dvw) == [(2, 1), (3, 1)] - dvd = dict(dv(weight='foo')) - assert dvd[0] == 1 - assert dvd[1] == 4 - assert dvd[2] == 1 - assert dvd[3] == 1 - - -class TestInDegreeView(TestDegreeView): - GRAPH = nx.DiGraph - dview = nx.reportviews.InDegreeView - - def test_str(self): - dv = self.dview(self.G) - rep = str([(0, 0), (1, 1), (2, 1), (3, 2), (4, 1), (5, 1)]) - assert str(dv) == rep - dv = self.G.in_degree() - assert str(dv) == rep - - def test_repr(self): - dv = self.G.in_degree() - rep = "InDegreeView({0: 0, 1: 1, 2: 1, 3: 2, 4: 1, 5: 1})" - assert repr(dv) == rep - - def test_nbunch(self): - dv = self.dview(self.G) - dvn = dv(0) - assert dvn == 0 - dvn = dv([2, 3]) - assert sorted(dvn) == [(2, 1), (3, 2)] - - def test_getitem(self): - dv = self.dview(self.G) - assert dv[0] == 0 - assert dv[1] == 1 - assert dv[2] == 1 - assert dv[3] == 2 - dv = self.dview(self.G, weight='foo') - assert dv[0] == 0 - assert dv[1] == 1 - assert dv[2] == 1 - assert dv[3] == 4 - - def test_weight(self): - dv = self.dview(self.G) - dvw = dv(0, weight='foo') - assert dvw == 0 - dvw = dv(1, weight='foo') - assert dvw == 1 - dvw = dv([2, 3], weight='foo') - assert sorted(dvw) == [(2, 1), (3, 4)] - dvd = dict(dv(weight='foo')) - assert dvd[0] == 0 - assert dvd[1] == 1 - assert dvd[2] == 1 - assert dvd[3] == 4 - - -class TestMultiDegreeView(TestDegreeView): - GRAPH = nx.MultiGraph - dview = nx.reportviews.MultiDegreeView - - def test_str(self): - dv = self.dview(self.G) - rep = str([(0, 1), (1, 4), (2, 2), (3, 4), (4, 2), (5, 1)]) - assert str(dv) == rep - dv = self.G.degree() - assert str(dv) == rep - - def test_repr(self): - dv = self.G.degree() - rep = "MultiDegreeView({0: 1, 1: 4, 2: 2, 3: 4, 4: 2, 5: 1})" - assert repr(dv) == rep - - def test_nbunch(self): - dv = self.dview(self.G) - dvn = dv(0) - assert dvn == 1 - dvn = dv([2, 3]) - assert sorted(dvn) == [(2, 2), (3, 4)] - - def test_getitem(self): - dv = self.dview(self.G) - assert dv[0] == 1 - assert dv[1] == 4 - assert dv[2] == 2 - assert dv[3] == 4 - dv = self.dview(self.G, weight='foo') - assert dv[0] == 1 - assert dv[1] == 7 - assert dv[2] == 2 - assert dv[3] == 7 - - def test_weight(self): - dv = self.dview(self.G) - dvw = dv(0, weight='foo') - assert dvw == 1 - dvw = dv(1, weight='foo') - assert dvw == 7 - dvw = dv([2, 3], weight='foo') - assert sorted(dvw) == [(2, 2), (3, 7)] - dvd = dict(dv(weight='foo')) - assert dvd[0] == 1 - assert dvd[1] == 7 - assert dvd[2] == 2 - assert dvd[3] == 7 - - -class TestDiMultiDegreeView(TestMultiDegreeView): - GRAPH = nx.MultiDiGraph - dview = nx.reportviews.DiMultiDegreeView - - def test_repr(self): - dv = self.G.degree() - rep = "DiMultiDegreeView({0: 1, 1: 4, 2: 2, 3: 4, 4: 2, 5: 1})" - assert repr(dv) == rep - - -class TestOutMultiDegreeView(TestDegreeView): - GRAPH = nx.MultiDiGraph - dview = nx.reportviews.OutMultiDegreeView - - def test_str(self): - dv = self.dview(self.G) - rep = str([(0, 1), (1, 3), (2, 1), (3, 1), (4, 1), (5, 0)]) - assert str(dv) == rep - dv = self.G.out_degree() - assert str(dv) == rep - - def test_repr(self): - dv = self.G.out_degree() - rep = "OutMultiDegreeView({0: 1, 1: 3, 2: 1, 3: 1, 4: 1, 5: 0})" - assert repr(dv) == rep - - def test_nbunch(self): - dv = self.dview(self.G) - dvn = dv(0) - assert dvn == 1 - dvn = dv([2, 3]) - assert sorted(dvn) == [(2, 1), (3, 1)] - - def test_getitem(self): - dv = self.dview(self.G) - assert dv[0] == 1 - assert dv[1] == 3 - assert dv[2] == 1 - assert dv[3] == 1 - dv = self.dview(self.G, weight='foo') - assert dv[0] == 1 - assert dv[1] == 6 - assert dv[2] == 1 - assert dv[3] == 1 - - def test_weight(self): - dv = self.dview(self.G) - dvw = dv(0, weight='foo') - assert dvw == 1 - dvw = dv(1, weight='foo') - assert dvw == 6 - dvw = dv([2, 3], weight='foo') - assert sorted(dvw) == [(2, 1), (3, 1)] - dvd = dict(dv(weight='foo')) - assert dvd[0] == 1 - assert dvd[1] == 6 - assert dvd[2] == 1 - assert dvd[3] == 1 - - -class TestInMultiDegreeView(TestDegreeView): - GRAPH = nx.MultiDiGraph - dview = nx.reportviews.InMultiDegreeView - - def test_str(self): - dv = self.dview(self.G) - rep = str([(0, 0), (1, 1), (2, 1), (3, 3), (4, 1), (5, 1)]) - assert str(dv) == rep - dv = self.G.in_degree() - assert str(dv) == rep - - def test_repr(self): - dv = self.G.in_degree() - rep = "InMultiDegreeView({0: 0, 1: 1, 2: 1, 3: 3, 4: 1, 5: 1})" - assert repr(dv) == rep - - def test_nbunch(self): - dv = self.dview(self.G) - dvn = dv(0) - assert dvn == 0 - dvn = dv([2, 3]) - assert sorted(dvn) == [(2, 1), (3, 3)] - - def test_getitem(self): - dv = self.dview(self.G) - assert dv[0] == 0 - assert dv[1] == 1 - assert dv[2] == 1 - assert dv[3] == 3 - dv = self.dview(self.G, weight='foo') - assert dv[0] == 0 - assert dv[1] == 1 - assert dv[2] == 1 - assert dv[3] == 6 - - def test_weight(self): - dv = self.dview(self.G) - dvw = dv(0, weight='foo') - assert dvw == 0 - dvw = dv(1, weight='foo') - assert dvw == 1 - dvw = dv([2, 3], weight='foo') - assert sorted(dvw) == [(2, 1), (3, 6)] - dvd = dict(dv(weight='foo')) - assert dvd[0] == 0 - assert dvd[1] == 1 - assert dvd[2] == 1 - assert dvd[3] == 6 diff --git a/extensions/fablabchemnitz/networkx/classes/tests/test_special.py b/extensions/fablabchemnitz/networkx/classes/tests/test_special.py deleted file mode 100644 index bc4b83ce..00000000 --- a/extensions/fablabchemnitz/networkx/classes/tests/test_special.py +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/env python -from collections import OrderedDict -import networkx as nx -from .test_graph import TestGraph -from .test_digraph import TestDiGraph -from .test_multigraph import TestMultiGraph -from .test_multidigraph import TestMultiDiGraph - - -def test_factories(): - class mydict1(dict): - pass - - class mydict2(dict): - pass - - class mydict3(dict): - pass - - class mydict4(dict): - pass - - class mydict5(dict): - pass - - for Graph in (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph): - # print("testing class: ", Graph.__name__) - class MyGraph(Graph): - node_dict_factory = mydict1 - adjlist_outer_dict_factory = mydict2 - adjlist_inner_dict_factory = mydict3 - edge_key_dict_factory = mydict4 - edge_attr_dict_factory = mydict5 - G = MyGraph() - assert isinstance(G._node, mydict1) - assert isinstance(G._adj, mydict2) - G.add_node(1) - assert isinstance(G._adj[1], mydict3) - if G.is_directed(): - assert isinstance(G._pred, mydict2) - assert isinstance(G._succ, mydict2) - assert isinstance(G._pred[1], mydict3) - G.add_edge(1, 2) - if G.is_multigraph(): - assert isinstance(G._adj[1][2], mydict4) - assert isinstance(G._adj[1][2][0], mydict5) - else: - assert isinstance(G._adj[1][2], mydict5) - - -class SpecialGraphTester(TestGraph): - def setUp(self): - TestGraph.setUp(self) - self.Graph = nx.Graph - - -class OrderedGraphTester(TestGraph): - def setUp(self): - TestGraph.setUp(self) - - class MyGraph(nx.Graph): - node_dict_factory = OrderedDict - adjlist_outer_dict_factory = OrderedDict - adjlist_inner_dict_factory = OrderedDict - edge_attr_dict_factory = OrderedDict - self.Graph = MyGraph - - -class ThinGraphTester(TestGraph): - def setUp(self): - all_edge_dict = {'weight': 1} - - class MyGraph(nx.Graph): - def edge_attr_dict_factory(self): return all_edge_dict - self.Graph = MyGraph - # build dict-of-dict-of-dict K3 - ed1, ed2, ed3 = (all_edge_dict, all_edge_dict, all_edge_dict) - self.k3adj = {0: {1: ed1, 2: ed2}, - 1: {0: ed1, 2: ed3}, - 2: {0: ed2, 1: ed3}} - self.k3edges = [(0, 1), (0, 2), (1, 2)] - self.k3nodes = [0, 1, 2] - self.K3 = self.Graph() - self.K3._adj = self.k3adj - self.K3._node = {} - self.K3._node[0] = {} - self.K3._node[1] = {} - self.K3._node[2] = {} - - -class SpecialDiGraphTester(TestDiGraph): - def setUp(self): - TestDiGraph.setUp(self) - self.Graph = nx.DiGraph - - -class OrderedDiGraphTester(TestDiGraph): - def setUp(self): - TestGraph.setUp(self) - - class MyGraph(nx.DiGraph): - node_dict_factory = OrderedDict - adjlist_outer_dict_factory = OrderedDict - adjlist_inner_dict_factory = OrderedDict - edge_attr_dict_factory = OrderedDict - self.Graph = MyGraph - - -class ThinDiGraphTester(TestDiGraph): - def setUp(self): - all_edge_dict = {'weight': 1} - - class MyGraph(nx.DiGraph): - def edge_attr_dict_factory(self): return all_edge_dict - self.Graph = MyGraph - # build dict-of-dict-of-dict K3 - ed1, ed2, ed3 = (all_edge_dict, all_edge_dict, all_edge_dict) - self.k3adj = {0: {1: ed1, 2: ed2}, - 1: {0: ed1, 2: ed3}, - 2: {0: ed2, 1: ed3}} - self.k3edges = [(0, 1), (0, 2), (1, 2)] - self.k3nodes = [0, 1, 2] - self.K3 = self.Graph() - self.K3.adj = self.k3adj - self.K3._node = {} - self.K3._node[0] = {} - self.K3._node[1] = {} - self.K3._node[2] = {} - - -class SpecialMultiGraphTester(TestMultiGraph): - def setUp(self): - TestMultiGraph.setUp(self) - self.Graph = nx.MultiGraph - - -class OrderedMultiGraphTester(TestMultiGraph): - def setUp(self): - TestMultiGraph.setUp(self) - - class MyGraph(nx.MultiGraph): - node_dict_factory = OrderedDict - adjlist_outer_dict_factory = OrderedDict - adjlist_inner_dict_factory = OrderedDict - edge_key_dict_factory = OrderedDict - edge_attr_dict_factory = OrderedDict - self.Graph = MyGraph - - -class SpecialMultiDiGraphTester(TestMultiDiGraph): - def setUp(self): - TestMultiDiGraph.setUp(self) - self.Graph = nx.MultiDiGraph - - -class OrderedMultiDiGraphTester(TestMultiDiGraph): - def setUp(self): - TestMultiDiGraph.setUp(self) - - class MyGraph(nx.MultiDiGraph): - node_dict_factory = OrderedDict - adjlist_outer_dict_factory = OrderedDict - adjlist_inner_dict_factory = OrderedDict - edge_key_dict_factory = OrderedDict - edge_attr_dict_factory = OrderedDict - self.Graph = MyGraph diff --git a/extensions/fablabchemnitz/networkx/classes/tests/test_subgraphviews.py b/extensions/fablabchemnitz/networkx/classes/tests/test_subgraphviews.py deleted file mode 100644 index dd93a494..00000000 --- a/extensions/fablabchemnitz/networkx/classes/tests/test_subgraphviews.py +++ /dev/null @@ -1,354 +0,0 @@ -import pytest - -import networkx as nx - - -class TestSubGraphView(object): - gview = staticmethod(nx.graphviews.subgraph_view) - graph = nx.Graph - hide_edges_filter = staticmethod(nx.filters.hide_edges) - show_edges_filter = staticmethod(nx.filters.show_edges) - - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, create_using=cls.graph()) - cls.hide_edges_w_hide_nodes = {(3, 4), (4, 5), (5, 6)} - - def test_hidden_nodes(self): - hide_nodes = [4, 5, 111] - nodes_gone = nx.filters.hide_nodes(hide_nodes) - gview = self.gview - print(gview) - G = gview(self.G, filter_node=nodes_gone) - assert self.G.nodes - G.nodes == {4, 5} - assert self.G.edges - G.edges == self.hide_edges_w_hide_nodes - if G.is_directed(): - assert list(G[3]) == [] - assert list(G[2]) == [3] - else: - assert list(G[3]) == [2] - assert set(G[2]) == {1, 3} - pytest.raises(KeyError, G.__getitem__, 4) - pytest.raises(KeyError, G.__getitem__, 112) - pytest.raises(KeyError, G.__getitem__, 111) - assert G.degree(3) == (3 if G.is_multigraph() else 1) - assert G.size() == (7 if G.is_multigraph() else 5) - - def test_hidden_edges(self): - hide_edges = [(2, 3), (8, 7), (222, 223)] - edges_gone = self.hide_edges_filter(hide_edges) - gview = self.gview - G = gview(self.G, filter_edge=edges_gone) - assert self.G.nodes == G.nodes - if G.is_directed(): - assert self.G.edges - G.edges == {(2, 3)} - assert list(G[2]) == [] - assert list(G.pred[3]) == [] - assert list(G.pred[2]) == [1] - assert G.size() == 7 - else: - assert self.G.edges - G.edges == {(2, 3), (7, 8)} - assert list(G[2]) == [1] - assert G.size() == 6 - assert list(G[3]) == [4] - pytest.raises(KeyError, G.__getitem__, 221) - pytest.raises(KeyError, G.__getitem__, 222) - assert G.degree(3) == 1 - - def test_shown_node(self): - induced_subgraph = nx.filters.show_nodes([2, 3, 111]) - gview = self.gview - G = gview(self.G, filter_node=induced_subgraph) - assert set(G.nodes) == {2, 3} - if G.is_directed(): - assert list(G[3]) == [] - else: - assert list(G[3]) == [2] - assert list(G[2]) == [3] - pytest.raises(KeyError, G.__getitem__, 4) - pytest.raises(KeyError, G.__getitem__, 112) - pytest.raises(KeyError, G.__getitem__, 111) - assert G.degree(3) == (3 if G.is_multigraph() else 1) - assert G.size() == (3 if G.is_multigraph() else 1) - - def test_shown_edges(self): - show_edges = [(2, 3), (8, 7), (222, 223)] - edge_subgraph = self.show_edges_filter(show_edges) - G = self.gview(self.G, filter_edge=edge_subgraph) - assert self.G.nodes == G.nodes - if G.is_directed(): - assert G.edges == {(2, 3)} - assert list(G[3]) == [] - assert list(G[2]) == [3] - assert list(G.pred[3]) == [2] - assert list(G.pred[2]) == [] - assert G.size() == 1 - else: - assert G.edges == {(2, 3), (7, 8)} - assert list(G[3]) == [2] - assert list(G[2]) == [3] - assert G.size() == 2 - pytest.raises(KeyError, G.__getitem__, 221) - pytest.raises(KeyError, G.__getitem__, 222) - assert G.degree(3) == 1 - - -class TestSubDiGraphView(TestSubGraphView): - gview = staticmethod(nx.graphviews.subgraph_view) - graph = nx.DiGraph - hide_edges_filter = staticmethod(nx.filters.hide_diedges) - show_edges_filter = staticmethod(nx.filters.show_diedges) - hide_edges = [(2, 3), (8, 7), (222, 223)] - excluded = {(2, 3), (3, 4), (4, 5), (5, 6)} - - def test_inoutedges(self): - edges_gone = self.hide_edges_filter(self.hide_edges) - hide_nodes = [4, 5, 111] - nodes_gone = nx.filters.hide_nodes(hide_nodes) - G = self.gview(self.G, nodes_gone, edges_gone) - - assert self.G.in_edges - G.in_edges == self.excluded - assert self.G.out_edges - G.out_edges == self.excluded - - def test_pred(self): - edges_gone = self.hide_edges_filter(self.hide_edges) - hide_nodes = [4, 5, 111] - nodes_gone = nx.filters.hide_nodes(hide_nodes) - G = self.gview(self.G, nodes_gone, edges_gone) - - assert list(G.pred[2]) == [1] - assert list(G.pred[6]) == [] - - def test_inout_degree(self): - edges_gone = self.hide_edges_filter(self.hide_edges) - hide_nodes = [4, 5, 111] - nodes_gone = nx.filters.hide_nodes(hide_nodes) - G = self.gview(self.G, nodes_gone, edges_gone) - - assert G.degree(2) == 1 - assert G.out_degree(2) == 0 - assert G.in_degree(2) == 1 - assert G.size() == 4 - - -# multigraph -class TestMultiGraphView(TestSubGraphView): - gview = staticmethod(nx.graphviews.subgraph_view) - graph = nx.MultiGraph - hide_edges_filter = staticmethod(nx.filters.hide_multiedges) - show_edges_filter = staticmethod(nx.filters.show_multiedges) - - @classmethod - def setup_class(cls): - cls.G = nx.path_graph(9, create_using=cls.graph()) - multiedges = {(2, 3, 4), (2, 3, 5)} - cls.G.add_edges_from(multiedges) - cls.hide_edges_w_hide_nodes = {(3, 4, 0), (4, 5, 0), (5, 6, 0)} - - def test_hidden_edges(self): - hide_edges = [(2, 3, 4), (2, 3, 3), (8, 7, 0), (222, 223, 0)] - edges_gone = self.hide_edges_filter(hide_edges) - G = self.gview(self.G, filter_edge=edges_gone) - assert self.G.nodes == G.nodes - if G.is_directed(): - assert self.G.edges - G.edges == {(2, 3, 4)} - assert list(G[3]) == [4] - assert list(G[2]) == [3] - assert list(G.pred[3]) == [2] # only one 2 but two edges - assert list(G.pred[2]) == [1] - assert G.size() == 9 - else: - assert self.G.edges - G.edges == {(2, 3, 4), (7, 8, 0)} - assert list(G[3]) == [2, 4] - assert list(G[2]) == [1, 3] - assert G.size() == 8 - assert G.degree(3) == 3 - pytest.raises(KeyError, G.__getitem__, 221) - pytest.raises(KeyError, G.__getitem__, 222) - - def test_shown_edges(self): - show_edges = [(2, 3, 4), (2, 3, 3), (8, 7, 0), (222, 223, 0)] - edge_subgraph = self.show_edges_filter(show_edges) - G = self.gview(self.G, filter_edge=edge_subgraph) - assert self.G.nodes == G.nodes - if G.is_directed(): - assert G.edges == {(2, 3, 4)} - assert list(G[3]) == [] - assert list(G.pred[3]) == [2] - assert list(G.pred[2]) == [] - assert G.size() == 1 - else: - assert G.edges == {(2, 3, 4), (7, 8, 0)} - assert G.size() == 2 - assert list(G[3]) == [2] - assert G.degree(3) == 1 - assert list(G[2]) == [3] - pytest.raises(KeyError, G.__getitem__, 221) - pytest.raises(KeyError, G.__getitem__, 222) - - -# multidigraph -class TestMultiDiGraphView(TestMultiGraphView, TestSubDiGraphView): - gview = staticmethod(nx.graphviews.subgraph_view) - graph = nx.MultiDiGraph - hide_edges_filter = staticmethod(nx.filters.hide_multidiedges) - show_edges_filter = staticmethod(nx.filters.show_multidiedges) - hide_edges = [(2, 3, 0), (8, 7, 0), (222, 223, 0)] - excluded = {(2, 3, 0), (3, 4, 0), (4, 5, 0), (5, 6, 0)} - - def test_inout_degree(self): - edges_gone = self.hide_edges_filter(self.hide_edges) - hide_nodes = [4, 5, 111] - nodes_gone = nx.filters.hide_nodes(hide_nodes) - G = self.gview(self.G, nodes_gone, edges_gone) - - assert G.degree(2) == 3 - assert G.out_degree(2) == 2 - assert G.in_degree(2) == 1 - assert G.size() == 6 - - -# induced_subgraph -class TestInducedSubGraph(object): - @classmethod - def setup_class(cls): - cls.K3 = G = nx.complete_graph(3) - G.graph['foo'] = [] - G.nodes[0]['foo'] = [] - G.remove_edge(1, 2) - ll = [] - G.add_edge(1, 2, foo=ll) - G.add_edge(2, 1, foo=ll) - - def test_full_graph(self): - G = self.K3 - H = nx.induced_subgraph(G, [0, 1, 2, 5]) - assert H.name == G.name - self.graphs_equal(H, G) - self.same_attrdict(H, G) - - def test_partial_subgraph(self): - G = self.K3 - H = nx.induced_subgraph(G, 0) - assert dict(H.adj) == {0: {}} - assert dict(G.adj) != {0: {}} - - H = nx.induced_subgraph(G, [0, 1]) - assert dict(H.adj) == {0: {1: {}}, 1: {0: {}}} - - def same_attrdict(self, H, G): - old_foo = H[1][2]['foo'] - H.edges[1, 2]['foo'] = 'baz' - assert G.edges == H.edges - H.edges[1, 2]['foo'] = old_foo - assert G.edges == H.edges - old_foo = H.nodes[0]['foo'] - H.nodes[0]['foo'] = 'baz' - assert G.nodes == H.nodes - H.nodes[0]['foo'] = old_foo - assert G.nodes == H.nodes - - def graphs_equal(self, H, G): - assert G._adj == H._adj - assert G._node == H._node - assert G.graph == H.graph - assert G.name == H.name - if not G.is_directed() and not H.is_directed(): - assert H._adj[1][2] is H._adj[2][1] - assert G._adj[1][2] is G._adj[2][1] - else: # at least one is directed - if not G.is_directed(): - G._pred = G._adj - G._succ = G._adj - if not H.is_directed(): - H._pred = H._adj - H._succ = H._adj - assert G._pred == H._pred - assert G._succ == H._succ - assert H._succ[1][2] is H._pred[2][1] - assert G._succ[1][2] is G._pred[2][1] - - -# edge_subgraph -class TestEdgeSubGraph(object): - @classmethod - def setup_class(cls): - # Create a path graph on five nodes. - cls.G = G = nx.path_graph(5) - # Add some node, edge, and graph attributes. - for i in range(5): - G.nodes[i]['name'] = 'node{}'.format(i) - G.edges[0, 1]['name'] = 'edge01' - G.edges[3, 4]['name'] = 'edge34' - G.graph['name'] = 'graph' - # Get the subgraph induced by the first and last edges. - cls.H = nx.edge_subgraph(G, [(0, 1), (3, 4)]) - - def test_correct_nodes(self): - """Tests that the subgraph has the correct nodes.""" - assert [0, 1, 3, 4] == sorted(self.H.nodes) - - def test_correct_edges(self): - """Tests that the subgraph has the correct edges.""" - assert ([(0, 1, 'edge01'), (3, 4, 'edge34')] == - sorted(self.H.edges(data='name'))) - - def test_add_node(self): - """Tests that adding a node to the original graph does not - affect the nodes of the subgraph. - - """ - self.G.add_node(5) - assert [0, 1, 3, 4] == sorted(self.H.nodes) - self.G.remove_node(5) - - def test_remove_node(self): - """Tests that removing a node in the original graph - removes the nodes of the subgraph. - - """ - self.G.remove_node(0) - assert [1, 3, 4] == sorted(self.H.nodes) - self.G.add_edge(0, 1) - - def test_node_attr_dict(self): - """Tests that the node attribute dictionary of the two graphs is - the same object. - - """ - for v in self.H: - assert self.G.nodes[v] == self.H.nodes[v] - # Making a change to G should make a change in H and vice versa. - self.G.nodes[0]['name'] = 'foo' - assert self.G.nodes[0] == self.H.nodes[0] - self.H.nodes[1]['name'] = 'bar' - assert self.G.nodes[1] == self.H.nodes[1] - - def test_edge_attr_dict(self): - """Tests that the edge attribute dictionary of the two graphs is - the same object. - - """ - for u, v in self.H.edges(): - assert self.G.edges[u, v] == self.H.edges[u, v] - # Making a change to G should make a change in H and vice versa. - self.G.edges[0, 1]['name'] = 'foo' - assert (self.G.edges[0, 1]['name'] == - self.H.edges[0, 1]['name']) - self.H.edges[3, 4]['name'] = 'bar' - assert (self.G.edges[3, 4]['name'] == - self.H.edges[3, 4]['name']) - - def test_graph_attr_dict(self): - """Tests that the graph attribute dictionary of the two graphs - is the same object. - - """ - assert self.G.graph is self.H.graph - - def test_readonly(self): - """Tests that the subgraph cannot change the graph structure""" - pytest.raises(nx.NetworkXError, self.H.add_node, 5) - pytest.raises(nx.NetworkXError, self.H.remove_node, 0) - pytest.raises(nx.NetworkXError, self.H.add_edge, 5, 6) - pytest.raises(nx.NetworkXError, self.H.remove_edge, 0, 1) diff --git a/extensions/fablabchemnitz/networkx/convert.py b/extensions/fablabchemnitz/networkx/convert.py deleted file mode 100644 index 6cf18c02..00000000 --- a/extensions/fablabchemnitz/networkx/convert.py +++ /dev/null @@ -1,391 +0,0 @@ -"""Functions to convert NetworkX graphs to and from other formats. - -The preferred way of converting data to a NetworkX graph is through the -graph constructor. The constructor calls the to_networkx_graph() function -which attempts to guess the input type and convert it automatically. - -Examples --------- -Create a graph with a single edge from a dictionary of dictionaries - ->>> d={0: {1: 1}} # dict-of-dicts single edge (0,1) ->>> G=nx.Graph(d) - -See Also --------- -nx_agraph, nx_pydot -""" -# Copyright (C) 2006-2013 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -import warnings -import networkx as nx -__author__ = """\n""".join(['Aric Hagberg ', - 'Pieter Swart (swart@lanl.gov)', - 'Dan Schult(dschult@colgate.edu)']) -__all__ = ['to_networkx_graph', - 'from_dict_of_dicts', 'to_dict_of_dicts', - 'from_dict_of_lists', 'to_dict_of_lists', - 'from_edgelist', 'to_edgelist'] - - -def to_networkx_graph(data, create_using=None, multigraph_input=False): - """Make a NetworkX graph from a known data structure. - - The preferred way to call this is automatically - from the class constructor - - >>> d = {0: {1: {'weight':1}}} # dict-of-dicts single edge (0,1) - >>> G = nx.Graph(d) - - instead of the equivalent - - >>> G = nx.from_dict_of_dicts(d) - - Parameters - ---------- - data : object to be converted - - Current known types are: - any NetworkX graph - dict-of-dicts - dict-of-lists - list of edges - Pandas DataFrame (row per edge) - numpy matrix - numpy ndarray - scipy sparse matrix - pygraphviz agraph - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - multigraph_input : bool (default False) - If True and data is a dict_of_dicts, - try to create a multigraph assuming dict_of_dict_of_lists. - If data and create_using are both multigraphs then create - a multigraph from a multigraph. - - """ - # NX graph - if hasattr(data, "adj"): - try: - result = from_dict_of_dicts(data.adj, - create_using=create_using, - multigraph_input=data.is_multigraph()) - if hasattr(data, 'graph'): # data.graph should be dict-like - result.graph.update(data.graph) - if hasattr(data, 'nodes'): # data.nodes should be dict-like - # result.add_node_from(data.nodes.items()) possible but - # for custom node_attr_dict_factory which may be hashable - # will be unexpected behavior - for n, dd in data.nodes.items(): - result._node[n].update(dd) - return result - except: - raise nx.NetworkXError("Input is not a correct NetworkX graph.") - - # pygraphviz agraph - if hasattr(data, "is_strict"): - try: - return nx.nx_agraph.from_agraph(data, create_using=create_using) - except: - raise nx.NetworkXError("Input is not a correct pygraphviz graph.") - - # dict of dicts/lists - if isinstance(data, dict): - try: - return from_dict_of_dicts(data, create_using=create_using, - multigraph_input=multigraph_input) - except: - try: - return from_dict_of_lists(data, create_using=create_using) - except: - raise TypeError("Input is not known type.") - - # list or generator of edges - - if (isinstance(data, (list, tuple)) or - any(hasattr(data, attr) for attr in ['_adjdict', 'next', '__next__'])): - try: - return from_edgelist(data, create_using=create_using) - except: - raise nx.NetworkXError("Input is not a valid edge list") - - # Pandas DataFrame - try: - import pandas as pd - if isinstance(data, pd.DataFrame): - if data.shape[0] == data.shape[1]: - try: - return nx.from_pandas_adjacency(data, create_using=create_using) - except: - msg = "Input is not a correct Pandas DataFrame adjacency matrix." - raise nx.NetworkXError(msg) - else: - try: - return nx.from_pandas_edgelist(data, edge_attr=True, create_using=create_using) - except: - msg = "Input is not a correct Pandas DataFrame edge-list." - raise nx.NetworkXError(msg) - except ImportError: - msg = 'pandas not found, skipping conversion test.' - warnings.warn(msg, ImportWarning) - - # numpy matrix or ndarray - try: - import numpy - if isinstance(data, (numpy.matrix, numpy.ndarray)): - try: - return nx.from_numpy_matrix(data, create_using=create_using) - except: - raise nx.NetworkXError( - "Input is not a correct numpy matrix or array.") - except ImportError: - warnings.warn('numpy not found, skipping conversion test.', - ImportWarning) - - # scipy sparse matrix - any format - try: - import scipy - if hasattr(data, "format"): - try: - return nx.from_scipy_sparse_matrix(data, create_using=create_using) - except: - raise nx.NetworkXError( - "Input is not a correct scipy sparse matrix type.") - except ImportError: - warnings.warn('scipy not found, skipping conversion test.', - ImportWarning) - - raise nx.NetworkXError( - "Input is not a known data type for conversion.") - - -def to_dict_of_lists(G, nodelist=None): - """Returns adjacency representation of graph as a dictionary of lists. - - Parameters - ---------- - G : graph - A NetworkX graph - - nodelist : list - Use only nodes specified in nodelist - - Notes - ----- - Completely ignores edge data for MultiGraph and MultiDiGraph. - - """ - if nodelist is None: - nodelist = G - - d = {} - for n in nodelist: - d[n] = [nbr for nbr in G.neighbors(n) if nbr in nodelist] - return d - - -def from_dict_of_lists(d, create_using=None): - """Returns a graph from a dictionary of lists. - - Parameters - ---------- - d : dictionary of lists - A dictionary of lists adjacency representation. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Examples - -------- - >>> dol = {0: [1]} # single edge (0,1) - >>> G = nx.from_dict_of_lists(dol) - - or - - >>> G = nx.Graph(dol) # use Graph constructor - - """ - G = nx.empty_graph(0, create_using) - G.add_nodes_from(d) - if G.is_multigraph() and not G.is_directed(): - # a dict_of_lists can't show multiedges. BUT for undirected graphs, - # each edge shows up twice in the dict_of_lists. - # So we need to treat this case separately. - seen = {} - for node, nbrlist in d.items(): - for nbr in nbrlist: - if nbr not in seen: - G.add_edge(node, nbr) - seen[node] = 1 # don't allow reverse edge to show up - else: - G.add_edges_from(((node, nbr) for node, nbrlist in d.items() - for nbr in nbrlist)) - return G - - -def to_dict_of_dicts(G, nodelist=None, edge_data=None): - """Returns adjacency representation of graph as a dictionary of dictionaries. - - Parameters - ---------- - G : graph - A NetworkX graph - - nodelist : list - Use only nodes specified in nodelist - - edge_data : list, optional - If provided, the value of the dictionary will be - set to edge_data for all edges. This is useful to make - an adjacency matrix type representation with 1 as the edge data. - If edgedata is None, the edgedata in G is used to fill the values. - If G is a multigraph, the edgedata is a dict for each pair (u,v). - """ - dod = {} - if nodelist is None: - if edge_data is None: - for u, nbrdict in G.adjacency(): - dod[u] = nbrdict.copy() - else: # edge_data is not None - for u, nbrdict in G.adjacency(): - dod[u] = dod.fromkeys(nbrdict, edge_data) - else: # nodelist is not None - if edge_data is None: - for u in nodelist: - dod[u] = {} - for v, data in ((v, data) for v, data in G[u].items() if v in nodelist): - dod[u][v] = data - else: # nodelist and edge_data are not None - for u in nodelist: - dod[u] = {} - for v in (v for v in G[u] if v in nodelist): - dod[u][v] = edge_data - return dod - - -def from_dict_of_dicts(d, create_using=None, multigraph_input=False): - """Returns a graph from a dictionary of dictionaries. - - Parameters - ---------- - d : dictionary of dictionaries - A dictionary of dictionaries adjacency representation. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - multigraph_input : bool (default False) - When True, the values of the inner dict are assumed - to be containers of edge data for multiple edges. - Otherwise this routine assumes the edge data are singletons. - - Examples - -------- - >>> dod = {0: {1: {'weight': 1}}} # single edge (0,1) - >>> G = nx.from_dict_of_dicts(dod) - - or - - >>> G = nx.Graph(dod) # use Graph constructor - - """ - G = nx.empty_graph(0, create_using) - G.add_nodes_from(d) - # is dict a MultiGraph or MultiDiGraph? - if multigraph_input: - # make a copy of the list of edge data (but not the edge data) - if G.is_directed(): - if G.is_multigraph(): - G.add_edges_from((u, v, key, data) - for u, nbrs in d.items() - for v, datadict in nbrs.items() - for key, data in datadict.items()) - else: - G.add_edges_from((u, v, data) - for u, nbrs in d.items() - for v, datadict in nbrs.items() - for key, data in datadict.items()) - else: # Undirected - if G.is_multigraph(): - seen = set() # don't add both directions of undirected graph - for u, nbrs in d.items(): - for v, datadict in nbrs.items(): - if (u, v) not in seen: - G.add_edges_from((u, v, key, data) - for key, data in datadict.items()) - seen.add((v, u)) - else: - seen = set() # don't add both directions of undirected graph - for u, nbrs in d.items(): - for v, datadict in nbrs.items(): - if (u, v) not in seen: - G.add_edges_from((u, v, data) - for key, data in datadict.items()) - seen.add((v, u)) - - else: # not a multigraph to multigraph transfer - if G.is_multigraph() and not G.is_directed(): - # d can have both representations u-v, v-u in dict. Only add one. - # We don't need this check for digraphs since we add both directions, - # or for Graph() since it is done implicitly (parallel edges not allowed) - seen = set() - for u, nbrs in d.items(): - for v, data in nbrs.items(): - if (u, v) not in seen: - G.add_edge(u, v, key=0) - G[u][v][0].update(data) - seen.add((v, u)) - else: - G.add_edges_from(((u, v, data) - for u, nbrs in d.items() - for v, data in nbrs.items())) - return G - - -def to_edgelist(G, nodelist=None): - """Returns a list of edges in the graph. - - Parameters - ---------- - G : graph - A NetworkX graph - - nodelist : list - Use only nodes specified in nodelist - - """ - if nodelist is None: - return G.edges(data=True) - return G.edges(nodelist, data=True) - - -def from_edgelist(edgelist, create_using=None): - """Returns a graph from a list of edges. - - Parameters - ---------- - edgelist : list or iterator - Edge tuples - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Examples - -------- - >>> edgelist = [(0, 1)] # single edge (0,1) - >>> G = nx.from_edgelist(edgelist) - - or - - >>> G = nx.Graph(edgelist) # use Graph constructor - - """ - G = nx.empty_graph(0, create_using) - G.add_edges_from(edgelist) - return G diff --git a/extensions/fablabchemnitz/networkx/convert_matrix.py b/extensions/fablabchemnitz/networkx/convert_matrix.py deleted file mode 100644 index bae02a13..00000000 --- a/extensions/fablabchemnitz/networkx/convert_matrix.py +++ /dev/null @@ -1,1249 +0,0 @@ -# Copyright (C) 2006-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -"""Functions to convert NetworkX graphs to and from numpy/scipy matrices. - -The preferred way of converting data to a NetworkX graph is through the -graph constructor. The constructor calls the to_networkx_graph() function -which attempts to guess the input type and convert it automatically. - -Examples --------- -Create a 10 node random graph from a numpy matrix - ->>> import numpy as np ->>> a = np.random.randint(0, 2, size=(10, 10)) ->>> D = nx.DiGraph(a) - -or equivalently - ->>> D = nx.to_networkx_graph(a, create_using=nx.DiGraph) - -See Also --------- -nx_agraph, nx_pydot -""" - -import itertools -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ['from_numpy_matrix', 'to_numpy_matrix', - 'from_pandas_adjacency', 'to_pandas_adjacency', - 'from_pandas_edgelist', 'to_pandas_edgelist', - 'to_numpy_recarray', - 'from_scipy_sparse_matrix', 'to_scipy_sparse_matrix', - 'from_numpy_array', 'to_numpy_array'] - - -def to_pandas_adjacency(G, nodelist=None, dtype=None, order=None, - multigraph_weight=sum, weight='weight', nonedge=0.0): - """Returns the graph adjacency matrix as a Pandas DataFrame. - - Parameters - ---------- - G : graph - The NetworkX graph used to construct the Pandas DataFrame. - - nodelist : list, optional - The rows and columns are ordered according to the nodes in `nodelist`. - If `nodelist` is None, then the ordering is produced by G.nodes(). - - multigraph_weight : {sum, min, max}, optional - An operator that determines how weights in multigraphs are handled. - The default is to sum the weights of the multiple edges. - - weight : string or None, optional - The edge attribute that holds the numerical value used for - the edge weight. If an edge does not have that attribute, then the - value 1 is used instead. - - nonedge : float, optional - The matrix values corresponding to nonedges are typically set to zero. - However, this could be undesirable if there are matrix values - corresponding to actual edges that also have the value zero. If so, - one might prefer nonedges to have some other value, such as nan. - - Returns - ------- - df : Pandas DataFrame - Graph adjacency matrix - - Notes - ----- - For directed graphs, entry i,j corresponds to an edge from i to j. - - The DataFrame entries are assigned to the weight edge attribute. When - an edge does not have a weight attribute, the value of the entry is set to - the number 1. For multiple (parallel) edges, the values of the entries - are determined by the 'multigraph_weight' parameter. The default is to - sum the weight attributes for each of the parallel edges. - - When `nodelist` does not contain every node in `G`, the matrix is built - from the subgraph of `G` that is induced by the nodes in `nodelist`. - - The convention used for self-loop edges in graphs is to assign the - diagonal matrix entry value to the weight attribute of the edge - (or the number 1 if the edge has no weight attribute). If the - alternate convention of doubling the edge weight is desired the - resulting Pandas DataFrame can be modified as follows: - - >>> import pandas as pd - >>> pd.options.display.max_columns = 20 - >>> import numpy as np - >>> G = nx.Graph([(1, 1)]) - >>> df = nx.to_pandas_adjacency(G, dtype=int) - >>> df - 1 - 1 1 - >>> df.values[np.diag_indices_from(df)] *= 2 - >>> df - 1 - 1 2 - - Examples - -------- - >>> G = nx.MultiDiGraph() - >>> G.add_edge(0, 1, weight=2) - 0 - >>> G.add_edge(1, 0) - 0 - >>> G.add_edge(2, 2, weight=3) - 0 - >>> G.add_edge(2, 2) - 1 - >>> nx.to_pandas_adjacency(G, nodelist=[0, 1, 2], dtype=int) - 0 1 2 - 0 0 2 0 - 1 1 0 0 - 2 0 0 4 - - """ - import pandas as pd - M = to_numpy_array(G, nodelist=nodelist, dtype=dtype, order=order, - multigraph_weight=multigraph_weight, weight=weight, - nonedge=nonedge) - if nodelist is None: - nodelist = list(G) - return pd.DataFrame(data=M, index=nodelist, columns=nodelist) - - -def from_pandas_adjacency(df, create_using=None): - r"""Returns a graph from Pandas DataFrame. - - The Pandas DataFrame is interpreted as an adjacency matrix for the graph. - - Parameters - ---------- - df : Pandas DataFrame - An adjacency matrix representation of a graph - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Notes - ----- - For directed graphs, explicitly mention create_using=nx.Digraph, - and entry i,j of df corresponds to an edge from i to j. - - If the numpy matrix has a single data type for each matrix entry it - will be converted to an appropriate Python data type. - - If the numpy matrix has a user-specified compound data type the names - of the data fields will be used as attribute keys in the resulting - NetworkX graph. - - See Also - -------- - to_pandas_adjacency - - Examples - -------- - Simple integer weights on edges: - - >>> import pandas as pd - >>> pd.options.display.max_columns = 20 - >>> df = pd.DataFrame([[1, 1], [2, 1]]) - >>> df - 0 1 - 0 1 1 - 1 2 1 - >>> G = nx.from_pandas_adjacency(df) - >>> G.name = 'Graph from pandas adjacency matrix' - >>> print(nx.info(G)) - Name: Graph from pandas adjacency matrix - Type: Graph - Number of nodes: 2 - Number of edges: 3 - Average degree: 3.0000 - - """ - - try: - df = df[df.index] - except Exception: - msg = "%s not in columns" - missing = list(set(df.index).difference(set(df.columns))) - raise nx.NetworkXError("Columns must match Indices.", msg % missing) - - A = df.values - G = from_numpy_matrix(A, create_using=create_using) - - nx.relabel.relabel_nodes(G, dict(enumerate(df.columns)), copy=False) - return G - - -def to_pandas_edgelist(G, source='source', target='target', nodelist=None, - dtype=None, order=None): - """Returns the graph edge list as a Pandas DataFrame. - - Parameters - ---------- - G : graph - The NetworkX graph used to construct the Pandas DataFrame. - - source : str or int, optional - A valid column name (string or integer) for the source nodes (for the - directed case). - - target : str or int, optional - A valid column name (string or integer) for the target nodes (for the - directed case). - - nodelist : list, optional - Use only nodes specified in nodelist - - Returns - ------- - df : Pandas DataFrame - Graph edge list - - Examples - -------- - >>> G = nx.Graph([('A', 'B', {'cost': 1, 'weight': 7}), - ... ('C', 'E', {'cost': 9, 'weight': 10})]) - >>> df = nx.to_pandas_edgelist(G, nodelist=['A', 'C']) - >>> df[['source', 'target', 'cost', 'weight']] - source target cost weight - 0 A B 1 7 - 1 C E 9 10 - - """ - import pandas as pd - if nodelist is None: - edgelist = G.edges(data=True) - else: - edgelist = G.edges(nodelist, data=True) - source_nodes = [s for s, t, d in edgelist] - target_nodes = [t for s, t, d in edgelist] - all_keys = set().union(*(d.keys() for s, t, d in edgelist)) - edge_attr = {k: [d.get(k, float("nan")) for s, t, d in edgelist] - for k in all_keys} - edgelistdict = {source: source_nodes, target: target_nodes} - edgelistdict.update(edge_attr) - return pd.DataFrame(edgelistdict) - - -def from_pandas_edgelist(df, source='source', target='target', edge_attr=None, - create_using=None): - """Returns a graph from Pandas DataFrame containing an edge list. - - The Pandas DataFrame should contain at least two columns of node names and - zero or more columns of edge attributes. Each row will be processed as one - edge instance. - - Note: This function iterates over DataFrame.values, which is not - guaranteed to retain the data type across columns in the row. This is only - a problem if your row is entirely numeric and a mix of ints and floats. In - that case, all values will be returned as floats. See the - DataFrame.iterrows documentation for an example. - - Parameters - ---------- - df : Pandas DataFrame - An edge list representation of a graph - - source : str or int - A valid column name (string or integer) for the source nodes (for the - directed case). - - target : str or int - A valid column name (string or integer) for the target nodes (for the - directed case). - - edge_attr : str or int, iterable, True, or None - A valid column name (str or int) or iterable of column names that are - used to retrieve items and add them to the graph as edge attributes. - If `True`, all of the remaining columns will be added. - If `None`, no edge attributes are added to the graph. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - See Also - -------- - to_pandas_edgelist - - Examples - -------- - Simple integer weights on edges: - - >>> import pandas as pd - >>> pd.options.display.max_columns = 20 - >>> import numpy as np - >>> rng = np.random.RandomState(seed=5) - >>> ints = rng.randint(1, 11, size=(3,2)) - >>> a = ['A', 'B', 'C'] - >>> b = ['D', 'A', 'E'] - >>> df = pd.DataFrame(ints, columns=['weight', 'cost']) - >>> df[0] = a - >>> df['b'] = b - >>> df[['weight', 'cost', 0, 'b']] - weight cost 0 b - 0 4 7 A D - 1 7 1 B A - 2 10 9 C E - >>> G = nx.from_pandas_edgelist(df, 0, 'b', ['weight', 'cost']) - >>> G['E']['C']['weight'] - 10 - >>> G['E']['C']['cost'] - 9 - >>> edges = pd.DataFrame({'source': [0, 1, 2], - ... 'target': [2, 2, 3], - ... 'weight': [3, 4, 5], - ... 'color': ['red', 'blue', 'blue']}) - >>> G = nx.from_pandas_edgelist(edges, edge_attr=True) - >>> G[0][2]['color'] - 'red' - - """ - g = nx.empty_graph(0, create_using) - - if edge_attr is None: - g.add_edges_from(zip(df[source], df[target])) - return g - - # Additional columns requested - if edge_attr is True: - cols = [c for c in df.columns if c is not source and c is not target] - elif isinstance(edge_attr, (list, tuple)): - cols = edge_attr - else: - cols = [edge_attr] - if len(cols) == 0: - msg = "Invalid edge_attr argument. No columns found with name: %s" - raise nx.NetworkXError(msg % cols) - - try: - eattrs = zip(*[df[col] for col in cols]) - except (KeyError, TypeError) as e: - msg = "Invalid edge_attr argument: %s" % edge_attr - raise nx.NetworkXError(msg) - for s, t, attrs in zip(df[source], df[target], eattrs): - if g.is_multigraph(): - key = g.add_edge(s, t) - g[s][t][key].update(zip(cols, attrs)) - else: - g.add_edge(s, t) - g[s][t].update(zip(cols, attrs)) - - return g - - -def to_numpy_matrix(G, nodelist=None, dtype=None, order=None, - multigraph_weight=sum, weight='weight', nonedge=0.0): - """Returns the graph adjacency matrix as a NumPy matrix. - - Parameters - ---------- - G : graph - The NetworkX graph used to construct the NumPy matrix. - - nodelist : list, optional - The rows and columns are ordered according to the nodes in `nodelist`. - If `nodelist` is None, then the ordering is produced by G.nodes(). - - dtype : NumPy data type, optional - A valid single NumPy data type used to initialize the array. - This must be a simple type such as int or numpy.float64 and - not a compound data type (see to_numpy_recarray) - If None, then the NumPy default is used. - - order : {'C', 'F'}, optional - Whether to store multidimensional data in C- or Fortran-contiguous - (row- or column-wise) order in memory. If None, then the NumPy default - is used. - - multigraph_weight : {sum, min, max}, optional - An operator that determines how weights in multigraphs are handled. - The default is to sum the weights of the multiple edges. - - weight : string or None optional (default = 'weight') - The edge attribute that holds the numerical value used for - the edge weight. If an edge does not have that attribute, then the - value 1 is used instead. - - nonedge : float (default = 0.0) - The matrix values corresponding to nonedges are typically set to zero. - However, this could be undesirable if there are matrix values - corresponding to actual edges that also have the value zero. If so, - one might prefer nonedges to have some other value, such as nan. - - Returns - ------- - M : NumPy matrix - Graph adjacency matrix - - See Also - -------- - to_numpy_recarray, from_numpy_matrix - - Notes - ----- - For directed graphs, entry i,j corresponds to an edge from i to j. - - The matrix entries are assigned to the weight edge attribute. When - an edge does not have a weight attribute, the value of the entry is set to - the number 1. For multiple (parallel) edges, the values of the entries - are determined by the `multigraph_weight` parameter. The default is to - sum the weight attributes for each of the parallel edges. - - When `nodelist` does not contain every node in `G`, the matrix is built - from the subgraph of `G` that is induced by the nodes in `nodelist`. - - The convention used for self-loop edges in graphs is to assign the - diagonal matrix entry value to the weight attribute of the edge - (or the number 1 if the edge has no weight attribute). If the - alternate convention of doubling the edge weight is desired the - resulting Numpy matrix can be modified as follows: - - >>> import numpy as np - >>> G = nx.Graph([(1, 1)]) - >>> A = nx.to_numpy_matrix(G) - >>> A - matrix([[1.]]) - >>> A[np.diag_indices_from(A)] *= 2 - >>> A - matrix([[2.]]) - - Examples - -------- - >>> G = nx.MultiDiGraph() - >>> G.add_edge(0, 1, weight=2) - 0 - >>> G.add_edge(1, 0) - 0 - >>> G.add_edge(2, 2, weight=3) - 0 - >>> G.add_edge(2, 2) - 1 - >>> nx.to_numpy_matrix(G, nodelist=[0, 1, 2]) - matrix([[0., 2., 0.], - [1., 0., 0.], - [0., 0., 4.]]) - - """ - import numpy as np - - A = to_numpy_array(G, nodelist=nodelist, dtype=dtype, order=order, - multigraph_weight=multigraph_weight, weight=weight, - nonedge=nonedge) - M = np.asmatrix(A, dtype=dtype) - return M - - -def from_numpy_matrix(A, parallel_edges=False, create_using=None): - """Returns a graph from numpy matrix. - - The numpy matrix is interpreted as an adjacency matrix for the graph. - - Parameters - ---------- - A : numpy matrix - An adjacency matrix representation of a graph - - parallel_edges : Boolean - If True, `create_using` is a multigraph, and `A` is an - integer matrix, then entry *(i, j)* in the matrix is interpreted as the - number of parallel edges joining vertices *i* and *j* in the graph. - If False, then the entries in the adjacency matrix are interpreted as - the weight of a single edge joining the vertices. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Notes - ----- - For directed graphs, explicitly mention create_using=nx.Digraph, - and entry i,j of A corresponds to an edge from i to j. - - If `create_using` is :class:`networkx.MultiGraph` or - :class:`networkx.MultiDiGraph`, `parallel_edges` is True, and the - entries of `A` are of type :class:`int`, then this function returns a - multigraph (constructed from `create_using`) with parallel edges. - - If `create_using` indicates an undirected multigraph, then only the edges - indicated by the upper triangle of the matrix `A` will be added to the - graph. - - If the numpy matrix has a single data type for each matrix entry it - will be converted to an appropriate Python data type. - - If the numpy matrix has a user-specified compound data type the names - of the data fields will be used as attribute keys in the resulting - NetworkX graph. - - See Also - -------- - to_numpy_matrix, to_numpy_recarray - - Examples - -------- - Simple integer weights on edges: - - >>> import numpy as np - >>> A = np.array([[1, 1], [2, 1]]) - >>> G = nx.from_numpy_matrix(A) - - If `create_using` indicates a multigraph and the matrix has only integer - entries and `parallel_edges` is False, then the entries will be treated - as weights for edges joining the nodes (without creating parallel edges): - - >>> A = np.array([[1, 1], [1, 2]]) - >>> G = nx.from_numpy_matrix(A, create_using=nx.MultiGraph) - >>> G[1][1] - AtlasView({0: {'weight': 2}}) - - If `create_using` indicates a multigraph and the matrix has only integer - entries and `parallel_edges` is True, then the entries will be treated - as the number of parallel edges joining those two vertices: - - >>> A = np.array([[1, 1], [1, 2]]) - >>> temp = nx.MultiGraph() - >>> G = nx.from_numpy_matrix(A, parallel_edges=True, create_using=temp) - >>> G[1][1] - AtlasView({0: {'weight': 1}, 1: {'weight': 1}}) - - User defined compound data type on edges: - - >>> dt = [('weight', float), ('cost', int)] - >>> A = np.array([[(1.0, 2)]], dtype=dt) - >>> G = nx.from_numpy_matrix(A) - >>> list(G.edges()) - [(0, 0)] - >>> G[0][0]['cost'] - 2 - >>> G[0][0]['weight'] - 1.0 - - """ - # This should never fail if you have created a numpy matrix with numpy... - import numpy as np - kind_to_python_type = {'f': float, - 'i': int, - 'u': int, - 'b': bool, - 'c': complex, - 'S': str, - 'V': 'void'} - try: # Python 3.x - blurb = chr(1245) # just to trigger the exception - kind_to_python_type['U'] = str - except ValueError: # Python 2.7 - kind_to_python_type['U'] = unicode - G = nx.empty_graph(0, create_using) - n, m = A.shape - if n != m: - raise nx.NetworkXError("Adjacency matrix is not square.", - "nx,ny=%s" % (A.shape,)) - dt = A.dtype - try: - python_type = kind_to_python_type[dt.kind] - except Exception: - raise TypeError("Unknown numpy data type: %s" % dt) - - # Make sure we get even the isolated nodes of the graph. - G.add_nodes_from(range(n)) - # Get a list of all the entries in the matrix with nonzero entries. These - # coordinates will become the edges in the graph. - edges = map(lambda e: (int(e[0]), int(e[1])), - zip(*(np.asarray(A).nonzero()))) - # handle numpy constructed data type - if python_type == 'void': - # Sort the fields by their offset, then by dtype, then by name. - fields = sorted((offset, dtype, name) for name, (dtype, offset) in - A.dtype.fields.items()) - triples = ((u, v, {name: kind_to_python_type[dtype.kind](val) - for (_, dtype, name), val in zip(fields, A[u, v])}) - for u, v in edges) - # If the entries in the adjacency matrix are integers, the graph is a - # multigraph, and parallel_edges is True, then create parallel edges, each - # with weight 1, for each entry in the adjacency matrix. Otherwise, create - # one edge for each positive entry in the adjacency matrix and set the - # weight of that edge to be the entry in the matrix. - elif python_type is int and G.is_multigraph() and parallel_edges: - chain = itertools.chain.from_iterable - # The following line is equivalent to: - # - # for (u, v) in edges: - # for d in range(A[u, v]): - # G.add_edge(u, v, weight=1) - # - triples = chain(((u, v, dict(weight=1)) for d in range(A[u, v])) - for (u, v) in edges) - else: # basic data type - triples = ((u, v, dict(weight=python_type(A[u, v]))) - for u, v in edges) - # If we are creating an undirected multigraph, only add the edges from the - # upper triangle of the matrix. Otherwise, add all the edges. This relies - # on the fact that the vertices created in the - # `_generated_weighted_edges()` function are actually the row/column - # indices for the matrix `A`. - # - # Without this check, we run into a problem where each edge is added twice - # when `G.add_edges_from()` is invoked below. - if G.is_multigraph() and not G.is_directed(): - triples = ((u, v, d) for u, v, d in triples if u <= v) - G.add_edges_from(triples) - return G - - -@not_implemented_for('multigraph') -def to_numpy_recarray(G, nodelist=None, dtype=None, order=None): - """Returns the graph adjacency matrix as a NumPy recarray. - - Parameters - ---------- - G : graph - The NetworkX graph used to construct the NumPy matrix. - - nodelist : list, optional - The rows and columns are ordered according to the nodes in `nodelist`. - If `nodelist` is None, then the ordering is produced by G.nodes(). - - dtype : NumPy data-type, optional - A valid NumPy named dtype used to initialize the NumPy recarray. - The data type names are assumed to be keys in the graph edge attribute - dictionary. - - order : {'C', 'F'}, optional - Whether to store multidimensional data in C- or Fortran-contiguous - (row- or column-wise) order in memory. If None, then the NumPy default - is used. - - Returns - ------- - M : NumPy recarray - The graph with specified edge data as a Numpy recarray - - Notes - ----- - When `nodelist` does not contain every node in `G`, the matrix is built - from the subgraph of `G` that is induced by the nodes in `nodelist`. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_edge(1, 2, weight=7.0, cost=5) - >>> A = nx.to_numpy_recarray(G, dtype=[('weight', float), ('cost', int)]) - >>> print(A.weight) - [[0. 7.] - [7. 0.]] - >>> print(A.cost) - [[0 5] - [5 0]] - - """ - if dtype is None: - dtype = [('weight', float)] - import numpy as np - if nodelist is None: - nodelist = list(G) - nodeset = set(nodelist) - if len(nodelist) != len(nodeset): - msg = "Ambiguous ordering: `nodelist` contained duplicates." - raise nx.NetworkXError(msg) - nlen = len(nodelist) - undirected = not G.is_directed() - index = dict(zip(nodelist, range(nlen))) - M = np.zeros((nlen, nlen), dtype=dtype, order=order) - - names = M.dtype.names - for u, v, attrs in G.edges(data=True): - if (u in nodeset) and (v in nodeset): - i, j = index[u], index[v] - values = tuple([attrs[n] for n in names]) - M[i, j] = values - if undirected: - M[j, i] = M[i, j] - - return M.view(np.recarray) - - -def to_scipy_sparse_matrix(G, nodelist=None, dtype=None, - weight='weight', format='csr'): - """Returns the graph adjacency matrix as a SciPy sparse matrix. - - Parameters - ---------- - G : graph - The NetworkX graph used to construct the NumPy matrix. - - nodelist : list, optional - The rows and columns are ordered according to the nodes in `nodelist`. - If `nodelist` is None, then the ordering is produced by G.nodes(). - - dtype : NumPy data-type, optional - A valid NumPy dtype used to initialize the array. If None, then the - NumPy default is used. - - weight : string or None optional (default='weight') - The edge attribute that holds the numerical value used for - the edge weight. If None then all edge weights are 1. - - format : str in {'bsr', 'csr', 'csc', 'coo', 'lil', 'dia', 'dok'} - The type of the matrix to be returned (default 'csr'). For - some algorithms different implementations of sparse matrices - can perform better. See [1]_ for details. - - Returns - ------- - M : SciPy sparse matrix - Graph adjacency matrix. - - Notes - ----- - For directed graphs, matrix entry i,j corresponds to an edge from i to j. - - The matrix entries are populated using the edge attribute held in - parameter weight. When an edge does not have that attribute, the - value of the entry is 1. - - For multiple edges the matrix values are the sums of the edge weights. - - When `nodelist` does not contain every node in `G`, the matrix is built - from the subgraph of `G` that is induced by the nodes in `nodelist`. - - Uses coo_matrix format. To convert to other formats specify the - format= keyword. - - The convention used for self-loop edges in graphs is to assign the - diagonal matrix entry value to the weight attribute of the edge - (or the number 1 if the edge has no weight attribute). If the - alternate convention of doubling the edge weight is desired the - resulting Scipy sparse matrix can be modified as follows: - - >>> import scipy as sp - >>> G = nx.Graph([(1, 1)]) - >>> A = nx.to_scipy_sparse_matrix(G) - >>> print(A.todense()) - [[1]] - >>> A.setdiag(A.diagonal() * 2) - >>> print(A.todense()) - [[2]] - - Examples - -------- - >>> G = nx.MultiDiGraph() - >>> G.add_edge(0, 1, weight=2) - 0 - >>> G.add_edge(1, 0) - 0 - >>> G.add_edge(2, 2, weight=3) - 0 - >>> G.add_edge(2, 2) - 1 - >>> S = nx.to_scipy_sparse_matrix(G, nodelist=[0, 1, 2]) - >>> print(S.todense()) - [[0 2 0] - [1 0 0] - [0 0 4]] - - References - ---------- - .. [1] Scipy Dev. References, "Sparse Matrices", - https://docs.scipy.org/doc/scipy/reference/sparse.html - """ - from scipy import sparse - if nodelist is None: - nodelist = list(G) - nlen = len(nodelist) - if nlen == 0: - raise nx.NetworkXError("Graph has no nodes or edges") - - if len(nodelist) != len(set(nodelist)): - msg = "Ambiguous ordering: `nodelist` contained duplicates." - raise nx.NetworkXError(msg) - - index = dict(zip(nodelist, range(nlen))) - coefficients = zip(*((index[u], index[v], d.get(weight, 1)) - for u, v, d in G.edges(nodelist, data=True) - if u in index and v in index)) - try: - row, col, data = coefficients - except ValueError: - # there is no edge in the subgraph - row, col, data = [], [], [] - - if G.is_directed(): - M = sparse.coo_matrix((data, (row, col)), - shape=(nlen, nlen), dtype=dtype) - else: - # symmetrize matrix - d = data + data - r = row + col - c = col + row - # selfloop entries get double counted when symmetrizing - # so we subtract the data on the diagonal - selfloops = list(nx.selfloop_edges(G, data=True)) - if selfloops: - diag_index, diag_data = zip(*((index[u], -d.get(weight, 1)) - for u, v, d in selfloops - if u in index and v in index)) - d += diag_data - r += diag_index - c += diag_index - M = sparse.coo_matrix((d, (r, c)), shape=(nlen, nlen), dtype=dtype) - try: - return M.asformat(format) - # From Scipy 1.1.0, asformat will throw a ValueError instead of an - # AttributeError if the format if not recognized. - except (AttributeError, ValueError): - raise nx.NetworkXError("Unknown sparse matrix format: %s" % format) - - -def _csr_gen_triples(A): - """Converts a SciPy sparse matrix in **Compressed Sparse Row** format to - an iterable of weighted edge triples. - - """ - nrows = A.shape[0] - data, indices, indptr = A.data, A.indices, A.indptr - for i in range(nrows): - for j in range(indptr[i], indptr[i + 1]): - yield i, indices[j], data[j] - - -def _csc_gen_triples(A): - """Converts a SciPy sparse matrix in **Compressed Sparse Column** format to - an iterable of weighted edge triples. - - """ - ncols = A.shape[1] - data, indices, indptr = A.data, A.indices, A.indptr - for i in range(ncols): - for j in range(indptr[i], indptr[i + 1]): - yield indices[j], i, data[j] - - -def _coo_gen_triples(A): - """Converts a SciPy sparse matrix in **Coordinate** format to an iterable - of weighted edge triples. - - """ - row, col, data = A.row, A.col, A.data - return zip(row, col, data) - - -def _dok_gen_triples(A): - """Converts a SciPy sparse matrix in **Dictionary of Keys** format to an - iterable of weighted edge triples. - - """ - for (r, c), v in A.items(): - yield r, c, v - - -def _generate_weighted_edges(A): - """Returns an iterable over (u, v, w) triples, where u and v are adjacent - vertices and w is the weight of the edge joining u and v. - - `A` is a SciPy sparse matrix (in any format). - - """ - if A.format == 'csr': - return _csr_gen_triples(A) - if A.format == 'csc': - return _csc_gen_triples(A) - if A.format == 'dok': - return _dok_gen_triples(A) - # If A is in any other format (including COO), convert it to COO format. - return _coo_gen_triples(A.tocoo()) - - -def from_scipy_sparse_matrix(A, parallel_edges=False, create_using=None, - edge_attribute='weight'): - """Creates a new graph from an adjacency matrix given as a SciPy sparse - matrix. - - Parameters - ---------- - A: scipy sparse matrix - An adjacency matrix representation of a graph - - parallel_edges : Boolean - If this is True, `create_using` is a multigraph, and `A` is an - integer matrix, then entry *(i, j)* in the matrix is interpreted as the - number of parallel edges joining vertices *i* and *j* in the graph. - If it is False, then the entries in the matrix are interpreted as - the weight of a single edge joining the vertices. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - edge_attribute: string - Name of edge attribute to store matrix numeric value. The data will - have the same type as the matrix entry (int, float, (real,imag)). - - Notes - ----- - For directed graphs, explicitly mention create_using=nx.Digraph, - and entry i,j of A corresponds to an edge from i to j. - - If `create_using` is :class:`networkx.MultiGraph` or - :class:`networkx.MultiDiGraph`, `parallel_edges` is True, and the - entries of `A` are of type :class:`int`, then this function returns a - multigraph (constructed from `create_using`) with parallel edges. - In this case, `edge_attribute` will be ignored. - - If `create_using` indicates an undirected multigraph, then only the edges - indicated by the upper triangle of the matrix `A` will be added to the - graph. - - Examples - -------- - >>> import scipy as sp - >>> A = sp.sparse.eye(2, 2, 1) - >>> G = nx.from_scipy_sparse_matrix(A) - - If `create_using` indicates a multigraph and the matrix has only integer - entries and `parallel_edges` is False, then the entries will be treated - as weights for edges joining the nodes (without creating parallel edges): - - >>> A = sp.sparse.csr_matrix([[1, 1], [1, 2]]) - >>> G = nx.from_scipy_sparse_matrix(A, create_using=nx.MultiGraph) - >>> G[1][1] - AtlasView({0: {'weight': 2}}) - - If `create_using` indicates a multigraph and the matrix has only integer - entries and `parallel_edges` is True, then the entries will be treated - as the number of parallel edges joining those two vertices: - - >>> A = sp.sparse.csr_matrix([[1, 1], [1, 2]]) - >>> G = nx.from_scipy_sparse_matrix(A, parallel_edges=True, - ... create_using=nx.MultiGraph) - >>> G[1][1] - AtlasView({0: {'weight': 1}, 1: {'weight': 1}}) - - """ - G = nx.empty_graph(0, create_using) - n, m = A.shape - if n != m: - raise nx.NetworkXError( - "Adjacency matrix is not square. nx,ny=%s" % (A.shape,)) - # Make sure we get even the isolated nodes of the graph. - G.add_nodes_from(range(n)) - # Create an iterable over (u, v, w) triples and for each triple, add an - # edge from u to v with weight w. - triples = _generate_weighted_edges(A) - # If the entries in the adjacency matrix are integers, the graph is a - # multigraph, and parallel_edges is True, then create parallel edges, each - # with weight 1, for each entry in the adjacency matrix. Otherwise, create - # one edge for each positive entry in the adjacency matrix and set the - # weight of that edge to be the entry in the matrix. - if A.dtype.kind in ('i', 'u') and G.is_multigraph() and parallel_edges: - chain = itertools.chain.from_iterable - # The following line is equivalent to: - # - # for (u, v) in edges: - # for d in range(A[u, v]): - # G.add_edge(u, v, weight=1) - # - triples = chain(((u, v, 1) for d in range(w)) for (u, v, w) in triples) - # If we are creating an undirected multigraph, only add the edges from the - # upper triangle of the matrix. Otherwise, add all the edges. This relies - # on the fact that the vertices created in the - # `_generated_weighted_edges()` function are actually the row/column - # indices for the matrix `A`. - # - # Without this check, we run into a problem where each edge is added twice - # when `G.add_weighted_edges_from()` is invoked below. - if G.is_multigraph() and not G.is_directed(): - triples = ((u, v, d) for u, v, d in triples if u <= v) - G.add_weighted_edges_from(triples, weight=edge_attribute) - return G - - -def to_numpy_array(G, nodelist=None, dtype=None, order=None, - multigraph_weight=sum, weight='weight', nonedge=0.0): - """Returns the graph adjacency matrix as a NumPy array. - - Parameters - ---------- - G : graph - The NetworkX graph used to construct the NumPy array. - - nodelist : list, optional - The rows and columns are ordered according to the nodes in `nodelist`. - If `nodelist` is None, then the ordering is produced by G.nodes(). - - dtype : NumPy data type, optional - A valid single NumPy data type used to initialize the array. - This must be a simple type such as int or numpy.float64 and - not a compound data type (see to_numpy_recarray) - If None, then the NumPy default is used. - - order : {'C', 'F'}, optional - Whether to store multidimensional data in C- or Fortran-contiguous - (row- or column-wise) order in memory. If None, then the NumPy default - is used. - - multigraph_weight : {sum, min, max}, optional - An operator that determines how weights in multigraphs are handled. - The default is to sum the weights of the multiple edges. - - weight : string or None optional (default = 'weight') - The edge attribute that holds the numerical value used for - the edge weight. If an edge does not have that attribute, then the - value 1 is used instead. - - nonedge : float (default = 0.0) - The array values corresponding to nonedges are typically set to zero. - However, this could be undesirable if there are array values - corresponding to actual edges that also have the value zero. If so, - one might prefer nonedges to have some other value, such as nan. - - Returns - ------- - A : NumPy ndarray - Graph adjacency matrix - - See Also - -------- - from_numpy_array - - Notes - ----- - For directed graphs, entry i,j corresponds to an edge from i to j. - - Entries in the adjacency matrix are assigned to the weight edge attribute. - When an edge does not have a weight attribute, the value of the entry is - set to the number 1. For multiple (parallel) edges, the values of the - entries are determined by the `multigraph_weight` parameter. The default is - to sum the weight attributes for each of the parallel edges. - - When `nodelist` does not contain every node in `G`, the adjacency matrix is - built from the subgraph of `G` that is induced by the nodes in `nodelist`. - - The convention used for self-loop edges in graphs is to assign the - diagonal array entry value to the weight attribute of the edge - (or the number 1 if the edge has no weight attribute). If the - alternate convention of doubling the edge weight is desired the - resulting NumPy array can be modified as follows: - - >>> import numpy as np - >>> G = nx.Graph([(1, 1)]) - >>> A = nx.to_numpy_array(G) - >>> A - array([[1.]]) - >>> A[np.diag_indices_from(A)] *= 2 - >>> A - array([[2.]]) - - Examples - -------- - >>> G = nx.MultiDiGraph() - >>> G.add_edge(0, 1, weight=2) - 0 - >>> G.add_edge(1, 0) - 0 - >>> G.add_edge(2, 2, weight=3) - 0 - >>> G.add_edge(2, 2) - 1 - >>> nx.to_numpy_array(G, nodelist=[0, 1, 2]) - array([[0., 2., 0.], - [1., 0., 0.], - [0., 0., 4.]]) - - """ - import numpy as np - - if nodelist is None: - nodelist = list(G) - nodeset = set(nodelist) - if len(nodelist) != len(nodeset): - msg = "Ambiguous ordering: `nodelist` contained duplicates." - raise nx.NetworkXError(msg) - - nlen = len(nodelist) - undirected = not G.is_directed() - index = dict(zip(nodelist, range(nlen))) - - # Initially, we start with an array of nans. Then we populate the array - # using data from the graph. Afterwards, any leftover nans will be - # converted to the value of `nonedge`. Note, we use nans initially, - # instead of zero, for two reasons: - # - # 1) It can be important to distinguish a real edge with the value 0 - # from a nonedge with the value 0. - # - # 2) When working with multi(di)graphs, we must combine the values of all - # edges between any two nodes in some manner. This often takes the - # form of a sum, min, or max. Using the value 0 for a nonedge would - # have undesirable effects with min and max, but using nanmin and - # nanmax with initially nan values is not problematic at all. - # - # That said, there are still some drawbacks to this approach. Namely, if - # a real edge is nan, then that value is a) not distinguishable from - # nonedges and b) is ignored by the default combinator (nansum, nanmin, - # nanmax) functions used for multi(di)graphs. If this becomes an issue, - # an alternative approach is to use masked arrays. Initially, every - # element is masked and set to some `initial` value. As we populate the - # graph, elements are unmasked (automatically) when we combine the initial - # value with the values given by real edges. At the end, we convert all - # masked values to `nonedge`. Using masked arrays fully addresses reason 1, - # but for reason 2, we would still have the issue with min and max if the - # initial values were 0.0. Note: an initial value of +inf is appropriate - # for min, while an initial value of -inf is appropriate for max. When - # working with sum, an initial value of zero is appropriate. Ideally then, - # we'd want to allow users to specify both a value for nonedges and also - # an initial value. For multi(di)graphs, the choice of the initial value - # will, in general, depend on the combinator function---sensible defaults - # can be provided. - - if G.is_multigraph(): - # Handle MultiGraphs and MultiDiGraphs - A = np.full((nlen, nlen), np.nan, order=order) - # use numpy nan-aware operations - operator = {sum: np.nansum, min: np.nanmin, max: np.nanmax} - try: - op = operator[multigraph_weight] - except Exception: - raise ValueError('multigraph_weight must be sum, min, or max') - - for u, v, attrs in G.edges(data=True): - if (u in nodeset) and (v in nodeset): - i, j = index[u], index[v] - e_weight = attrs.get(weight, 1) - A[i, j] = op([e_weight, A[i, j]]) - if undirected: - A[j, i] = A[i, j] - else: - # Graph or DiGraph, this is much faster than above - A = np.full((nlen, nlen), np.nan, order=order) - for u, nbrdict in G.adjacency(): - for v, d in nbrdict.items(): - try: - A[index[u], index[v]] = d.get(weight, 1) - except KeyError: - # This occurs when there are fewer desired nodes than - # there are nodes in the graph: len(nodelist) < len(G) - pass - - A[np.isnan(A)] = nonedge - A = np.asarray(A, dtype=dtype) - return A - - -def from_numpy_array(A, parallel_edges=False, create_using=None): - """Returns a graph from NumPy array. - - The NumPy array is interpreted as an adjacency matrix for the graph. - - Parameters - ---------- - A : NumPy ndarray - An adjacency matrix representation of a graph - - parallel_edges : Boolean - If this is True, `create_using` is a multigraph, and `A` is an - integer array, then entry *(i, j)* in the array is interpreted as the - number of parallel edges joining vertices *i* and *j* in the graph. - If it is False, then the entries in the array are interpreted as - the weight of a single edge joining the vertices. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Notes - ----- - For directed graphs, explicitly mention create_using=nx.Digraph, - and entry i,j of A corresponds to an edge from i to j. - - If `create_using` is :class:`networkx.MultiGraph` or - :class:`networkx.MultiDiGraph`, `parallel_edges` is True, and the - entries of `A` are of type :class:`int`, then this function returns a - multigraph (of the same type as `create_using`) with parallel edges. - - If `create_using` indicates an undirected multigraph, then only the edges - indicated by the upper triangle of the array `A` will be added to the - graph. - - If the NumPy array has a single data type for each array entry it - will be converted to an appropriate Python data type. - - If the NumPy array has a user-specified compound data type the names - of the data fields will be used as attribute keys in the resulting - NetworkX graph. - - See Also - -------- - to_numpy_array - - Examples - -------- - Simple integer weights on edges: - - >>> import numpy as np - >>> A = np.array([[1, 1], [2, 1]]) - >>> G = nx.from_numpy_array(A) - >>> G.edges(data=True) - EdgeDataView([(0, 0, {'weight': 1}), (0, 1, {'weight': 2}), \ -(1, 1, {'weight': 1})]) - - If `create_using` indicates a multigraph and the array has only integer - entries and `parallel_edges` is False, then the entries will be treated - as weights for edges joining the nodes (without creating parallel edges): - - >>> A = np.array([[1, 1], [1, 2]]) - >>> G = nx.from_numpy_array(A, create_using=nx.MultiGraph) - >>> G[1][1] - AtlasView({0: {'weight': 2}}) - - If `create_using` indicates a multigraph and the array has only integer - entries and `parallel_edges` is True, then the entries will be treated - as the number of parallel edges joining those two vertices: - - >>> A = np.array([[1, 1], [1, 2]]) - >>> temp = nx.MultiGraph() - >>> G = nx.from_numpy_array(A, parallel_edges=True, create_using=temp) - >>> G[1][1] - AtlasView({0: {'weight': 1}, 1: {'weight': 1}}) - - User defined compound data type on edges: - - >>> dt = [('weight', float), ('cost', int)] - >>> A = np.array([[(1.0, 2)]], dtype=dt) - >>> G = nx.from_numpy_array(A) - >>> G.edges() - EdgeView([(0, 0)]) - >>> G[0][0]['cost'] - 2 - >>> G[0][0]['weight'] - 1.0 - - """ - return from_numpy_matrix(A, parallel_edges=parallel_edges, - create_using=create_using) - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') - pandas = pytest.importorskip('pandas') diff --git a/extensions/fablabchemnitz/networkx/drawing/__init__.py b/extensions/fablabchemnitz/networkx/drawing/__init__.py deleted file mode 100644 index 1e8542fe..00000000 --- a/extensions/fablabchemnitz/networkx/drawing/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# graph drawing and interface to graphviz - -from .layout import * -from .nx_pylab import * -from . import nx_agraph -from . import nx_pydot diff --git a/extensions/fablabchemnitz/networkx/drawing/layout.py b/extensions/fablabchemnitz/networkx/drawing/layout.py deleted file mode 100644 index a9ec5b47..00000000 --- a/extensions/fablabchemnitz/networkx/drawing/layout.py +++ /dev/null @@ -1,1078 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# Richard Penney -# Michael Fedell -# Valentino Constantinou -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg , -# Dan Schult -""" -****** -Layout -****** - -Node positioning algorithms for graph drawing. - -For `random_layout()` the possible resulting shape -is a square of side [0, scale] (default: [0, 1]) -Changing `center` shifts the layout by that amount. - -For the other layout routines, the extent is -[center - scale, center + scale] (default: [-1, 1]). - -Warning: Most layout routines have only been tested in 2-dimensions. - -""" -import networkx as nx -from networkx.utils import random_state - -__all__ = ['bipartite_layout', - 'circular_layout', - 'kamada_kawai_layout', - 'random_layout', - 'rescale_layout', - 'shell_layout', - 'spring_layout', - 'spectral_layout', - 'planar_layout', - 'fruchterman_reingold_layout', - 'spiral_layout'] - - -def _process_params(G, center, dim): - # Some boilerplate code. - import numpy as np - - if not isinstance(G, nx.Graph): - empty_graph = nx.Graph() - empty_graph.add_nodes_from(G) - G = empty_graph - - if center is None: - center = np.zeros(dim) - else: - center = np.asarray(center) - - if len(center) != dim: - msg = "length of center coordinates must match dimension of layout" - raise ValueError(msg) - - return G, center - - -@random_state(3) -def random_layout(G, center=None, dim=2, seed=None): - """Position nodes uniformly at random in the unit square. - - For every node, a position is generated by choosing each of dim - coordinates uniformly at random on the interval [0.0, 1.0). - - NumPy (http://scipy.org) is required for this function. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - - center : array-like or None - Coordinate pair around which to center the layout. - - dim : int - Dimension of layout. - - seed : int, RandomState instance or None optional (default=None) - Set the random state for deterministic node layouts. - If int, `seed` is the seed used by the random number generator, - if numpy.random.RandomState instance, `seed` is the random - number generator, - if None, the random number generator is the RandomState instance used - by numpy.random. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node - - Examples - -------- - >>> G = nx.lollipop_graph(4, 3) - >>> pos = nx.random_layout(G) - - """ - import numpy as np - - G, center = _process_params(G, center, dim) - pos = seed.rand(len(G), dim) + center - pos = pos.astype(np.float32) - pos = dict(zip(G, pos)) - - return pos - - -def circular_layout(G, scale=1, center=None, dim=2): - # dim=2 only - """Position nodes on a circle. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - - scale : number (default: 1) - Scale factor for positions. - - center : array-like or None - Coordinate pair around which to center the layout. - - dim : int - Dimension of layout. - If dim>2, the remaining dimensions are set to zero - in the returned positions. - If dim<2, a ValueError is raised. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node - - Raises - ------- - ValueError - If dim < 2 - - Examples - -------- - >>> G = nx.path_graph(4) - >>> pos = nx.circular_layout(G) - - Notes - ----- - This algorithm currently only works in two dimensions and does not - try to minimize edge crossings. - - """ - import numpy as np - - if dim < 2: - raise ValueError('cannot handle dimensions < 2') - - G, center = _process_params(G, center, dim) - - paddims = max(0, (dim - 2)) - - if len(G) == 0: - pos = {} - elif len(G) == 1: - pos = {nx.utils.arbitrary_element(G): center} - else: - # Discard the extra angle since it matches 0 radians. - theta = np.linspace(0, 1, len(G) + 1)[:-1] * 2 * np.pi - theta = theta.astype(np.float32) - pos = np.column_stack([np.cos(theta), np.sin(theta), - np.zeros((len(G), paddims))]) - pos = rescale_layout(pos, scale=scale) + center - pos = dict(zip(G, pos)) - - return pos - - -def shell_layout(G, nlist=None, scale=1, center=None, dim=2): - """Position nodes in concentric circles. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - - nlist : list of lists - List of node lists for each shell. - - scale : number (default: 1) - Scale factor for positions. - - center : array-like or None - Coordinate pair around which to center the layout. - - dim : int - Dimension of layout, currently only dim=2 is supported. - Other dimension values result in a ValueError. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node - - Raises - ------- - ValueError - If dim != 2 - - Examples - -------- - >>> G = nx.path_graph(4) - >>> shells = [[0], [1, 2, 3]] - >>> pos = nx.shell_layout(G, shells) - - Notes - ----- - This algorithm currently only works in two dimensions and does not - try to minimize edge crossings. - - """ - import numpy as np - - if dim != 2: - raise ValueError('can only handle 2 dimensions') - - G, center = _process_params(G, center, dim) - - if len(G) == 0: - return {} - if len(G) == 1: - return {nx.utils.arbitrary_element(G): center} - - if nlist is None: - # draw the whole graph in one shell - nlist = [list(G)] - - if len(nlist[0]) == 1: - # single node at center - radius = 0.0 - else: - # else start at r=1 - radius = 1.0 - - npos = {} - for nodes in nlist: - # Discard the extra angle since it matches 0 radians. - theta = np.linspace(0, 1, len(nodes) + 1)[:-1] * 2 * np.pi - theta = theta.astype(np.float32) - pos = np.column_stack([np.cos(theta), np.sin(theta)]) - if len(pos) > 1: - pos = rescale_layout(pos, scale=scale * radius / len(nlist)) + center - else: - pos = np.array([(scale * radius + center[0], center[1])]) - npos.update(zip(nodes, pos)) - radius += 1.0 - - return npos - - -def bipartite_layout(G, nodes, align='vertical', - scale=1, center=None, aspect_ratio=4/3): - """Position nodes in two straight lines. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - - nodes : list or container - Nodes in one node set of the bipartite graph. - This set will be placed on left or top. - - align : string (default='vertical') - The alignment of nodes. Vertical or horizontal. - - scale : number (default: 1) - Scale factor for positions. - - center : array-like or None - Coordinate pair around which to center the layout. - - aspect_ratio : number (default=4/3): - The ratio of the width to the height of the layout. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node. - - Examples - -------- - >>> G = nx.bipartite.gnmk_random_graph(3, 5, 10, seed=123) - >>> top = nx.bipartite.sets(G)[0] - >>> pos = nx.bipartite_layout(G, top) - - Notes - ----- - This algorithm currently only works in two dimensions and does not - try to minimize edge crossings. - - """ - - import numpy as np - - G, center = _process_params(G, center=center, dim=2) - if len(G) == 0: - return {} - - height = 1 - width = aspect_ratio * height - offset = (width/2, height/2) - - top = set(nodes) - bottom = set(G) - top - nodes = list(top) + list(bottom) - - if align == 'vertical': - left_xs = np.repeat(0, len(top)) - right_xs = np.repeat(width, len(bottom)) - left_ys = np.linspace(0, height, len(top)) - right_ys = np.linspace(0, height, len(bottom)) - - top_pos = np.column_stack([left_xs, left_ys]) - offset - bottom_pos = np.column_stack([right_xs, right_ys]) - offset - - pos = np.concatenate([top_pos, bottom_pos]) - pos = rescale_layout(pos, scale=scale) + center - pos = dict(zip(nodes, pos)) - return pos - - if align == 'horizontal': - top_ys = np.repeat(height, len(top)) - bottom_ys = np.repeat(0, len(bottom)) - top_xs = np.linspace(0, width, len(top)) - bottom_xs = np.linspace(0, width, len(bottom)) - - top_pos = np.column_stack([top_xs, top_ys]) - offset - bottom_pos = np.column_stack([bottom_xs, bottom_ys]) - offset - - pos = np.concatenate([top_pos, bottom_pos]) - pos = rescale_layout(pos, scale=scale) + center - pos = dict(zip(nodes, pos)) - return pos - - msg = 'align must be either vertical or horizontal.' - raise ValueError(msg) - - -@random_state(10) -def fruchterman_reingold_layout(G, - k=None, - pos=None, - fixed=None, - iterations=50, - threshold=1e-4, - weight='weight', - scale=1, - center=None, - dim=2, - seed=None): - """Position nodes using Fruchterman-Reingold force-directed algorithm. - - The algorithm simulates a force-directed representation of the network - treating edges as springs holding nodes close, while treating nodes - as repelling objects, sometimes called an anti-gravity force. - Simulation continues until the positions are close to an equilibrium. - - There are some hard-coded values: minimal distance between - nodes (0.01) and "temperature" of 0.1 to ensure nodes don't fly away. - During the simulation, `k` helps determine the distance between nodes, - though `scale` and `center` determine the size and place after - rescaling occurs at the end of the simulation. - - Fixing some nodes doesn't allow them to move in the simulation. - It also turns off the rescaling feature at the simulation's end. - In addition, setting `scale` to `None` turns off rescaling. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - - k : float (default=None) - Optimal distance between nodes. If None the distance is set to - 1/sqrt(n) where n is the number of nodes. Increase this value - to move nodes farther apart. - - pos : dict or None optional (default=None) - Initial positions for nodes as a dictionary with node as keys - and values as a coordinate list or tuple. If None, then use - random initial positions. - - fixed : list or None optional (default=None) - Nodes to keep fixed at initial position. - ValueError raised if `fixed` specified and `pos` not. - - iterations : int optional (default=50) - Maximum number of iterations taken - - threshold: float optional (default = 1e-4) - Threshold for relative error in node position changes. - The iteration stops if the error is below this threshold. - - weight : string or None optional (default='weight') - The edge attribute that holds the numerical value used for - the edge weight. If None, then all edge weights are 1. - - scale : number or None (default: 1) - Scale factor for positions. Not used unless `fixed is None`. - If scale is None, no rescaling is performed. - - center : array-like or None - Coordinate pair around which to center the layout. - Not used unless `fixed is None`. - - dim : int - Dimension of layout. - - seed : int, RandomState instance or None optional (default=None) - Set the random state for deterministic node layouts. - If int, `seed` is the seed used by the random number generator, - if numpy.random.RandomState instance, `seed` is the random - number generator, - if None, the random number generator is the RandomState instance used - by numpy.random. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node - - Examples - -------- - >>> G = nx.path_graph(4) - >>> pos = nx.spring_layout(G) - - # The same using longer but equivalent function name - >>> pos = nx.fruchterman_reingold_layout(G) - """ - import numpy as np - - G, center = _process_params(G, center, dim) - - if fixed is not None: - if pos is None: - raise ValueError('nodes are fixed without positions given') - for node in fixed: - if node not in pos: - raise ValueError('nodes are fixed without positions given') - nfixed = {node: i for i, node in enumerate(G)} - fixed = np.asarray([nfixed[node] for node in fixed]) - - if pos is not None: - # Determine size of existing domain to adjust initial positions - dom_size = max(coord for pos_tup in pos.values() for coord in pos_tup) - if dom_size == 0: - dom_size = 1 - pos_arr = seed.rand(len(G), dim) * dom_size + center - - for i, n in enumerate(G): - if n in pos: - pos_arr[i] = np.asarray(pos[n]) - else: - pos_arr = None - dom_size = 1 - - if len(G) == 0: - return {} - if len(G) == 1: - return {nx.utils.arbitrary_element(G.nodes()): center} - - try: - # Sparse matrix - if len(G) < 500: # sparse solver for large graphs - raise ValueError - A = nx.to_scipy_sparse_matrix(G, weight=weight, dtype='f') - if k is None and fixed is not None: - # We must adjust k by domain size for layouts not near 1x1 - nnodes, _ = A.shape - k = dom_size / np.sqrt(nnodes) - pos = _sparse_fruchterman_reingold(A, k, pos_arr, fixed, - iterations, threshold, - dim, seed) - except: - A = nx.to_numpy_array(G, weight=weight) - if k is None and fixed is not None: - # We must adjust k by domain size for layouts not near 1x1 - nnodes, _ = A.shape - k = dom_size / np.sqrt(nnodes) - pos = _fruchterman_reingold(A, k, pos_arr, fixed, iterations, - threshold, dim, seed) - if fixed is None and scale is not None: - pos = rescale_layout(pos, scale=scale) + center - pos = dict(zip(G, pos)) - return pos - - -spring_layout = fruchterman_reingold_layout - - -@random_state(7) -def _fruchterman_reingold(A, k=None, pos=None, fixed=None, iterations=50, - threshold=1e-4, dim=2, seed=None): - # Position nodes in adjacency matrix A using Fruchterman-Reingold - # Entry point for NetworkX graph is fruchterman_reingold_layout() - import numpy as np - - try: - nnodes, _ = A.shape - except AttributeError: - msg = "fruchterman_reingold() takes an adjacency matrix as input" - raise nx.NetworkXError(msg) - - if pos is None: - # random initial positions - pos = np.asarray(seed.rand(nnodes, dim), dtype=A.dtype) - else: - # make sure positions are of same type as matrix - pos = pos.astype(A.dtype) - - # optimal distance between nodes - if k is None: - k = np.sqrt(1.0 / nnodes) - # the initial "temperature" is about .1 of domain area (=1x1) - # this is the largest step allowed in the dynamics. - # We need to calculate this in case our fixed positions force our domain - # to be much bigger than 1x1 - t = max(max(pos.T[0]) - min(pos.T[0]), max(pos.T[1]) - min(pos.T[1])) * 0.1 - # simple cooling scheme. - # linearly step down by dt on each iteration so last iteration is size dt. - dt = t / float(iterations + 1) - delta = np.zeros((pos.shape[0], pos.shape[0], pos.shape[1]), dtype=A.dtype) - # the inscrutable (but fast) version - # this is still O(V^2) - # could use multilevel methods to speed this up significantly - for iteration in range(iterations): - # matrix of difference between points - delta = pos[:, np.newaxis, :] - pos[np.newaxis, :, :] - # distance between points - distance = np.linalg.norm(delta, axis=-1) - # enforce minimum distance of 0.01 - np.clip(distance, 0.01, None, out=distance) - # displacement "force" - displacement = np.einsum('ijk,ij->ik', - delta, - (k * k / distance**2 - A * distance / k)) - # update positions - length = np.linalg.norm(displacement, axis=-1) - length = np.where(length < 0.01, 0.1, length) - delta_pos = np.einsum('ij,i->ij', displacement, t / length) - if fixed is not None: - # don't change positions of fixed nodes - delta_pos[fixed] = 0.0 - pos += delta_pos - # cool temperature - t -= dt - err = np.linalg.norm(delta_pos) / nnodes - if err < threshold: - break - return pos - - -@random_state(7) -def _sparse_fruchterman_reingold(A, k=None, pos=None, fixed=None, - iterations=50, threshold=1e-4, dim=2, - seed=None): - # Position nodes in adjacency matrix A using Fruchterman-Reingold - # Entry point for NetworkX graph is fruchterman_reingold_layout() - # Sparse version - import numpy as np - - try: - nnodes, _ = A.shape - except AttributeError: - msg = "fruchterman_reingold() takes an adjacency matrix as input" - raise nx.NetworkXError(msg) - try: - from scipy.sparse import spdiags, coo_matrix - except ImportError: - msg = "_sparse_fruchterman_reingold() scipy numpy: http://scipy.org/ " - raise ImportError(msg) - # make sure we have a LIst of Lists representation - try: - A = A.tolil() - except: - A = (coo_matrix(A)).tolil() - - if pos is None: - # random initial positions - pos = np.asarray(seed.rand(nnodes, dim), dtype=A.dtype) - else: - # make sure positions are of same type as matrix - pos = pos.astype(A.dtype) - - # no fixed nodes - if fixed is None: - fixed = [] - - # optimal distance between nodes - if k is None: - k = np.sqrt(1.0 / nnodes) - # the initial "temperature" is about .1 of domain area (=1x1) - # this is the largest step allowed in the dynamics. - t = max(max(pos.T[0]) - min(pos.T[0]), max(pos.T[1]) - min(pos.T[1])) * 0.1 - # simple cooling scheme. - # linearly step down by dt on each iteration so last iteration is size dt. - dt = t / float(iterations + 1) - - displacement = np.zeros((dim, nnodes)) - for iteration in range(iterations): - displacement *= 0 - # loop over rows - for i in range(A.shape[0]): - if i in fixed: - continue - # difference between this row's node position and all others - delta = (pos[i] - pos).T - # distance between points - distance = np.sqrt((delta**2).sum(axis=0)) - # enforce minimum distance of 0.01 - distance = np.where(distance < 0.01, 0.01, distance) - # the adjacency matrix row - Ai = np.asarray(A.getrowview(i).toarray()) - # displacement "force" - displacement[:, i] +=\ - (delta * (k * k / distance**2 - Ai * distance / k)).sum(axis=1) - # update positions - length = np.sqrt((displacement**2).sum(axis=0)) - length = np.where(length < 0.01, 0.1, length) - delta_pos = (displacement * t / length).T - pos += delta_pos - # cool temperature - t -= dt - err = np.linalg.norm(delta_pos) / nnodes - if err < threshold: - break - return pos - - -def kamada_kawai_layout(G, dist=None, - pos=None, - weight='weight', - scale=1, - center=None, - dim=2): - """Position nodes using Kamada-Kawai path-length cost-function. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - - dist : float (default=None) - A two-level dictionary of optimal distances between nodes, - indexed by source and destination node. - If None, the distance is computed using shortest_path_length(). - - pos : dict or None optional (default=None) - Initial positions for nodes as a dictionary with node as keys - and values as a coordinate list or tuple. If None, then use - circular_layout() for dim >= 2 and a linear layout for dim == 1. - - weight : string or None optional (default='weight') - The edge attribute that holds the numerical value used for - the edge weight. If None, then all edge weights are 1. - - scale : number (default: 1) - Scale factor for positions. - - center : array-like or None - Coordinate pair around which to center the layout. - - dim : int - Dimension of layout. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node - - Examples - -------- - >>> G = nx.path_graph(4) - >>> pos = nx.kamada_kawai_layout(G) - """ - import numpy as np - - G, center = _process_params(G, center, dim) - nNodes = len(G) - - if dist is None: - dist = dict(nx.shortest_path_length(G, weight=weight)) - dist_mtx = 1e6 * np.ones((nNodes, nNodes)) - for row, nr in enumerate(G): - if nr not in dist: - continue - rdist = dist[nr] - for col, nc in enumerate(G): - if nc not in rdist: - continue - dist_mtx[row][col] = rdist[nc] - - if pos is None: - if dim >= 2: - pos = circular_layout(G, dim=dim) - else: - pos = {n: pt for n, pt in zip(G, np.linspace(0, 1, len(G)))} - pos_arr = np.array([pos[n] for n in G]) - - pos = _kamada_kawai_solve(dist_mtx, pos_arr, dim) - - pos = rescale_layout(pos, scale=scale) + center - return dict(zip(G, pos)) - - -def _kamada_kawai_solve(dist_mtx, pos_arr, dim): - # Anneal node locations based on the Kamada-Kawai cost-function, - # using the supplied matrix of preferred inter-node distances, - # and starting locations. - - import numpy as np - from scipy.optimize import minimize - - meanwt = 1e-3 - costargs = (np, 1 / (dist_mtx + np.eye(dist_mtx.shape[0]) * 1e-3), - meanwt, dim) - - optresult = minimize(_kamada_kawai_costfn, pos_arr.ravel(), - method='L-BFGS-B', args=costargs, jac=True) - - return optresult.x.reshape((-1, dim)) - - -def _kamada_kawai_costfn(pos_vec, np, invdist, meanweight, dim): - # Cost-function and gradient for Kamada-Kawai layout algorithm - nNodes = invdist.shape[0] - pos_arr = pos_vec.reshape((nNodes, dim)) - - delta = pos_arr[:, np.newaxis, :] - pos_arr[np.newaxis, :, :] - nodesep = np.linalg.norm(delta, axis=-1) - direction = np.einsum('ijk,ij->ijk', - delta, - 1 / (nodesep + np.eye(nNodes) * 1e-3)) - - offset = nodesep * invdist - 1.0 - offset[np.diag_indices(nNodes)] = 0 - - cost = 0.5 * np.sum(offset ** 2) - grad = (np.einsum('ij,ij,ijk->ik', invdist, offset, direction) - - np.einsum('ij,ij,ijk->jk', invdist, offset, direction)) - - # Additional parabolic term to encourage mean position to be near origin: - sumpos = np.sum(pos_arr, axis=0) - cost += 0.5 * meanweight * np.sum(sumpos ** 2) - grad += meanweight * sumpos - - return (cost, grad.ravel()) - - -def spectral_layout(G, weight='weight', scale=1, center=None, dim=2): - """Position nodes using the eigenvectors of the graph Laplacian. - - Using the unnormalized Laplacion, the layout shows possible clusters of - nodes which are an approximation of the ratio cut. If dim is the number of - dimensions then the positions are the entries of the dim eigenvectors - corresponding to the ascending eigenvalues starting from the second one. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - - weight : string or None optional (default='weight') - The edge attribute that holds the numerical value used for - the edge weight. If None, then all edge weights are 1. - - scale : number (default: 1) - Scale factor for positions. - - center : array-like or None - Coordinate pair around which to center the layout. - - dim : int - Dimension of layout. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node - - Examples - -------- - >>> G = nx.path_graph(4) - >>> pos = nx.spectral_layout(G) - - Notes - ----- - Directed graphs will be considered as undirected graphs when - positioning the nodes. - - For larger graphs (>500 nodes) this will use the SciPy sparse - eigenvalue solver (ARPACK). - """ - # handle some special cases that break the eigensolvers - import numpy as np - - G, center = _process_params(G, center, dim) - - if len(G) <= 2: - if len(G) == 0: - pos = np.array([]) - elif len(G) == 1: - pos = np.array([center]) - else: - pos = np.array([np.zeros(dim), np.array(center) * 2.0]) - return dict(zip(G, pos)) - try: - # Sparse matrix - if len(G) < 500: # dense solver is faster for small graphs - raise ValueError - A = nx.to_scipy_sparse_matrix(G, weight=weight, dtype='d') - # Symmetrize directed graphs - if G.is_directed(): - A = A + np.transpose(A) - pos = _sparse_spectral(A, dim) - except (ImportError, ValueError): - # Dense matrix - A = nx.to_numpy_array(G, weight=weight) - # Symmetrize directed graphs - if G.is_directed(): - A += A.T - pos = _spectral(A, dim) - - pos = rescale_layout(pos, scale=scale) + center - pos = dict(zip(G, pos)) - return pos - - -def _spectral(A, dim=2): - # Input adjacency matrix A - # Uses dense eigenvalue solver from numpy - import numpy as np - - try: - nnodes, _ = A.shape - except AttributeError: - msg = "spectral() takes an adjacency matrix as input" - raise nx.NetworkXError(msg) - - # form Laplacian matrix where D is diagonal of degrees - D = np.identity(nnodes, dtype=A.dtype) * np.sum(A, axis=1) - L = D - A - - eigenvalues, eigenvectors = np.linalg.eig(L) - # sort and keep smallest nonzero - index = np.argsort(eigenvalues)[1:dim + 1] # 0 index is zero eigenvalue - return np.real(eigenvectors[:, index]) - - -def _sparse_spectral(A, dim=2): - # Input adjacency matrix A - # Uses sparse eigenvalue solver from scipy - # Could use multilevel methods here, see Koren "On spectral graph drawing" - import numpy as np - from scipy.sparse import spdiags - from scipy.sparse.linalg.eigen import eigsh - - try: - nnodes, _ = A.shape - except AttributeError: - msg = "sparse_spectral() takes an adjacency matrix as input" - raise nx.NetworkXError(msg) - - # form Laplacian matrix - data = np.asarray(A.sum(axis=1).T) - D = spdiags(data, 0, nnodes, nnodes) - L = D - A - - k = dim + 1 - # number of Lanczos vectors for ARPACK solver.What is the right scaling? - ncv = max(2 * k + 1, int(np.sqrt(nnodes))) - # return smallest k eigenvalues and eigenvectors - eigenvalues, eigenvectors = eigsh(L, k, which='SM', ncv=ncv) - index = np.argsort(eigenvalues)[1:k] # 0 index is zero eigenvalue - return np.real(eigenvectors[:, index]) - - -def planar_layout(G, scale=1, center=None, dim=2): - """Position nodes without edge intersections. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. If G is of type - PlanarEmbedding, the positions are selected accordingly. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. If G is of type - nx.PlanarEmbedding, the positions are selected accordingly. - - scale : number (default: 1) - Scale factor for positions. - - center : array-like or None - Coordinate pair around which to center the layout. - - dim : int - Dimension of layout. - - Returns - ------- - pos : dict - A dictionary of positions keyed by node - - Raises - ------ - nx.NetworkXException - If G is not planar - - Examples - -------- - >>> G = nx.path_graph(4) - >>> pos = nx.planar_layout(G) - """ - import numpy as np - - if dim != 2: - raise ValueError('can only handle 2 dimensions') - - G, center = _process_params(G, center, dim) - - if len(G) == 0: - return {} - - if isinstance(G, nx.PlanarEmbedding): - embedding = G - else: - is_planar, embedding = nx.check_planarity(G) - if not is_planar: - raise nx.NetworkXException("G is not planar.") - pos = nx.combinatorial_embedding_to_pos(embedding) - node_list = list(embedding) - pos = np.row_stack((pos[x] for x in node_list)) - pos = pos.astype(np.float64) - pos = rescale_layout(pos, scale=scale) + center - return dict(zip(node_list, pos)) - - -def spiral_layout(G, scale=1, center=None, dim=2, - resolution=0.35, equidistant=False): - """Position nodes in a spiral layout. - - Parameters - ---------- - G : NetworkX graph or list of nodes - A position will be assigned to every node in G. - scale : number (default: 1) - Scale factor for positions. - center : array-like or None - Coordinate pair around which to center the layout. - dim : int - Dimension of layout, currently only dim=2 is supported. - Other dimension values result in a ValueError. - resolution : float - The compactness of the spiral layout returned. - Lower values result in more compressed spiral layouts. - equidistant : bool - If True, nodes will be plotted equidistant from each other. - Returns - ------- - pos : dict - A dictionary of positions keyed by node - Raises - ------- - ValueError - If dim != 2 - Examples - -------- - >>> G = nx.path_graph(4) - >>> pos = nx.spiral_layout(G) - - Notes - ----- - This algorithm currently only works in two dimensions. - - """ - import numpy as np - - if dim != 2: - raise ValueError('can only handle 2 dimensions') - - G, center = _process_params(G, center, dim) - - if len(G) == 0: - return {} - if len(G) == 1: - return {nx.utils.arbitrary_element(G): center} - - pos = [] - if equidistant: - chord = 1 - step = 0.5 - theta = resolution - for _ in range(len(G)): - r = step * theta - theta += chord / r - pos.append([np.cos(theta) * r, np.sin(theta) * r]) - - else: - # set the starting angle and step - step = 1 - angle = 0.0 - dist = 0.0 - # set the radius for the spiral to the number of nodes in the graph - radius = len(G) - - while dist * np.hypot(np.cos(angle), np.sin(angle)) < radius: - pos.append([dist * np.cos(angle), dist * np.sin(angle)]) - dist += step - angle += resolution - - pos = rescale_layout(np.array(pos), scale=scale) + center - - pos = dict(zip(G, pos)) - - return pos - - -def rescale_layout(pos, scale=1): - """Returns scaled position array to (-scale, scale) in all axes. - - The function acts on NumPy arrays which hold position information. - Each position is one row of the array. The dimension of the space - equals the number of columns. Each coordinate in one column. - - To rescale, the mean (center) is subtracted from each axis separately. - Then all values are scaled so that the largest magnitude value - from all axes equals `scale` (thus, the aspect ratio is preserved). - The resulting NumPy Array is returned (order of rows unchanged). - - Parameters - ---------- - pos : numpy array - positions to be scaled. Each row is a position. - - scale : number (default: 1) - The size of the resulting extent in all directions. - - Returns - ------- - pos : numpy array - scaled positions. Each row is a position. - - """ - # Find max length over all dimensions - lim = 0 # max coordinate for all axes - for i in range(pos.shape[1]): - pos[:, i] -= pos[:, i].mean() - lim = max(abs(pos[:, i]).max(), lim) - # rescale to (-scale, scale) in all directions, preserves aspect - if lim > 0: - for i in range(pos.shape[1]): - pos[:, i] *= scale / lim - return pos - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/drawing/nx_agraph.py b/extensions/fablabchemnitz/networkx/drawing/nx_agraph.py deleted file mode 100644 index 0ec1ffaa..00000000 --- a/extensions/fablabchemnitz/networkx/drawing/nx_agraph.py +++ /dev/null @@ -1,473 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Author: Aric Hagberg (hagberg@lanl.gov) -""" -*************** -Graphviz AGraph -*************** - -Interface to pygraphviz AGraph class. - -Examples --------- ->>> G = nx.complete_graph(5) ->>> A = nx.nx_agraph.to_agraph(G) ->>> H = nx.nx_agraph.from_agraph(A) - -See Also --------- -Pygraphviz: http://pygraphviz.github.io/ -""" -import os -import tempfile -import networkx as nx - -__all__ = ['from_agraph', 'to_agraph', - 'write_dot', 'read_dot', - 'graphviz_layout', - 'pygraphviz_layout', - 'view_pygraphviz'] - - -def from_agraph(A, create_using=None): - """Returns a NetworkX Graph or DiGraph from a PyGraphviz graph. - - Parameters - ---------- - A : PyGraphviz AGraph - A graph created with PyGraphviz - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Examples - -------- - >>> K5 = nx.complete_graph(5) - >>> A = nx.nx_agraph.to_agraph(K5) - >>> G = nx.nx_agraph.from_agraph(A) - - Notes - ----- - The Graph G will have a dictionary G.graph_attr containing - the default graphviz attributes for graphs, nodes and edges. - - Default node attributes will be in the dictionary G.node_attr - which is keyed by node. - - Edge attributes will be returned as edge data in G. With - edge_attr=False the edge data will be the Graphviz edge weight - attribute or the value 1 if no edge weight attribute is found. - - """ - if create_using is None: - if A.is_directed(): - if A.is_strict(): - create_using = nx.DiGraph - else: - create_using = nx.MultiDiGraph - else: - if A.is_strict(): - create_using = nx.Graph - else: - create_using = nx.MultiGraph - - # assign defaults - N = nx.empty_graph(0, create_using) - if A.name is not None: - N.name = A.name - - # add graph attributes - N.graph.update(A.graph_attr) - - # add nodes, attributes to N.node_attr - for n in A.nodes(): - str_attr = {str(k): v for k, v in n.attr.items()} - N.add_node(str(n), **str_attr) - - # add edges, assign edge data as dictionary of attributes - for e in A.edges(): - u, v = str(e[0]), str(e[1]) - attr = dict(e.attr) - str_attr = {str(k): v for k, v in attr.items()} - if not N.is_multigraph(): - if e.name is not None: - str_attr['key'] = e.name - N.add_edge(u, v, **str_attr) - else: - N.add_edge(u, v, key=e.name, **str_attr) - - # add default attributes for graph, nodes, and edges - # hang them on N.graph_attr - N.graph['graph'] = dict(A.graph_attr) - N.graph['node'] = dict(A.node_attr) - N.graph['edge'] = dict(A.edge_attr) - return N - - -def to_agraph(N): - """Returns a pygraphviz graph from a NetworkX graph N. - - Parameters - ---------- - N : NetworkX graph - A graph created with NetworkX - - Examples - -------- - >>> K5 = nx.complete_graph(5) - >>> A = nx.nx_agraph.to_agraph(K5) - - Notes - ----- - If N has an dict N.graph_attr an attempt will be made first - to copy properties attached to the graph (see from_agraph) - and then updated with the calling arguments if any. - - """ - try: - import pygraphviz - except ImportError: - raise ImportError('requires pygraphviz ', - 'http://pygraphviz.github.io/') - directed = N.is_directed() - strict = nx.number_of_selfloops(N) == 0 and not N.is_multigraph() - A = pygraphviz.AGraph(name=N.name, strict=strict, directed=directed) - - # default graph attributes - A.graph_attr.update(N.graph.get('graph', {})) - A.node_attr.update(N.graph.get('node', {})) - A.edge_attr.update(N.graph.get('edge', {})) - - A.graph_attr.update((k, v) for k, v in N.graph.items() - if k not in ('graph', 'node', 'edge')) - - # add nodes - for n, nodedata in N.nodes(data=True): - A.add_node(n) - if nodedata is not None: - a = A.get_node(n) - a.attr.update({k: str(v) for k, v in nodedata.items()}) - - # loop over edges - if N.is_multigraph(): - for u, v, key, edgedata in N.edges(data=True, keys=True): - str_edgedata = {k: str(v) for k, v in edgedata.items() - if k != 'key'} - A.add_edge(u, v, key=str(key)) - if edgedata is not None: - a = A.get_edge(u, v) - a.attr.update(str_edgedata) - - else: - for u, v, edgedata in N.edges(data=True): - str_edgedata = {k: str(v) for k, v in edgedata.items()} - A.add_edge(u, v) - if edgedata is not None: - a = A.get_edge(u, v) - a.attr.update(str_edgedata) - - return A - - -def write_dot(G, path): - """Write NetworkX graph G to Graphviz dot format on path. - - Parameters - ---------- - G : graph - A networkx graph - path : filename - Filename or file handle to write - """ - try: - import pygraphviz - except ImportError: - raise ImportError('requires pygraphviz ', - 'http://pygraphviz.github.io/') - A = to_agraph(G) - A.write(path) - A.clear() - return - - -def read_dot(path): - """Returns a NetworkX graph from a dot file on path. - - Parameters - ---------- - path : file or string - File name or file handle to read. - """ - try: - import pygraphviz - except ImportError: - raise ImportError('read_dot() requires pygraphviz ', - 'http://pygraphviz.github.io/') - A = pygraphviz.AGraph(file=path) - return from_agraph(A) - - -def graphviz_layout(G, prog='neato', root=None, args=''): - """Create node positions for G using Graphviz. - - Parameters - ---------- - G : NetworkX graph - A graph created with NetworkX - prog : string - Name of Graphviz layout program - root : string, optional - Root node for twopi layout - args : string, optional - Extra arguments to Graphviz layout program - - Returns - ------- - Dictionary of x, y, positions keyed by node. - - Examples - -------- - >>> G = nx.petersen_graph() - >>> pos = nx.nx_agraph.graphviz_layout(G) - >>> pos = nx.nx_agraph.graphviz_layout(G, prog='dot') - - Notes - ----- - This is a wrapper for pygraphviz_layout. - """ - return pygraphviz_layout(G, prog=prog, root=root, args=args) - - -def pygraphviz_layout(G, prog='neato', root=None, args=''): - """Create node positions for G using Graphviz. - - Parameters - ---------- - G : NetworkX graph - A graph created with NetworkX - prog : string - Name of Graphviz layout program - root : string, optional - Root node for twopi layout - args : string, optional - Extra arguments to Graphviz layout program - - Returns : dictionary - Dictionary of x, y, positions keyed by node. - - Examples - -------- - >>> G = nx.petersen_graph() - >>> pos = nx.nx_agraph.graphviz_layout(G) - >>> pos = nx.nx_agraph.graphviz_layout(G, prog='dot') - - Notes - ----- - If you use complex node objects, they may have the same string - representation and GraphViz could treat them as the same node. - The layout may assign both nodes a single location. See Issue #1568 - If this occurs in your case, consider relabeling the nodes just - for the layout computation using something similar to: - - H = nx.convert_node_labels_to_integers(G, label_attribute='node_label') - H_layout = nx.nx_agraph.pygraphviz_layout(G, prog='dot') - G_layout = {H.nodes[n]['node_label']: p for n, p in H_layout.items()} - - """ - try: - import pygraphviz - except ImportError: - raise ImportError('requires pygraphviz ', - 'http://pygraphviz.github.io/') - if root is not None: - args += "-Groot=%s" % root - A = to_agraph(G) - A.layout(prog=prog, args=args) - node_pos = {} - for n in G: - node = pygraphviz.Node(A, n) - try: - xs = node.attr["pos"].split(',') - node_pos[n] = tuple(float(x) for x in xs) - except: - print("no position for node", n) - node_pos[n] = (0.0, 0.0) - return node_pos - - -@nx.utils.open_file(5, 'w+b') -def view_pygraphviz(G, edgelabel=None, prog='dot', args='', - suffix='', path=None): - """Views the graph G using the specified layout algorithm. - - Parameters - ---------- - G : NetworkX graph - The machine to draw. - edgelabel : str, callable, None - If a string, then it specifes the edge attribute to be displayed - on the edge labels. If a callable, then it is called for each - edge and it should return the string to be displayed on the edges. - The function signature of `edgelabel` should be edgelabel(data), - where `data` is the edge attribute dictionary. - prog : string - Name of Graphviz layout program. - args : str - Additional arguments to pass to the Graphviz layout program. - suffix : str - If `filename` is None, we save to a temporary file. The value of - `suffix` will appear at the tail end of the temporary filename. - path : str, None - The filename used to save the image. If None, save to a temporary - file. File formats are the same as those from pygraphviz.agraph.draw. - - Returns - ------- - path : str - The filename of the generated image. - A : PyGraphviz graph - The PyGraphviz graph instance used to generate the image. - - Notes - ----- - If this function is called in succession too quickly, sometimes the - image is not displayed. So you might consider time.sleep(.5) between - calls if you experience problems. - - """ - if not len(G): - raise nx.NetworkXException("An empty graph cannot be drawn.") - - import pygraphviz - - # If we are providing default values for graphviz, these must be set - # before any nodes or edges are added to the PyGraphviz graph object. - # The reason for this is that default values only affect incoming objects. - # If you change the default values after the objects have been added, - # then they inherit no value and are set only if explicitly set. - - # to_agraph() uses these values. - attrs = ['edge', 'node', 'graph'] - for attr in attrs: - if attr not in G.graph: - G.graph[attr] = {} - - # These are the default values. - edge_attrs = {'fontsize': '10'} - node_attrs = {'style': 'filled', - 'fillcolor': '#0000FF40', - 'height': '0.75', - 'width': '0.75', - 'shape': 'circle'} - graph_attrs = {} - - def update_attrs(which, attrs): - # Update graph attributes. Return list of those which were added. - added = [] - for k, v in attrs.items(): - if k not in G.graph[which]: - G.graph[which][k] = v - added.append(k) - - def clean_attrs(which, added): - # Remove added attributes - for attr in added: - del G.graph[which][attr] - if not G.graph[which]: - del G.graph[which] - - # Update all default values - update_attrs('edge', edge_attrs) - update_attrs('node', node_attrs) - update_attrs('graph', graph_attrs) - - # Convert to agraph, so we inherit default values - A = to_agraph(G) - - # Remove the default values we added to the original graph. - clean_attrs('edge', edge_attrs) - clean_attrs('node', node_attrs) - clean_attrs('graph', graph_attrs) - - # If the user passed in an edgelabel, we update the labels for all edges. - if edgelabel is not None: - if not hasattr(edgelabel, '__call__'): - def func(data): - return ''.join([" ", str(data[edgelabel]), " "]) - else: - func = edgelabel - - # update all the edge labels - if G.is_multigraph(): - for u, v, key, data in G.edges(keys=True, data=True): - # PyGraphviz doesn't convert the key to a string. See #339 - edge = A.get_edge(u, v, str(key)) - edge.attr['label'] = str(func(data)) - else: - for u, v, data in G.edges(data=True): - edge = A.get_edge(u, v) - edge.attr['label'] = str(func(data)) - - if path is None: - ext = 'png' - if suffix: - suffix = '_%s.%s' % (suffix, ext) - else: - suffix = '.%s' % (ext,) - path = tempfile.NamedTemporaryFile(suffix=suffix, delete=False) - else: - # Assume the decorator worked and it is a file-object. - pass - - display_pygraphviz(A, path=path, prog=prog, args=args) - - return path.name, A - - -def display_pygraphviz(graph, path, format=None, prog=None, args=''): - """Internal function to display a graph in OS dependent manner. - - Parameters - ---------- - graph : PyGraphviz graph - A PyGraphviz AGraph instance. - path : file object - An already opened file object that will be closed. - format : str, None - An attempt is made to guess the output format based on the extension - of the filename. If that fails, the value of `format` is used. - prog : string - Name of Graphviz layout program. - args : str - Additional arguments to pass to the Graphviz layout program. - - Notes - ----- - If this function is called in succession too quickly, sometimes the - image is not displayed. So you might consider time.sleep(.5) between - calls if you experience problems. - - """ - if format is None: - filename = path.name - format = os.path.splitext(filename)[1].lower()[1:] - if not format: - # Let the draw() function use its default - format = None - - # Save to a file and display in the default viewer. - # We must close the file before viewing it. - graph.draw(path, format, prog, args) - path.close() - nx.utils.default_opener(filename) - - -# fixture for pytest -def setup_module(module): - import pytest - pygraphviz = pytest.importorskip('pygraphviz') diff --git a/extensions/fablabchemnitz/networkx/drawing/nx_pydot.py b/extensions/fablabchemnitz/networkx/drawing/nx_pydot.py deleted file mode 100644 index 88497776..00000000 --- a/extensions/fablabchemnitz/networkx/drawing/nx_pydot.py +++ /dev/null @@ -1,354 +0,0 @@ -""" -***** -Pydot -***** - -Import and export NetworkX graphs in Graphviz dot format using pydot. - -Either this module or nx_agraph can be used to interface with graphviz. - -See Also --------- -pydot: https://github.com/erocarrera/pydot -Graphviz: https://www.graphviz.org -DOT Language: http://www.graphviz.org/doc/info/lang.html -""" -# Author: Aric Hagberg (aric.hagberg@gmail.com) - -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# Cecil Curry -# All rights reserved. -# BSD license. -from locale import getpreferredencoding -from networkx.utils import open_file, make_str -import networkx as nx - -__all__ = ['write_dot', 'read_dot', 'graphviz_layout', 'pydot_layout', - 'to_pydot', 'from_pydot'] - -# 2.x/3.x compatibility -try: - basestring -except NameError: - basestring = str - unicode = str - - -@open_file(1, mode='w') -def write_dot(G, path): - """Write NetworkX graph G to Graphviz dot format on path. - - Path can be a string or a file handle. - """ - P = to_pydot(G) - path.write(P.to_string()) - return - - -@open_file(0, mode='r') -def read_dot(path): - """Returns a NetworkX :class:`MultiGraph` or :class:`MultiDiGraph` from the - dot file with the passed path. - - If this file contains multiple graphs, only the first such graph is - returned. All graphs _except_ the first are silently ignored. - - Parameters - ---------- - path : str or file - Filename or file handle. - - Returns - ------- - G : MultiGraph or MultiDiGraph - A :class:`MultiGraph` or :class:`MultiDiGraph`. - - Notes - ----- - Use `G = nx.Graph(read_dot(path))` to return a :class:`Graph` instead of a - :class:`MultiGraph`. - """ - import pydot - data = path.read() - - # List of one or more "pydot.Dot" instances deserialized from this file. - P_list = pydot.graph_from_dot_data(data) - - # Convert only the first such instance into a NetworkX graph. - return from_pydot(P_list[0]) - - -def from_pydot(P): - """Returns a NetworkX graph from a Pydot graph. - - Parameters - ---------- - P : Pydot graph - A graph created with Pydot - - Returns - ------- - G : NetworkX multigraph - A MultiGraph or MultiDiGraph. - - Examples - -------- - >>> K5 = nx.complete_graph(5) - >>> A = nx.nx_pydot.to_pydot(K5) - >>> G = nx.nx_pydot.from_pydot(A) # return MultiGraph - - # make a Graph instead of MultiGraph - >>> G = nx.Graph(nx.nx_pydot.from_pydot(A)) - - """ - if P.get_strict(None): # pydot bug: get_strict() shouldn't take argument - multiedges = False - else: - multiedges = True - - if P.get_type() == 'graph': # undirected - if multiedges: - N = nx.MultiGraph() - else: - N = nx.Graph() - else: - if multiedges: - N = nx.MultiDiGraph() - else: - N = nx.DiGraph() - - # assign defaults - name = P.get_name().strip('"') - if name != '': - N.name = name - - # add nodes, attributes to N.node_attr - for p in P.get_node_list(): - n = p.get_name().strip('"') - if n in ('node', 'graph', 'edge'): - continue - N.add_node(n, **p.get_attributes()) - - # add edges - for e in P.get_edge_list(): - u = e.get_source() - v = e.get_destination() - attr = e.get_attributes() - s = [] - d = [] - - if isinstance(u, basestring): - s.append(u.strip('"')) - else: - for unodes in u['nodes']: - s.append(unodes.strip('"')) - - if isinstance(v, basestring): - d.append(v.strip('"')) - else: - for vnodes in v['nodes']: - d.append(vnodes.strip('"')) - - for source_node in s: - for destination_node in d: - N.add_edge(source_node, destination_node, **attr) - - # add default attributes for graph, nodes, edges - pattr = P.get_attributes() - if pattr: - N.graph['graph'] = pattr - try: - N.graph['node'] = P.get_node_defaults()[0] - except (IndexError, TypeError): - pass # N.graph['node']={} - try: - N.graph['edge'] = P.get_edge_defaults()[0] - except (IndexError, TypeError): - pass # N.graph['edge']={} - return N - - -def to_pydot(N): - """Returns a pydot graph from a NetworkX graph N. - - Parameters - ---------- - N : NetworkX graph - A graph created with NetworkX - - Examples - -------- - >>> K5 = nx.complete_graph(5) - >>> P = nx.nx_pydot.to_pydot(K5) - - Notes - ----- - - """ - import pydot - - # set Graphviz graph type - if N.is_directed(): - graph_type = 'digraph' - else: - graph_type = 'graph' - strict = nx.number_of_selfloops(N) == 0 and not N.is_multigraph() - - name = N.name - graph_defaults = N.graph.get('graph', {}) - if name == '': - P = pydot.Dot('', graph_type=graph_type, strict=strict, - **graph_defaults) - else: - P = pydot.Dot('"%s"' % name, graph_type=graph_type, strict=strict, - **graph_defaults) - try: - P.set_node_defaults(**N.graph['node']) - except KeyError: - pass - try: - P.set_edge_defaults(**N.graph['edge']) - except KeyError: - pass - - for n, nodedata in N.nodes(data=True): - str_nodedata = dict((k, make_str(v)) for k, v in nodedata.items()) - p = pydot.Node(make_str(n), **str_nodedata) - P.add_node(p) - - if N.is_multigraph(): - for u, v, key, edgedata in N.edges(data=True, keys=True): - str_edgedata = dict((k, make_str(v)) for k, v in edgedata.items() - if k != 'key') - edge = pydot.Edge(make_str(u), make_str(v), - key=make_str(key), **str_edgedata) - P.add_edge(edge) - - else: - for u, v, edgedata in N.edges(data=True): - str_edgedata = dict((k, make_str(v)) for k, v in edgedata.items()) - edge = pydot.Edge(make_str(u), make_str(v), **str_edgedata) - P.add_edge(edge) - return P - - -def graphviz_layout(G, prog='neato', root=None): - """Create node positions using Pydot and Graphviz. - - Returns a dictionary of positions keyed by node. - - Parameters - ---------- - G : NetworkX Graph - The graph for which the layout is computed. - prog : string (default: 'neato') - The name of the GraphViz program to use for layout. - Options depend on GraphViz version but may include: - 'dot', 'twopi', 'fdp', 'sfdp', 'circo' - root : Node from G or None (default: None) - The node of G from which to start some layout algorithms. - - Returns - ------- - Dictionary of (x, y) positions keyed by node. - - Examples - -------- - >>> G = nx.complete_graph(4) - >>> pos = nx.nx_pydot.graphviz_layout(G) - >>> pos = nx.nx_pydot.graphviz_layout(G, prog='dot') - - Notes - ----- - This is a wrapper for pydot_layout. - """ - return pydot_layout(G=G, prog=prog, root=root) - - -def pydot_layout(G, prog='neato', root=None): - """Create node positions using :mod:`pydot` and Graphviz. - - Parameters - -------- - G : Graph - NetworkX graph to be laid out. - prog : string (default: 'neato') - Name of the GraphViz command to use for layout. - Options depend on GraphViz version but may include: - 'dot', 'twopi', 'fdp', 'sfdp', 'circo' - root : Node from G or None (default: None) - The node of G from which to start some layout algorithms. - - Returns - -------- - dict - Dictionary of positions keyed by node. - - Examples - -------- - >>> G = nx.complete_graph(4) - >>> pos = nx.nx_pydot.pydot_layout(G) - >>> pos = nx.nx_pydot.pydot_layout(G, prog='dot') - - Notes - ----- - If you use complex node objects, they may have the same string - representation and GraphViz could treat them as the same node. - The layout may assign both nodes a single location. See Issue #1568 - If this occurs in your case, consider relabeling the nodes just - for the layout computation using something similar to: - - H = nx.convert_node_labels_to_integers(G, label_attribute='node_label') - H_layout = nx.nx_pydot.pydot_layout(G, prog='dot') - G_layout = {H.nodes[n]['node_label']: p for n, p in H_layout.items()} - - """ - import pydot - P = to_pydot(G) - if root is not None: - P.set("root", make_str(root)) - - # List of low-level bytes comprising a string in the dot language converted - # from the passed graph with the passed external GraphViz command. - D_bytes = P.create_dot(prog=prog) - - # Unique string decoded from these bytes with the preferred locale encoding - D = unicode(D_bytes, encoding=getpreferredencoding()) - - if D == "": # no data returned - print("Graphviz layout with %s failed" % (prog)) - print() - print("To debug what happened try:") - print("P = nx.nx_pydot.to_pydot(G)") - print("P.write_dot(\"file.dot\")") - print("And then run %s on file.dot" % (prog)) - return - - # List of one or more "pydot.Dot" instances deserialized from this string. - Q_list = pydot.graph_from_dot_data(D) - assert len(Q_list) == 1 - - # The first and only such instance, as guaranteed by the above assertion. - Q = Q_list[0] - - node_pos = {} - for n in G.nodes(): - pydot_node = pydot.Node(make_str(n)).get_name() - node = Q.get_node(pydot_node) - - if isinstance(node, list): - node = node[0] - pos = node.get_pos()[1:-1] # strip leading and trailing double quotes - if pos is not None: - xx, yy = pos.split(",") - node_pos[n] = (float(xx), float(yy)) - return node_pos - - -# fixture for pytest -def setup_module(module): - import pytest - pytdot = pytest.importorskip('pytdot') diff --git a/extensions/fablabchemnitz/networkx/drawing/nx_pylab.py b/extensions/fablabchemnitz/networkx/drawing/nx_pylab.py deleted file mode 100644 index 012ccfeb..00000000 --- a/extensions/fablabchemnitz/networkx/drawing/nx_pylab.py +++ /dev/null @@ -1,1186 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Author: Aric Hagberg (hagberg@lanl.gov) -""" -********** -Matplotlib -********** - -Draw networks with matplotlib. - -See Also --------- - -matplotlib: http://matplotlib.org/ - -pygraphviz: http://pygraphviz.github.io/ - -""" -from numbers import Number -import networkx as nx -from networkx.utils import is_string_like -from networkx.drawing.layout import shell_layout, \ - circular_layout, kamada_kawai_layout, spectral_layout, \ - spring_layout, random_layout, planar_layout - -__all__ = ['draw', - 'draw_networkx', - 'draw_networkx_nodes', - 'draw_networkx_edges', - 'draw_networkx_labels', - 'draw_networkx_edge_labels', - 'draw_circular', - 'draw_kamada_kawai', - 'draw_random', - 'draw_spectral', - 'draw_spring', - 'draw_planar', - 'draw_shell'] - - -def draw(G, pos=None, ax=None, **kwds): - """Draw the graph G with Matplotlib. - - Draw the graph as a simple representation with no node - labels or edge labels and using the full Matplotlib figure area - and no axis labels by default. See draw_networkx() for more - full-featured drawing that allows title, axis labels etc. - - Parameters - ---------- - G : graph - A networkx graph - - pos : dictionary, optional - A dictionary with nodes as keys and positions as values. - If not specified a spring layout positioning will be computed. - See :py:mod:`networkx.drawing.layout` for functions that - compute node positions. - - ax : Matplotlib Axes object, optional - Draw the graph in specified Matplotlib axes. - - kwds : optional keywords - See networkx.draw_networkx() for a description of optional keywords. - - Examples - -------- - >>> G = nx.dodecahedral_graph() - >>> nx.draw(G) - >>> nx.draw(G, pos=nx.spring_layout(G)) # use spring layout - - See Also - -------- - draw_networkx() - draw_networkx_nodes() - draw_networkx_edges() - draw_networkx_labels() - draw_networkx_edge_labels() - - Notes - ----- - This function has the same name as pylab.draw and pyplot.draw - so beware when using `from networkx import *` - - since you might overwrite the pylab.draw function. - - With pyplot use - - >>> import matplotlib.pyplot as plt - >>> import networkx as nx - >>> G = nx.dodecahedral_graph() - >>> nx.draw(G) # networkx draw() - >>> plt.draw() # pyplot draw() - - Also see the NetworkX drawing examples at - https://networkx.github.io/documentation/latest/auto_examples/index.html - """ - try: - import matplotlib.pyplot as plt - except ImportError: - raise ImportError("Matplotlib required for draw()") - except RuntimeError: - print("Matplotlib unable to open display") - raise - - if ax is None: - cf = plt.gcf() - else: - cf = ax.get_figure() - cf.set_facecolor('w') - if ax is None: - if cf._axstack() is None: - ax = cf.add_axes((0, 0, 1, 1)) - else: - ax = cf.gca() - - if 'with_labels' not in kwds: - kwds['with_labels'] = 'labels' in kwds - - draw_networkx(G, pos=pos, ax=ax, **kwds) - ax.set_axis_off() - plt.draw_if_interactive() - return - - -def draw_networkx(G, pos=None, arrows=True, with_labels=True, **kwds): - """Draw the graph G using Matplotlib. - - Draw the graph with Matplotlib with options for node positions, - labeling, titles, and many other drawing features. - See draw() for simple drawing without labels or axes. - - Parameters - ---------- - G : graph - A networkx graph - - pos : dictionary, optional - A dictionary with nodes as keys and positions as values. - If not specified a spring layout positioning will be computed. - See :py:mod:`networkx.drawing.layout` for functions that - compute node positions. - - arrows : bool, optional (default=True) - For directed graphs, if True draw arrowheads. - Note: Arrows will be the same color as edges. - - arrowstyle : str, optional (default='-|>') - For directed graphs, choose the style of the arrowsheads. - See :py:class: `matplotlib.patches.ArrowStyle` for more - options. - - arrowsize : int, optional (default=10) - For directed graphs, choose the size of the arrow head head's length and - width. See :py:class: `matplotlib.patches.FancyArrowPatch` for attribute - `mutation_scale` for more info. - - with_labels : bool, optional (default=True) - Set to True to draw labels on the nodes. - - ax : Matplotlib Axes object, optional - Draw the graph in the specified Matplotlib axes. - - nodelist : list, optional (default G.nodes()) - Draw only specified nodes - - edgelist : list, optional (default=G.edges()) - Draw only specified edges - - node_size : scalar or array, optional (default=300) - Size of nodes. If an array is specified it must be the - same length as nodelist. - - node_color : color or array of colors (default='#1f78b4') - Node color. Can be a single color or a sequence of colors with the same - length as nodelist. Color can be string, or rgb (or rgba) tuple of - floats from 0-1. If numeric values are specified they will be - mapped to colors using the cmap and vmin,vmax parameters. See - matplotlib.scatter for more details. - - node_shape : string, optional (default='o') - The shape of the node. Specification is as matplotlib.scatter - marker, one of 'so^>v>> G = nx.dodecahedral_graph() - >>> nx.draw(G) - >>> nx.draw(G, pos=nx.spring_layout(G)) # use spring layout - - >>> import matplotlib.pyplot as plt - >>> limits = plt.axis('off') # turn of axis - - Also see the NetworkX drawing examples at - https://networkx.github.io/documentation/latest/auto_examples/index.html - - See Also - -------- - draw() - draw_networkx_nodes() - draw_networkx_edges() - draw_networkx_labels() - draw_networkx_edge_labels() - """ - try: - import matplotlib.pyplot as plt - except ImportError: - raise ImportError("Matplotlib required for draw()") - except RuntimeError: - print("Matplotlib unable to open display") - raise - - if pos is None: - pos = nx.drawing.spring_layout(G) # default to spring layout - - node_collection = draw_networkx_nodes(G, pos, **kwds) - edge_collection = draw_networkx_edges(G, pos, arrows=arrows, **kwds) - if with_labels: - draw_networkx_labels(G, pos, **kwds) - plt.draw_if_interactive() - - -def draw_networkx_nodes(G, pos, - nodelist=None, - node_size=300, - node_color='#1f78b4', - node_shape='o', - alpha=None, - cmap=None, - vmin=None, - vmax=None, - ax=None, - linewidths=None, - edgecolors=None, - label=None, - **kwds): - """Draw the nodes of the graph G. - - This draws only the nodes of the graph G. - - Parameters - ---------- - G : graph - A networkx graph - - pos : dictionary - A dictionary with nodes as keys and positions as values. - Positions should be sequences of length 2. - - ax : Matplotlib Axes object, optional - Draw the graph in the specified Matplotlib axes. - - nodelist : list, optional - Draw only specified nodes (default G.nodes()) - - node_size : scalar or array - Size of nodes (default=300). If an array is specified it must be the - same length as nodelist. - - node_color : color or array of colors (default='#1f78b4') - Node color. Can be a single color or a sequence of colors with the same - length as nodelist. Color can be string, or rgb (or rgba) tuple of - floats from 0-1. If numeric values are specified they will be - mapped to colors using the cmap and vmin,vmax parameters. See - matplotlib.scatter for more details. - - node_shape : string - The shape of the node. Specification is as matplotlib.scatter - marker, one of 'so^>v>> G = nx.dodecahedral_graph() - >>> nodes = nx.draw_networkx_nodes(G, pos=nx.spring_layout(G)) - - Also see the NetworkX drawing examples at - https://networkx.github.io/documentation/latest/auto_examples/index.html - - See Also - -------- - draw() - draw_networkx() - draw_networkx_edges() - draw_networkx_labels() - draw_networkx_edge_labels() - """ - from collections.abc import Iterable - try: - import matplotlib.pyplot as plt - import numpy as np - except ImportError: - raise ImportError("Matplotlib required for draw()") - except RuntimeError: - print("Matplotlib unable to open display") - raise - - if ax is None: - ax = plt.gca() - - if nodelist is None: - nodelist = list(G) - - if len(nodelist) == 0: # empty nodelist, no drawing - return - - try: - xy = np.asarray([pos[v] for v in nodelist]) - except KeyError as e: - raise nx.NetworkXError('Node %s has no position.' % e) - except ValueError: - raise nx.NetworkXError('Bad value in node positions.') - - if isinstance(alpha, Iterable): - node_color = apply_alpha(node_color, alpha, nodelist, cmap, vmin, vmax) - alpha = None - - node_collection = ax.scatter(xy[:, 0], xy[:, 1], - s=node_size, - c=node_color, - marker=node_shape, - cmap=cmap, - vmin=vmin, - vmax=vmax, - alpha=alpha, - linewidths=linewidths, - edgecolors=edgecolors, - label=label) - ax.tick_params( - axis='both', - which='both', - bottom=False, - left=False, - labelbottom=False, - labelleft=False) - - node_collection.set_zorder(2) - return node_collection - - -def draw_networkx_edges(G, pos, - edgelist=None, - width=1.0, - edge_color='k', - style='solid', - alpha=None, - arrowstyle='-|>', - arrowsize=10, - edge_cmap=None, - edge_vmin=None, - edge_vmax=None, - ax=None, - arrows=True, - label=None, - node_size=300, - nodelist=None, - node_shape="o", - connectionstyle=None, - min_source_margin=0, - min_target_margin=0, - **kwds): - """Draw the edges of the graph G. - - This draws only the edges of the graph G. - - Parameters - ---------- - G : graph - A networkx graph - - pos : dictionary - A dictionary with nodes as keys and positions as values. - Positions should be sequences of length 2. - - edgelist : collection of edge tuples - Draw only specified edges(default=G.edges()) - - width : float, or array of floats - Line width of edges (default=1.0) - - edge_color : color or array of colors (default='k') - Edge color. Can be a single color or a sequence of colors with the same - length as edgelist. Color can be string, or rgb (or rgba) tuple of - floats from 0-1. If numeric values are specified they will be - mapped to colors using the edge_cmap and edge_vmin,edge_vmax parameters. - - style : string - Edge line style (default='solid') (solid|dashed|dotted,dashdot) - - alpha : float - The edge transparency (default=None) - - edge_ cmap : Matplotlib colormap - Colormap for mapping intensities of edges (default=None) - - edge_vmin,edge_vmax : floats - Minimum and maximum for edge colormap scaling (default=None) - - ax : Matplotlib Axes object, optional - Draw the graph in the specified Matplotlib axes. - - arrows : bool, optional (default=True) - For directed graphs, if True draw arrowheads. - Note: Arrows will be the same color as edges. - - arrowstyle : str, optional (default='-|>') - For directed graphs, choose the style of the arrow heads. - See :py:class: `matplotlib.patches.ArrowStyle` for more - options. - - arrowsize : int, optional (default=10) - For directed graphs, choose the size of the arrow head head's length and - width. See :py:class: `matplotlib.patches.FancyArrowPatch` for attribute - `mutation_scale` for more info. - - connectionstyle : str, optional (default=None) - Pass the connectionstyle parameter to create curved arc of rounding - radius rad. For example, connectionstyle='arc3,rad=0.2'. - See :py:class: `matplotlib.patches.ConnectionStyle` and - :py:class: `matplotlib.patches.FancyArrowPatch` for more info. - - label : [None| string] - Label for legend - - min_source_margin : int, optional (default=0) - The minimum margin (gap) at the begining of the edge at the source. - - min_target_margin : int, optional (default=0) - The minimum margin (gap) at the end of the edge at the target. - - Returns - ------- - matplotlib.collection.LineCollection - `LineCollection` of the edges - - list of matplotlib.patches.FancyArrowPatch - `FancyArrowPatch` instances of the directed edges - - Depending whether the drawing includes arrows or not. - - Notes - ----- - For directed graphs, arrows are drawn at the head end. Arrows can be - turned off with keyword arrows=False. Be sure to include `node_size` as a - keyword argument; arrows are drawn considering the size of nodes. - - Examples - -------- - >>> G = nx.dodecahedral_graph() - >>> edges = nx.draw_networkx_edges(G, pos=nx.spring_layout(G)) - - >>> G = nx.DiGraph() - >>> G.add_edges_from([(1, 2), (1, 3), (2, 3)]) - >>> arcs = nx.draw_networkx_edges(G, pos=nx.spring_layout(G)) - >>> alphas = [0.3, 0.4, 0.5] - >>> for i, arc in enumerate(arcs): # change alpha values of arcs - ... arc.set_alpha(alphas[i]) - - Also see the NetworkX drawing examples at - https://networkx.github.io/documentation/latest/auto_examples/index.html - - See Also - -------- - draw() - draw_networkx() - draw_networkx_nodes() - draw_networkx_labels() - draw_networkx_edge_labels() - """ - try: - import matplotlib - import matplotlib.pyplot as plt - from matplotlib.colors import colorConverter, Colormap, Normalize - from matplotlib.collections import LineCollection - from matplotlib.patches import FancyArrowPatch - import numpy as np - except ImportError: - raise ImportError("Matplotlib required for draw()") - except RuntimeError: - print("Matplotlib unable to open display") - raise - - if ax is None: - ax = plt.gca() - - if edgelist is None: - edgelist = list(G.edges()) - - if not edgelist or len(edgelist) == 0: # no edges! - return None - - if nodelist is None: - nodelist = list(G.nodes()) - - # FancyArrowPatch handles color=None different from LineCollection - if edge_color is None: - edge_color = 'k' - - # set edge positions - edge_pos = np.asarray([(pos[e[0]], pos[e[1]]) for e in edgelist]) - - # Check if edge_color is an array of floats and map to edge_cmap. - # This is the only case handled differently from matplotlib - if np.iterable(edge_color) and (len(edge_color) == len(edge_pos)) \ - and np.alltrue([isinstance(c, Number) for c in edge_color]): - if edge_cmap is not None: - assert(isinstance(edge_cmap, Colormap)) - else: - edge_cmap = plt.get_cmap() - if edge_vmin is None: - edge_vmin = min(edge_color) - if edge_vmax is None: - edge_vmax = max(edge_color) - color_normal = Normalize(vmin=edge_vmin, vmax=edge_vmax) - edge_color = [edge_cmap(color_normal(e)) for e in edge_color] - - if (not G.is_directed() or not arrows): - edge_collection = LineCollection(edge_pos, - colors=edge_color, - linewidths=width, - antialiaseds=(1,), - linestyle=style, - transOffset=ax.transData, - alpha=alpha - ) - - edge_collection.set_zorder(1) # edges go behind nodes - edge_collection.set_label(label) - ax.add_collection(edge_collection) - - return edge_collection - - arrow_collection = None - - if G.is_directed() and arrows: - # Note: Waiting for someone to implement arrow to intersection with - # marker. Meanwhile, this works well for polygons with more than 4 - # sides and circle. - - def to_marker_edge(marker_size, marker): - if marker in "s^>v>> G = nx.dodecahedral_graph() - >>> labels = nx.draw_networkx_labels(G, pos=nx.spring_layout(G)) - - Also see the NetworkX drawing examples at - https://networkx.github.io/documentation/latest/auto_examples/index.html - - See Also - -------- - draw() - draw_networkx() - draw_networkx_nodes() - draw_networkx_edges() - draw_networkx_edge_labels() - """ - try: - import matplotlib.pyplot as plt - except ImportError: - raise ImportError("Matplotlib required for draw()") - except RuntimeError: - print("Matplotlib unable to open display") - raise - - if ax is None: - ax = plt.gca() - - if labels is None: - labels = dict((n, n) for n in G.nodes()) - - # set optional alignment - horizontalalignment = kwds.get('horizontalalignment', 'center') - verticalalignment = kwds.get('verticalalignment', 'center') - - text_items = {} # there is no text collection so we'll fake one - for n, label in labels.items(): - (x, y) = pos[n] - if not is_string_like(label): - label = str(label) # this makes "1" and 1 labeled the same - t = ax.text(x, y, - label, - size=font_size, - color=font_color, - family=font_family, - weight=font_weight, - alpha=alpha, - horizontalalignment=horizontalalignment, - verticalalignment=verticalalignment, - transform=ax.transData, - bbox=bbox, - clip_on=True, - ) - text_items[n] = t - - ax.tick_params( - axis='both', - which='both', - bottom=False, - left=False, - labelbottom=False, - labelleft=False) - - return text_items - - -def draw_networkx_edge_labels(G, pos, - edge_labels=None, - label_pos=0.5, - font_size=10, - font_color='k', - font_family='sans-serif', - font_weight='normal', - alpha=None, - bbox=None, - ax=None, - rotate=True, - **kwds): - """Draw edge labels. - - Parameters - ---------- - G : graph - A networkx graph - - pos : dictionary - A dictionary with nodes as keys and positions as values. - Positions should be sequences of length 2. - - ax : Matplotlib Axes object, optional - Draw the graph in the specified Matplotlib axes. - - alpha : float or None - The text transparency (default=None) - - edge_labels : dictionary - Edge labels in a dictionary keyed by edge two-tuple of text - labels (default=None). Only labels for the keys in the dictionary - are drawn. - - label_pos : float - Position of edge label along edge (0=head, 0.5=center, 1=tail) - - font_size : int - Font size for text labels (default=12) - - font_color : string - Font color string (default='k' black) - - font_weight : string - Font weight (default='normal') - - font_family : string - Font family (default='sans-serif') - - bbox : Matplotlib bbox - Specify text box shape and colors. - - clip_on : bool - Turn on clipping at axis boundaries (default=True) - - Returns - ------- - dict - `dict` of labels keyed on the edges - - Examples - -------- - >>> G = nx.dodecahedral_graph() - >>> edge_labels = nx.draw_networkx_edge_labels(G, pos=nx.spring_layout(G)) - - Also see the NetworkX drawing examples at - https://networkx.github.io/documentation/latest/auto_examples/index.html - - See Also - -------- - draw() - draw_networkx() - draw_networkx_nodes() - draw_networkx_edges() - draw_networkx_labels() - """ - try: - import matplotlib.pyplot as plt - import numpy as np - except ImportError: - raise ImportError("Matplotlib required for draw()") - except RuntimeError: - print("Matplotlib unable to open display") - raise - - if ax is None: - ax = plt.gca() - if edge_labels is None: - labels = {(u, v): d for u, v, d in G.edges(data=True)} - else: - labels = edge_labels - text_items = {} - for (n1, n2), label in labels.items(): - (x1, y1) = pos[n1] - (x2, y2) = pos[n2] - (x, y) = (x1 * label_pos + x2 * (1.0 - label_pos), - y1 * label_pos + y2 * (1.0 - label_pos)) - - if rotate: - # in degrees - angle = np.arctan2(y2 - y1, x2 - x1) / (2.0 * np.pi) * 360 - # make label orientation "right-side-up" - if angle > 90: - angle -= 180 - if angle < - 90: - angle += 180 - # transform data coordinate angle to screen coordinate angle - xy = np.array((x, y)) - trans_angle = ax.transData.transform_angles(np.array((angle,)), - xy.reshape((1, 2)))[0] - else: - trans_angle = 0.0 - # use default box of white with white border - if bbox is None: - bbox = dict(boxstyle='round', - ec=(1.0, 1.0, 1.0), - fc=(1.0, 1.0, 1.0), - ) - if not is_string_like(label): - label = str(label) # this makes "1" and 1 labeled the same - - # set optional alignment - horizontalalignment = kwds.get('horizontalalignment', 'center') - verticalalignment = kwds.get('verticalalignment', 'center') - - t = ax.text(x, y, - label, - size=font_size, - color=font_color, - family=font_family, - weight=font_weight, - alpha=alpha, - horizontalalignment=horizontalalignment, - verticalalignment=verticalalignment, - rotation=trans_angle, - transform=ax.transData, - bbox=bbox, - zorder=1, - clip_on=True, - ) - text_items[(n1, n2)] = t - - ax.tick_params( - axis='both', - which='both', - bottom=False, - left=False, - labelbottom=False, - labelleft=False) - - return text_items - - -def draw_circular(G, **kwargs): - """Draw the graph G with a circular layout. - - Parameters - ---------- - G : graph - A networkx graph - - kwargs : optional keywords - See networkx.draw_networkx() for a description of optional keywords, - with the exception of the pos parameter which is not used by this - function. - """ - draw(G, circular_layout(G), **kwargs) - - -def draw_kamada_kawai(G, **kwargs): - """Draw the graph G with a Kamada-Kawai force-directed layout. - - Parameters - ---------- - G : graph - A networkx graph - - kwargs : optional keywords - See networkx.draw_networkx() for a description of optional keywords, - with the exception of the pos parameter which is not used by this - function. - """ - draw(G, kamada_kawai_layout(G), **kwargs) - - -def draw_random(G, **kwargs): - """Draw the graph G with a random layout. - - Parameters - ---------- - G : graph - A networkx graph - - kwargs : optional keywords - See networkx.draw_networkx() for a description of optional keywords, - with the exception of the pos parameter which is not used by this - function. - """ - draw(G, random_layout(G), **kwargs) - - -def draw_spectral(G, **kwargs): - """Draw the graph G with a spectral 2D layout. - - Using the unnormalized Laplacion, the layout shows possible clusters of - nodes which are an approximation of the ratio cut. The positions are the - entries of the second and third eigenvectors corresponding to the - ascending eigenvalues starting from the second one. - - Parameters - ---------- - G : graph - A networkx graph - - kwargs : optional keywords - See networkx.draw_networkx() for a description of optional keywords, - with the exception of the pos parameter which is not used by this - function. - """ - draw(G, spectral_layout(G), **kwargs) - - -def draw_spring(G, **kwargs): - """Draw the graph G with a spring layout. - - Parameters - ---------- - G : graph - A networkx graph - - kwargs : optional keywords - See networkx.draw_networkx() for a description of optional keywords, - with the exception of the pos parameter which is not used by this - function. - """ - draw(G, spring_layout(G), **kwargs) - - -def draw_shell(G, **kwargs): - """Draw networkx graph with shell layout. - - Parameters - ---------- - G : graph - A networkx graph - - kwargs : optional keywords - See networkx.draw_networkx() for a description of optional keywords, - with the exception of the pos parameter which is not used by this - function. - """ - nlist = kwargs.get('nlist', None) - if nlist is not None: - del(kwargs['nlist']) - draw(G, shell_layout(G, nlist=nlist), **kwargs) - - -def draw_planar(G, **kwargs): - """Draw a planar networkx graph with planar layout. - - Parameters - ---------- - G : graph - A planar networkx graph - - kwargs : optional keywords - See networkx.draw_networkx() for a description of optional keywords, - with the exception of the pos parameter which is not used by this - function. - """ - draw(G, planar_layout(G), **kwargs) - - -def apply_alpha(colors, alpha, elem_list, cmap=None, vmin=None, vmax=None): - """Apply an alpha (or list of alphas) to the colors provided. - - Parameters - ---------- - - colors : color string, or array of floats - Color of element. Can be a single color format string (default='r'), - or a sequence of colors with the same length as nodelist. - If numeric values are specified they will be mapped to - colors using the cmap and vmin,vmax parameters. See - matplotlib.scatter for more details. - - alpha : float or array of floats - Alpha values for elements. This can be a single alpha value, in - which case it will be applied to all the elements of color. Otherwise, - if it is an array, the elements of alpha will be applied to the colors - in order (cycling through alpha multiple times if necessary). - - elem_list : array of networkx objects - The list of elements which are being colored. These could be nodes, - edges or labels. - - cmap : matplotlib colormap - Color map for use if colors is a list of floats corresponding to points - on a color mapping. - - vmin, vmax : float - Minimum and maximum values for normalizing colors if a color mapping is - used. - - Returns - ------- - - rgba_colors : numpy ndarray - Array containing RGBA format values for each of the node colours. - - """ - from itertools import islice, cycle - - try: - import numpy as np - from matplotlib.colors import colorConverter - import matplotlib.cm as cm - except ImportError: - raise ImportError("Matplotlib required for draw()") - - # If we have been provided with a list of numbers as long as elem_list, - # apply the color mapping. - if len(colors) == len(elem_list) and isinstance(colors[0], Number): - mapper = cm.ScalarMappable(cmap=cmap) - mapper.set_clim(vmin, vmax) - rgba_colors = mapper.to_rgba(colors) - # Otherwise, convert colors to matplotlib's RGB using the colorConverter - # object. These are converted to numpy ndarrays to be consistent with the - # to_rgba method of ScalarMappable. - else: - try: - rgba_colors = np.array([colorConverter.to_rgba(colors)]) - except ValueError: - rgba_colors = np.array([colorConverter.to_rgba(color) - for color in colors]) - # Set the final column of the rgba_colors to have the relevant alpha values - try: - # If alpha is longer than the number of colors, resize to the number of - # elements. Also, if rgba_colors.size (the number of elements of - # rgba_colors) is the same as the number of elements, resize the array, - # to avoid it being interpreted as a colormap by scatter() - if len(alpha) > len(rgba_colors) or rgba_colors.size == len(elem_list): - rgba_colors = np.resize(rgba_colors, (len(elem_list), 4)) - rgba_colors[1:, 0] = rgba_colors[0, 0] - rgba_colors[1:, 1] = rgba_colors[0, 1] - rgba_colors[1:, 2] = rgba_colors[0, 2] - rgba_colors[:, 3] = list(islice(cycle(alpha), len(rgba_colors))) - except TypeError: - rgba_colors[:, -1] = alpha - return rgba_colors - - -# fixture for pytest -def setup_module(module): - import pytest - mpl = pytest.importorskip('matplotlib') - mpl.use('PS', warn=False) - plt = pytest.importorskip('matplotlib.pyplot') diff --git a/extensions/fablabchemnitz/networkx/drawing/tests/__init__.py b/extensions/fablabchemnitz/networkx/drawing/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/drawing/tests/test_agraph.py b/extensions/fablabchemnitz/networkx/drawing/tests/test_agraph.py deleted file mode 100644 index 11ae6268..00000000 --- a/extensions/fablabchemnitz/networkx/drawing/tests/test_agraph.py +++ /dev/null @@ -1,120 +0,0 @@ -"""Unit tests for PyGraphviz interface.""" -import os -import tempfile -import pytest -import pytest -pygraphviz = pytest.importorskip('pygraphviz') - - -from networkx.testing import assert_edges_equal, assert_nodes_equal, \ - assert_graphs_equal - -import networkx as nx - - -class TestAGraph(object): - - def build_graph(self, G): - edges = [('A', 'B'), ('A', 'C'), ('A', 'C'), ('B', 'C'), ('A', 'D')] - G.add_edges_from(edges) - G.add_node('E') - G.graph['metal'] = 'bronze' - return G - - def assert_equal(self, G1, G2): - assert_nodes_equal(G1.nodes(), G2.nodes()) - assert_edges_equal(G1.edges(), G2.edges()) - assert G1.graph['metal'] == G2.graph['metal'] - - def agraph_checks(self, G): - G = self.build_graph(G) - A = nx.nx_agraph.to_agraph(G) - H = nx.nx_agraph.from_agraph(A) - self.assert_equal(G, H) - - fname = tempfile.mktemp() - nx.drawing.nx_agraph.write_dot(H, fname) - Hin = nx.nx_agraph.read_dot(fname) - os.unlink(fname) - self.assert_equal(H, Hin) - - (fd, fname) = tempfile.mkstemp() - with open(fname, 'w') as fh: - nx.drawing.nx_agraph.write_dot(H, fh) - - with open(fname, 'r') as fh: - Hin = nx.nx_agraph.read_dot(fh) - os.unlink(fname) - self.assert_equal(H, Hin) - - def test_from_agraph_name(self): - G = nx.Graph(name='test') - A = nx.nx_agraph.to_agraph(G) - H = nx.nx_agraph.from_agraph(A) - assert G.name == 'test' - - def test_undirected(self): - self.agraph_checks(nx.Graph()) - - def test_directed(self): - self.agraph_checks(nx.DiGraph()) - - def test_multi_undirected(self): - self.agraph_checks(nx.MultiGraph()) - - def test_multi_directed(self): - self.agraph_checks(nx.MultiDiGraph()) - - def test_view_pygraphviz(self): - G = nx.Graph() # "An empty graph cannot be drawn." - pytest.raises(nx.NetworkXException, nx.nx_agraph.view_pygraphviz, G) - G = nx.barbell_graph(4, 6) - nx.nx_agraph.view_pygraphviz(G) - - def test_view_pygraphviz_edgelable(self): - G = nx.Graph() - G.add_edge(1, 2, weight=7) - G.add_edge(2, 3, weight=8) - nx.nx_agraph.view_pygraphviz(G, edgelabel='weight') - - def test_graph_with_reserved_keywords(self): - # test attribute/keyword clash case for #1582 - # node: n - # edges: u,v - G = nx.Graph() - G = self.build_graph(G) - G.nodes['E']['n'] = 'keyword' - G.edges[('A', 'B')]['u'] = 'keyword' - G.edges[('A', 'B')]['v'] = 'keyword' - A = nx.nx_agraph.to_agraph(G) - - def test_round_trip(self): - G = nx.Graph() - A = nx.nx_agraph.to_agraph(G) - H = nx.nx_agraph.from_agraph(A) - #assert_graphs_equal(G, H) - AA = nx.nx_agraph.to_agraph(H) - HH = nx.nx_agraph.from_agraph(AA) - assert_graphs_equal(H, HH) - G.graph['graph'] = {} - G.graph['node'] = {} - G.graph['edge'] = {} - assert_graphs_equal(G, HH) - - def test_2d_layout(self): - G = nx.Graph() - G = self.build_graph(G) - G.graph["dimen"] = 2 - pos = nx.nx_agraph.pygraphviz_layout(G, prog='neato') - pos = list(pos.values()) - assert len(pos) == 5 - assert len(pos[0]) == 2 - - def test_3d_layout(self): - G = nx.Graph() - G = self.build_graph(G) - G.graph["dimen"] = 3 - pos = nx.nx_agraph.pygraphviz_layout(G, prog='neato') - pos = list(pos.values()) - assert len(pos) == 5 - assert len(pos[0]) == 3 diff --git a/extensions/fablabchemnitz/networkx/drawing/tests/test_layout.py b/extensions/fablabchemnitz/networkx/drawing/tests/test_layout.py deleted file mode 100644 index d392d83f..00000000 --- a/extensions/fablabchemnitz/networkx/drawing/tests/test_layout.py +++ /dev/null @@ -1,343 +0,0 @@ -"""Unit tests for layout functions.""" -import pytest -numpy = pytest.importorskip('numpy') -test_smoke_empty_graphscipy = pytest.importorskip('scipy') - - -import pytest -import networkx as nx -from networkx.testing import almost_equal - -class TestLayout(object): - - @classmethod - def setup_class(cls): - cls.Gi = nx.grid_2d_graph(5, 5) - cls.Gs = nx.Graph() - nx.add_path(cls.Gs, 'abcdef') - cls.bigG = nx.grid_2d_graph(25, 25) # > 500 nodes for sparse - - @staticmethod - def collect_node_distances(positions): - distances = [] - prev_val = None - for k in positions: - if prev_val is not None: - diff = positions[k] - prev_val - distances.append(numpy.dot(diff, diff) ** 0.5) - prev_val = positions[k] - return distances - - def test_spring_fixed_without_pos(self): - G = nx.path_graph(4) - pytest.raises(ValueError, nx.spring_layout, G, fixed=[0]) - pos = {0: (1, 1), 2: (0, 0)} - pytest.raises(ValueError, nx.spring_layout, G, fixed=[0, 1], pos=pos) - nx.spring_layout(G, fixed=[0, 2], pos=pos) # No ValueError - - def test_spring_init_pos(self): - # Tests GH #2448 - import math - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (2, 0), (2, 3)]) - - init_pos = {0: (0.0, 0.0)} - fixed_pos = [0] - pos = nx.fruchterman_reingold_layout(G, pos=init_pos, fixed=fixed_pos) - has_nan = any(math.isnan(c) for coords in pos.values() for c in coords) - assert not has_nan, 'values should not be nan' - - def test_smoke_empty_graph(self): - G = [] - vpos = nx.random_layout(G) - vpos = nx.circular_layout(G) - vpos = nx.planar_layout(G) - vpos = nx.spring_layout(G) - vpos = nx.fruchterman_reingold_layout(G) - vpos = nx.spectral_layout(G) - vpos = nx.shell_layout(G) - vpos = nx.bipartite_layout(G, G) - vpos = nx.spiral_layout(G) - # FIXME vpos = nx.kamada_kawai_layout(G) - - def test_smoke_int(self): - G = self.Gi - vpos = nx.random_layout(G) - vpos = nx.circular_layout(G) - vpos = nx.planar_layout(G) - vpos = nx.spring_layout(G) - vpos = nx.fruchterman_reingold_layout(G) - vpos = nx.fruchterman_reingold_layout(self.bigG) - vpos = nx.spectral_layout(G) - vpos = nx.spectral_layout(G.to_directed()) - vpos = nx.spectral_layout(self.bigG) - vpos = nx.spectral_layout(self.bigG.to_directed()) - vpos = nx.shell_layout(G) - vpos = nx.spiral_layout(G) - vpos = nx.kamada_kawai_layout(G) - vpos = nx.kamada_kawai_layout(G, dim=1) - - def test_smoke_string(self): - G = self.Gs - vpos = nx.random_layout(G) - vpos = nx.circular_layout(G) - vpos = nx.planar_layout(G) - vpos = nx.spring_layout(G) - vpos = nx.fruchterman_reingold_layout(G) - vpos = nx.spectral_layout(G) - vpos = nx.shell_layout(G) - vpos = nx.spiral_layout(G) - vpos = nx.kamada_kawai_layout(G) - vpos = nx.kamada_kawai_layout(G, dim=1) - - def check_scale_and_center(self, pos, scale, center): - center = numpy.array(center) - low = center - scale - hi = center + scale - vpos = numpy.array(list(pos.values())) - length = vpos.max(0) - vpos.min(0) - assert (length <= 2 * scale).all() - assert (vpos >= low).all() - assert (vpos <= hi).all() - - def test_scale_and_center_arg(self): - sc = self.check_scale_and_center - c = (4, 5) - G = nx.complete_graph(9) - G.add_node(9) - sc(nx.random_layout(G, center=c), scale=0.5, center=(4.5, 5.5)) - # rest can have 2*scale length: [-scale, scale] - sc(nx.spring_layout(G, scale=2, center=c), scale=2, center=c) - sc(nx.spectral_layout(G, scale=2, center=c), scale=2, center=c) - sc(nx.circular_layout(G, scale=2, center=c), scale=2, center=c) - sc(nx.shell_layout(G, scale=2, center=c), scale=2, center=c) - sc(nx.spiral_layout(G, scale=2, center=c), scale=2, center=c) - sc(nx.kamada_kawai_layout(G, scale=2, center=c), scale=2, center=c) - - def test_planar_layout_non_planar_input(self): - G = nx.complete_graph(9) - pytest.raises(nx.NetworkXException, nx.planar_layout, G) - - def test_smoke_planar_layout_embedding_input(self): - embedding = nx.PlanarEmbedding() - embedding.set_data({0: [1, 2], 1: [0, 2], 2: [0, 1]}) - nx.planar_layout(embedding) - - def test_default_scale_and_center(self): - sc = self.check_scale_and_center - c = (0, 0) - G = nx.complete_graph(9) - G.add_node(9) - sc(nx.random_layout(G), scale=0.5, center=(0.5, 0.5)) - sc(nx.spring_layout(G), scale=1, center=c) - sc(nx.spectral_layout(G), scale=1, center=c) - sc(nx.circular_layout(G), scale=1, center=c) - sc(nx.shell_layout(G), scale=1, center=c) - sc(nx.spiral_layout(G), scale=1, center=c) - sc(nx.kamada_kawai_layout(G), scale=1, center=c) - - def test_circular_planar_and_shell_dim_error(self): - G = nx.path_graph(4) - pytest.raises(ValueError, nx.circular_layout, G, dim=1) - pytest.raises(ValueError, nx.shell_layout, G, dim=1) - pytest.raises(ValueError, nx.shell_layout, G, dim=3) - pytest.raises(ValueError, nx.planar_layout, G, dim=1) - pytest.raises(ValueError, nx.planar_layout, G, dim=3) - - def test_adjacency_interface_numpy(self): - A = nx.to_numpy_array(self.Gs) - pos = nx.drawing.layout._fruchterman_reingold(A) - assert pos.shape == (6, 2) - pos = nx.drawing.layout._fruchterman_reingold(A, dim=3) - assert pos.shape == (6, 3) - - def test_adjacency_interface_scipy(self): - A = nx.to_scipy_sparse_matrix(self.Gs, dtype='d') - pos = nx.drawing.layout._sparse_fruchterman_reingold(A) - assert pos.shape == (6, 2) - pos = nx.drawing.layout._sparse_spectral(A) - assert pos.shape == (6, 2) - pos = nx.drawing.layout._sparse_fruchterman_reingold(A, dim=3) - assert pos.shape == (6, 3) - - def test_single_nodes(self): - G = nx.path_graph(1) - vpos = nx.shell_layout(G) - assert not vpos[0].any() - G = nx.path_graph(4) - vpos = nx.shell_layout(G, [[0], [1, 2], [3]]) - assert not vpos[0].any() - assert vpos[3].any() # ensure node 3 not at origin (#3188) - - def test_smoke_initial_pos_fruchterman_reingold(self): - pos = nx.circular_layout(self.Gi) - npos = nx.fruchterman_reingold_layout(self.Gi, pos=pos) - - def test_fixed_node_fruchterman_reingold(self): - # Dense version (numpy based) - pos = nx.circular_layout(self.Gi) - npos = nx.spring_layout(self.Gi, pos=pos, fixed=[(0, 0)]) - assert tuple(pos[(0, 0)]) == tuple(npos[(0, 0)]) - # Sparse version (scipy based) - pos = nx.circular_layout(self.bigG) - npos = nx.spring_layout(self.bigG, pos=pos, fixed=[(0, 0)]) - for axis in range(2): - assert almost_equal(pos[(0, 0)][axis], npos[(0, 0)][axis]) - - def test_center_parameter(self): - G = nx.path_graph(1) - vpos = nx.random_layout(G, center=(1, 1)) - vpos = nx.circular_layout(G, center=(1, 1)) - assert tuple(vpos[0]) == (1, 1) - vpos = nx.planar_layout(G, center=(1, 1)) - assert tuple(vpos[0]) == (1, 1) - vpos = nx.spring_layout(G, center=(1, 1)) - assert tuple(vpos[0]) == (1, 1) - vpos = nx.fruchterman_reingold_layout(G, center=(1, 1)) - assert tuple(vpos[0]) == (1, 1) - vpos = nx.spectral_layout(G, center=(1, 1)) - assert tuple(vpos[0]) == (1, 1) - vpos = nx.shell_layout(G, center=(1, 1)) - assert tuple(vpos[0]) == (1, 1) - vpos = nx.spiral_layout(G, center=(1, 1)) - assert tuple(vpos[0]) == (1, 1) - - def test_center_wrong_dimensions(self): - G = nx.path_graph(1) - assert id(nx.spring_layout) == id(nx.fruchterman_reingold_layout) - pytest.raises(ValueError, nx.random_layout, G, center=(1, 1, 1)) - pytest.raises(ValueError, nx.circular_layout, G, center=(1, 1, 1)) - pytest.raises(ValueError, nx.planar_layout, G, center=(1, 1, 1)) - pytest.raises(ValueError, nx.spring_layout, G, center=(1, 1, 1)) - pytest.raises(ValueError, nx.spring_layout, G, dim=3, center=(1, 1)) - pytest.raises(ValueError, nx.spectral_layout, G, center=(1, 1, 1)) - pytest.raises(ValueError, nx.spectral_layout, G, dim=3, center=(1, 1)) - pytest.raises(ValueError, nx.shell_layout, G, center=(1, 1, 1)) - pytest.raises(ValueError, nx.spiral_layout, G, center=(1, 1, 1)) - - def test_empty_graph(self): - G = nx.empty_graph() - vpos = nx.random_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.circular_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.planar_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.bipartite_layout(G, G) - assert vpos == {} - vpos = nx.spring_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.fruchterman_reingold_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.spectral_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.shell_layout(G, center=(1, 1)) - assert vpos == {} - vpos = nx.spiral_layout(G, center=(1, 1)) - assert vpos == {} - - def test_bipartite_layout(self): - G = nx.complete_bipartite_graph(3, 5) - top, bottom = nx.bipartite.sets(G) - - vpos = nx.bipartite_layout(G, top) - assert len(vpos) == len(G) - - top_x = vpos[list(top)[0]][0] - bottom_x = vpos[list(bottom)[0]][0] - for node in top: - assert vpos[node][0] == top_x - for node in bottom: - assert vpos[node][0] == bottom_x - - vpos = nx.bipartite_layout(G, top, - align='horizontal', - center=(2, 2), - scale=2, - aspect_ratio=1) - assert len(vpos) == len(G) - - top_y = vpos[list(top)[0]][1] - bottom_y = vpos[list(bottom)[0]][1] - for node in top: - assert vpos[node][1] == top_y - for node in bottom: - assert vpos[node][1] == bottom_y - - pytest.raises(ValueError, nx.bipartite_layout, G, top, align='foo') - - def test_kamada_kawai_costfn_1d(self): - costfn = nx.drawing.layout._kamada_kawai_costfn - - pos = numpy.array([4.0, 7.0]) - invdist = 1 / numpy.array([[0.1, 2.0], [2.0, 0.3]]) - - cost, grad = costfn(pos, numpy, invdist, meanweight=0, dim=1) - - assert almost_equal(cost, ((3 / 2.0 - 1) ** 2)) - assert almost_equal(grad[0], -0.5) - assert almost_equal(grad[1], 0.5) - - def test_kamada_kawai_costfn_2d(self): - costfn = nx.drawing.layout._kamada_kawai_costfn - - pos = numpy.array([[1.3, -3.2], - [2.7, -0.3], - [5.1, 2.5]]) - invdist = 1 / numpy.array([[0.1, 2.1, 1.7], - [2.1, 0.2, 0.6], - [1.7, 0.6, 0.3]]) - meanwt = 0.3 - - cost, grad = costfn(pos.ravel(), numpy, invdist, - meanweight=meanwt, dim=2) - - expected_cost = 0.5 * meanwt * numpy.sum(numpy.sum(pos, axis=0) ** 2) - for i in range(pos.shape[0]): - for j in range(i + 1, pos.shape[0]): - diff = numpy.linalg.norm(pos[i] - pos[j]) - expected_cost += (diff * invdist[i][j] - 1.0) ** 2 - - assert almost_equal(cost, expected_cost) - - dx = 1e-4 - for nd in range(pos.shape[0]): - for dm in range(pos.shape[1]): - idx = nd * pos.shape[1] + dm - pos0 = pos.flatten() - - pos0[idx] += dx - cplus = costfn(pos0, numpy, invdist, - meanweight=meanwt, dim=pos.shape[1])[0] - - pos0[idx] -= 2 * dx - cminus = costfn(pos0, numpy, invdist, - meanweight=meanwt, dim=pos.shape[1])[0] - - assert almost_equal(grad[idx], (cplus - cminus) / (2 * dx), - places=5) - - def test_spiral_layout(self): - - G = self.Gs - - # a lower value of resolution should result in a more compact layout - # intuitively, the total distance from the start and end nodes - # via each node in between (transiting through each) will be less, - # assuming rescaling does not occur on the computed node positions - pos_standard = nx.spiral_layout(G, resolution=0.35) - pos_tighter = nx.spiral_layout(G, resolution=0.34) - distances = self.collect_node_distances(pos_standard) - distances_tighter = self.collect_node_distances(pos_tighter) - assert sum(distances) > sum(distances_tighter) - - # return near-equidistant points after the first value if set to true - pos_equidistant = nx.spiral_layout(G, equidistant=True) - distances_equidistant = self.collect_node_distances(pos_equidistant) - for d in range(1, len(distances_equidistant) - 1): - # test similarity to two decimal places - assert almost_equal( - distances_equidistant[d], - distances_equidistant[d+1], - 2 - ) diff --git a/extensions/fablabchemnitz/networkx/drawing/tests/test_pydot.py b/extensions/fablabchemnitz/networkx/drawing/tests/test_pydot.py deleted file mode 100644 index 41e737f4..00000000 --- a/extensions/fablabchemnitz/networkx/drawing/tests/test_pydot.py +++ /dev/null @@ -1,107 +0,0 @@ -"""Unit tests for pydot drawing functions.""" -try: - try: - from cStringIO import StringIO - except ImportError: - from StringIO import StringIO -except ImportError: - from io import StringIO -import sys -import tempfile -import networkx as nx -from networkx.testing import assert_graphs_equal - - -class TestPydot(object): - @classmethod - def setup_class(cls): - ''' - Fixture defining the `pydot` global to be the `pydot` module if both - importable and of sufficient version _or_ skipping this test. - ''' - global pydot - pydot = nx.nx_pydot.setup_module(sys.modules[__name__]) - assert pydot is not None - - def pydot_checks(self, G, prog): - ''' - Validate :mod:`pydot`-based usage of the passed NetworkX graph with the - passed basename of an external GraphViz command (e.g., `dot`, `neato`). - ''' - - # Set the name of this graph to... "G". Failing to do so will - # subsequently trip an assertion expecting this name. - G.graph['name'] = 'G' - - # Add arbitrary nodes and edges to the passed empty graph. - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'C'), ('A', 'D')]) - G.add_node('E') - - # Validate layout of this graph with the passed GraphViz command. - graph_layout = nx.nx_pydot.pydot_layout(G, prog=prog) - assert isinstance(graph_layout, dict) - - # Convert this graph into a "pydot.Dot" instance. - P = nx.nx_pydot.to_pydot(G) - - # Convert this "pydot.Dot" instance back into a graph of the same type. - G2 = G.__class__(nx.nx_pydot.from_pydot(P)) - - # Validate the original and resulting graphs to be the same. - assert_graphs_equal(G, G2) - - # Serialize this "pydot.Dot" instance to a temporary file in dot format - fname = tempfile.mktemp() - P.write_raw(fname) - - # Deserialize a list of new "pydot.Dot" instances back from this file. - Pin_list = pydot.graph_from_dot_file(path=fname, encoding='utf-8') - - # Validate this file to contain only one graph. - assert len(Pin_list) == 1 - - # The single "pydot.Dot" instance deserialized from this file. - Pin = Pin_list[0] - - # Sorted list of all nodes in the original "pydot.Dot" instance. - n1 = sorted([p.get_name() for p in P.get_node_list()]) - - # Sorted list of all nodes in the deserialized "pydot.Dot" instance. - n2 = sorted([p.get_name() for p in Pin.get_node_list()]) - - # Validate these instances to contain the same nodes. - assert n1 == n2 - - # Sorted list of all edges in the original "pydot.Dot" instance. - e1 = sorted([ - (e.get_source(), e.get_destination()) for e in P.get_edge_list()]) - - # Sorted list of all edges in the original "pydot.Dot" instance. - e2 = sorted([(e.get_source(), e.get_destination()) - for e in Pin.get_edge_list()]) - - # Validate these instances to contain the same edges. - assert e1 == e2 - - # Deserialize a new graph of the same type back from this file. - Hin = nx.nx_pydot.read_dot(fname) - Hin = G.__class__(Hin) - - # Validate the original and resulting graphs to be the same. - assert_graphs_equal(G, Hin) - - def test_undirected(self): - self.pydot_checks(nx.Graph(), prog='neato') - - def test_directed(self): - self.pydot_checks(nx.DiGraph(), prog='dot') - - def test_read_write(self): - G = nx.MultiGraph() - G.graph['name'] = 'G' - G.add_edge('1', '2', key='0') # read assumes strings - fh = StringIO() - nx.nx_pydot.write_dot(G, fh) - fh.seek(0) - H = nx.nx_pydot.read_dot(fh) - assert_graphs_equal(G, H) diff --git a/extensions/fablabchemnitz/networkx/drawing/tests/test_pylab.py b/extensions/fablabchemnitz/networkx/drawing/tests/test_pylab.py deleted file mode 100644 index bff1c4a0..00000000 --- a/extensions/fablabchemnitz/networkx/drawing/tests/test_pylab.py +++ /dev/null @@ -1,191 +0,0 @@ -"""Unit tests for matplotlib drawing functions.""" -import os -import itertools -import pytest - -mpl = pytest.importorskip('matplotlib') -mpl.use('PS', warn=False) -plt = pytest.importorskip('matplotlib.pyplot') -plt.rcParams['text.usetex'] = False - -import networkx as nx - - -class TestPylab(object): - - @classmethod - def setup_class(cls): - cls.G = nx.barbell_graph(4, 6) - - def test_draw(self): - try: - functions = [nx.draw_circular, - nx.draw_kamada_kawai, - nx.draw_planar, - nx.draw_random, - nx.draw_spectral, - nx.draw_spring, - nx.draw_shell] - options = [{ - 'node_color': 'black', - 'node_size': 100, - 'width': 3, - }] - for function, option in itertools.product(functions, options): - function(self.G, **option) - plt.savefig('test.ps') - - finally: - try: - os.unlink('test.ps') - except OSError: - pass - - def test_draw_shell_nlist(self): - try: - nlist = [list(range(4)), list(range(4, 10)), list(range(10, 14))] - nx.draw_shell(self.G, nlist=nlist) - plt.savefig('test.ps') - finally: - try: - os.unlink('test.ps') - except OSError: - pass - - def test_edge_colormap(self): - colors = range(self.G.number_of_edges()) - nx.draw_spring(self.G, edge_color=colors, width=4, - edge_cmap=plt.cm.Blues, with_labels=True) - plt.show() - - def test_arrows(self): - nx.draw_spring(self.G.to_directed()) - plt.show() - - def test_edge_colors_and_widths(self): - pos = nx.circular_layout(self.G) - for G in (self.G, self.G.to_directed()): - nx.draw_networkx_nodes(G, pos, node_color=[(1.0, 1.0, 0.2, 0.5)]) - nx.draw_networkx_labels(G, pos) - # edge with default color and width - nx.draw_networkx_edges(G, pos, edgelist=[(0, 1)], - width=None, - edge_color=None) - # edges with global color strings and widths in lists - nx.draw_networkx_edges(G, pos, edgelist=[(0, 2), (0, 3)], - width=[3], - edge_color=['r']) - # edges with color strings and widths for each edge - nx.draw_networkx_edges(G, pos, edgelist=[(0, 2), (0, 3)], - width=[1, 3], - edge_color=['r', 'b']) - # edges with fewer color strings and widths than edges - nx.draw_networkx_edges(G, pos, - edgelist=[(1, 2), (1, 3), (2, 3), (3, 4)], - width=[1, 3], - edge_color=['g', 'm', 'c']) - # edges with more color strings and widths than edges - nx.draw_networkx_edges(G, pos, edgelist=[(3, 4)], - width=[1, 2, 3, 4], - edge_color=['r', 'b', 'g', 'k']) - # with rgb tuple and 3 edges - is interpreted with cmap - nx.draw_networkx_edges(G, pos, edgelist=[(4, 5), (5, 6), (6, 7)], - edge_color=(1.0, 0.4, 0.3)) - # with rgb tuple in list - nx.draw_networkx_edges(G, pos, edgelist=[(7, 8), (8, 9)], - edge_color=[(0.4, 1.0, 0.0)]) - # with rgba tuple and 4 edges - is interpretted with cmap - nx.draw_networkx_edges(G, pos, edgelist=[(9, 10), (10, 11), - (10, 12), (10, 13)], - edge_color=(0.0, 1.0, 1.0, 0.5)) - # with rgba tuple in list - nx.draw_networkx_edges(G, pos, edgelist=[(9, 10), (10, 11), - (10, 12), (10, 13)], - edge_color=[(0.0, 1.0, 1.0, 0.5)]) - # with color string and global alpha - nx.draw_networkx_edges(G, pos, edgelist=[(11, 12), (11, 13)], - edge_color='purple', alpha=0.2) - # with color string in a list - nx.draw_networkx_edges(G, pos, edgelist=[(11, 12), (11, 13)], - edge_color=['purple']) - # with single edge and hex color string - nx.draw_networkx_edges(G, pos, edgelist=[(12, 13)], - edge_color='#1f78b4f0') - - # edge_color as numeric using vmin, vmax - nx.draw_networkx_edges(G, pos, edgelist=[(7, 8), (8, 9)], - edge_color=[0.2, 0.5], - edge_vmin=0.1, edge_max=0.6) - - plt.show() - - def test_labels_and_colors(self): - G = nx.cubical_graph() - pos = nx.spring_layout(G) # positions for all nodes - # nodes - nx.draw_networkx_nodes(G, pos, - nodelist=[0, 1, 2, 3], - node_color='r', - node_size=500, - alpha=0.75) - nx.draw_networkx_nodes(G, pos, - nodelist=[4, 5, 6, 7], - node_color='b', - node_size=500, - alpha=[0.25, 0.5, 0.75, 1.0]) - # edges - nx.draw_networkx_edges(G, pos, width=1.0, alpha=0.5) - nx.draw_networkx_edges(G, pos, - edgelist=[(0, 1), (1, 2), (2, 3), (3, 0)], - width=8, alpha=0.5, edge_color='r') - nx.draw_networkx_edges(G, pos, - edgelist=[(4, 5), (5, 6), (6, 7), (7, 4)], - width=8, alpha=0.5, edge_color='b') - nx.draw_networkx_edges(G, pos, - edgelist=[(4, 5), (5, 6), (6, 7), (7, 4)], - min_source_margin=0.5, min_target_margin=0.75, - width=8, edge_color='b') - # some math labels - labels = {} - labels[0] = r'$a$' - labels[1] = r'$b$' - labels[2] = r'$c$' - labels[3] = r'$d$' - labels[4] = r'$\alpha$' - labels[5] = r'$\beta$' - labels[6] = r'$\gamma$' - labels[7] = r'$\delta$' - nx.draw_networkx_labels(G, pos, labels, font_size=16) - nx.draw_networkx_edge_labels(G, pos, edge_labels=None, rotate=False) - nx.draw_networkx_edge_labels(G, pos, edge_labels={(4, 5): '4-5'}) - plt.show() - - def test_axes(self): - fig, ax = plt.subplots() - nx.draw(self.G, ax=ax) - - def test_empty_graph(self): - G = nx.Graph() - nx.draw(G) - - def test_multigraph_edgelist_tuples(self): - # See Issue #3295 - G = nx.path_graph(3, create_using=nx.MultiDiGraph) - nx.draw_networkx(G, edgelist=[(0, 1, 0)]) - nx.draw_networkx(G, edgelist=[(0, 1, 0)], node_size=[10, 20]) - - def test_alpha_iter(self): - pos = nx.random_layout(self.G) - # with fewer alpha elements than nodes - plt.subplot(131) - nx.draw_networkx_nodes(self.G, pos, alpha=[0.1, 0.2]) - # with equal alpha elements and nodes - num_nodes = len(self.G.nodes) - alpha = [x / num_nodes for x in range(num_nodes)] - colors = range(num_nodes) - plt.subplot(132) - nx.draw_networkx_nodes(self.G, pos, node_color=colors, alpha=alpha) - # with more alpha elements than nodes - alpha.append(1) - plt.subplot(133) - nx.draw_networkx_nodes(self.G, pos, alpha=alpha) diff --git a/extensions/fablabchemnitz/networkx/exception.py b/extensions/fablabchemnitz/networkx/exception.py deleted file mode 100644 index f0d221c4..00000000 --- a/extensions/fablabchemnitz/networkx/exception.py +++ /dev/null @@ -1,138 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: -# Aric Hagberg -# Pieter Swart -# Dan Schult -# Loïc Séguin-C. -""" -********** -Exceptions -********** - -Base exceptions and errors for NetworkX. -""" - -__all__ = [ - 'HasACycle', - 'NodeNotFound', - 'PowerIterationFailedConvergence', - 'ExceededMaxIterations', - 'AmbiguousSolution', - 'NetworkXAlgorithmError', - 'NetworkXException', - 'NetworkXError', - 'NetworkXNoCycle', - 'NetworkXNoPath', - 'NetworkXNotImplemented', - 'NetworkXPointlessConcept', - 'NetworkXUnbounded', - 'NetworkXUnfeasible', -] - - -class NetworkXException(Exception): - """Base class for exceptions in NetworkX.""" - - -class NetworkXError(NetworkXException): - """Exception for a serious error in NetworkX""" - - -class NetworkXPointlessConcept(NetworkXException): - """Raised when a null graph is provided as input to an algorithm - that cannot use it. - - The null graph is sometimes considered a pointless concept [1]_, - thus the name of the exception. - - References - ---------- - .. [1] Harary, F. and Read, R. "Is the Null Graph a Pointless - Concept?" In Graphs and Combinatorics Conference, George - Washington University. New York: Springer-Verlag, 1973. - - """ - - -class NetworkXAlgorithmError(NetworkXException): - """Exception for unexpected termination of algorithms.""" - - -class NetworkXUnfeasible(NetworkXAlgorithmError): - """Exception raised by algorithms trying to solve a problem - instance that has no feasible solution.""" - - -class NetworkXNoPath(NetworkXUnfeasible): - """Exception for algorithms that should return a path when running - on graphs where such a path does not exist.""" - - -class NetworkXNoCycle(NetworkXUnfeasible): - """Exception for algorithms that should return a cycle when running - on graphs where such a cycle does not exist.""" - - -class HasACycle(NetworkXException): - """Raised if a graph has a cycle when an algorithm expects that it - will have no cycles. - - """ - - -class NetworkXUnbounded(NetworkXAlgorithmError): - """Exception raised by algorithms trying to solve a maximization - or a minimization problem instance that is unbounded.""" - - -class NetworkXNotImplemented(NetworkXException): - """Exception raised by algorithms not implemented for a type of graph.""" - - -class NodeNotFound(NetworkXException): - """Exception raised if requested node is not present in the graph""" - - -class AmbiguousSolution(NetworkXException): - """Raised if more than one valid solution exists for an intermediary step - of an algorithm. - - In the face of ambiguity, refuse the temptation to guess. - This may occur, for example, when trying to determine the - bipartite node sets in a disconnected bipartite graph when - computing bipartite matchings. - - """ - - -class ExceededMaxIterations(NetworkXException): - """Raised if a loop iterates too many times without breaking. - - This may occur, for example, in an algorithm that computes - progressively better approximations to a value but exceeds an - iteration bound specified by the user. - - """ - - -class PowerIterationFailedConvergence(ExceededMaxIterations): - """Raised when the power iteration method fails to converge within a - specified iteration limit. - - `num_iterations` is the number of iterations that have been - completed when this exception was raised. - - """ - - def __init__(self, num_iterations, *args, **kw): - msg = 'power iteration failed to converge within {} iterations' - exception_message = msg.format(num_iterations) - superinit = super(PowerIterationFailedConvergence, self).__init__ - superinit(self, exception_message, *args, **kw) diff --git a/extensions/fablabchemnitz/networkx/generators/__init__.py b/extensions/fablabchemnitz/networkx/generators/__init__.py deleted file mode 100644 index 864a88e9..00000000 --- a/extensions/fablabchemnitz/networkx/generators/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -A package for generating various graphs in networkx. - -""" -from networkx.generators.atlas import * -from networkx.generators.classic import * -from networkx.generators.cographs import * -from networkx.generators.community import * -from networkx.generators.degree_seq import * -from networkx.generators.directed import * -from networkx.generators.duplication import * -from networkx.generators.ego import * -from networkx.generators.expanders import * -from networkx.generators.geometric import * -from networkx.generators.internet_as_graphs import * -from networkx.generators.intersection import * -from networkx.generators.joint_degree_seq import * -from networkx.generators.lattice import * -from networkx.generators.line import * -from networkx.generators.mycielski import * -from networkx.generators.nonisomorphic_trees import * -from networkx.generators.random_clustered import * -from networkx.generators.random_graphs import * -from networkx.generators.small import * -from networkx.generators.social import * -from networkx.generators.spectral_graph_forge import * -from networkx.generators.stochastic import * -from networkx.generators.trees import * -from networkx.generators.triads import * diff --git a/extensions/fablabchemnitz/networkx/generators/atlas.dat.gz b/extensions/fablabchemnitz/networkx/generators/atlas.dat.gz deleted file mode 100644 index b0a98701..00000000 Binary files a/extensions/fablabchemnitz/networkx/generators/atlas.dat.gz and /dev/null differ diff --git a/extensions/fablabchemnitz/networkx/generators/atlas.py b/extensions/fablabchemnitz/networkx/generators/atlas.py deleted file mode 100644 index cfbb237b..00000000 --- a/extensions/fablabchemnitz/networkx/generators/atlas.py +++ /dev/null @@ -1,186 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Author: -# Pieter Swart -""" -Generators for the small graph atlas. -""" -import gzip -from itertools import islice -import os -import os.path - -import networkx as nx - -__all__ = ['graph_atlas', 'graph_atlas_g'] - -#: The total number of graphs in the atlas. -#: -#: The graphs are labeled starting from 0 and extending to (but not -#: including) this number. -NUM_GRAPHS = 1253 - -#: The absolute path representing the directory containing this file. -THIS_DIR = os.path.dirname(os.path.abspath(__file__)) - -#: The path to the data file containing the graph edge lists. -#: -#: This is the absolute filename of the gzipped text file containing the -#: edge list for each graph in the atlas. The file contains one entry -#: per graph in the atlas, in sequential order, starting from graph -#: number 0 and extending through graph number 1252 (see -#: :data:`NUM_GRAPHS`). Each entry looks like -#: -#: .. sourcecode:: text -#: -#: GRAPH 6 -#: NODES 3 -#: 0 1 -#: 0 2 -#: -#: where the first two lines are the graph's index in the atlas and the -#: number of nodes in the graph, and the remaining lines are the edge -#: list. -#: -#: This file was generated from a Python list of graphs via code like -#: the following:: -#: -#: import gzip -#: from networkx.generators.atlas import graph_atlas_g -#: from networkx.readwrite.edgelist import write_edgelist -#: -#: with gzip.open('atlas.dat.gz', 'wb') as f: -#: for i, G in enumerate(graph_atlas_g()): -#: f.write(bytes('GRAPH {}\n'.format(i), encoding='utf-8')) -#: f.write(bytes('NODES {}\n'.format(len(G)), encoding='utf-8')) -#: write_edgelist(G, f, data=False) -#: -ATLAS_FILE = os.path.join(THIS_DIR, 'atlas.dat.gz') - - -def _generate_graphs(): - """Sequentially read the file containing the edge list data for the - graphs in the atlas and generate the graphs one at a time. - - This function reads the file given in :data:`.ATLAS_FILE`. - - """ - with gzip.open(ATLAS_FILE, 'rb') as f: - line = f.readline() - while line and line.startswith(b'GRAPH'): - # The first two lines of each entry tell us the index of the - # graph in the list and the number of nodes in the graph. - # They look like this: - # - # GRAPH 3 - # NODES 2 - # - graph_index = int(line[6:].rstrip()) - line = f.readline() - num_nodes = int(line[6:].rstrip()) - # The remaining lines contain the edge list, until the next - # GRAPH line (or until the end of the file). - edgelist = [] - line = f.readline() - while line and not line.startswith(b'GRAPH'): - edgelist.append(line.rstrip()) - line = f.readline() - G = nx.Graph() - G.name = 'G{}'.format(graph_index) - G.add_nodes_from(range(num_nodes)) - G.add_edges_from(tuple(map(int, e.split())) for e in edgelist) - yield G - - -def graph_atlas(i): - """Returns graph number `i` from the Graph Atlas. - - For more information, see :func:`.graph_atlas_g`. - - Parameters - ---------- - i : int - The index of the graph from the atlas to get. The graph at index - 0 is assumed to be the null graph. - - Returns - ------- - list - A list of :class:`~networkx.Graph` objects, the one at index *i* - corresponding to the graph *i* in the Graph Atlas. - - See also - -------- - graph_atlas_g - - Notes - ----- - The time required by this function increases linearly with the - argument `i`, since it reads a large file sequentially in order to - generate the graph [1]_. - - References - ---------- - .. [1] Ronald C. Read and Robin J. Wilson, *An Atlas of Graphs*. - Oxford University Press, 1998. - - """ - if not (0 <= i < NUM_GRAPHS): - raise ValueError('index must be between 0 and {}'.format(NUM_GRAPHS)) - return next(islice(_generate_graphs(), i, None)) - - -def graph_atlas_g(): - """Returns the list of all graphs with up to seven nodes named in the - Graph Atlas. - - The graphs are listed in increasing order by - - 1. number of nodes, - 2. number of edges, - 3. degree sequence (for example 111223 < 112222), - 4. number of automorphisms, - - in that order, with three exceptions as described in the *Notes* - section below. This causes the list to correspond with the index of - the graphs in the Graph Atlas [atlas]_, with the first graph, - ``G[0]``, being the null graph. - - Returns - ------- - list - A list of :class:`~networkx.Graph` objects, the one at index *i* - corresponding to the graph *i* in the Graph Atlas. - - See also - -------- - graph_atlas - - Notes - ----- - This function may be expensive in both time and space, since it - reads a large file sequentially in order to populate the list. - - Although the NetworkX atlas functions match the order of graphs - given in the "Atlas of Graphs" book, there are (at least) three - errors in the ordering described in the book. The following three - pairs of nodes violate the lexicographically nondecreasing sorted - degree sequence rule: - - - graphs 55 and 56 with degree sequences 001111 and 000112, - - graphs 1007 and 1008 with degree sequences 3333444 and 3333336, - - graphs 1012 and 1213 with degree sequences 1244555 and 1244456. - - References - ---------- - .. [atlas] Ronald C. Read and Robin J. Wilson, - *An Atlas of Graphs*. - Oxford University Press, 1998. - - """ - return list(_generate_graphs()) diff --git a/extensions/fablabchemnitz/networkx/generators/classic.py b/extensions/fablabchemnitz/networkx/generators/classic.py deleted file mode 100644 index 698b61dc..00000000 --- a/extensions/fablabchemnitz/networkx/generators/classic.py +++ /dev/null @@ -1,756 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg (hagberg@lanl.gov) -# Pieter Swart (swart@lanl.gov) -"""Generators for some classic graphs. - -The typical graph generator is called as follows: - ->>> G = nx.complete_graph(100) - -returning the complete graph on n nodes labeled 0, .., 99 -as a simple graph. Except for empty_graph, all the generators -in this module return a Graph class (i.e. a simple, undirected graph). - -""" - -import itertools - -import networkx as nx -from networkx.classes import Graph -from networkx.exception import NetworkXError -from networkx.utils import accumulate -from networkx.utils import nodes_or_number -from networkx.utils import pairwise - -__all__ = ['balanced_tree', - 'barbell_graph', - 'binomial_tree', - 'complete_graph', - 'complete_multipartite_graph', - 'circular_ladder_graph', - 'circulant_graph', - 'cycle_graph', - 'dorogovtsev_goltsev_mendes_graph', - 'empty_graph', - 'full_rary_tree', - 'ladder_graph', - 'lollipop_graph', - 'null_graph', - 'path_graph', - 'star_graph', - 'trivial_graph', - 'turan_graph', - 'wheel_graph'] - - -# ------------------------------------------------------------------- -# Some Classic Graphs -# ------------------------------------------------------------------- - -def _tree_edges(n, r): - if n == 0: - return - # helper function for trees - # yields edges in rooted tree at 0 with n nodes and branching ratio r - nodes = iter(range(n)) - parents = [next(nodes)] # stack of max length r - while parents: - source = parents.pop(0) - for i in range(r): - try: - target = next(nodes) - parents.append(target) - yield source, target - except StopIteration: - break - - -def full_rary_tree(r, n, create_using=None): - """Creates a full r-ary tree of n vertices. - - Sometimes called a k-ary, n-ary, or m-ary tree. - "... all non-leaf vertices have exactly r children and all levels - are full except for some rightmost position of the bottom level - (if a leaf at the bottom level is missing, then so are all of the - leaves to its right." [1]_ - - Parameters - ---------- - r : int - branching factor of the tree - n : int - Number of nodes in the tree - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : networkx Graph - An r-ary tree with n nodes - - References - ---------- - .. [1] An introduction to data structures and algorithms, - James Andrew Storer, Birkhauser Boston 2001, (page 225). - """ - G = empty_graph(n, create_using) - G.add_edges_from(_tree_edges(n, r)) - return G - - -def balanced_tree(r, h, create_using=None): - """Returns the perfectly balanced `r`-ary tree of height `h`. - - Parameters - ---------- - r : int - Branching factor of the tree; each node will have `r` - children. - - h : int - Height of the tree. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : NetworkX graph - A balanced `r`-ary tree of height `h`. - - Notes - ----- - This is the rooted tree where all leaves are at distance `h` from - the root. The root has degree `r` and all other internal nodes - have degree `r + 1`. - - Node labels are integers, starting from zero. - - A balanced tree is also known as a *complete r-ary tree*. - - """ - # The number of nodes in the balanced tree is `1 + r + ... + r^h`, - # which is computed by using the closed-form formula for a geometric - # sum with ratio `r`. In the special case that `r` is 1, the number - # of nodes is simply `h + 1` (since the tree is actually a path - # graph). - if r == 1: - n = h + 1 - else: - # This must be an integer if both `r` and `h` are integers. If - # they are not, we force integer division anyway. - n = (1 - r ** (h + 1)) // (1 - r) - return full_rary_tree(r, n, create_using=create_using) - - -def barbell_graph(m1, m2, create_using=None): - """Returns the Barbell Graph: two complete graphs connected by a path. - - For $m1 > 1$ and $m2 >= 0$. - - Two identical complete graphs $K_{m1}$ form the left and right bells, - and are connected by a path $P_{m2}$. - - The `2*m1+m2` nodes are numbered - `0, ..., m1-1` for the left barbell, - `m1, ..., m1+m2-1` for the path, - and `m1+m2, ..., 2*m1+m2-1` for the right barbell. - - The 3 subgraphs are joined via the edges `(m1-1, m1)` and - `(m1+m2-1, m1+m2)`. If `m2=0`, this is merely two complete - graphs joined together. - - This graph is an extremal example in David Aldous - and Jim Fill's e-text on Random Walks on Graphs. - - """ - if m1 < 2: - raise NetworkXError( - "Invalid graph description, m1 should be >=2") - if m2 < 0: - raise NetworkXError( - "Invalid graph description, m2 should be >=0") - - # left barbell - G = complete_graph(m1, create_using) - if G.is_directed(): - raise NetworkXError("Directed Graph not supported") - - # connecting path - G.add_nodes_from(range(m1, m1 + m2 - 1)) - if m2 > 1: - G.add_edges_from(pairwise(range(m1, m1 + m2))) - # right barbell - G.add_edges_from((u, v) for u in range(m1 + m2, 2 * m1 + m2) - for v in range(u + 1, 2 * m1 + m2)) - # connect it up - G.add_edge(m1 - 1, m1) - if m2 > 0: - G.add_edge(m1 + m2 - 1, m1 + m2) - return G - -def binomial_tree(n): - """Returns the Binomial Tree of order n. - - The binomial tree of order 0 consists of a single vertex. A binomial tree of order k - is defined recursively by linking two binomial trees of order k-1: the root of one is - the leftmost child of the root of the other. - - Parameters - ---------- - n : int - Order of the binomial tree. - - Returns - ------- - G : NetworkX graph - A binomial tree of $2^n$ vertices and $2^n - 1$ edges. - - """ - G = nx.empty_graph(1) - N = 1 - for i in range(n): - edges = [(u + N, v + N) for (u, v) in G.edges] - G.add_edges_from(edges) - G.add_edge(0,N) - N *= 2 - return G - -@nodes_or_number(0) -def complete_graph(n, create_using=None): - """ Return the complete graph `K_n` with n nodes. - - Parameters - ---------- - n : int or iterable container of nodes - If n is an integer, nodes are from range(n). - If n is a container of nodes, those nodes appear in the graph. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Examples - -------- - >>> G = nx.complete_graph(9) - >>> len(G) - 9 - >>> G.size() - 36 - >>> G = nx.complete_graph(range(11, 14)) - >>> list(G.nodes()) - [11, 12, 13] - >>> G = nx.complete_graph(4, nx.DiGraph()) - >>> G.is_directed() - True - - """ - n_name, nodes = n - G = empty_graph(n_name, create_using) - if len(nodes) > 1: - if G.is_directed(): - edges = itertools.permutations(nodes, 2) - else: - edges = itertools.combinations(nodes, 2) - G.add_edges_from(edges) - return G - - -def circular_ladder_graph(n, create_using=None): - """Returns the circular ladder graph $CL_n$ of length n. - - $CL_n$ consists of two concentric n-cycles in which - each of the n pairs of concentric nodes are joined by an edge. - - Node labels are the integers 0 to n-1 - - """ - G = ladder_graph(n, create_using) - G.add_edge(0, n - 1) - G.add_edge(n, 2 * n - 1) - return G - - -def circulant_graph(n, offsets, create_using=None): - """Generates the circulant graph $Ci_n(x_1, x_2, ..., x_m)$ with $n$ vertices. - - Returns - ------- - The graph $Ci_n(x_1, ..., x_m)$ consisting of $n$ vertices $0, ..., n-1$ such - that the vertex with label $i$ is connected to the vertices labelled $(i + x)$ - and $(i - x)$, for all $x$ in $x_1$ up to $x_m$, with the indices taken modulo $n$. - - Parameters - ---------- - n : integer - The number of vertices the generated graph is to contain. - offsets : list of integers - A list of vertex offsets, $x_1$ up to $x_m$, as described above. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Examples - -------- - Many well-known graph families are subfamilies of the circulant graphs; - for example, to generate the cycle graph on n points, we connect every - vertex to every other at offset plus or minus one. For n = 10, - - >>> import networkx - >>> G = networkx.generators.classic.circulant_graph(10, [1]) - >>> edges = [ - ... (0, 9), (0, 1), (1, 2), (2, 3), (3, 4), - ... (4, 5), (5, 6), (6, 7), (7, 8), (8, 9)] - ... - >>> sorted(edges) == sorted(G.edges()) - True - - Similarly, we can generate the complete graph on 5 points with the set of - offsets [1, 2]: - - >>> G = networkx.generators.classic.circulant_graph(5, [1, 2]) - >>> edges = [ - ... (0, 1), (0, 2), (0, 3), (0, 4), (1, 2), - ... (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)] - ... - >>> sorted(edges) == sorted(G.edges()) - True - - """ - G = empty_graph(n, create_using) - for i in range(n): - for j in offsets: - G.add_edge(i, (i - j) % n) - G.add_edge(i, (i + j) % n) - return G - - -@nodes_or_number(0) -def cycle_graph(n, create_using=None): - """Returns the cycle graph $C_n$ of cyclically connected nodes. - - $C_n$ is a path with its two end-nodes connected. - - Parameters - ---------- - n : int or iterable container of nodes - If n is an integer, nodes are from `range(n)`. - If n is a container of nodes, those nodes appear in the graph. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Notes - ----- - If create_using is directed, the direction is in increasing order. - - """ - n_orig, nodes = n - G = empty_graph(nodes, create_using) - G.add_edges_from(pairwise(nodes)) - G.add_edge(nodes[-1], nodes[0]) - return G - - -def dorogovtsev_goltsev_mendes_graph(n, create_using=None): - """Returns the hierarchically constructed Dorogovtsev-Goltsev-Mendes graph. - - n is the generation. - See: arXiv:/cond-mat/0112143 by Dorogovtsev, Goltsev and Mendes. - - """ - G = empty_graph(0, create_using) - if G.is_directed(): - raise NetworkXError("Directed Graph not supported") - if G.is_multigraph(): - raise NetworkXError("Multigraph not supported") - - G.add_edge(0, 1) - if n == 0: - return G - new_node = 2 # next node to be added - for i in range(1, n + 1): # iterate over number of generations. - last_generation_edges = list(G.edges()) - number_of_edges_in_last_generation = len(last_generation_edges) - for j in range(0, number_of_edges_in_last_generation): - G.add_edge(new_node, last_generation_edges[j][0]) - G.add_edge(new_node, last_generation_edges[j][1]) - new_node += 1 - return G - - -@nodes_or_number(0) -def empty_graph(n=0, create_using=None, default=nx.Graph): - """Returns the empty graph with n nodes and zero edges. - - Parameters - ---------- - n : int or iterable container of nodes (default = 0) - If n is an integer, nodes are from `range(n)`. - If n is a container of nodes, those nodes appear in the graph. - create_using : Graph Instance, Constructor or None - Indicator of type of graph to return. - If a Graph-type instance, then clear and use it. - If None, use the `default` constructor. - If a constructor, call it to create an empty graph. - default : Graph constructor (optional, default = nx.Graph) - The constructor to use if create_using is None. - If None, then nx.Graph is used. - This is used when passing an unknown `create_using` value - through your home-grown function to `empty_graph` and - you want a default constructor other than nx.Graph. - - Examples - -------- - >>> G = nx.empty_graph(10) - >>> G.number_of_nodes() - 10 - >>> G.number_of_edges() - 0 - >>> G = nx.empty_graph("ABC") - >>> G.number_of_nodes() - 3 - >>> sorted(G) - ['A', 'B', 'C'] - - Notes - ----- - The variable create_using should be a Graph Constructor or a - "graph"-like object. Constructors, e.g. `nx.Graph` or `nx.MultiGraph` - will be used to create the returned graph. "graph"-like objects - will be cleared (nodes and edges will be removed) and refitted as - an empty "graph" with nodes specified in n. This capability - is useful for specifying the class-nature of the resulting empty - "graph" (i.e. Graph, DiGraph, MyWeirdGraphClass, etc.). - - The variable create_using has three main uses: - Firstly, the variable create_using can be used to create an - empty digraph, multigraph, etc. For example, - - >>> n = 10 - >>> G = nx.empty_graph(n, create_using=nx.DiGraph) - - will create an empty digraph on n nodes. - - Secondly, one can pass an existing graph (digraph, multigraph, - etc.) via create_using. For example, if G is an existing graph - (resp. digraph, multigraph, etc.), then empty_graph(n, create_using=G) - will empty G (i.e. delete all nodes and edges using G.clear()) - and then add n nodes and zero edges, and return the modified graph. - - Thirdly, when constructing your home-grown graph creation function - you can use empty_graph to construct the graph by passing a user - defined create_using to empty_graph. In this case, if you want the - default constructor to be other than nx.Graph, specify `default`. - - >>> def mygraph(n, create_using=None): - ... G = nx.empty_graph(n, create_using, nx.MultiGraph) - ... G.add_edges_from([(0, 1), (0, 1)]) - ... return G - >>> G = mygraph(3) - >>> G.is_multigraph() - True - >>> G = mygraph(3, nx.Graph) - >>> G.is_multigraph() - False - - See also create_empty_copy(G). - - """ - if create_using is None: - G = default() - elif hasattr(create_using, '_adj'): - # create_using is a NetworkX style Graph - create_using.clear() - G = create_using - else: - # try create_using as constructor - G = create_using() - - n_name, nodes = n - G.add_nodes_from(nodes) - return G - - -def ladder_graph(n, create_using=None): - """Returns the Ladder graph of length n. - - This is two paths of n nodes, with - each pair connected by a single edge. - - Node labels are the integers 0 to 2*n - 1. - - """ - G = empty_graph(2 * n, create_using) - if G.is_directed(): - raise NetworkXError("Directed Graph not supported") - G.add_edges_from(pairwise(range(n))) - G.add_edges_from(pairwise(range(n, 2 * n))) - G.add_edges_from((v, v + n) for v in range(n)) - return G - - -@nodes_or_number([0, 1]) -def lollipop_graph(m, n, create_using=None): - """Returns the Lollipop Graph; `K_m` connected to `P_n`. - - This is the Barbell Graph without the right barbell. - - Parameters - ---------- - m, n : int or iterable container of nodes (default = 0) - If an integer, nodes are from `range(m)` and `range(m,m+n)`. - If a container, the entries are the coordinate of the node. - - The nodes for m appear in the complete graph $K_m$ and the nodes - for n appear in the path $P_n$ - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Notes - ----- - The 2 subgraphs are joined via an edge (m-1, m). - If n=0, this is merely a complete graph. - - (This graph is an extremal example in David Aldous and Jim - Fill's etext on Random Walks on Graphs.) - - """ - m, m_nodes = m - n, n_nodes = n - M = len(m_nodes) - N = len(n_nodes) - if isinstance(m, int): - n_nodes = [len(m_nodes) + i for i in n_nodes] - if M < 2: - raise NetworkXError( - "Invalid graph description, m should be >=2") - if N < 0: - raise NetworkXError( - "Invalid graph description, n should be >=0") - - # the ball - G = complete_graph(m_nodes, create_using) - if G.is_directed(): - raise NetworkXError("Directed Graph not supported") - # the stick - G.add_nodes_from(n_nodes) - if N > 1: - G.add_edges_from(pairwise(n_nodes)) - # connect ball to stick - if M > 0 and N > 0: - G.add_edge(m_nodes[-1], n_nodes[0]) - return G - - -def null_graph(create_using=None): - """Returns the Null graph with no nodes or edges. - - See empty_graph for the use of create_using. - - """ - G = empty_graph(0, create_using) - return G - - -@nodes_or_number(0) -def path_graph(n, create_using=None): - """Returns the Path graph `P_n` of linearly connected nodes. - - Parameters - ---------- - n : int or iterable - If an integer, node labels are 0 to n with center 0. - If an iterable of nodes, the center is the first. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - """ - n_name, nodes = n - G = empty_graph(nodes, create_using) - G.add_edges_from(pairwise(nodes)) - return G - - -@nodes_or_number(0) -def star_graph(n, create_using=None): - """ Return the star graph - - The star graph consists of one center node connected to n outer nodes. - - Parameters - ---------- - n : int or iterable - If an integer, node labels are 0 to n with center 0. - If an iterable of nodes, the center is the first. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Notes - ----- - The graph has n+1 nodes for integer n. - So star_graph(3) is the same as star_graph(range(4)). - """ - n_name, nodes = n - if isinstance(n_name, int): - nodes = nodes + [n_name] # there should be n+1 nodes - first = nodes[0] - G = empty_graph(nodes, create_using) - if G.is_directed(): - raise NetworkXError("Directed Graph not supported") - G.add_edges_from((first, v) for v in nodes[1:]) - return G - - -def trivial_graph(create_using=None): - """ Return the Trivial graph with one node (with label 0) and no edges. - - """ - G = empty_graph(1, create_using) - return G - - -def turan_graph(n, r): - r""" Return the Turan Graph - - The Turan Graph is a complete multipartite graph on $n$ vertices - with $r$ disjoint subsets. It is the graph with the edges for any graph with - $n$ vertices and $r$ disjoint subsets. - - Given $n$ and $r$, we generate a complete multipartite graph with - $r-(n \mod r)$ partitions of size $n/r$, rounded down, and - $n \mod r$ partitions of size $n/r+1$, rounded down. - - Parameters - ---------- - n : int - The number of vertices. - r : int - The number of partitions. - Must be less than or equal to n. - - Notes - ----- - Must satisfy $1 <= r <= n$. - The graph has $(r-1)(n^2)/(2r)$ edges, rounded down. - """ - - if not 1 <= r <= n: - raise NetworkXError("Must satisfy 1 <= r <= n") - - partitions = [n // r] * (r - (n % r)) + [n // r + 1] * (n % r) - G = complete_multipartite_graph(*partitions) - return G - - -@nodes_or_number(0) -def wheel_graph(n, create_using=None): - """ Return the wheel graph - - The wheel graph consists of a hub node connected to a cycle of (n-1) nodes. - - Parameters - ---------- - n : int or iterable - If an integer, node labels are 0 to n with center 0. - If an iterable of nodes, the center is the first. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Node labels are the integers 0 to n - 1. - """ - n_name, nodes = n - if n_name == 0: - G = empty_graph(0, create_using) - return G - G = star_graph(nodes, create_using) - if len(G) > 2: - G.add_edges_from(pairwise(nodes[1:])) - G.add_edge(nodes[-1], nodes[1]) - return G - - -def complete_multipartite_graph(*subset_sizes): - """Returns the complete multipartite graph with the specified subset sizes. - - Parameters - ---------- - subset_sizes : tuple of integers or tuple of node iterables - The arguments can either all be integer number of nodes or they - can all be iterables of nodes. If integers, they represent the - number of vertices in each subset of the multipartite graph. - If iterables, each is used to create the nodes for that subset. - The length of subset_sizes is the number of subsets. - - Returns - ------- - G : NetworkX Graph - Returns the complete multipartite graph with the specified subsets. - - For each node, the node attribute 'subset' is an integer - indicating which subset contains the node. - - Examples - -------- - Creating a complete tripartite graph, with subsets of one, two, and three - vertices, respectively. - - >>> import networkx as nx - >>> G = nx.complete_multipartite_graph(1, 2, 3) - >>> [G.nodes[u]['subset'] for u in G] - [0, 1, 1, 2, 2, 2] - >>> list(G.edges(0)) - [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5)] - >>> list(G.edges(2)) - [(2, 0), (2, 3), (2, 4), (2, 5)] - >>> list(G.edges(4)) - [(4, 0), (4, 1), (4, 2)] - - >>> G = nx.complete_multipartite_graph('a', 'bc', 'def') - >>> [G.nodes[u]['subset'] for u in sorted(G)] - [0, 1, 1, 2, 2, 2] - - Notes - ----- - This function generalizes several other graph generator functions. - - - If no subset sizes are given, this returns the null graph. - - If a single subset size `n` is given, this returns the empty graph on - `n` nodes. - - If two subset sizes `m` and `n` are given, this returns the complete - bipartite graph on `m + n` nodes. - - If subset sizes `1` and `n` are given, this returns the star graph on - `n + 1` nodes. - - See also - -------- - complete_bipartite_graph - """ - # The complete multipartite graph is an undirected simple graph. - G = Graph() - - if len(subset_sizes) == 0: - return G - - # set up subsets of nodes - try: - extents = pairwise(accumulate((0,) + subset_sizes)) - subsets = [range(start, end) for start, end in extents] - except TypeError: - subsets = subset_sizes - - # add nodes with subset attribute - # while checking that ints are not mixed with iterables - try: - for (i, subset) in enumerate(subsets): - G.add_nodes_from(subset, subset=i) - except TypeError: - raise NetworkXError("Arguments must be all ints or all iterables") - - # Across subsets, all vertices should be adjacent. - # We can use itertools.combinations() because undirected. - for subset1, subset2 in itertools.combinations(subsets, 2): - G.add_edges_from(itertools.product(subset1, subset2)) - return G diff --git a/extensions/fablabchemnitz/networkx/generators/cographs.py b/extensions/fablabchemnitz/networkx/generators/cographs.py deleted file mode 100644 index 3bf9bedd..00000000 --- a/extensions/fablabchemnitz/networkx/generators/cographs.py +++ /dev/null @@ -1,75 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Efraim Rodrigues (efraimnaassom@gmail.com) -r"""Generators for cographs - -A cograph is a graph containing no path on four vertices. -Cographs or $P_4$-free graphs can be obtained from a single vertex -by disjoint union and complementation operations. - -References ----------- -.. [0] D.G. Corneil, H. Lerchs, L.Stewart Burlingham, - "Complement reducible graphs", - Discrete Applied Mathematics, Volume 3, Issue 3, 1981, Pages 163-174, - ISSN 0166-218X. -""" -import networkx as nx -from networkx.utils import py_random_state - -__all__ = ['random_cograph'] - - -@py_random_state(1) -def random_cograph(n, seed=None): - r"""Returns a random cograph with $2 ^ n$ nodes. - - A cograph is a graph containing no path on four vertices. - Cographs or $P_4$-free graphs can be obtained from a single vertex - by disjoint union and complementation operations. - - This generator starts off from a single vertex and performes disjoint - union and full join operations on itself. - The decision on which operation will take place is random. - - Parameters - ---------- - n : int - The order of the cograph. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : A random graph containing no path on four vertices. - - See Also - -------- - full_join - union - - References - ---------- - .. [1] D.G. Corneil, H. Lerchs, L.Stewart Burlingham, - "Complement reducible graphs", - Discrete Applied Mathematics, Volume 3, Issue 3, 1981, Pages 163-174, - ISSN 0166-218X. - """ - R = nx.empty_graph(1) - - for i in range(n): - RR = nx.relabel_nodes(R.copy(), lambda x: x + len(R)) - - if seed.randint(0, 1) == 0: - R = nx.full_join(R, RR) - else: - R = nx.disjoint_union(R, RR) - - return R diff --git a/extensions/fablabchemnitz/networkx/generators/community.py b/extensions/fablabchemnitz/networkx/generators/community.py deleted file mode 100644 index fe16b909..00000000 --- a/extensions/fablabchemnitz/networkx/generators/community.py +++ /dev/null @@ -1,1030 +0,0 @@ -# Copyright(C) 2011-2019 by -# Ben Edwards -# Aric Hagberg -# Konstantinos Karakatsanis -# All rights reserved. -# BSD license. -# -# Authors: Ben Edwards (bedwards@cs.unm.edu) -# Aric Hagberg (hagberg@lanl.gov) -# Konstantinos Karakatsanis (dinoskarakas@gmail.com) -# Jean-Gabriel Young (jean.gabriel.young@gmail.com) -"""Generators for classes of graphs used in studying social networks.""" -import itertools -import math -import networkx as nx -from networkx.utils import py_random_state - -# Accommodates for both SciPy and non-SciPy implementations.. -try: - from scipy.special import zeta as _zeta - - def zeta(x, q, tolerance): - return _zeta(x, q) -except ImportError: - def zeta(x, q, tolerance): - """The Hurwitz zeta function, or the Riemann zeta function of two - arguments. - - ``x`` must be greater than one and ``q`` must be positive. - - This function repeatedly computes subsequent partial sums until - convergence, as decided by ``tolerance``. - """ - z = 0 - z_prev = -float('inf') - k = 0 - while abs(z - z_prev) > tolerance: - z_prev = z - z += 1 / ((k + q) ** x) - k += 1 - return z - -__all__ = ['caveman_graph', 'connected_caveman_graph', - 'relaxed_caveman_graph', 'random_partition_graph', - 'planted_partition_graph', 'gaussian_random_partition_graph', - 'ring_of_cliques', 'windmill_graph', 'stochastic_block_model', - 'LFR_benchmark_graph'] - - -def caveman_graph(l, k): - """Returns a caveman graph of `l` cliques of size `k`. - - Parameters - ---------- - l : int - Number of cliques - k : int - Size of cliques - - Returns - ------- - G : NetworkX Graph - caveman graph - - Notes - ----- - This returns an undirected graph, it can be converted to a directed - graph using :func:`nx.to_directed`, or a multigraph using - ``nx.MultiGraph(nx.caveman_graph(l, k))``. Only the undirected version is - described in [1]_ and it is unclear which of the directed - generalizations is most useful. - - Examples - -------- - >>> G = nx.caveman_graph(3, 3) - - See also - -------- - - connected_caveman_graph - - References - ---------- - .. [1] Watts, D. J. 'Networks, Dynamics, and the Small-World Phenomenon.' - Amer. J. Soc. 105, 493-527, 1999. - """ - # l disjoint cliques of size k - G = nx.empty_graph(l * k) - if k > 1: - for start in range(0, l * k, k): - edges = itertools.combinations(range(start, start + k), 2) - G.add_edges_from(edges) - return G - - -def connected_caveman_graph(l, k): - """Returns a connected caveman graph of `l` cliques of size `k`. - - The connected caveman graph is formed by creating `n` cliques of size - `k`, then a single edge in each clique is rewired to a node in an - adjacent clique. - - Parameters - ---------- - l : int - number of cliques - k : int - size of cliques - - Returns - ------- - G : NetworkX Graph - connected caveman graph - - Notes - ----- - This returns an undirected graph, it can be converted to a directed - graph using :func:`nx.to_directed`, or a multigraph using - ``nx.MultiGraph(nx.caveman_graph(l, k))``. Only the undirected version is - described in [1]_ and it is unclear which of the directed - generalizations is most useful. - - Examples - -------- - >>> G = nx.connected_caveman_graph(3, 3) - - References - ---------- - .. [1] Watts, D. J. 'Networks, Dynamics, and the Small-World Phenomenon.' - Amer. J. Soc. 105, 493-527, 1999. - """ - G = nx.caveman_graph(l, k) - for start in range(0, l * k, k): - G.remove_edge(start, start + 1) - G.add_edge(start, (start - 1) % (l * k)) - return G - - -@py_random_state(3) -def relaxed_caveman_graph(l, k, p, seed=None): - """Returns a relaxed caveman graph. - - A relaxed caveman graph starts with `l` cliques of size `k`. Edges are - then randomly rewired with probability `p` to link different cliques. - - Parameters - ---------- - l : int - Number of groups - k : int - Size of cliques - p : float - Probabilty of rewiring each edge. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : NetworkX Graph - Relaxed Caveman Graph - - Raises - ------ - NetworkXError: - If p is not in [0,1] - - Examples - -------- - >>> G = nx.relaxed_caveman_graph(2, 3, 0.1, seed=42) - - References - ---------- - .. [1] Santo Fortunato, Community Detection in Graphs, - Physics Reports Volume 486, Issues 3-5, February 2010, Pages 75-174. - https://arxiv.org/abs/0906.0612 - """ - G = nx.caveman_graph(l, k) - nodes = list(G) - for (u, v) in G.edges(): - if seed.random() < p: # rewire the edge - x = seed.choice(nodes) - if G.has_edge(u, x): - continue - G.remove_edge(u, v) - G.add_edge(u, x) - return G - - -@py_random_state(3) -def random_partition_graph(sizes, p_in, p_out, seed=None, directed=False): - """Returns the random partition graph with a partition of sizes. - - A partition graph is a graph of communities with sizes defined by - s in sizes. Nodes in the same group are connected with probability - p_in and nodes of different groups are connected with probability - p_out. - - Parameters - ---------- - sizes : list of ints - Sizes of groups - p_in : float - probability of edges with in groups - p_out : float - probability of edges between groups - directed : boolean optional, default=False - Whether to create a directed graph - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : NetworkX Graph or DiGraph - random partition graph of size sum(gs) - - Raises - ------ - NetworkXError - If p_in or p_out is not in [0,1] - - Examples - -------- - >>> G = nx.random_partition_graph([10,10,10],.25,.01) - >>> len(G) - 30 - >>> partition = G.graph['partition'] - >>> len(partition) - 3 - - Notes - ----- - This is a generalization of the planted-l-partition described in - [1]_. It allows for the creation of groups of any size. - - The partition is store as a graph attribute 'partition'. - - References - ---------- - .. [1] Santo Fortunato 'Community Detection in Graphs' Physical Reports - Volume 486, Issue 3-5 p. 75-174. https://arxiv.org/abs/0906.0612 - """ - # Use geometric method for O(n+m) complexity algorithm - # partition = nx.community_sets(nx.get_node_attributes(G, 'affiliation')) - if not 0.0 <= p_in <= 1.0: - raise nx.NetworkXError("p_in must be in [0,1]") - if not 0.0 <= p_out <= 1.0: - raise nx.NetworkXError("p_out must be in [0,1]") - - # create connection matrix - num_blocks = len(sizes) - p = [[p_out for s in range(num_blocks)] for r in range(num_blocks)] - for r in range(num_blocks): - p[r][r] = p_in - - return stochastic_block_model(sizes, p, nodelist=None, seed=seed, - directed=directed, selfloops=False, - sparse=True) - - -@py_random_state(4) -def planted_partition_graph(l, k, p_in, p_out, seed=None, directed=False): - """Returns the planted l-partition graph. - - This model partitions a graph with n=l*k vertices in - l groups with k vertices each. Vertices of the same - group are linked with a probability p_in, and vertices - of different groups are linked with probability p_out. - - Parameters - ---------- - l : int - Number of groups - k : int - Number of vertices in each group - p_in : float - probability of connecting vertices within a group - p_out : float - probability of connected vertices between groups - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - directed : bool,optional (default=False) - If True return a directed graph - - Returns - ------- - G : NetworkX Graph or DiGraph - planted l-partition graph - - Raises - ------ - NetworkXError: - If p_in,p_out are not in [0,1] or - - Examples - -------- - >>> G = nx.planted_partition_graph(4, 3, 0.5, 0.1, seed=42) - - See Also - -------- - random_partition_model - - References - ---------- - .. [1] A. Condon, R.M. Karp, Algorithms for graph partitioning - on the planted partition model, - Random Struct. Algor. 18 (2001) 116-140. - - .. [2] Santo Fortunato 'Community Detection in Graphs' Physical Reports - Volume 486, Issue 3-5 p. 75-174. https://arxiv.org/abs/0906.0612 - """ - return random_partition_graph([k] * l, p_in, p_out, seed, directed) - - -@py_random_state(6) -def gaussian_random_partition_graph(n, s, v, p_in, p_out, directed=False, - seed=None): - """Generate a Gaussian random partition graph. - - A Gaussian random partition graph is created by creating k partitions - each with a size drawn from a normal distribution with mean s and variance - s/v. Nodes are connected within clusters with probability p_in and - between clusters with probability p_out[1] - - Parameters - ---------- - n : int - Number of nodes in the graph - s : float - Mean cluster size - v : float - Shape parameter. The variance of cluster size distribution is s/v. - p_in : float - Probabilty of intra cluster connection. - p_out : float - Probability of inter cluster connection. - directed : boolean, optional default=False - Whether to create a directed graph or not - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : NetworkX Graph or DiGraph - gaussian random partition graph - - Raises - ------ - NetworkXError - If s is > n - If p_in or p_out is not in [0,1] - - Notes - ----- - Note the number of partitions is dependent on s,v and n, and that the - last partition may be considerably smaller, as it is sized to simply - fill out the nodes [1] - - See Also - -------- - random_partition_graph - - Examples - -------- - >>> G = nx.gaussian_random_partition_graph(100,10,10,.25,.1) - >>> len(G) - 100 - - References - ---------- - .. [1] Ulrik Brandes, Marco Gaertler, Dorothea Wagner, - Experiments on Graph Clustering Algorithms, - In the proceedings of the 11th Europ. Symp. Algorithms, 2003. - """ - if s > n: - raise nx.NetworkXError("s must be <= n") - assigned = 0 - sizes = [] - while True: - size = int(seed.gauss(s, float(s) / v + 0.5)) - if size < 1: # how to handle 0 or negative sizes? - continue - if assigned + size >= n: - sizes.append(n - assigned) - break - assigned += size - sizes.append(size) - return random_partition_graph(sizes, p_in, p_out, directed, seed) - - -def ring_of_cliques(num_cliques, clique_size): - """Defines a "ring of cliques" graph. - - A ring of cliques graph is consisting of cliques, connected through single - links. Each clique is a complete graph. - - Parameters - ---------- - num_cliques : int - Number of cliques - clique_size : int - Size of cliques - - Returns - ------- - G : NetworkX Graph - ring of cliques graph - - Raises - ------ - NetworkXError - If the number of cliques is lower than 2 or - if the size of cliques is smaller than 2. - - Examples - -------- - >>> G = nx.ring_of_cliques(8, 4) - - See Also - -------- - connected_caveman_graph - - Notes - ----- - The `connected_caveman_graph` graph removes a link from each clique to - connect it with the next clique. Instead, the `ring_of_cliques` graph - simply adds the link without removing any link from the cliques. - """ - if num_cliques < 2: - raise nx.NetworkXError('A ring of cliques must have at least ' - 'two cliques') - if clique_size < 2: - raise nx.NetworkXError('The cliques must have at least two nodes') - - G = nx.Graph() - for i in range(num_cliques): - edges = itertools.combinations(range(i * clique_size, i * clique_size + - clique_size), 2) - G.add_edges_from(edges) - G.add_edge(i * clique_size + 1, (i + 1) * clique_size % - (num_cliques * clique_size)) - return G - - -def windmill_graph(n, k): - """Generate a windmill graph. - A windmill graph is a graph of `n` cliques each of size `k` that are all - joined at one node. - It can be thought of as taking a disjoint union of `n` cliques of size `k`, - selecting one point from each, and contracting all of the selected points. - Alternatively, one could generate `n` cliques of size `k-1` and one node - that is connected to all other nodes in the graph. - - Parameters - ---------- - n : int - Number of cliques - k : int - Size of cliques - - Returns - ------- - G : NetworkX Graph - windmill graph with n cliques of size k - - Raises - ------ - NetworkXError - If the number of cliques is less than two - If the size of the cliques are less than two - - Examples - -------- - >>> G = nx.windmill_graph(4, 5) - - Notes - ----- - The node labeled `0` will be the node connected to all other nodes. - Note that windmill graphs are usually denoted `Wd(k,n)`, so the parameters - are in the opposite order as the parameters of this method. - """ - if n < 2: - msg = 'A windmill graph must have at least two cliques' - raise nx.NetworkXError(msg) - if k < 2: - raise nx.NetworkXError('The cliques must have at least two nodes') - - G = nx.disjoint_union_all(itertools.chain([nx.complete_graph(k)], - (nx.complete_graph(k - 1) - for _ in range(n - 1)))) - G.add_edges_from((0, i) for i in range(k, G.number_of_nodes())) - return G - - -@py_random_state(3) -def stochastic_block_model(sizes, p, nodelist=None, seed=None, - directed=False, selfloops=False, sparse=True): - """Returns a stochastic block model graph. - - This model partitions the nodes in blocks of arbitrary sizes, and places - edges between pairs of nodes independently, with a probability that depends - on the blocks. - - Parameters - ---------- - sizes : list of ints - Sizes of blocks - p : list of list of floats - Element (r,s) gives the density of edges going from the nodes - of group r to nodes of group s. - p must match the number of groups (len(sizes) == len(p)), - and it must be symmetric if the graph is undirected. - nodelist : list, optional - The block tags are assigned according to the node identifiers - in nodelist. If nodelist is None, then the ordering is the - range [0,sum(sizes)-1]. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - directed : boolean optional, default=False - Whether to create a directed graph or not. - selfloops : boolean optional, default=False - Whether to include self-loops or not. - sparse: boolean optional, default=True - Use the sparse heuristic to speed up the generator. - - Returns - ------- - g : NetworkX Graph or DiGraph - Stochastic block model graph of size sum(sizes) - - Raises - ------ - NetworkXError - If probabilities are not in [0,1]. - If the probability matrix is not square (directed case). - If the probability matrix is not symmetric (undirected case). - If the sizes list does not match nodelist or the probability matrix. - If nodelist contains duplicate. - - Examples - -------- - >>> sizes = [75, 75, 300] - >>> probs = [[0.25, 0.05, 0.02], - ... [0.05, 0.35, 0.07], - ... [0.02, 0.07, 0.40]] - >>> g = nx.stochastic_block_model(sizes, probs, seed=0) - >>> len(g) - 450 - >>> H = nx.quotient_graph(g, g.graph['partition'], relabel=True) - >>> for v in H.nodes(data=True): - ... print(round(v[1]['density'], 3)) - ... - 0.245 - 0.348 - 0.405 - >>> for v in H.edges(data=True): - ... print(round(1.0 * v[2]['weight'] / (sizes[v[0]] * sizes[v[1]]), 3)) - ... - 0.051 - 0.022 - 0.07 - - See Also - -------- - random_partition_graph - planted_partition_graph - gaussian_random_partition_graph - gnp_random_graph - - References - ---------- - .. [1] Holland, P. W., Laskey, K. B., & Leinhardt, S., - "Stochastic blockmodels: First steps", - Social networks, 5(2), 109-137, 1983. - """ - # Check if dimensions match - if len(sizes) != len(p): - raise nx.NetworkXException("'sizes' and 'p' do not match.") - # Check for probability symmetry (undirected) and shape (directed) - for row in p: - if len(p) != len(row): - raise nx.NetworkXException("'p' must be a square matrix.") - if not directed: - p_transpose = [list(i) for i in zip(*p)] - for i in zip(p, p_transpose): - for j in zip(i[0], i[1]): - if abs(j[0] - j[1]) > 1e-08: - raise nx.NetworkXException("'p' must be symmetric.") - # Check for probability range - for row in p: - for prob in row: - if prob < 0 or prob > 1: - raise nx.NetworkXException("Entries of 'p' not in [0,1].") - # Check for nodelist consistency - if nodelist is not None: - if len(nodelist) != sum(sizes): - raise nx.NetworkXException("'nodelist' and 'sizes' do not match.") - if len(nodelist) != len(set(nodelist)): - raise nx.NetworkXException("nodelist contains duplicate.") - else: - nodelist = range(0, sum(sizes)) - - # Setup the graph conditionally to the directed switch. - block_range = range(len(sizes)) - if directed: - g = nx.DiGraph() - block_iter = itertools.product(block_range, block_range) - else: - g = nx.Graph() - block_iter = itertools.combinations_with_replacement(block_range, 2) - # Split nodelist in a partition (list of sets). - size_cumsum = [sum(sizes[0:x]) for x in range(0, len(sizes) + 1)] - g.graph['partition'] = [set(nodelist[size_cumsum[x]:size_cumsum[x + 1]]) - for x in range(0, len(size_cumsum) - 1)] - # Setup nodes and graph name - for block_id, nodes in enumerate(g.graph['partition']): - for node in nodes: - g.add_node(node, block=block_id) - - g.name = "stochastic_block_model" - - # Test for edge existence - parts = g.graph['partition'] - for i, j in block_iter: - if i == j: - if directed: - if selfloops: - edges = itertools.product(parts[i], parts[i]) - else: - edges = itertools.permutations(parts[i], 2) - else: - edges = itertools.combinations(parts[i], 2) - if selfloops: - edges = itertools.chain(edges, zip(parts[i], parts[i])) - for e in edges: - if seed.random() < p[i][j]: - g.add_edge(*e) - else: - edges = itertools.product(parts[i], parts[j]) - if sparse: - if p[i][j] == 1: # Test edges cases p_ij = 0 or 1 - for e in edges: - g.add_edge(*e) - elif p[i][j] > 0: - while True: - try: - logrand = math.log(seed.random()) - skip = math.floor(logrand / math.log(1 - p[i][j])) - # consume "skip" edges - next(itertools.islice(edges, skip, skip), None) - e = next(edges) - g.add_edge(*e) # __safe - except StopIteration: - break - else: - for e in edges: - if seed.random() < p[i][j]: - g.add_edge(*e) # __safe - return g - - -def _zipf_rv_below(gamma, xmin, threshold, seed): - """Returns a random value chosen from the bounded Zipf distribution. - - Repeatedly draws values from the Zipf distribution until the - threshold is met, then returns that value. - """ - result = nx.utils.zipf_rv(gamma, xmin, seed) - while result > threshold: - result = nx.utils.zipf_rv(gamma, xmin, seed) - return result - - -def _powerlaw_sequence(gamma, low, high, condition, length, max_iters, seed): - """Returns a list of numbers obeying a constrained power law distribution. - - ``gamma`` and ``low`` are the parameters for the Zipf distribution. - - ``high`` is the maximum allowed value for values draw from the Zipf - distribution. For more information, see :func:`_zipf_rv_below`. - - ``condition`` and ``length`` are Boolean-valued functions on - lists. While generating the list, random values are drawn and - appended to the list until ``length`` is satisfied by the created - list. Once ``condition`` is satisfied, the sequence generated in - this way is returned. - - ``max_iters`` indicates the number of times to generate a list - satisfying ``length``. If the number of iterations exceeds this - value, :exc:`~networkx.exception.ExceededMaxIterations` is raised. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - """ - for i in range(max_iters): - seq = [] - while not length(seq): - seq.append(_zipf_rv_below(gamma, low, high, seed)) - if condition(seq): - return seq - raise nx.ExceededMaxIterations("Could not create power law sequence") - - -# TODO Needs documentation. -def _generate_min_degree(gamma, average_degree, max_degree, tolerance, - max_iters): - """Returns a minimum degree from the given average degree.""" - min_deg_top = max_degree - min_deg_bot = 1 - min_deg_mid = (min_deg_top - min_deg_bot) / 2 + min_deg_bot - itrs = 0 - mid_avg_deg = 0 - while abs(mid_avg_deg - average_degree) > tolerance: - if itrs > max_iters: - raise nx.ExceededMaxIterations("Could not match average_degree") - mid_avg_deg = 0 - for x in range(int(min_deg_mid), max_degree + 1): - mid_avg_deg += (x ** (-gamma + 1)) / zeta(gamma, min_deg_mid, - tolerance) - if mid_avg_deg > average_degree: - min_deg_top = min_deg_mid - min_deg_mid = (min_deg_top - min_deg_bot) / 2 + min_deg_bot - else: - min_deg_bot = min_deg_mid - min_deg_mid = (min_deg_top - min_deg_bot) / 2 + min_deg_bot - itrs += 1 - # return int(min_deg_mid + 0.5) - return round(min_deg_mid) - - -def _generate_communities(degree_seq, community_sizes, mu, max_iters, seed): - """Returns a list of sets, each of which represents a community. - - ``degree_seq`` is the degree sequence that must be met by the - graph. - - ``community_sizes`` is the community size distribution that must be - met by the generated list of sets. - - ``mu`` is a float in the interval [0, 1] indicating the fraction of - intra-community edges incident to each node. - - ``max_iters`` is the number of times to try to add a node to a - community. This must be greater than the length of - ``degree_seq``, otherwise this function will always fail. If - the number of iterations exceeds this value, - :exc:`~networkx.exception.ExceededMaxIterations` is raised. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - The communities returned by this are sets of integers in the set {0, - ..., *n* - 1}, where *n* is the length of ``degree_seq``. - - """ - # This assumes the nodes in the graph will be natural numbers. - result = [set() for _ in community_sizes] - n = len(degree_seq) - free = list(range(n)) - for i in range(max_iters): - v = free.pop() - c = seed.choice(range(len(community_sizes))) - # s = int(degree_seq[v] * (1 - mu) + 0.5) - s = round(degree_seq[v] * (1 - mu)) - # If the community is large enough, add the node to the chosen - # community. Otherwise, return it to the list of unaffiliated - # nodes. - if s < community_sizes[c]: - result[c].add(v) - else: - free.append(v) - # If the community is too big, remove a node from it. - if len(result[c]) > community_sizes[c]: - free.append(result[c].pop()) - if not free: - return result - msg = 'Could not assign communities; try increasing min_community' - raise nx.ExceededMaxIterations(msg) - - -@py_random_state(11) -def LFR_benchmark_graph(n, tau1, tau2, mu, average_degree=None, - min_degree=None, max_degree=None, min_community=None, - max_community=None, tol=1.0e-7, max_iters=500, - seed=None): - r"""Returns the LFR benchmark graph. - - This algorithm proceeds as follows: - - 1) Find a degree sequence with a power law distribution, and minimum - value ``min_degree``, which has approximate average degree - ``average_degree``. This is accomplished by either - - a) specifying ``min_degree`` and not ``average_degree``, - b) specifying ``average_degree`` and not ``min_degree``, in which - case a suitable minimum degree will be found. - - ``max_degree`` can also be specified, otherwise it will be set to - ``n``. Each node *u* will have `\mu \mathrm{deg}(u)` edges - joining it to nodes in communities other than its own and `(1 - - \mu) \mathrm{deg}(u)` edges joining it to nodes in its own - community. - 2) Generate community sizes according to a power law distribution - with exponent ``tau2``. If ``min_community`` and - ``max_community`` are not specified they will be selected to be - ``min_degree`` and ``max_degree``, respectively. Community sizes - are generated until the sum of their sizes equals ``n``. - 3) Each node will be randomly assigned a community with the - condition that the community is large enough for the node's - intra-community degree, `(1 - \mu) \mathrm{deg}(u)` as - described in step 2. If a community grows too large, a random node - will be selected for reassignment to a new community, until all - nodes have been assigned a community. - 4) Each node *u* then adds `(1 - \mu) \mathrm{deg}(u)` - intra-community edges and `\mu \mathrm{deg}(u)` inter-community - edges. - - Parameters - ---------- - n : int - Number of nodes in the created graph. - - tau1 : float - Power law exponent for the degree distribution of the created - graph. This value must be strictly greater than one. - - tau2 : float - Power law exponent for the community size distribution in the - created graph. This value must be strictly greater than one. - - mu : float - Fraction of intra-community edges incident to each node. This - value must be in the interval [0, 1]. - - average_degree : float - Desired average degree of nodes in the created graph. This value - must be in the interval [0, *n*]. Exactly one of this and - ``min_degree`` must be specified, otherwise a - :exc:`NetworkXError` is raised. - - min_degree : int - Minimum degree of nodes in the created graph. This value must be - in the interval [0, *n*]. Exactly one of this and - ``average_degree`` must be specified, otherwise a - :exc:`NetworkXError` is raised. - - max_degree : int - Maximum degree of nodes in the created graph. If not specified, - this is set to ``n``, the total number of nodes in the graph. - - min_community : int - Minimum size of communities in the graph. If not specified, this - is set to ``min_degree``. - - max_community : int - Maximum size of communities in the graph. If not specified, this - is set to ``n``, the total number of nodes in the graph. - - tol : float - Tolerance when comparing floats, specifically when comparing - average degree values. - - max_iters : int - Maximum number of iterations to try to create the community sizes, - degree distribution, and community affiliations. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : NetworkX graph - The LFR benchmark graph generated according to the specified - parameters. - - Each node in the graph has a node attribute ``'community'`` that - stores the community (that is, the set of nodes) that includes - it. - - Raises - ------ - NetworkXError - If any of the parameters do not meet their upper and lower bounds: - - - ``tau1`` and ``tau2`` must be strictly greater than 1. - - ``mu`` must be in [0, 1]. - - ``max_degree`` must be in {1, ..., *n*}. - - ``min_community`` and ``max_community`` must be in {0, ..., - *n*}. - - If not exactly one of ``average_degree`` and ``min_degree`` is - specified. - - If ``min_degree`` is not specified and a suitable ``min_degree`` - cannot be found. - - ExceededMaxIterations - If a valid degree sequence cannot be created within - ``max_iters`` number of iterations. - - If a valid set of community sizes cannot be created within - ``max_iters`` number of iterations. - - If a valid community assignment cannot be created within ``10 * - n * max_iters`` number of iterations. - - Examples - -------- - Basic usage:: - - >>> from networkx.generators.community import LFR_benchmark_graph - >>> n = 250 - >>> tau1 = 3 - >>> tau2 = 1.5 - >>> mu = 0.1 - >>> G = LFR_benchmark_graph(n, tau1, tau2, mu, average_degree=5, - ... min_community=20, seed=10) - - Continuing the example above, you can get the communities from the - node attributes of the graph:: - - >>> communities = {frozenset(G.nodes[v]['community']) for v in G} - - Notes - ----- - This algorithm differs slightly from the original way it was - presented in [1]. - - 1) Rather than connecting the graph via a configuration model then - rewiring to match the intra-community and inter-community - degrees, we do this wiring explicitly at the end, which should be - equivalent. - 2) The code posted on the author's website [2] calculates the random - power law distributed variables and their average using - continuous approximations, whereas we use the discrete - distributions here as both degree and community size are - discrete. - - Though the authors describe the algorithm as quite robust, testing - during development indicates that a somewhat narrower parameter set - is likely to successfully produce a graph. Some suggestions have - been provided in the event of exceptions. - - References - ---------- - .. [1] "Benchmark graphs for testing community detection algorithms", - Andrea Lancichinetti, Santo Fortunato, and Filippo Radicchi, - Phys. Rev. E 78, 046110 2008 - .. [2] http://santo.fortunato.googlepages.com/inthepress2 - - """ - # Perform some basic parameter validation. - if not tau1 > 1: - raise nx.NetworkXError("tau1 must be greater than one") - if not tau2 > 1: - raise nx.NetworkXError("tau2 must be greater than one") - if not 0 <= mu <= 1: - raise nx.NetworkXError("mu must be in the interval [0, 1]") - - # Validate parameters for generating the degree sequence. - if max_degree is None: - max_degree = n - elif not 0 < max_degree <= n: - raise nx.NetworkXError("max_degree must be in the interval (0, n]") - if not ((min_degree is None) ^ (average_degree is None)): - raise nx.NetworkXError("Must assign exactly one of min_degree and" - " average_degree") - if min_degree is None: - min_degree = _generate_min_degree(tau1, average_degree, max_degree, - tol, max_iters) - - # Generate a degree sequence with a power law distribution. - low, high = min_degree, max_degree - - def condition(seq): return sum(seq) % 2 == 0 - - def length(seq): return len(seq) >= n - deg_seq = _powerlaw_sequence(tau1, low, high, condition, - length, max_iters, seed) - - # Validate parameters for generating the community size sequence. - if min_community is None: - min_community = min(deg_seq) - if max_community is None: - max_community = max(deg_seq) - - # Generate a community size sequence with a power law distribution. - # - # TODO The original code incremented the number of iterations each - # time a new Zipf random value was drawn from the distribution. This - # differed from the way the number of iterations was incremented in - # `_powerlaw_degree_sequence`, so this code was changed to match - # that one. As a result, this code is allowed many more chances to - # generate a valid community size sequence. - low, high = min_community, max_community - - def condition(seq): return sum(seq) == n - - def length(seq): return sum(seq) >= n - comms = _powerlaw_sequence(tau2, low, high, condition, - length, max_iters, seed) - - # Generate the communities based on the given degree sequence and - # community sizes. - max_iters *= 10 * n - communities = _generate_communities(deg_seq, comms, mu, max_iters, seed) - - # Finally, generate the benchmark graph based on the given - # communities, joining nodes according to the intra- and - # inter-community degrees. - G = nx.Graph() - G.add_nodes_from(range(n)) - for c in communities: - for u in c: - while G.degree(u) < round(deg_seq[u] * (1 - mu)): - v = seed.choice(list(c)) - G.add_edge(u, v) - while G.degree(u) < deg_seq[u]: - v = seed.choice(range(n)) - if v not in c: - G.add_edge(u, v) - G.nodes[u]['community'] = c - return G diff --git a/extensions/fablabchemnitz/networkx/generators/degree_seq.py b/extensions/fablabchemnitz/networkx/generators/degree_seq.py deleted file mode 100644 index 99454720..00000000 --- a/extensions/fablabchemnitz/networkx/generators/degree_seq.py +++ /dev/null @@ -1,870 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg (aric.hagberg@gmail.com) -# Pieter Swart (swart@lanl.gov) -# Dan Schult (dschult@colgate.edu) -# Joel Miller (joel.c.miller.research@gmail.com) -# Nathan Lemons (nlemons@gmail.com) -# Brian Cloteaux (brian.cloteaux@nist.gov) -"""Generate graphs with a given degree sequence or expected degree sequence. -""" - -import heapq -from itertools import chain -from itertools import combinations -# In Python 3, the function is `zip_longest`, in Python 2 `izip_longest`. -try: - from itertools import zip_longest -except ImportError: - from itertools import izip_longest as zip_longest -import math -from operator import itemgetter - -import networkx as nx -from networkx.utils import random_weighted_sample, py_random_state - -__all__ = ['configuration_model', - 'directed_configuration_model', - 'expected_degree_graph', - 'havel_hakimi_graph', - 'directed_havel_hakimi_graph', - 'degree_sequence_tree', - 'random_degree_sequence_graph'] - -chaini = chain.from_iterable - - -def _to_stublist(degree_sequence): - """Returns a list of degree-repeated node numbers. - - ``degree_sequence`` is a list of nonnegative integers representing - the degrees of nodes in a graph. - - This function returns a list of node numbers with multiplicities - according to the given degree sequence. For example, if the first - element of ``degree_sequence`` is ``3``, then the first node number, - ``0``, will appear at the head of the returned list three times. The - node numbers are assumed to be the numbers zero through - ``len(degree_sequence) - 1``. - - Examples - -------- - - >>> degree_sequence = [1, 2, 3] - >>> _to_stublist(degree_sequence) - [0, 1, 1, 2, 2, 2] - - If a zero appears in the sequence, that means the node exists but - has degree zero, so that number will be skipped in the returned - list:: - - >>> degree_sequence = [2, 0, 1] - >>> _to_stublist(degree_sequence) - [0, 0, 2] - - """ - return list(chaini([n] * d for n, d in enumerate(degree_sequence))) - - -def _configuration_model(deg_sequence, create_using, directed=False, - in_deg_sequence=None, seed=None): - """Helper function for generating either undirected or directed - configuration model graphs. - - ``deg_sequence`` is a list of nonnegative integers representing the - degree of the node whose label is the index of the list element. - - ``create_using`` see :func:`~networkx.empty_graph`. - - ``directed`` and ``in_deg_sequence`` are required if you want the - returned graph to be generated using the directed configuration - model algorithm. If ``directed`` is ``False``, then ``deg_sequence`` - is interpreted as the degree sequence of an undirected graph and - ``in_deg_sequence`` is ignored. Otherwise, if ``directed`` is - ``True``, then ``deg_sequence`` is interpreted as the out-degree - sequence and ``in_deg_sequence`` as the in-degree sequence of a - directed graph. - - .. note:: - - ``deg_sequence`` and ``in_deg_sequence`` need not be the same - length. - - ``seed`` is a random.Random or numpy.random.RandomState instance - - This function returns a graph, directed if and only if ``directed`` - is ``True``, generated according to the configuration model - algorithm. For more information on the algorithm, see the - :func:`configuration_model` or :func:`directed_configuration_model` - functions. - - """ - n = len(deg_sequence) - G = nx.empty_graph(n, create_using) - # If empty, return the null graph immediately. - if n == 0: - return G - # Build a list of available degree-repeated nodes. For example, - # for degree sequence [3, 2, 1, 1, 1], the "stub list" is - # initially [0, 0, 0, 1, 1, 2, 3, 4], that is, node 0 has degree - # 3 and thus is repeated 3 times, etc. - # - # Also, shuffle the stub list in order to get a random sequence of - # node pairs. - if directed: - pairs = zip_longest(deg_sequence, in_deg_sequence, fillvalue=0) - # Unzip the list of pairs into a pair of lists. - out_deg, in_deg = zip(*pairs) - - out_stublist = _to_stublist(out_deg) - in_stublist = _to_stublist(in_deg) - - seed.shuffle(out_stublist) - seed.shuffle(in_stublist) - else: - stublist = _to_stublist(deg_sequence) - # Choose a random balanced bipartition of the stublist, which - # gives a random pairing of nodes. In this implementation, we - # shuffle the list and then split it in half. - n = len(stublist) - half = n // 2 - seed.shuffle(stublist) - out_stublist, in_stublist = stublist[:half], stublist[half:] - G.add_edges_from(zip(out_stublist, in_stublist)) - return G - - -@py_random_state(2) -def configuration_model(deg_sequence, create_using=None, seed=None): - """Returns a random graph with the given degree sequence. - - The configuration model generates a random pseudograph (graph with - parallel edges and self loops) by randomly assigning edges to - match the given degree sequence. - - Parameters - ---------- - deg_sequence : list of nonnegative integers - Each list entry corresponds to the degree of a node. - create_using : NetworkX graph constructor, optional (default MultiGraph) - Graph type to create. If graph instance, then cleared before populated. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : MultiGraph - A graph with the specified degree sequence. - Nodes are labeled starting at 0 with an index - corresponding to the position in deg_sequence. - - Raises - ------ - NetworkXError - If the degree sequence does not have an even sum. - - See Also - -------- - is_graphical - - Notes - ----- - As described by Newman [1]_. - - A non-graphical degree sequence (not realizable by some simple - graph) is allowed since this function returns graphs with self - loops and parallel edges. An exception is raised if the degree - sequence does not have an even sum. - - This configuration model construction process can lead to - duplicate edges and loops. You can remove the self-loops and - parallel edges (see below) which will likely result in a graph - that doesn't have the exact degree sequence specified. - - The density of self-loops and parallel edges tends to decrease as - the number of nodes increases. However, typically the number of - self-loops will approach a Poisson distribution with a nonzero mean, - and similarly for the number of parallel edges. Consider a node - with *k* stubs. The probability of being joined to another stub of - the same node is basically (*k* - *1*) / *N*, where *k* is the - degree and *N* is the number of nodes. So the probability of a - self-loop scales like *c* / *N* for some constant *c*. As *N* grows, - this means we expect *c* self-loops. Similarly for parallel edges. - - References - ---------- - .. [1] M.E.J. Newman, "The structure and function of complex networks", - SIAM REVIEW 45-2, pp 167-256, 2003. - - Examples - -------- - You can create a degree sequence following a particular distribution - by using the one of the distribution functions in - :mod:`~networkx.utils.random_sequence` (or one of your own). For - example, to create an undirected multigraph on one hundred nodes - with degree sequence chosen from the power law distribution: - - >>> sequence = nx.random_powerlaw_tree_sequence(100, tries=5000) - >>> G = nx.configuration_model(sequence) - >>> len(G) - 100 - >>> actual_degrees = [d for v, d in G.degree()] - >>> actual_degrees == sequence - True - - The returned graph is a multigraph, which may have parallel - edges. To remove any parallel edges from the returned graph: - - >>> G = nx.Graph(G) - - Similarly, to remove self-loops: - - >>> G.remove_edges_from(nx.selfloop_edges(G)) - - """ - if sum(deg_sequence) % 2 != 0: - msg = 'Invalid degree sequence: sum of degrees must be even, not odd' - raise nx.NetworkXError(msg) - - G = nx.empty_graph(0, create_using, default=nx.MultiGraph) - if G.is_directed(): - raise nx.NetworkXNotImplemented('not implemented for directed graphs') - - G = _configuration_model(deg_sequence, G, seed=seed) - - return G - - -@py_random_state(3) -def directed_configuration_model(in_degree_sequence, - out_degree_sequence, - create_using=None, seed=None): - """Returns a directed_random graph with the given degree sequences. - - The configuration model generates a random directed pseudograph - (graph with parallel edges and self loops) by randomly assigning - edges to match the given degree sequences. - - Parameters - ---------- - in_degree_sequence : list of nonnegative integers - Each list entry corresponds to the in-degree of a node. - out_degree_sequence : list of nonnegative integers - Each list entry corresponds to the out-degree of a node. - create_using : NetworkX graph constructor, optional (default MultiDiGraph) - Graph type to create. If graph instance, then cleared before populated. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : MultiDiGraph - A graph with the specified degree sequences. - Nodes are labeled starting at 0 with an index - corresponding to the position in deg_sequence. - - Raises - ------ - NetworkXError - If the degree sequences do not have the same sum. - - See Also - -------- - configuration_model - - Notes - ----- - Algorithm as described by Newman [1]_. - - A non-graphical degree sequence (not realizable by some simple - graph) is allowed since this function returns graphs with self - loops and parallel edges. An exception is raised if the degree - sequences does not have the same sum. - - This configuration model construction process can lead to - duplicate edges and loops. You can remove the self-loops and - parallel edges (see below) which will likely result in a graph - that doesn't have the exact degree sequence specified. This - "finite-size effect" decreases as the size of the graph increases. - - References - ---------- - .. [1] Newman, M. E. J. and Strogatz, S. H. and Watts, D. J. - Random graphs with arbitrary degree distributions and their applications - Phys. Rev. E, 64, 026118 (2001) - - Examples - -------- - One can modify the in- and out-degree sequences from an existing - directed graph in order to create a new directed graph. For example, - here we modify the directed path graph: - - >>> D = nx.DiGraph([(0, 1), (1, 2), (2, 3)]) - >>> din = list(d for n, d in D.in_degree()) - >>> dout = list(d for n, d in D.out_degree()) - >>> din.append(1) - >>> dout[0] = 2 - >>> # We now expect an edge from node 0 to a new node, node 3. - ... D = nx.directed_configuration_model(din, dout) - - The returned graph is a directed multigraph, which may have parallel - edges. To remove any parallel edges from the returned graph: - - >>> D = nx.DiGraph(D) - - Similarly, to remove self-loops: - - >>> D.remove_edges_from(nx.selfloop_edges(D)) - - """ - if sum(in_degree_sequence) != sum(out_degree_sequence): - msg = 'Invalid degree sequences: sequences must have equal sums' - raise nx.NetworkXError(msg) - - if create_using is None: - create_using = nx.MultiDiGraph - - G = _configuration_model(out_degree_sequence, create_using, directed=True, - in_deg_sequence=in_degree_sequence, seed=seed) - - name = "directed configuration_model {} nodes {} edges" - return G - - -@py_random_state(1) -def expected_degree_graph(w, seed=None, selfloops=True): - r"""Returns a random graph with given expected degrees. - - Given a sequence of expected degrees $W=(w_0,w_1,\ldots,w_{n-1})$ - of length $n$ this algorithm assigns an edge between node $u$ and - node $v$ with probability - - .. math:: - - p_{uv} = \frac{w_u w_v}{\sum_k w_k} . - - Parameters - ---------- - w : list - The list of expected degrees. - selfloops: bool (default=True) - Set to False to remove the possibility of self-loop edges. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - Graph - - Examples - -------- - >>> z=[10 for i in range(100)] - >>> G=nx.expected_degree_graph(z) - - Notes - ----- - The nodes have integer labels corresponding to index of expected degrees - input sequence. - - The complexity of this algorithm is $\mathcal{O}(n+m)$ where $n$ is the - number of nodes and $m$ is the expected number of edges. - - The model in [1]_ includes the possibility of self-loop edges. - Set selfloops=False to produce a graph without self loops. - - For finite graphs this model doesn't produce exactly the given - expected degree sequence. Instead the expected degrees are as - follows. - - For the case without self loops (selfloops=False), - - .. math:: - - E[deg(u)] = \sum_{v \ne u} p_{uv} - = w_u \left( 1 - \frac{w_u}{\sum_k w_k} \right) . - - - NetworkX uses the standard convention that a self-loop edge counts 2 - in the degree of a node, so with self loops (selfloops=True), - - .. math:: - - E[deg(u)] = \sum_{v \ne u} p_{uv} + 2 p_{uu} - = w_u \left( 1 + \frac{w_u}{\sum_k w_k} \right) . - - References - ---------- - .. [1] Fan Chung and L. Lu, Connected components in random graphs with - given expected degree sequences, Ann. Combinatorics, 6, - pp. 125-145, 2002. - .. [2] Joel Miller and Aric Hagberg, - Efficient generation of networks with given expected degrees, - in Algorithms and Models for the Web-Graph (WAW 2011), - Alan Frieze, Paul Horn, and Paweł Prałat (Eds), LNCS 6732, - pp. 115-126, 2011. - """ - n = len(w) - G = nx.empty_graph(n) - - # If there are no nodes are no edges in the graph, return the empty graph. - if n == 0 or max(w) == 0: - return G - - rho = 1 / sum(w) - # Sort the weights in decreasing order. The original order of the - # weights dictates the order of the (integer) node labels, so we - # need to remember the permutation applied in the sorting. - order = sorted(enumerate(w), key=itemgetter(1), reverse=True) - mapping = {c: u for c, (u, v) in enumerate(order)} - seq = [v for u, v in order] - last = n - if not selfloops: - last -= 1 - for u in range(last): - v = u - if not selfloops: - v += 1 - factor = seq[u] * rho - p = min(seq[v] * factor, 1) - while v < n and p > 0: - if p != 1: - r = seed.random() - v += int(math.floor(math.log(r, 1 - p))) - if v < n: - q = min(seq[v] * factor, 1) - if seed.random() < q / p: - G.add_edge(mapping[u], mapping[v]) - v += 1 - p = q - return G - - -def havel_hakimi_graph(deg_sequence, create_using=None): - """Returns a simple graph with given degree sequence constructed - using the Havel-Hakimi algorithm. - - Parameters - ---------- - deg_sequence: list of integers - Each integer corresponds to the degree of a node (need not be sorted). - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - Directed graphs are not allowed. - - Raises - ------ - NetworkXException - For a non-graphical degree sequence (i.e. one - not realizable by some simple graph). - - Notes - ----- - The Havel-Hakimi algorithm constructs a simple graph by - successively connecting the node of highest degree to other nodes - of highest degree, resorting remaining nodes by degree, and - repeating the process. The resulting graph has a high - degree-associativity. Nodes are labeled 1,.., len(deg_sequence), - corresponding to their position in deg_sequence. - - The basic algorithm is from Hakimi [1]_ and was generalized by - Kleitman and Wang [2]_. - - References - ---------- - .. [1] Hakimi S., On Realizability of a Set of Integers as - Degrees of the Vertices of a Linear Graph. I, - Journal of SIAM, 10(3), pp. 496-506 (1962) - .. [2] Kleitman D.J. and Wang D.L. - Algorithms for Constructing Graphs and Digraphs with Given Valences - and Factors Discrete Mathematics, 6(1), pp. 79-88 (1973) - """ - if not nx.is_graphical(deg_sequence): - raise nx.NetworkXError('Invalid degree sequence') - - p = len(deg_sequence) - G = nx.empty_graph(p, create_using) - if G.is_directed(): - raise nx.NetworkXError("Directed graphs are not supported") - num_degs = [[] for i in range(p)] - dmax, dsum, n = 0, 0, 0 - for d in deg_sequence: - # Process only the non-zero integers - if d > 0: - num_degs[d].append(n) - dmax, dsum, n = max(dmax, d), dsum + d, n + 1 - # Return graph if no edges - if n == 0: - return G - - modstubs = [(0, 0)] * (dmax + 1) - # Successively reduce degree sequence by removing the maximum degree - while n > 0: - # Retrieve the maximum degree in the sequence - while len(num_degs[dmax]) == 0: - dmax -= 1 - # If there are not enough stubs to connect to, then the sequence is - # not graphical - if dmax > n - 1: - raise nx.NetworkXError('Non-graphical integer sequence') - - # Remove largest stub in list - source = num_degs[dmax].pop() - n -= 1 - # Reduce the next dmax largest stubs - mslen = 0 - k = dmax - for i in range(dmax): - while len(num_degs[k]) == 0: - k -= 1 - target = num_degs[k].pop() - G.add_edge(source, target) - n -= 1 - if k > 1: - modstubs[mslen] = (k - 1, target) - mslen += 1 - # Add back to the list any nonzero stubs that were removed - for i in range(mslen): - (stubval, stubtarget) = modstubs[i] - num_degs[stubval].append(stubtarget) - n += 1 - - return G - - -def directed_havel_hakimi_graph(in_deg_sequence, - out_deg_sequence, - create_using=None): - """Returns a directed graph with the given degree sequences. - - Parameters - ---------- - in_deg_sequence : list of integers - Each list entry corresponds to the in-degree of a node. - out_deg_sequence : list of integers - Each list entry corresponds to the out-degree of a node. - create_using : NetworkX graph constructor, optional (default DiGraph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : DiGraph - A graph with the specified degree sequences. - Nodes are labeled starting at 0 with an index - corresponding to the position in deg_sequence - - Raises - ------ - NetworkXError - If the degree sequences are not digraphical. - - See Also - -------- - configuration_model - - Notes - ----- - Algorithm as described by Kleitman and Wang [1]_. - - References - ---------- - .. [1] D.J. Kleitman and D.L. Wang - Algorithms for Constructing Graphs and Digraphs with Given Valences - and Factors Discrete Mathematics, 6(1), pp. 79-88 (1973) - """ - in_deg_sequence = nx.utils.make_list_of_ints(in_deg_sequence) - out_deg_sequence = nx.utils.make_list_of_ints(out_deg_sequence) - - # Process the sequences and form two heaps to store degree pairs with - # either zero or nonzero out degrees - sumin, sumout = 0, 0 - nin, nout = len(in_deg_sequence), len(out_deg_sequence) - maxn = max(nin, nout) - G = nx.empty_graph(maxn, create_using, default=nx.DiGraph) - if maxn == 0: - return G - maxin = 0 - stubheap, zeroheap = [], [] - for n in range(maxn): - in_deg, out_deg = 0, 0 - if n < nout: - out_deg = out_deg_sequence[n] - if n < nin: - in_deg = in_deg_sequence[n] - if in_deg < 0 or out_deg < 0: - raise nx.NetworkXError( - 'Invalid degree sequences. Sequence values must be positive.') - sumin, sumout, maxin = sumin + in_deg, sumout + out_deg, max(maxin, in_deg) - if in_deg > 0: - stubheap.append((-1 * out_deg, -1 * in_deg, n)) - elif out_deg > 0: - zeroheap.append((-1 * out_deg, n)) - if sumin != sumout: - raise nx.NetworkXError( - 'Invalid degree sequences. Sequences must have equal sums.') - heapq.heapify(stubheap) - heapq.heapify(zeroheap) - - modstubs = [(0, 0, 0)] * (maxin + 1) - # Successively reduce degree sequence by removing the maximum - while stubheap: - # Remove first value in the sequence with a non-zero in degree - (freeout, freein, target) = heapq.heappop(stubheap) - freein *= -1 - if freein > len(stubheap) + len(zeroheap): - raise nx.NetworkXError('Non-digraphical integer sequence') - - # Attach arcs from the nodes with the most stubs - mslen = 0 - for i in range(freein): - if zeroheap and (not stubheap or stubheap[0][0] > zeroheap[0][0]): - (stubout, stubsource) = heapq.heappop(zeroheap) - stubin = 0 - else: - (stubout, stubin, stubsource) = heapq.heappop(stubheap) - if stubout == 0: - raise nx.NetworkXError('Non-digraphical integer sequence') - G.add_edge(stubsource, target) - # Check if source is now totally connected - if stubout + 1 < 0 or stubin < 0: - modstubs[mslen] = (stubout + 1, stubin, stubsource) - mslen += 1 - - # Add the nodes back to the heaps that still have available stubs - for i in range(mslen): - stub = modstubs[i] - if stub[1] < 0: - heapq.heappush(stubheap, stub) - else: - heapq.heappush(zeroheap, (stub[0], stub[2])) - if freeout < 0: - heapq.heappush(zeroheap, (freeout, target)) - - return G - - -def degree_sequence_tree(deg_sequence, create_using=None): - """Make a tree for the given degree sequence. - - A tree has #nodes-#edges=1 so - the degree sequence must have - len(deg_sequence)-sum(deg_sequence)/2=1 - """ - # The sum of the degree sequence must be even (for any undirected graph). - degree_sum = sum(deg_sequence) - if degree_sum % 2 != 0: - msg = 'Invalid degree sequence: sum of degrees must be even, not odd' - raise nx.NetworkXError(msg) - if len(deg_sequence) - degree_sum // 2 != 1: - msg = ('Invalid degree sequence: tree must have number of nodes equal' - ' to one less than the number of edges') - raise nx.NetworkXError(msg) - G = nx.empty_graph(0, create_using) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - # Sort all degrees greater than 1 in decreasing order. - # - # TODO Does this need to be sorted in reverse order? - deg = sorted((s for s in deg_sequence if s > 1), reverse=True) - - # make path graph as backbone - n = len(deg) + 2 - nx.add_path(G, range(n)) - last = n - - # add the leaves - for source in range(1, n - 1): - nedges = deg.pop() - 2 - for target in range(last, last + nedges): - G.add_edge(source, target) - last += nedges - - # in case we added one too many - if len(G) > len(deg_sequence): - G.remove_node(0) - return G - - -@py_random_state(1) -def random_degree_sequence_graph(sequence, seed=None, tries=10): - r"""Returns a simple random graph with the given degree sequence. - - If the maximum degree $d_m$ in the sequence is $O(m^{1/4})$ then the - algorithm produces almost uniform random graphs in $O(m d_m)$ time - where $m$ is the number of edges. - - Parameters - ---------- - sequence : list of integers - Sequence of degrees - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - tries : int, optional - Maximum number of tries to create a graph - - Returns - ------- - G : Graph - A graph with the specified degree sequence. - Nodes are labeled starting at 0 with an index - corresponding to the position in the sequence. - - Raises - ------ - NetworkXUnfeasible - If the degree sequence is not graphical. - NetworkXError - If a graph is not produced in specified number of tries - - See Also - -------- - is_graphical, configuration_model - - Notes - ----- - The generator algorithm [1]_ is not guaranteed to produce a graph. - - References - ---------- - .. [1] Moshen Bayati, Jeong Han Kim, and Amin Saberi, - A sequential algorithm for generating random graphs. - Algorithmica, Volume 58, Number 4, 860-910, - DOI: 10.1007/s00453-009-9340-1 - - Examples - -------- - >>> sequence = [1, 2, 2, 3] - >>> G = nx.random_degree_sequence_graph(sequence, seed=42) - >>> sorted(d for n, d in G.degree()) - [1, 2, 2, 3] - """ - DSRG = DegreeSequenceRandomGraph(sequence, seed) - for try_n in range(tries): - try: - return DSRG.generate() - except nx.NetworkXUnfeasible: - pass - raise nx.NetworkXError('failed to generate graph in %d tries' % tries) - - -class DegreeSequenceRandomGraph(object): - # class to generate random graphs with a given degree sequence - # use random_degree_sequence_graph() - def __init__(self, degree, rng): - if not nx.is_graphical(degree): - raise nx.NetworkXUnfeasible('degree sequence is not graphical') - self.rng = rng - self.degree = list(degree) - # node labels are integers 0,...,n-1 - self.m = sum(self.degree) / 2.0 # number of edges - try: - self.dmax = max(self.degree) # maximum degree - except ValueError: - self.dmax = 0 - - def generate(self): - # remaining_degree is mapping from int->remaining degree - self.remaining_degree = dict(enumerate(self.degree)) - # add all nodes to make sure we get isolated nodes - self.graph = nx.Graph() - self.graph.add_nodes_from(self.remaining_degree) - # remove zero degree nodes - for n, d in list(self.remaining_degree.items()): - if d == 0: - del self.remaining_degree[n] - if len(self.remaining_degree) > 0: - # build graph in three phases according to how many unmatched edges - self.phase1() - self.phase2() - self.phase3() - return self.graph - - def update_remaining(self, u, v, aux_graph=None): - # decrement remaining nodes, modify auxiliary graph if in phase3 - if aux_graph is not None: - # remove edges from auxiliary graph - aux_graph.remove_edge(u, v) - if self.remaining_degree[u] == 1: - del self.remaining_degree[u] - if aux_graph is not None: - aux_graph.remove_node(u) - else: - self.remaining_degree[u] -= 1 - if self.remaining_degree[v] == 1: - del self.remaining_degree[v] - if aux_graph is not None: - aux_graph.remove_node(v) - else: - self.remaining_degree[v] -= 1 - - def p(self, u, v): - # degree probability - return 1 - self.degree[u] * self.degree[v] / (4.0 * self.m) - - def q(self, u, v): - # remaining degree probability - norm = float(max(self.remaining_degree.values()))**2 - return self.remaining_degree[u] * self.remaining_degree[v] / norm - - def suitable_edge(self): - """Returns True if and only if an arbitrary remaining node can - potentially be joined with some other remaining node. - - """ - nodes = iter(self.remaining_degree) - u = next(nodes) - return any(v not in self.graph[u] for v in nodes) - - def phase1(self): - # choose node pairs from (degree) weighted distribution - rem_deg = self.remaining_degree - while sum(rem_deg.values()) >= 2 * self.dmax**2: - u, v = sorted(random_weighted_sample(rem_deg, 2, self.rng)) - if self.graph.has_edge(u, v): - continue - if self.rng.random() < self.p(u, v): # accept edge - self.graph.add_edge(u, v) - self.update_remaining(u, v) - - def phase2(self): - # choose remaining nodes uniformly at random and use rejection sampling - remaining_deg = self.remaining_degree - rng = self.rng - while len(remaining_deg) >= 2 * self.dmax: - while True: - u, v = sorted(rng.sample(remaining_deg.keys(), 2)) - if self.graph.has_edge(u, v): - continue - if rng.random() < self.q(u, v): - break - if rng.random() < self.p(u, v): # accept edge - self.graph.add_edge(u, v) - self.update_remaining(u, v) - - def phase3(self): - # build potential remaining edges and choose with rejection sampling - potential_edges = combinations(self.remaining_degree, 2) - # build auxiliary graph of potential edges not already in graph - H = nx.Graph([(u, v) for (u, v) in potential_edges - if not self.graph.has_edge(u, v)]) - rng = self.rng - while self.remaining_degree: - if not self.suitable_edge(): - raise nx.NetworkXUnfeasible('no suitable edges left') - while True: - u, v = sorted(rng.choice(list(H.edges()))) - if rng.random() < self.q(u, v): - break - if rng.random() < self.p(u, v): # accept edge - self.graph.add_edge(u, v) - self.update_remaining(u, v, aux_graph=H) diff --git a/extensions/fablabchemnitz/networkx/generators/directed.py b/extensions/fablabchemnitz/networkx/generators/directed.py deleted file mode 100644 index 7d36c253..00000000 --- a/extensions/fablabchemnitz/networkx/generators/directed.py +++ /dev/null @@ -1,459 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2006-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# Copyright (C) 2009 by Willem Ligtenberg -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg (hagberg@lanl.gov) -# Willem Ligtenberg (W.P.A.Ligtenberg@tue.nl) -""" -Generators for some directed graphs, including growing network (GN) graphs and -scale-free graphs. - -""" - -from collections import Counter - -import networkx as nx -from networkx.generators.classic import empty_graph -from networkx.utils import discrete_sequence -from networkx.utils import weighted_choice -from networkx.utils import py_random_state - -__all__ = ['gn_graph', 'gnc_graph', 'gnr_graph', 'random_k_out_graph', - 'scale_free_graph'] - - -@py_random_state(3) -def gn_graph(n, kernel=None, create_using=None, seed=None): - """Returns the growing network (GN) digraph with `n` nodes. - - The GN graph is built by adding nodes one at a time with a link to one - previously added node. The target node for the link is chosen with - probability based on degree. The default attachment kernel is a linear - function of the degree of a node. - - The graph is always a (directed) tree. - - Parameters - ---------- - n : int - The number of nodes for the generated graph. - kernel : function - The attachment kernel. - create_using : NetworkX graph constructor, optional (default DiGraph) - Graph type to create. If graph instance, then cleared before populated. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Examples - -------- - To create the undirected GN graph, use the :meth:`~DiGraph.to_directed` - method:: - - >>> D = nx.gn_graph(10) # the GN graph - >>> G = D.to_undirected() # the undirected version - - To specify an attachment kernel, use the `kernel` keyword argument:: - - >>> D = nx.gn_graph(10, kernel=lambda x: x ** 1.5) # A_k = k^1.5 - - References - ---------- - .. [1] P. L. Krapivsky and S. Redner, - Organization of Growing Random Networks, - Phys. Rev. E, 63, 066123, 2001. - """ - G = empty_graph(1, create_using, default=nx.DiGraph) - if not G.is_directed(): - raise nx.NetworkXError("create_using must indicate a Directed Graph") - - if kernel is None: - def kernel(x): return x - - if n == 1: - return G - - G.add_edge(1, 0) # get started - ds = [1, 1] # degree sequence - - for source in range(2, n): - # compute distribution from kernel and degree - dist = [kernel(d) for d in ds] - # choose target from discrete distribution - target = discrete_sequence(1, distribution=dist, seed=seed)[0] - G.add_edge(source, target) - ds.append(1) # the source has only one link (degree one) - ds[target] += 1 # add one to the target link degree - return G - - -@py_random_state(3) -def gnr_graph(n, p, create_using=None, seed=None): - """Returns the growing network with redirection (GNR) digraph with `n` - nodes and redirection probability `p`. - - The GNR graph is built by adding nodes one at a time with a link to one - previously added node. The previous target node is chosen uniformly at - random. With probabiliy `p` the link is instead "redirected" to the - successor node of the target. - - The graph is always a (directed) tree. - - Parameters - ---------- - n : int - The number of nodes for the generated graph. - p : float - The redirection probability. - create_using : NetworkX graph constructor, optional (default DiGraph) - Graph type to create. If graph instance, then cleared before populated. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Examples - -------- - To create the undirected GNR graph, use the :meth:`~DiGraph.to_directed` - method:: - - >>> D = nx.gnr_graph(10, 0.5) # the GNR graph - >>> G = D.to_undirected() # the undirected version - - References - ---------- - .. [1] P. L. Krapivsky and S. Redner, - Organization of Growing Random Networks, - Phys. Rev. E, 63, 066123, 2001. - """ - G = empty_graph(1, create_using, default=nx.DiGraph) - if not G.is_directed(): - raise nx.NetworkXError("create_using must indicate a Directed Graph") - - if n == 1: - return G - - for source in range(1, n): - target = seed.randrange(0, source) - if seed.random() < p and target != 0: - target = next(G.successors(target)) - G.add_edge(source, target) - return G - - -@py_random_state(2) -def gnc_graph(n, create_using=None, seed=None): - """Returns the growing network with copying (GNC) digraph with `n` nodes. - - The GNC graph is built by adding nodes one at a time with a link to one - previously added node (chosen uniformly at random) and to all of that - node's successors. - - Parameters - ---------- - n : int - The number of nodes for the generated graph. - create_using : NetworkX graph constructor, optional (default DiGraph) - Graph type to create. If graph instance, then cleared before populated. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - References - ---------- - .. [1] P. L. Krapivsky and S. Redner, - Network Growth by Copying, - Phys. Rev. E, 71, 036118, 2005k.}, - """ - G = empty_graph(1, create_using, default=nx.DiGraph) - if not G.is_directed(): - raise nx.NetworkXError("create_using must indicate a Directed Graph") - - if n == 1: - return G - - for source in range(1, n): - target = seed.randrange(0, source) - for succ in G.successors(target): - G.add_edge(source, succ) - G.add_edge(source, target) - return G - - -@py_random_state(7) -def scale_free_graph(n, alpha=0.41, beta=0.54, gamma=0.05, delta_in=0.2, - delta_out=0, create_using=None, seed=None): - """Returns a scale-free directed graph. - - Parameters - ---------- - n : integer - Number of nodes in graph - alpha : float - Probability for adding a new node connected to an existing node - chosen randomly according to the in-degree distribution. - beta : float - Probability for adding an edge between two existing nodes. - One existing node is chosen randomly according the in-degree - distribution and the other chosen randomly according to the out-degree - distribution. - gamma : float - Probability for adding a new node connected to an existing node - chosen randomly according to the out-degree distribution. - delta_in : float - Bias for choosing nodes from in-degree distribution. - delta_out : float - Bias for choosing nodes from out-degree distribution. - create_using : NetworkX graph constructor, optional - The default is a MultiDiGraph 3-cycle. - If a graph instance, use it without clearing first. - If a graph constructor, call it to construct an empty graph. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Examples - -------- - Create a scale-free graph on one hundred nodes:: - - >>> G = nx.scale_free_graph(100) - - Notes - ----- - The sum of `alpha`, `beta`, and `gamma` must be 1. - - References - ---------- - .. [1] B. Bollobás, C. Borgs, J. Chayes, and O. Riordan, - Directed scale-free graphs, - Proceedings of the fourteenth annual ACM-SIAM Symposium on - Discrete Algorithms, 132--139, 2003. - """ - - def _choose_node(G, distribution, delta, psum): - cumsum = 0.0 - # normalization - r = seed.random() - for n, d in distribution: - cumsum += (d + delta) / psum - if r < cumsum: - break - return n - - if create_using is None or not hasattr(create_using, '_adj'): - # start with 3-cycle - G = nx.empty_graph(3, create_using, default=nx.MultiDiGraph) - G.add_edges_from([(0, 1), (1, 2), (2, 0)]) - else: - G = create_using - if not (G.is_directed() and G.is_multigraph()): - raise nx.NetworkXError("MultiDiGraph required in create_using") - - if alpha <= 0: - raise ValueError('alpha must be > 0.') - if beta <= 0: - raise ValueError('beta must be > 0.') - if gamma <= 0: - raise ValueError('gamma must be > 0.') - - if abs(alpha + beta + gamma - 1.0) >= 1e-9: - raise ValueError('alpha+beta+gamma must equal 1.') - - number_of_edges = G.number_of_edges() - while len(G) < n: - psum_in = number_of_edges + delta_in * len(G) - psum_out = number_of_edges + delta_out * len(G) - r = seed.random() - # random choice in alpha,beta,gamma ranges - if r < alpha: - # alpha - # add new node v - v = len(G) - # choose w according to in-degree and delta_in - w = _choose_node(G, G.in_degree(), delta_in, psum_in) - elif r < alpha + beta: - # beta - # choose v according to out-degree and delta_out - v = _choose_node(G, G.out_degree(), delta_out, psum_out) - # choose w according to in-degree and delta_in - w = _choose_node(G, G.in_degree(), delta_in, psum_in) - else: - # gamma - # choose v according to out-degree and delta_out - v = _choose_node(G, G.out_degree(), delta_out, psum_out) - # add new node w - w = len(G) - G.add_edge(v, w) - number_of_edges += 1 - return G - - -@py_random_state(4) -def random_uniform_k_out_graph(n, k, self_loops=True, with_replacement=True, - seed=None): - """Returns a random `k`-out graph with uniform attachment. - - A random `k`-out graph with uniform attachment is a multidigraph - generated by the following algorithm. For each node *u*, choose - `k` nodes *v* uniformly at random (with replacement). Add a - directed edge joining *u* to *v*. - - Parameters - ---------- - n : int - The number of nodes in the returned graph. - - k : int - The out-degree of each node in the returned graph. - - self_loops : bool - If True, self-loops are allowed when generating the graph. - - with_replacement : bool - If True, neighbors are chosen with replacement and the - returned graph will be a directed multigraph. Otherwise, - neighbors are chosen without replacement and the returned graph - will be a directed graph. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - NetworkX graph - A `k`-out-regular directed graph generated according to the - above algorithm. It will be a multigraph if and only if - `with_replacement` is True. - - Raises - ------ - ValueError - If `with_replacement` is False and `k` is greater than - `n`. - - See also - -------- - random_k_out_graph - - Notes - ----- - The return digraph or multidigraph may not be strongly connected, or - even weakly connected. - - If `with_replacement` is True, this function is similar to - :func:`random_k_out_graph`, if that function had parameter `alpha` - set to positive infinity. - - """ - if with_replacement: - create_using = nx.MultiDiGraph() - - def sample(v, nodes): - if not self_loops: - nodes = nodes - {v} - return (seed.choice(list(nodes)) for i in range(k)) - - else: - create_using = nx.DiGraph() - - def sample(v, nodes): - if not self_loops: - nodes = nodes - {v} - return seed.sample(nodes, k) - - G = nx.empty_graph(n, create_using) - nodes = set(G) - for u in G: - G.add_edges_from((u, v) for v in sample(u, nodes)) - return G - - -@py_random_state(4) -def random_k_out_graph(n, k, alpha, self_loops=True, seed=None): - """Returns a random `k`-out graph with preferential attachment. - - A random `k`-out graph with preferential attachment is a - multidigraph generated by the following algorithm. - - 1. Begin with an empty digraph, and initially set each node to have - weight `alpha`. - 2. Choose a node `u` with out-degree less than `k` uniformly at - random. - 3. Choose a node `v` from with probability proportional to its - weight. - 4. Add a directed edge from `u` to `v`, and increase the weight - of `v` by one. - 5. If each node has out-degree `k`, halt, otherwise repeat from - step 2. - - For more information on this model of random graph, see [1]. - - Parameters - ---------- - n : int - The number of nodes in the returned graph. - - k : int - The out-degree of each node in the returned graph. - - alpha : float - A positive :class:`float` representing the initial weight of - each vertex. A higher number means that in step 3 above, nodes - will be chosen more like a true uniformly random sample, and a - lower number means that nodes are more likely to be chosen as - their in-degree increases. If this parameter is not positive, a - :exc:`ValueError` is raised. - - self_loops : bool - If True, self-loops are allowed when generating the graph. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - :class:`~networkx.classes.MultiDiGraph` - A `k`-out-regular multidigraph generated according to the above - algorithm. - - Raises - ------ - ValueError - If `alpha` is not positive. - - Notes - ----- - The returned multidigraph may not be strongly connected, or even - weakly connected. - - References - ---------- - [1]: Peterson, Nicholas R., and Boris Pittel. - "Distance between two random `k`-out digraphs, with and without - preferential attachment." - arXiv preprint arXiv:1311.5961 (2013). - - - """ - if alpha < 0: - raise ValueError('alpha must be positive') - G = nx.empty_graph(n, create_using=nx.MultiDiGraph) - weights = Counter({v: alpha for v in G}) - for i in range(k * n): - u = seed.choice([v for v, d in G.out_degree() if d < k]) - # If self-loops are not allowed, make the source node `u` have - # weight zero. - if not self_loops: - adjustment = Counter({u: weights[u]}) - else: - adjustment = Counter() - v = weighted_choice(weights - adjustment, seed=seed) - G.add_edge(u, v) - weights[v] += 1 - return G diff --git a/extensions/fablabchemnitz/networkx/generators/duplication.py b/extensions/fablabchemnitz/networkx/generators/duplication.py deleted file mode 100644 index 19242c3f..00000000 --- a/extensions/fablabchemnitz/networkx/generators/duplication.py +++ /dev/null @@ -1,173 +0,0 @@ -# duplication.py - functions for generating graphs by duplicating nodes -# -# Copyright 2016-2019 NetworkX developers. -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Functions for generating graphs based on the "duplication" method. - -These graph generators start with a small initial graph then duplicate -nodes and (partially) duplicate their edges. These functions are -generally inspired by biological networks. - -""" -import networkx as nx -from networkx.utils import py_random_state -from networkx.exception import NetworkXError - -__all__ = ['partial_duplication_graph', 'duplication_divergence_graph'] - - -@py_random_state(4) -def partial_duplication_graph(N, n, p, q, seed=None): - """Returns a random graph using the partial duplication model. - - Parameters - ---------- - N : int - The total number of nodes in the final graph. - - n : int - The number of nodes in the initial clique. - - p : float - The probability of joining each neighbor of a node to the - duplicate node. Must be a number in the between zero and one, - inclusive. - - q : float - The probability of joining the source node to the duplicate - node. Must be a number in the between zero and one, inclusive. - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Notes - ----- - A graph of nodes is grown by creating a fully connected graph - of size `n`. The following procedure is then repeated until - a total of `N` nodes have been reached. - - 1. A random node, *u*, is picked and a new node, *v*, is created. - 2. For each neighbor of *u* an edge from the neighbor to *v* is created - with probability `p`. - 3. An edge from *u* to *v* is created with probability `q`. - - This algorithm appears in [1]. - - This implementation allows the possibility of generating - disconnected graphs. - - References - ---------- - .. [1] Knudsen Michael, and Carsten Wiuf. "A Markov chain approach to - randomly grown graphs." Journal of Applied Mathematics 2008. - - - """ - if p < 0 or p > 1 or q < 0 or q > 1: - msg = "partial duplication graph must have 0 <= p, q <= 1." - raise NetworkXError(msg) - if n > N: - raise NetworkXError("partial duplication graph must have n <= N.") - - G = nx.complete_graph(n) - for new_node in range(n, N): - # Pick a random vertex, u, already in the graph. - src_node = seed.randint(0, new_node - 1) - - # Add a new vertex, v, to the graph. - G.add_node(new_node) - - # For each neighbor of u... - for neighbor_node in list(nx.all_neighbors(G, src_node)): - # Add the neighbor to v with probability p. - if seed.random() < p: - G.add_edge(new_node, neighbor_node) - - # Join v and u with probability q. - if seed.random() < q: - G.add_edge(new_node, src_node) - return G - - -@py_random_state(2) -def duplication_divergence_graph(n, p, seed=None): - """Returns an undirected graph using the duplication-divergence model. - - A graph of `n` nodes is created by duplicating the initial nodes - and retaining edges incident to the original nodes with a retention - probability `p`. - - Parameters - ---------- - n : int - The desired number of nodes in the graph. - p : float - The probability for retaining the edge of the replicated node. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : Graph - - Raises - ------ - NetworkXError - If `p` is not a valid probability. - If `n` is less than 2. - - Notes - ----- - This algorithm appears in [1]. - - This implementation disallows the possibility of generating - disconnected graphs. - - References - ---------- - .. [1] I. Ispolatov, P. L. Krapivsky, A. Yuryev, - "Duplication-divergence model of protein interaction network", - Phys. Rev. E, 71, 061911, 2005. - - """ - if p > 1 or p < 0: - msg = "NetworkXError p={0} is not in [0,1].".format(p) - raise nx.NetworkXError(msg) - if n < 2: - msg = 'n must be greater than or equal to 2' - raise nx.NetworkXError(msg) - - G = nx.Graph() - - # Initialize the graph with two connected nodes. - G.add_edge(0, 1) - i = 2 - while i < n: - # Choose a random node from current graph to duplicate. - random_node = seed.choice(list(G)) - # Make the replica. - G.add_node(i) - # flag indicates whether at least one edge is connected on the replica. - flag = False - for nbr in G.neighbors(random_node): - if seed.random() < p: - # Link retention step. - G.add_edge(i, nbr) - flag = True - if not flag: - # Delete replica if no edges retained. - G.remove_node(i) - else: - # Successful duplication. - i += 1 - return G diff --git a/extensions/fablabchemnitz/networkx/generators/ego.py b/extensions/fablabchemnitz/networkx/generators/ego.py deleted file mode 100644 index 2a417ce1..00000000 --- a/extensions/fablabchemnitz/networkx/generators/ego.py +++ /dev/null @@ -1,71 +0,0 @@ -""" -Ego graph. -""" -# Copyright (C) 2010 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -__author__ = """\n""".join(['Drew Conway ', - 'Aric Hagberg ']) -__all__ = ['ego_graph'] - -import networkx as nx - - -def ego_graph(G, n, radius=1, center=True, undirected=False, distance=None): - """Returns induced subgraph of neighbors centered at node n within - a given radius. - - Parameters - ---------- - G : graph - A NetworkX Graph or DiGraph - - n : node - A single node - - radius : number, optional - Include all neighbors of distance<=radius from n. - - center : bool, optional - If False, do not include center node in graph - - undirected : bool, optional - If True use both in- and out-neighbors of directed graphs. - - distance : key, optional - Use specified edge data key as distance. For example, setting - distance='weight' will use the edge weight to measure the - distance from the node n. - - Notes - ----- - For directed graphs D this produces the "out" neighborhood - or successors. If you want the neighborhood of predecessors - first reverse the graph with D.reverse(). If you want both - directions use the keyword argument undirected=True. - - Node, edge, and graph attributes are copied to the returned subgraph. - """ - if undirected: - if distance is not None: - sp, _ = nx.single_source_dijkstra(G.to_undirected(), - n, cutoff=radius, - weight=distance) - else: - sp = dict(nx.single_source_shortest_path_length(G.to_undirected(), - n, cutoff=radius)) - else: - if distance is not None: - sp, _ = nx.single_source_dijkstra(G, - n, cutoff=radius, - weight=distance) - else: - sp = dict(nx.single_source_shortest_path_length(G, n, cutoff=radius)) - - H = G.subgraph(sp).copy() - if not center: - H.remove_node(n) - return H diff --git a/extensions/fablabchemnitz/networkx/generators/expanders.py b/extensions/fablabchemnitz/networkx/generators/expanders.py deleted file mode 100644 index ff9bbc50..00000000 --- a/extensions/fablabchemnitz/networkx/generators/expanders.py +++ /dev/null @@ -1,144 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright 2014 "cheebee7i". -# Copyright 2014 "alexbrc". -# Copyright 2014 Jeffrey Finkelstein . -"""Provides explicit constructions of expander graphs. - -""" -import itertools -import networkx as nx - -__all__ = ['margulis_gabber_galil_graph', 'chordal_cycle_graph'] - - -# Other discrete torus expanders can be constructed by using the following edge -# sets. For more information, see Chapter 4, "Expander Graphs", in -# "Pseudorandomness", by Salil Vadhan. -# -# For a directed expander, add edges from (x, y) to: -# -# (x, y), -# ((x + 1) % n, y), -# (x, (y + 1) % n), -# (x, (x + y) % n), -# (-y % n, x) -# -# For an undirected expander, add the reverse edges. -# -# Also appearing in the paper of Gabber and Galil: -# -# (x, y), -# (x, (x + y) % n), -# (x, (x + y + 1) % n), -# ((x + y) % n, y), -# ((x + y + 1) % n, y) -# -# and: -# -# (x, y), -# ((x + 2*y) % n, y), -# ((x + (2*y + 1)) % n, y), -# ((x + (2*y + 2)) % n, y), -# (x, (y + 2*x) % n), -# (x, (y + (2*x + 1)) % n), -# (x, (y + (2*x + 2)) % n), -# -def margulis_gabber_galil_graph(n, create_using=None): - r"""Returns the Margulis-Gabber-Galil undirected MultiGraph on `n^2` nodes. - - The undirected MultiGraph is regular with degree `8`. Nodes are integer - pairs. The second-largest eigenvalue of the adjacency matrix of the graph - is at most `5 \sqrt{2}`, regardless of `n`. - - Parameters - ---------- - n : int - Determines the number of nodes in the graph: `n^2`. - create_using : NetworkX graph constructor, optional (default MultiGraph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : graph - The constructed undirected multigraph. - - Raises - ------ - NetworkXError - If the graph is directed or not a multigraph. - - """ - G = nx.empty_graph(0, create_using, default=nx.MultiGraph) - if G.is_directed() or not G.is_multigraph(): - msg = "`create_using` must be an undirected multigraph." - raise nx.NetworkXError(msg) - - for (x, y) in itertools.product(range(n), repeat=2): - for (u, v) in (((x + 2 * y) % n, y), ((x + (2 * y + 1)) % n, y), - (x, (y + 2 * x) % n), (x, (y + (2 * x + 1)) % n)): - G.add_edge((x, y), (u, v)) - G.graph['name'] = "margulis_gabber_galil_graph({0})".format(n) - return G - - -def chordal_cycle_graph(p, create_using=None): - """Returns the chordal cycle graph on `p` nodes. - - The returned graph is a cycle graph on `p` nodes with chords joining each - vertex `x` to its inverse modulo `p`. This graph is a (mildly explicit) - 3-regular expander [1]_. - - `p` *must* be a prime number. - - Parameters - ---------- - p : a prime number - - The number of vertices in the graph. This also indicates where the - chordal edges in the cycle will be created. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - G : graph - The constructed undirected multigraph. - - Raises - ------ - NetworkXError - - If `create_using` indicates directed or not a multigraph. - - References - ---------- - - .. [1] Theorem 4.4.2 in A. Lubotzky. "Discrete groups, expanding graphs and - invariant measures", volume 125 of Progress in Mathematics. - Birkhäuser Verlag, Basel, 1994. - - """ - G = nx.empty_graph(0, create_using, default=nx.MultiGraph) - if G.is_directed() or not G.is_multigraph(): - msg = "`create_using` must be an undirected multigraph." - raise nx.NetworkXError(msg) - - for x in range(p): - left = (x - 1) % p - right = (x + 1) % p - # Here we apply Fermat's Little Theorem to compute the multiplicative - # inverse of x in Z/pZ. By Fermat's Little Theorem, - # - # x^p = x (mod p) - # - # Therefore, - # - # x * x^(p - 2) = 1 (mod p) - # - # The number 0 is a special case: we just let its inverse be itself. - chord = pow(x, p - 2, p) if x > 0 else 0 - for y in (left, right, chord): - G.add_edge(x, y) - G.graph['name'] = "chordal_cycle_graph({0})".format(p) - return G diff --git a/extensions/fablabchemnitz/networkx/generators/geometric.py b/extensions/fablabchemnitz/networkx/generators/geometric.py deleted file mode 100644 index b567bfac..00000000 --- a/extensions/fablabchemnitz/networkx/generators/geometric.py +++ /dev/null @@ -1,797 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg (hagberg@lanl.gov) -# Dan Schult (dschult@colgate.edu) -# Ben Edwards (BJEdwards@gmail.com) -# Arya McCarthy (admccarthy@smu.edu) -# Cole MacLean (maclean.cole@gmail.com) - -"""Generators for geometric graphs. -""" - -from bisect import bisect_left -from itertools import combinations -from itertools import product -from math import sqrt -import math -try: - from scipy.spatial import cKDTree as KDTree -except ImportError: - _is_scipy_available = False -else: - _is_scipy_available = True - -import networkx as nx -from networkx.utils import nodes_or_number, py_random_state - -__all__ = ['geographical_threshold_graph', 'waxman_graph', - 'navigable_small_world_graph', 'random_geometric_graph', - 'soft_random_geometric_graph', 'thresholded_random_geometric_graph'] - - -def euclidean(x, y): - """Returns the Euclidean distance between the vectors ``x`` and ``y``. - - Each of ``x`` and ``y`` can be any iterable of numbers. The - iterables must be of the same length. - - """ - return sqrt(sum((a - b) ** 2 for a, b in zip(x, y))) - - -def _fast_edges(G, radius, p): - """Returns edge list of node pairs within `radius` of each other - using scipy KDTree and Minkowski distance metric `p` - - Requires scipy to be installed. - """ - pos = nx.get_node_attributes(G, 'pos') - nodes, coords = list(zip(*pos.items())) - kdtree = KDTree(coords) # Cannot provide generator. - edge_indexes = kdtree.query_pairs(radius, p) - edges = ((nodes[u], nodes[v]) for u, v in edge_indexes) - return edges - - -def _slow_edges(G, radius, p): - """Returns edge list of node pairs within `radius` of each other - using Minkowski distance metric `p` - - Works without scipy, but in `O(n^2)` time. - """ - # TODO This can be parallelized. - edges = [] - for (u, pu), (v, pv) in combinations(G.nodes(data='pos'), 2): - if sum(abs(a - b) ** p for a, b in zip(pu, pv)) <= radius ** p: - edges.append((u, v)) - return edges - - -@py_random_state(5) -@nodes_or_number(0) -def random_geometric_graph(n, radius, dim=2, pos=None, p=2, seed=None): - """Returns a random geometric graph in the unit cube of dimensions `dim`. - - The random geometric graph model places `n` nodes uniformly at - random in the unit cube. Two nodes are joined by an edge if the - distance between the nodes is at most `radius`. - - Edges are determined using a KDTree when SciPy is available. - This reduces the time complexity from $O(n^2)$ to $O(n)$. - - Parameters - ---------- - n : int or iterable - Number of nodes or iterable of nodes - radius: float - Distance threshold value - dim : int, optional - Dimension of graph - pos : dict, optional - A dictionary keyed by node with node positions as values. - p : float, optional - Which Minkowski distance metric to use. `p` has to meet the condition - ``1 <= p <= infinity``. - - If this argument is not specified, the :math:`L^2` metric - (the Euclidean distance metric), p = 2 is used. - This should not be confused with the `p` of an Erdős-Rényi random - graph, which represents probability. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - Graph - A random geometric graph, undirected and without self-loops. - Each node has a node attribute ``'pos'`` that stores the - position of that node in Euclidean space as provided by the - ``pos`` keyword argument or, if ``pos`` was not provided, as - generated by this function. - - Examples - -------- - Create a random geometric graph on twenty nodes where nodes are joined by - an edge if their distance is at most 0.1:: - - >>> G = nx.random_geometric_graph(20, 0.1) - - Notes - ----- - This uses a *k*-d tree to build the graph. - - The `pos` keyword argument can be used to specify node positions so you - can create an arbitrary distribution and domain for positions. - - For example, to use a 2D Gaussian distribution of node positions with mean - (0, 0) and standard deviation 2:: - - >>> import random - >>> n = 20 - >>> pos = {i: (random.gauss(0, 2), random.gauss(0, 2)) for i in range(n)} - >>> G = nx.random_geometric_graph(n, 0.2, pos=pos) - - References - ---------- - .. [1] Penrose, Mathew, *Random Geometric Graphs*, - Oxford Studies in Probability, 5, 2003. - - """ - # TODO Is this function just a special case of the geographical - # threshold graph? - # - # n_name, nodes = n - # half_radius = {v: radius / 2 for v in nodes} - # return geographical_threshold_graph(nodes, theta=1, alpha=1, - # weight=half_radius) - # - n_name, nodes = n - G = nx.Graph() - G.add_nodes_from(nodes) - # If no positions are provided, choose uniformly random vectors in - # Euclidean space of the specified dimension. - if pos is None: - pos = {v: [seed.random() for i in range(dim)] for v in nodes} - nx.set_node_attributes(G, pos, 'pos') - - if _is_scipy_available: - edges = _fast_edges(G, radius, p) - else: - edges = _slow_edges(G, radius, p) - G.add_edges_from(edges) - - return G - - -@py_random_state(6) -@nodes_or_number(0) -def soft_random_geometric_graph(n, radius, dim=2, pos=None, p=2, p_dist=None, - seed=None): - r"""Returns a soft random geometric graph in the unit cube. - - The soft random geometric graph [1] model places `n` nodes uniformly at - random in the unit cube in dimension `dim`. Two nodes of distance, `dist`, - computed by the `p`-Minkowski distance metric are joined by an edge with - probability `p_dist` if the computed distance metric value of the nodes - is at most `radius`, otherwise they are not joined. - - Edges within `radius` of each other are determined using a KDTree when - SciPy is available. This reduces the time complexity from :math:`O(n^2)` - to :math:`O(n)`. - - Parameters - ---------- - n : int or iterable - Number of nodes or iterable of nodes - radius: float - Distance threshold value - dim : int, optional - Dimension of graph - pos : dict, optional - A dictionary keyed by node with node positions as values. - p : float, optional - Which Minkowski distance metric to use. - `p` has to meet the condition ``1 <= p <= infinity``. - - If this argument is not specified, the :math:`L^2` metric - (the Euclidean distance metric), p = 2 is used. - - This should not be confused with the `p` of an Erdős-Rényi random - graph, which represents probability. - p_dist : function, optional - A probability density function computing the probability of - connecting two nodes that are of distance, dist, computed by the - Minkowski distance metric. The probability density function, `p_dist`, - must be any function that takes the metric value as input - and outputs a single probability value between 0-1. The scipy.stats - package has many probability distribution functions implemented and - tools for custom probability distribution definitions [2], and passing - the .pdf method of scipy.stats distributions can be used here. If the - probability function, `p_dist`, is not supplied, the default function - is an exponential distribution with rate parameter :math:`\lambda=1`. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - Graph - A soft random geometric graph, undirected and without self-loops. - Each node has a node attribute ``'pos'`` that stores the - position of that node in Euclidean space as provided by the - ``pos`` keyword argument or, if ``pos`` was not provided, as - generated by this function. - - Examples - -------- - Default Graph: - - G = nx.soft_random_geometric_graph(50, 0.2) - - Custom Graph: - - Create a soft random geometric graph on 100 uniformly distributed nodes - where nodes are joined by an edge with probability computed from an - exponential distribution with rate parameter :math:`\lambda=1` if their - Euclidean distance is at most 0.2. - - Notes - ----- - This uses a *k*-d tree to build the graph. - - The `pos` keyword argument can be used to specify node positions so you - can create an arbitrary distribution and domain for positions. - - For example, to use a 2D Gaussian distribution of node positions with mean - (0, 0) and standard deviation 2 - - The scipy.stats package can be used to define the probability distribution - with the .pdf method used as `p_dist`. - - :: - - >>> import random - >>> import math - >>> n = 100 - >>> pos = {i: (random.gauss(0, 2), random.gauss(0, 2)) for i in range(n)} - >>> p_dist = lambda dist : math.exp(-dist) - >>> G = nx.soft_random_geometric_graph(n, 0.2, pos=pos, p_dist=p_dist) - - References - ---------- - .. [1] Penrose, Mathew D. "Connectivity of soft random geometric graphs." - The Annals of Applied Probability 26.2 (2016): 986-1028. - [2] scipy.stats - - https://docs.scipy.org/doc/scipy/reference/tutorial/stats.html - - """ - n_name, nodes = n - G = nx.Graph() - G.name = 'soft_random_geometric_graph({}, {}, {})'.format(n, radius, dim) - G.add_nodes_from(nodes) - # If no positions are provided, choose uniformly random vectors in - # Euclidean space of the specified dimension. - if pos is None: - pos = {v: [seed.random() for i in range(dim)] for v in nodes} - nx.set_node_attributes(G, pos, 'pos') - - # if p_dist function not supplied the default function is an exponential - # distribution with rate parameter :math:`\lambda=1`. - if p_dist is None: - - def p_dist(dist): - return math.exp(-dist) - - def should_join(pair): - u, v = pair - u_pos, v_pos = pos[u], pos[v] - dist = (sum(abs(a - b) ** p for a, b in zip(u_pos, v_pos)))**(1 / p) - # Check if dist <= radius parameter. This check is redundant if scipy - # is available and _fast_edges routine is used, but provides the - # check in case scipy is not available and all edge combinations - # need to be checked - if dist <= radius: - return seed.random() < p_dist(dist) - else: - return False - - if _is_scipy_available: - edges = _fast_edges(G, radius, p) - G.add_edges_from(filter(should_join, edges)) - else: - G.add_edges_from(filter(should_join, combinations(G, 2))) - - return G - - -@py_random_state(7) -@nodes_or_number(0) -def geographical_threshold_graph(n, theta, dim=2, pos=None, weight=None, - metric=None, p_dist=None, seed=None): - r"""Returns a geographical threshold graph. - - The geographical threshold graph model places $n$ nodes uniformly at - random in a rectangular domain. Each node $u$ is assigned a weight - $w_u$. Two nodes $u$ and $v$ are joined by an edge if - - .. math:: - - (w_u + w_v)h(r) \ge \theta - - where `r` is the distance between `u` and `v`, h(r) is a probability of - connection as a function of `r`, and :math:`\theta` as the threshold - parameter. h(r) corresponds to the p_dist parameter. - - Parameters - ---------- - n : int or iterable - Number of nodes or iterable of nodes - theta: float - Threshold value - dim : int, optional - Dimension of graph - pos : dict - Node positions as a dictionary of tuples keyed by node. - weight : dict - Node weights as a dictionary of numbers keyed by node. - metric : function - A metric on vectors of numbers (represented as lists or - tuples). This must be a function that accepts two lists (or - tuples) as input and yields a number as output. The function - must also satisfy the four requirements of a `metric`_. - Specifically, if $d$ is the function and $x$, $y$, - and $z$ are vectors in the graph, then $d$ must satisfy - - 1. $d(x, y) \ge 0$, - 2. $d(x, y) = 0$ if and only if $x = y$, - 3. $d(x, y) = d(y, x)$, - 4. $d(x, z) \le d(x, y) + d(y, z)$. - - If this argument is not specified, the Euclidean distance metric is - used. - - .. _metric: https://en.wikipedia.org/wiki/Metric_%28mathematics%29 - p_dist : function, optional - A probability density function computing the probability of - connecting two nodes that are of distance, r, computed by metric. - The probability density function, `p_dist`, must - be any function that takes the metric value as input - and outputs a single probability value between 0-1. - The scipy.stats package has many probability distribution functions - implemented and tools for custom probability distribution - definitions [2], and passing the .pdf method of scipy.stats - distributions can be used here. If the probability - function, `p_dist`, is not supplied, the default exponential function - :math: `r^{-2}` is used. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - Graph - A random geographic threshold graph, undirected and without - self-loops. - - Each node has a node attribute ``pos`` that stores the - position of that node in Euclidean space as provided by the - ``pos`` keyword argument or, if ``pos`` was not provided, as - generated by this function. Similarly, each node has a node - attribute ``weight`` that stores the weight of that node as - provided or as generated. - - Examples - -------- - Specify an alternate distance metric using the ``metric`` keyword - argument. For example, to use the `taxicab metric`_ instead of the - default `Euclidean metric`_:: - - >>> dist = lambda x, y: sum(abs(a - b) for a, b in zip(x, y)) - >>> G = nx.geographical_threshold_graph(10, 0.1, metric=dist) - - .. _taxicab metric: https://en.wikipedia.org/wiki/Taxicab_geometry - .. _Euclidean metric: https://en.wikipedia.org/wiki/Euclidean_distance - - Notes - ----- - If weights are not specified they are assigned to nodes by drawing randomly - from the exponential distribution with rate parameter $\lambda=1$. - To specify weights from a different distribution, use the `weight` keyword - argument:: - - >>> import random - >>> n = 20 - >>> w = {i: random.expovariate(5.0) for i in range(n)} - >>> G = nx.geographical_threshold_graph(20, 50, weight=w) - - If node positions are not specified they are randomly assigned from the - uniform distribution. - - References - ---------- - .. [1] Masuda, N., Miwa, H., Konno, N.: - Geographical threshold graphs with small-world and scale-free - properties. - Physical Review E 71, 036108 (2005) - .. [2] Milan Bradonjić, Aric Hagberg and Allon G. Percus, - Giant component and connectivity in geographical threshold graphs, - in Algorithms and Models for the Web-Graph (WAW 2007), - Antony Bonato and Fan Chung (Eds), pp. 209--216, 2007 - """ - n_name, nodes = n - G = nx.Graph() - G.add_nodes_from(nodes) - # If no weights are provided, choose them from an exponential - # distribution. - if weight is None: - weight = {v: seed.expovariate(1) for v in G} - # If no positions are provided, choose uniformly random vectors in - # Euclidean space of the specified dimension. - if pos is None: - pos = {v: [seed.random() for i in range(dim)] for v in nodes} - # If no distance metric is provided, use Euclidean distance. - if metric is None: - metric = euclidean - nx.set_node_attributes(G, weight, 'weight') - nx.set_node_attributes(G, pos, 'pos') - - # if p_dist is not supplied, use default r^-2 - if p_dist is None: - def p_dist(r): - return r**-2 - - # Returns ``True`` if and only if the nodes whose attributes are - # ``du`` and ``dv`` should be joined, according to the threshold - # condition. - def should_join(pair): - u, v = pair - u_pos, v_pos = pos[u], pos[v] - u_weight, v_weight = weight[u], weight[v] - return (u_weight + v_weight) * p_dist(metric(u_pos, v_pos)) >= theta - - G.add_edges_from(filter(should_join, combinations(G, 2))) - return G - - -@py_random_state(6) -@nodes_or_number(0) -def waxman_graph(n, beta=0.4, alpha=0.1, L=None, domain=(0, 0, 1, 1), - metric=None, seed=None): - r"""Returns a Waxman random graph. - - The Waxman random graph model places `n` nodes uniformly at random - in a rectangular domain. Each pair of nodes at distance `d` is - joined by an edge with probability - - .. math:: - p = \beta \exp(-d / \alpha L). - - This function implements both Waxman models, using the `L` keyword - argument. - - * Waxman-1: if `L` is not specified, it is set to be the maximum distance - between any pair of nodes. - * Waxman-2: if `L` is specified, the distance between a pair of nodes is - chosen uniformly at random from the interval `[0, L]`. - - Parameters - ---------- - n : int or iterable - Number of nodes or iterable of nodes - beta: float - Model parameter - alpha: float - Model parameter - L : float, optional - Maximum distance between nodes. If not specified, the actual distance - is calculated. - domain : four-tuple of numbers, optional - Domain size, given as a tuple of the form `(x_min, y_min, x_max, - y_max)`. - metric : function - A metric on vectors of numbers (represented as lists or - tuples). This must be a function that accepts two lists (or - tuples) as input and yields a number as output. The function - must also satisfy the four requirements of a `metric`_. - Specifically, if $d$ is the function and $x$, $y$, - and $z$ are vectors in the graph, then $d$ must satisfy - - 1. $d(x, y) \ge 0$, - 2. $d(x, y) = 0$ if and only if $x = y$, - 3. $d(x, y) = d(y, x)$, - 4. $d(x, z) \le d(x, y) + d(y, z)$. - - If this argument is not specified, the Euclidean distance metric is - used. - - .. _metric: https://en.wikipedia.org/wiki/Metric_%28mathematics%29 - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - Graph - A random Waxman graph, undirected and without self-loops. Each - node has a node attribute ``'pos'`` that stores the position of - that node in Euclidean space as generated by this function. - - Examples - -------- - Specify an alternate distance metric using the ``metric`` keyword - argument. For example, to use the "`taxicab metric`_" instead of the - default `Euclidean metric`_:: - - >>> dist = lambda x, y: sum(abs(a - b) for a, b in zip(x, y)) - >>> G = nx.waxman_graph(10, 0.5, 0.1, metric=dist) - - .. _taxicab metric: https://en.wikipedia.org/wiki/Taxicab_geometry - .. _Euclidean metric: https://en.wikipedia.org/wiki/Euclidean_distance - - Notes - ----- - Starting in NetworkX 2.0 the parameters alpha and beta align with their - usual roles in the probability distribution. In earlier versions their - positions in the expression were reversed. Their position in the calling - sequence reversed as well to minimize backward incompatibility. - - References - ---------- - .. [1] B. M. Waxman, *Routing of multipoint connections*. - IEEE J. Select. Areas Commun. 6(9),(1988) 1617--1622. - """ - n_name, nodes = n - G = nx.Graph() - G.add_nodes_from(nodes) - (xmin, ymin, xmax, ymax) = domain - # Each node gets a uniformly random position in the given rectangle. - pos = {v: (seed.uniform(xmin, xmax), seed.uniform(ymin, ymax)) for v in G} - nx.set_node_attributes(G, pos, 'pos') - # If no distance metric is provided, use Euclidean distance. - if metric is None: - metric = euclidean - # If the maximum distance L is not specified (that is, we are in the - # Waxman-1 model), then find the maximum distance between any pair - # of nodes. - # - # In the Waxman-1 model, join nodes randomly based on distance. In - # the Waxman-2 model, join randomly based on random l. - if L is None: - L = max(metric(x, y) for x, y in combinations(pos.values(), 2)) - - def dist(u, v): return metric(pos[u], pos[v]) - else: - def dist(u, v): return seed.random() * L - - # `pair` is the pair of nodes to decide whether to join. - def should_join(pair): - return seed.random() < beta * math.exp(-dist(*pair) / (alpha * L)) - - G.add_edges_from(filter(should_join, combinations(G, 2))) - return G - - -@py_random_state(5) -def navigable_small_world_graph(n, p=1, q=1, r=2, dim=2, seed=None): - r"""Returns a navigable small-world graph. - - A navigable small-world graph is a directed grid with additional long-range - connections that are chosen randomly. - - [...] we begin with a set of nodes [...] that are identified with the set - of lattice points in an $n \times n$ square, - $\{(i, j): i \in \{1, 2, \ldots, n\}, j \in \{1, 2, \ldots, n\}\}$, - and we define the *lattice distance* between two nodes $(i, j)$ and - $(k, l)$ to be the number of "lattice steps" separating them: - $d((i, j), (k, l)) = |k - i| + |l - j|$. - - For a universal constant $p >= 1$, the node $u$ has a directed edge to - every other node within lattice distance $p$---these are its *local - contacts*. For universal constants $q >= 0$ and $r >= 0$ we also - construct directed edges from $u$ to $q$ other nodes (the *long-range - contacts*) using independent random trials; the $i$th directed edge from - $u$ has endpoint $v$ with probability proportional to $[d(u,v)]^{-r}$. - - -- [1]_ - - Parameters - ---------- - n : int - The length of one side of the lattice; the number of nodes in - the graph is therefore $n^2$. - p : int - The diameter of short range connections. Each node is joined with every - other node within this lattice distance. - q : int - The number of long-range connections for each node. - r : float - Exponent for decaying probability of connections. The probability of - connecting to a node at lattice distance $d$ is $1/d^r$. - dim : int - Dimension of grid - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - References - ---------- - .. [1] J. Kleinberg. The small-world phenomenon: An algorithmic - perspective. Proc. 32nd ACM Symposium on Theory of Computing, 2000. - """ - if (p < 1): - raise nx.NetworkXException("p must be >= 1") - if (q < 0): - raise nx.NetworkXException("q must be >= 0") - if (r < 0): - raise nx.NetworkXException("r must be >= 1") - - G = nx.DiGraph() - nodes = list(product(range(n), repeat=dim)) - for p1 in nodes: - probs = [0] - for p2 in nodes: - if p1 == p2: - continue - d = sum((abs(b - a) for a, b in zip(p1, p2))) - if d <= p: - G.add_edge(p1, p2) - probs.append(d**-r) - cdf = list(nx.utils.accumulate(probs)) - for _ in range(q): - target = nodes[bisect_left(cdf, seed.uniform(0, cdf[-1]))] - G.add_edge(p1, target) - return G - - -@py_random_state(7) -@nodes_or_number(0) -def thresholded_random_geometric_graph(n, radius, theta, dim=2, - pos=None, weight=None, p=2, seed=None): - r"""Returns a thresholded random geometric graph in the unit cube. - - The thresholded random geometric graph [1] model places `n` nodes - uniformly at random in the unit cube of dimensions `dim`. Each node - `u` is assigned a weight :math:`w_u`. Two nodes `u` and `v` are - joined by an edge if they are within the maximum connection distance, - `radius` computed by the `p`-Minkowski distance and the summation of - weights :math:`w_u` + :math:`w_v` is greater than or equal - to the threshold parameter `theta`. - - Edges within `radius` of each other are determined using a KDTree when - SciPy is available. This reduces the time complexity from :math:`O(n^2)` - to :math:`O(n)`. - - Parameters - ---------- - n : int or iterable - Number of nodes or iterable of nodes - radius: float - Distance threshold value - theta: float - Threshold value - dim : int, optional - Dimension of graph - pos : dict, optional - A dictionary keyed by node with node positions as values. - weight : dict, optional - Node weights as a dictionary of numbers keyed by node. - p : float, optional - Which Minkowski distance metric to use. `p` has to meet the condition - ``1 <= p <= infinity``. - - If this argument is not specified, the :math:`L^2` metric - (the Euclidean distance metric), p = 2 is used. - - This should not be confused with the `p` of an Erdős-Rényi random - graph, which represents probability. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - Graph - A thresholded random geographic graph, undirected and without - self-loops. - - Each node has a node attribute ``'pos'`` that stores the - position of that node in Euclidean space as provided by the - ``pos`` keyword argument or, if ``pos`` was not provided, as - generated by this function. Similarly, each node has a nodethre - attribute ``'weight'`` that stores the weight of that node as - provided or as generated. - - Examples - -------- - Default Graph: - - G = nx.thresholded_random_geometric_graph(50, 0.2, 0.1) - - Custom Graph: - - Create a thresholded random geometric graph on 50 uniformly distributed - nodes where nodes are joined by an edge if their sum weights drawn from - a exponential distribution with rate = 5 are >= theta = 0.1 and their - Euclidean distance is at most 0.2. - - Notes - ----- - This uses a *k*-d tree to build the graph. - - The `pos` keyword argument can be used to specify node positions so you - can create an arbitrary distribution and domain for positions. - - For example, to use a 2D Gaussian distribution of node positions with mean - (0, 0) and standard deviation 2 - - If weights are not specified they are assigned to nodes by drawing randomly - from the exponential distribution with rate parameter :math:`\lambda=1`. - To specify weights from a different distribution, use the `weight` keyword - argument:: - - :: - - >>> import random - >>> import math - >>> n = 50 - >>> pos = {i: (random.gauss(0, 2), random.gauss(0, 2)) for i in range(n)} - >>> w = {i: random.expovariate(5.0) for i in range(n)} - >>> G = nx.thresholded_random_geometric_graph(n, 0.2, 0.1, 2, pos, w) - - References - ---------- - .. [1] http://cole-maclean.github.io/blog/files/thesis.pdf - - """ - - n_name, nodes = n - G = nx.Graph() - namestr = 'thresholded_random_geometric_graph({}, {}, {}, {})' - G.name = namestr.format(n, radius, theta, dim) - G.add_nodes_from(nodes) - # If no weights are provided, choose them from an exponential - # distribution. - if weight is None: - weight = {v: seed.expovariate(1) for v in G} - # If no positions are provided, choose uniformly random vectors in - # Euclidean space of the specified dimension. - if pos is None: - pos = {v: [seed.random() for i in range(dim)] for v in nodes} - # If no distance metric is provided, use Euclidean distance. - - nx.set_node_attributes(G, weight, 'weight') - nx.set_node_attributes(G, pos, 'pos') - - # Returns ``True`` if and only if the nodes whose attributes are - # ``du`` and ``dv`` should be joined, according to the threshold - # condition and node pairs are within the maximum connection - # distance, ``radius``. - def should_join(pair): - u, v = pair - u_weight, v_weight = weight[u], weight[v] - u_pos, v_pos = pos[u], pos[v] - dist = (sum(abs(a - b) ** p for a, b in zip(u_pos, v_pos)))**(1 / p) - # Check if dist is <= radius parameter. This check is redundant if - # scipy is available and _fast_edges routine is used, but provides - # the check in case scipy is not available and all edge combinations - # need to be checked - if dist <= radius: - return theta <= u_weight + v_weight - else: - return False - - if _is_scipy_available: - edges = _fast_edges(G, radius, p) - G.add_edges_from(filter(should_join, edges)) - else: - G.add_edges_from(filter(should_join, combinations(G, 2))) - - return G diff --git a/extensions/fablabchemnitz/networkx/generators/harary_graph.py b/extensions/fablabchemnitz/networkx/generators/harary_graph.py deleted file mode 100644 index ec4aa530..00000000 --- a/extensions/fablabchemnitz/networkx/generators/harary_graph.py +++ /dev/null @@ -1,205 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2018-2019 by -# Weisheng Si -# All rights reserved. -# BSD license. -# -# Authors: Weisheng Si (w.si@westernsydney.edu.au) -# -"""Generators for Harary graphs - -This module gives two generators for the Harary graph, which was -introduced by the famous mathematician Frank Harary in his 1962 work [H]_. -The first generator gives the Harary graph that maximizes the node -connectivity with given number of nodes and given number of edges. -The second generator gives the Harary graph that minimizes -the number of edges in the graph with given node connectivity and -number of nodes. - -References ----------- -.. [H] Harary, F. "The Maximum Connectivity of a Graph." - Proc. Nat. Acad. Sci. USA 48, 1142-1146, 1962. - -""" - -import networkx as nx -from networkx.exception import NetworkXError - -__all__ = ['hnm_harary_graph', 'hkn_harary_graph'] - - -def hnm_harary_graph(n, m, create_using=None): - """Returns the Harary graph with given numbers of nodes and edges. - - The Harary graph $H_{n,m}$ is the graph that maximizes node connectivity - with $n$ nodes and $m$ edges. - - This maximum node connectivity is known to be floor($2m/n$). [1]_ - - Parameters - ---------- - n: integer - The number of nodes the generated graph is to contain - - m: integer - The number of edges the generated graph is to contain - - create_using : NetworkX graph constructor, optional Graph type - to create (default=nx.Graph). If graph instance, then cleared - before populated. - - Returns - ------- - NetworkX graph - The Harary graph $H_{n,m}$. - - See Also - -------- - hkn_harary_graph - - Notes - ----- - This algorithm runs in $O(m)$ time. - It is implemented by following the Reference [2]_. - - References - ---------- - .. [1] F. T. Boesch, A. Satyanarayana, and C. L. Suffel, - "A Survey of Some Network Reliability Analysis and Synthesis Results," - Networks, pp. 99-107, 2009. - - .. [2] Harary, F. "The Maximum Connectivity of a Graph." - Proc. Nat. Acad. Sci. USA 48, 1142-1146, 1962. - """ - - if n < 1: - raise NetworkXError("The number of nodes must be >= 1!") - if m < n - 1: - raise NetworkXError("The number of edges must be >= n - 1 !") - if m > n * (n - 1) // 2: - raise NetworkXError("The number of edges must be <= n(n-1)/2") - - # Construct an empty graph with n nodes first - H = nx.empty_graph(n, create_using) - # Get the floor of average node degree - d = 2 * m // n - - # Test the parity of n and d - if (n % 2 == 0) or (d % 2 == 0): - # Start with a regular graph of d degrees - offset = d // 2 - for i in range(n): - for j in range(1, offset + 1): - H.add_edge(i, (i - j) % n) - H.add_edge(i, (i + j) % n) - if d & 1: - # in case d is odd; n must be even in this case - half = n // 2 - for i in range(0, half): - # add edges diagonally - H.add_edge(i, i + half) - # Get the remainder of 2*m modulo n - r = 2 * m % n - if r > 0: - # add remaining edges at offset+1 - for i in range(0, r // 2): - H.add_edge(i, i + offset + 1) - else: - # Start with a regular graph of (d - 1) degrees - offset = (d - 1) // 2 - for i in range(n): - for j in range(1, offset + 1): - H.add_edge(i, (i - j) % n) - H.add_edge(i, (i + j) % n) - half = n // 2 - for i in range(0, m - n * offset): - # add the remaining m - n*offset edges between i and i+half - H.add_edge(i, (i + half) % n) - - return H - - -def hkn_harary_graph(k, n, create_using=None): - """Returns the Harary graph with given node connectivity and node number. - - The Harary graph $H_{k,n}$ is the graph that minimizes the number of - edges needed with given node connectivity $k$ and node number $n$. - - This smallest number of edges is known to be ceil($kn/2$) [1]_. - - Parameters - ---------- - k: integer - The node connectivity of the generated graph - - n: integer - The number of nodes the generated graph is to contain - - create_using : NetworkX graph constructor, optional Graph type - to create (default=nx.Graph). If graph instance, then cleared - before populated. - - Returns - ------- - NetworkX graph - The Harary graph $H_{k,n}$. - - See Also - -------- - hnm_harary_graph - - Notes - ----- - This algorithm runs in $O(kn)$ time. - It is implemented by following the Reference [2]_. - - References - ---------- - .. [1] Weisstein, Eric W. "Harary Graph." From MathWorld--A Wolfram Web - Resource. http://mathworld.wolfram.com/HararyGraph.html. - - .. [2] Harary, F. "The Maximum Connectivity of a Graph." - Proc. Nat. Acad. Sci. USA 48, 1142-1146, 1962. - """ - - if k < 1: - raise NetworkXError("The node connectivity must be >= 1!") - if n < k + 1: - raise NetworkXError("The number of nodes must be >= k+1 !") - - # in case of connectivity 1, simply return the path graph - if k == 1: - H = nx.path_graph(n, create_using) - return H - - # Construct an empty graph with n nodes first - H = nx.empty_graph(n, create_using) - - # Test the parity of k and n - if (k % 2 == 0) or (n % 2 == 0): - # Construct a regular graph with k degrees - offset = k // 2 - for i in range(n): - for j in range(1, offset + 1): - H.add_edge(i, (i - j) % n) - H.add_edge(i, (i + j) % n) - if k & 1: - # odd degree; n must be even in this case - half = n // 2 - for i in range(0, half): - # add edges diagonally - H.add_edge(i, i + half) - else: - # Construct a regular graph with (k - 1) degrees - offset = (k - 1) // 2 - for i in range(n): - for j in range(1, offset + 1): - H.add_edge(i, (i - j) % n) - H.add_edge(i, (i + j) % n) - half = n // 2 - for i in range(0, half + 1): - # add half+1 edges between i and i+half - H.add_edge(i, (i + half) % n) - - return H diff --git a/extensions/fablabchemnitz/networkx/generators/internet_as_graphs.py b/extensions/fablabchemnitz/networkx/generators/internet_as_graphs.py deleted file mode 100644 index d7fe8dec..00000000 --- a/extensions/fablabchemnitz/networkx/generators/internet_as_graphs.py +++ /dev/null @@ -1,446 +0,0 @@ -# Copyright (C) 2019 by -# Luca Baldesi -# BSD license. -# -# Author: Luca Baldesi (baldo.plus@gmail.com) -"""Generates graphs resembling the Internet Autonomous System network""" - -import networkx as nx -from networkx.utils import py_random_state - -__all__ = ['random_internet_as_graph'] - - -def uniform_int_from_avg(a, m, seed): - """ Pick a random integer with uniform probability. - - Returns a random integer uniformly taken from a distribution with - minimum value 'a' and average value 'm', X~U(a,b), E[X]=m, X in N where - b = 2*m - a. - - Notes - ----- - p = (b-floor(b))/2 - X = X1 + X2; X1~U(a,floor(b)), X2~B(p) - E[X] = E[X1] + E[X2] = (floor(b)+a)/2 + (b-floor(b))/2 = (b+a)/2 = m - """ - - from math import floor - assert(m >= a) - b = 2*m - a - p = (b-floor(b))/2 - X1 = int(round(seed.random()*(floor(b)-a) + a)) - if seed.random() < p: - X2 = 1 - else: - X2 = 0 - return X1 + X2 - - -def choose_pref_attach(degs, seed): - """ Pick a random value, with a probability given by its weight. - - Returns a random choice among degs keys, each of which has a - probability proportional to the corresponding dictionary value. - - Parameters - ---------- - degs: dictionary - It contains the possible values (keys) and the corresponding - probabilities (values) - seed: random state - - Returns - ------- - v: object - A key of degs or None if degs is empty - """ - - if len(degs) == 0: - return None - s = sum(degs.values()) - if s == 0: - return seed.choice(list(degs.keys())) - v = seed.random() * s - - nodes = list(degs.keys()) - i = 0 - acc = degs[nodes[i]] - while v > acc: - i += 1 - acc += degs[nodes[i]] - return nodes[i] - - -class AS_graph_generator(object): - """ Generates random internet AS graphs. - """ - - def __init__(self, n, seed): - """ Initializes variables. Immediate numbers are taken from [1]. - - Parameters - ---------- - n: integer - Number of graph nodes - seed: random state - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - GG: AS_graph_generator object - - References - ---------- - [1] A. Elmokashfi, A. Kvalbein and C. Dovrolis, "On the Scalability of - BGP: The Role of Topology Growth," in IEEE Journal on Selected Areas - in Communications, vol. 28, no. 8, pp. 1250-1261, October 2010. - """ - - self.seed = seed - self.n_t = min(n, int(round(self.seed.random()*2+4))) # num of T nodes - self.n_m = int(round(0.15*n)) # number of M nodes - self.n_cp = int(round(0.05*n)) # number of CP nodes - self.n_c = max(0, n-self.n_t-self.n_m-self.n_cp) # number of C nodes - - self.d_m = 2 + (2.5*n)/10000 # average multihoming degree for M nodes - self.d_cp = 2 + (1.5*n)/10000 # avg multihoming degree for CP nodes - self.d_c = 1 + (5*n)/100000 # average multihoming degree for C nodes - - self.p_m_m = 1 + (2*n)/10000 # avg num of peer edges between M and M - self.p_cp_m = 0.2 + (2*n)/10000 # avg num of peer edges between CP, M - self.p_cp_cp = 0.05 + (2*n)/100000 # avg num of peer edges btwn CP, CP - - self.t_m = 0.375 # probability M's provider is T - self.t_cp = 0.375 # probability CP's provider is T - self.t_c = 0.125 # probability C's provider is T - - def t_graph(self): - """ Generates the core mesh network of tier one nodes of a AS graph. - - Returns - ------- - G: Networkx Graph - Core network - """ - - self.G = nx.Graph() - for i in range(self.n_t): - self.G.add_node(i, type="T") - for r in self.regions: - self.regions[r].add(i) - for j in self.G.nodes(): - if i != j: - self.add_edge(i, j, 'peer') - self.customers[i] = set([]) - self.providers[i] = set([]) - return self.G - - def add_edge(self, i, j, kind): - if kind == 'transit': - customer = str(i) - else: - customer = 'none' - self.G.add_edge(i, j, type=kind, customer=customer) - - def choose_peer_pref_attach(self, node_list): - """ Pick a node with a probability weighted by its peer degree. - - Pick a node from node_list with preferential attachment - computed only on their peer degree - """ - - d = {} - for n in node_list: - d[n] = self.G.nodes[n]['peers'] - return choose_pref_attach(d, self.seed) - - def choose_node_pref_attach(self, node_list): - """ Pick a node with a probability weighted by its degree. - - Pick a node from node_list with preferential attachment - computed on their degree - """ - - degs = dict(self.G.degree(node_list)) - return choose_pref_attach(degs, self.seed) - - def add_customer(self, i, j): - """ Keep the dictionaries 'customers' and 'providers' consistent. - """ - - self.customers[j].add(i) - self.providers[i].add(j) - for z in self.providers[j]: - self.customers[z].add(i) - self.providers[i].add(z) - - def add_node(self, i, kind, reg2prob, avg_deg, t_edge_prob): - """ Add a node and its customer transit edges to the graph. - - Parameters - ---------- - i: object - Identifier of the new node - kind: string - Type of the new node. Options are: 'M' for middle node, 'CP' for - content provider and 'C' for customer. - reg2prob: float - Probability the new node can be in two different regions. - avg_deg: float - Average number of transit nodes of which node i is customer. - t_edge_prob: float - Probability node i establish a customer transit edge with a tier - one (T) node - - Returns - ------- - i: object - Identifier of the new node - """ - - regs = 1 # regions in which node resides - if self.seed.random() < reg2prob: # node is in two regions - regs = 2 - node_options = set() - - self.G.add_node(i, type=kind, peers=0) - self.customers[i] = set() - self.providers[i] = set() - self.nodes[kind].add(i) - for r in self.seed.sample(list(self.regions), regs): - node_options = node_options.union(self.regions[r]) - self.regions[r].add(i) - - edge_num = uniform_int_from_avg(1, avg_deg, self.seed) - - t_options = node_options.intersection(self.nodes['T']) - m_options = node_options.intersection(self.nodes['M']) - if i in m_options: - m_options.remove(i) - d = 0 - while d < edge_num and (len(t_options) > 0 or len(m_options) > 0): - if len(m_options) == 0 or (len(t_options) > 0 and - self.seed.random() < t_edge_prob): # add edge to a T node - j = self.choose_node_pref_attach(t_options) - t_options.remove(j) - else: - j = self.choose_node_pref_attach(m_options) - m_options.remove(j) - self.add_edge(i, j, 'transit') - self.add_customer(i, j) - d += 1 - - return i - - def add_m_peering_link(self, m, to_kind): - """ Add a peering link between two middle tier (M) nodes. - - Target node j is drawn considering a preferential attachment based on - other M node peering degree. - - Parameters - ---------- - m: object - Node identifier - to_kind: string - type for target node j (must be always M) - - Returns - ------- - success: boolean - """ - - # candidates are of type 'M' and are not customers of m - node_options = self.nodes['M'].difference(self.customers[m]) - # candidates are not providers of m - node_options = node_options.difference(self.providers[m]) - # remove self - if m in node_options: - node_options.remove(m) - - # remove candidates we are already connected to - for j in self.G.neighbors(m): - if j in node_options: - node_options.remove(j) - - if len(node_options) > 0: - j = self.choose_peer_pref_attach(node_options) - self.add_edge(m, j, 'peer') - self.G.nodes[m]['peers'] += 1 - self.G.nodes[j]['peers'] += 1 - return True - else: - return False - - def add_cp_peering_link(self, cp, to_kind): - """ Add a peering link to a content provider (CP) node. - - Target node j can be CP or M and it is drawn uniformely among the nodes - belonging to the same region as cp. - - Parameters - ---------- - cp: object - Node identifier - to_kind: string - type for target node j (must be M or CP) - - Returns - ------- - success: boolean - """ - - node_options = set() - for r in self.regions: # options include nodes in the same region(s) - if cp in self.regions[r]: - node_options = node_options.union(self.regions[r]) - - # options are restricted to the indicated kind ('M' or 'CP') - node_options = self.nodes[to_kind].intersection(node_options) - - # remove self - if cp in node_options: - node_options.remove(cp) - - # remove nodes that are cp's providers - node_options = node_options.difference(self.providers[cp]) - - # remove nodes we are already connected to - for j in self.G.neighbors(cp): - if j in node_options: - node_options.remove(j) - - if len(node_options) > 0: - j = self.seed.sample(node_options, 1)[0] - self.add_edge(cp, j, 'peer') - self.G.nodes[cp]['peers'] += 1 - self.G.nodes[j]['peers'] += 1 - return True - else: - return False - - def graph_regions(self, rn): - """ Initializes AS network regions. - - Parameters - ---------- - rn: integer - Number of regions - """ - - self.regions = {} - for i in range(rn): - self.regions["REG"+str(i)] = set() - - def add_peering_links(self, from_kind, to_kind): - """ Utility function to add peering links among node groups. - """ - peer_link_method = None - if from_kind == 'M': - peer_link_method = self.add_m_peering_link - m = self.p_m_m - if from_kind == 'CP': - peer_link_method = self.add_cp_peering_link - if to_kind == 'M': - m = self.p_cp_m - else: - m = self.p_cp_cp - - for i in self.nodes[from_kind]: - num = uniform_int_from_avg(0, m, self.seed) - for _ in range(num): - peer_link_method(i, to_kind) - - def generate(self): - """ Generates a random AS network graph as described in [1]. - - Returns - ------- - G: Graph object - - Notes - ----- - The process steps are the following: first we create the core network - of tier one nodes, then we add the middle tier (M), the content - provider (CP) and the customer (C) nodes along with their transit edges - (link i,j means i is customer of j). Finally we add peering links - between M nodes, between M and CP nodes and between CP node couples. - For a detailed description of the algorithm, please refer to [1]. - - References - ---------- - [1] A. Elmokashfi, A. Kvalbein and C. Dovrolis, "On the Scalability of - BGP: The Role of Topology Growth," in IEEE Journal on Selected Areas - in Communications, vol. 28, no. 8, pp. 1250-1261, October 2010. - """ - - self.graph_regions(5) - self.customers = {} - self.providers = {} - self.nodes = {'T': set([]), 'M': set([]), 'CP': set([]), 'C': set([])} - - self.t_graph() - self.nodes['T'] = set(list(self.G.nodes())) - - i = len(self.nodes['T']) - for _ in range(self.n_m): - self.nodes['M'].add(self.add_node(i, 'M', 0.2, self.d_m, self.t_m)) - i += 1 - for _ in range(self.n_cp): - self.nodes['CP'].add(self.add_node(i, 'CP', 0.05, self.d_cp, - self.t_cp)) - i += 1 - for _ in range(self.n_c): - self.nodes['C'].add(self.add_node(i, 'C', 0, self.d_c, self.t_c)) - i += 1 - - self.add_peering_links('M', 'M') - self.add_peering_links('CP', 'M') - self.add_peering_links('CP', 'CP') - - return self.G - - -@py_random_state(1) -def random_internet_as_graph(n, seed=None): - """ Generates a random undirected graph resembling the Internet AS network - - Parameters - ---------- - n: integer in [1000, 10000] - Number of graph nodes - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G: Networkx Graph object - A randomly generated undirected graph - - Notes - ----- - This algorithm returns an undirected graph resembling the Internet - Autonomous System (AS) network, it uses the approach by Elmokashfi et al. - [1] and it grants the properties described in the related paper [1]. - - Each node models an autonomous system, with an attribute 'type' specifying - its kind; tier-1 (T), mid-level (M), customer (C) or content-provider (CP). - Each edge models an ADV communication link (hence, bidirectional) with - attributes: - - type: transit|peer, the kind of commercial agreement between nodes; - - customer: , the identifier of the node acting as customer - ('none' if type is peer). - - References - ---------- - [1] A. Elmokashfi, A. Kvalbein and C. Dovrolis, "On the Scalability of - BGP: The Role of Topology Growth," in IEEE Journal on Selected Areas - in Communications, vol. 28, no. 8, pp. 1250-1261, October 2010. - """ - - GG = AS_graph_generator(n, seed) - G = GG.generate() - return G diff --git a/extensions/fablabchemnitz/networkx/generators/intersection.py b/extensions/fablabchemnitz/networkx/generators/intersection.py deleted file mode 100644 index 18080cb6..00000000 --- a/extensions/fablabchemnitz/networkx/generators/intersection.py +++ /dev/null @@ -1,129 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Generators for random intersection graphs. -""" -# Copyright (C) 2011 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -import random -import networkx as nx -from networkx.algorithms import bipartite -from networkx.utils import py_random_state - -__author__ = "\n".join(['Aric Hagberg (hagberg@lanl.gov)']) - -__all__ = ['uniform_random_intersection_graph', - 'k_random_intersection_graph', - 'general_random_intersection_graph', - ] - - -@py_random_state(3) -def uniform_random_intersection_graph(n, m, p, seed=None): - """Returns a uniform random intersection graph. - - Parameters - ---------- - n : int - The number of nodes in the first bipartite set (nodes) - m : int - The number of nodes in the second bipartite set (attributes) - p : float - Probability of connecting nodes between bipartite sets - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - See Also - -------- - gnp_random_graph - - References - ---------- - .. [1] K.B. Singer-Cohen, Random Intersection Graphs, 1995, - PhD thesis, Johns Hopkins University - .. [2] Fill, J. A., Scheinerman, E. R., and Singer-Cohen, K. B., - Random intersection graphs when m = !(n): - An equivalence theorem relating the evolution of the g(n, m, p) - and g(n, p) models. Random Struct. Algorithms 16, 2 (2000), 156–176. - """ - G = bipartite.random_graph(n, m, p, seed) - return nx.projected_graph(G, range(n)) - - -@py_random_state(3) -def k_random_intersection_graph(n, m, k, seed=None): - """Returns a intersection graph with randomly chosen attribute sets for - each node that are of equal size (k). - - Parameters - ---------- - n : int - The number of nodes in the first bipartite set (nodes) - m : int - The number of nodes in the second bipartite set (attributes) - k : float - Size of attribute set to assign to each node. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - See Also - -------- - gnp_random_graph, uniform_random_intersection_graph - - References - ---------- - .. [1] Godehardt, E., and Jaworski, J. - Two models of random intersection graphs and their applications. - Electronic Notes in Discrete Mathematics 10 (2001), 129--132. - """ - G = nx.empty_graph(n + m) - mset = range(n, n + m) - for v in range(n): - targets = seed.sample(mset, k) - G.add_edges_from(zip([v] * len(targets), targets)) - return nx.projected_graph(G, range(n)) - - -@py_random_state(3) -def general_random_intersection_graph(n, m, p, seed=None): - """Returns a random intersection graph with independent probabilities - for connections between node and attribute sets. - - Parameters - ---------- - n : int - The number of nodes in the first bipartite set (nodes) - m : int - The number of nodes in the second bipartite set (attributes) - p : list of floats of length m - Probabilities for connecting nodes to each attribute - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - See Also - -------- - gnp_random_graph, uniform_random_intersection_graph - - References - ---------- - .. [1] Nikoletseas, S. E., Raptopoulos, C., and Spirakis, P. G. - The existence and efficient construction of large independent sets - in general random intersection graphs. In ICALP (2004), J. D´ıaz, - J. Karhum¨aki, A. Lepist¨o, and D. Sannella, Eds., vol. 3142 - of Lecture Notes in Computer Science, Springer, pp. 1029–1040. - """ - if len(p) != m: - raise ValueError("Probability list p must have m elements.") - G = nx.empty_graph(n + m) - mset = range(n, n + m) - for u in range(n): - for v, q in zip(mset, p): - if seed.random() < q: - G.add_edge(u, v) - return nx.projected_graph(G, range(n)) diff --git a/extensions/fablabchemnitz/networkx/generators/joint_degree_seq.py b/extensions/fablabchemnitz/networkx/generators/joint_degree_seq.py deleted file mode 100644 index e7c47688..00000000 --- a/extensions/fablabchemnitz/networkx/generators/joint_degree_seq.py +++ /dev/null @@ -1,667 +0,0 @@ -# Copyright (C) 2016-2019 by -# Minas Gjoka -# Balint Tillman -# BSD license. -# -# Authors: Minas Gjoka (minas.gjoka@gmail.com) -# Balint Tillman (tillman.balint@gmail.com) -"""Generate graphs with a given joint degree and directed joint degree""" - -import networkx as nx -from networkx.utils import py_random_state - -__all__ = ['is_valid_joint_degree', - 'is_valid_directed_joint_degree', - 'joint_degree_graph', - 'directed_joint_degree_graph'] - - -def is_valid_joint_degree(joint_degrees): - """ Checks whether the given joint degree dictionary is realizable. - - A *joint degree dictionary* is a dictionary of dictionaries, in - which entry ``joint_degrees[k][l]`` is an integer representing the - number of edges joining nodes of degree *k* with nodes of degree - *l*. Such a dictionary is realizable as a simple graph if and only - if the following conditions are satisfied. - - - each entry must be an integer, - - the total number of nodes of degree *k*, computed by - ``sum(joint_degrees[k].values()) / k``, must be an integer, - - the total number of edges joining nodes of degree *k* with - nodes of degree *l* cannot exceed the total number of possible edges, - - each diagonal entry ``joint_degrees[k][k]`` must be even (this is - a convention assumed by the :func:`joint_degree_graph` function). - - - Parameters - ---------- - joint_degrees : dictionary of dictionary of integers - A joint degree dictionary in which entry ``joint_degrees[k][l]`` - is the number of edges joining nodes of degree *k* with nodes of - degree *l*. - - Returns - ------- - bool - Whether the given joint degree dictionary is realizable as a - simple graph. - - References - ---------- - .. [1] M. Gjoka, M. Kurant, A. Markopoulou, "2.5K Graphs: from Sampling - to Generation", IEEE Infocom, 2013. - .. [2] I. Stanton, A. Pinar, "Constructing and sampling graphs with a - prescribed joint degree distribution", Journal of Experimental - Algorithmics, 2012. - """ - - degree_count = {} - for k in joint_degrees: - if k > 0: - k_size = sum(joint_degrees[k].values()) / k - if not k_size.is_integer(): - return False - degree_count[k] = k_size - - for k in joint_degrees: - for l in joint_degrees[k]: - if not float(joint_degrees[k][l]).is_integer(): - return False - - if (k != l) and (joint_degrees[k][l] > - degree_count[k] * degree_count[l]): - return False - elif k == l: - if (joint_degrees[k][k] > degree_count[k] * - (degree_count[k] - 1)): - return False - if joint_degrees[k][k] % 2 != 0: - return False - - # if all above conditions have been satisfied then the input - # joint degree is realizable as a simple graph. - return True - - -def _neighbor_switch(G, w, unsat, h_node_residual, avoid_node_id=None): - """ Releases one free stub for ``w``, while preserving joint degree in G. - - Parameters - ---------- - G : NetworkX graph - Graph in which the neighbor switch will take place. - w : integer - Node id for which we will execute this neighbor switch. - unsat : set of integers - Set of unsaturated node ids that have the same degree as w. - h_node_residual: dictionary of integers - Keeps track of the remaining stubs for a given node. - avoid_node_id: integer - Node id to avoid when selecting w_prime. - - Notes - ----- - First, it selects *w_prime*, an unsaturated node that has the same degree - as ``w``. Second, it selects *switch_node*, a neighbor node of ``w`` that - is not connected to *w_prime*. Then it executes an edge swap i.e. removes - (``w``,*switch_node*) and adds (*w_prime*,*switch_node*). Gjoka et. al. [1] - prove that such an edge swap is always possible. - - References - ---------- - .. [1] M. Gjoka, B. Tillman, A. Markopoulou, "Construction of Simple - Graphs with a Target Joint Degree Matrix and Beyond", IEEE Infocom, '15 - """ - - if (avoid_node_id is None) or (h_node_residual[avoid_node_id] > 1): - # select unsatured node w_prime that has the same degree as w - w_prime = next(iter(unsat)) - else: - # assume that the node pair (v,w) has been selected for connection. if - # - neighbor_switch is called for node w, - # - nodes v and w have the same degree, - # - node v=avoid_node_id has only one stub left, - # then prevent v=avoid_node_id from being selected as w_prime. - - iter_var = iter(unsat) - while True: - w_prime = next(iter_var) - if w_prime != avoid_node_id: - break - - # select switch_node, a neighbor of w, that is not connected to w_prime - w_prime_neighbs = G[w_prime] # slightly faster declaring this variable - for v in G[w]: - if (v not in w_prime_neighbs) and (v != w_prime): - switch_node = v - break - - # remove edge (w,switch_node), add edge (w_prime,switch_node) and update - # data structures - G.remove_edge(w, switch_node) - G.add_edge(w_prime, switch_node) - h_node_residual[w] += 1 - h_node_residual[w_prime] -= 1 - if h_node_residual[w_prime] == 0: - unsat.remove(w_prime) - - -@py_random_state(1) -def joint_degree_graph(joint_degrees, seed=None): - """ Generates a random simple graph with the given joint degree dictionary. - - Parameters - ---------- - joint_degrees : dictionary of dictionary of integers - A joint degree dictionary in which entry ``joint_degrees[k][l]`` is the - number of edges joining nodes of degree *k* with nodes of degree *l*. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : Graph - A graph with the specified joint degree dictionary. - - Raises - ------ - NetworkXError - If *joint_degrees* dictionary is not realizable. - - Notes - ----- - In each iteration of the "while loop" the algorithm picks two disconnected - nodes *v* and *w*, of degree *k* and *l* correspondingly, for which - ``joint_degrees[k][l]`` has not reached its target yet. It then adds - edge (*v*, *w*) and increases the number of edges in graph G by one. - - The intelligence of the algorithm lies in the fact that it is always - possible to add an edge between such disconnected nodes *v* and *w*, - even if one or both nodes do not have free stubs. That is made possible by - executing a "neighbor switch", an edge rewiring move that releases - a free stub while keeping the joint degree of G the same. - - The algorithm continues for E (number of edges) iterations of - the "while loop", at the which point all entries of the given - ``joint_degrees[k][l]`` have reached their target values and the - construction is complete. - - References - ---------- - .. [1] M. Gjoka, B. Tillman, A. Markopoulou, "Construction of Simple - Graphs with a Target Joint Degree Matrix and Beyond", IEEE Infocom, '15 - - Examples - -------- - >>> import networkx as nx - >>> joint_degrees = {1: {4: 1}, - ... 2: {2: 2, 3: 2, 4: 2}, - ... 3: {2: 2, 4: 1}, - ... 4: {1: 1, 2: 2, 3: 1}} - >>> G=nx.joint_degree_graph(joint_degrees) - >>> - """ - - if not is_valid_joint_degree(joint_degrees): - msg = 'Input joint degree dict not realizable as a simple graph' - raise nx.NetworkXError(msg) - - # compute degree count from joint_degrees - degree_count = {k: sum(l.values()) // k for k, l in joint_degrees.items() - if k > 0} - - # start with empty N-node graph - N = sum(degree_count.values()) - G = nx.empty_graph(N) - - # for a given degree group, keep the list of all node ids - h_degree_nodelist = {} - - # for a given node, keep track of the remaining stubs - h_node_residual = {} - - # populate h_degree_nodelist and h_node_residual - nodeid = 0 - for degree, num_nodes in degree_count.items(): - h_degree_nodelist[degree] = range(nodeid, nodeid + num_nodes) - for v in h_degree_nodelist[degree]: - h_node_residual[v] = degree - nodeid += int(num_nodes) - - # iterate over every degree pair (k,l) and add the number of edges given - # for each pair - for k in joint_degrees: - for l in joint_degrees[k]: - - # n_edges_add is the number of edges to add for the - # degree pair (k,l) - n_edges_add = joint_degrees[k][l] - - if (n_edges_add > 0) and (k >= l): - - # number of nodes with degree k and l - k_size = degree_count[k] - l_size = degree_count[l] - - # k_nodes and l_nodes consist of all nodes of degree k and l - k_nodes = h_degree_nodelist[k] - l_nodes = h_degree_nodelist[l] - - # k_unsat and l_unsat consist of nodes of degree k and l that - # are unsaturated (nodes that have at least 1 available stub) - k_unsat = set(v for v in k_nodes if h_node_residual[v] > 0) - - if k != l: - l_unsat = set(w for w in l_nodes if h_node_residual[w] > 0) - else: - l_unsat = k_unsat - n_edges_add = joint_degrees[k][l] // 2 - - while n_edges_add > 0: - - # randomly pick nodes v and w that have degrees k and l - v = k_nodes[seed.randrange(k_size)] - w = l_nodes[seed.randrange(l_size)] - - # if nodes v and w are disconnected then attempt to connect - if not G.has_edge(v, w) and (v != w): - - # if node v has no free stubs then do neighbor switch - if h_node_residual[v] == 0: - _neighbor_switch(G, v, k_unsat, h_node_residual) - - # if node w has no free stubs then do neighbor switch - if h_node_residual[w] == 0: - if k != l: - _neighbor_switch(G, w, l_unsat, - h_node_residual) - else: - _neighbor_switch(G, w, l_unsat, - h_node_residual, - avoid_node_id=v) - - # add edge (v, w) and update data structures - G.add_edge(v, w) - h_node_residual[v] -= 1 - h_node_residual[w] -= 1 - n_edges_add -= 1 - - if h_node_residual[v] == 0: - k_unsat.discard(v) - if h_node_residual[w] == 0: - l_unsat.discard(w) - return G - - -def is_valid_directed_joint_degree(in_degrees, out_degrees, nkk): - """ Checks whether the given directed joint degree input is realizable - - Parameters - ---------- - in_degrees : list of integers - in degree sequence contains the in degrees of nodes. - out_degrees : list of integers - out degree sequence contains the out degrees of nodes. - nkk : dictionary of dictionary of integers - directed joint degree dictionary. for nodes of out degree k (first - level of dict) and nodes of in degree l (seconnd level of dict) - describes the number of edges. - - Returns - ------- - boolean - returns true if given input is realizable, else returns false. - - Notes - ----- - Here is the list of conditions that the inputs (in/out degree sequences, - nkk) need to satisfy for simple directed graph realizability: - - - Condition 0: in_degrees and out_degrees have the same length - - Condition 1: nkk[k][l] is integer for all k,l - - Condition 2: sum(nkk[k])/k = number of nodes with partition id k, is an - integer and matching degree sequence - - Condition 3: number of edges and non-chords between k and l cannot exceed - maximum possible number of edges - - - References - ---------- - [1] B. Tillman, A. Markopoulou, C. T. Butts & M. Gjoka, - "Construction of Directed 2K Graphs". In Proc. of KDD 2017. - """ - V = {} # number of nodes with in/out degree. - forbidden = {} - if len(in_degrees) != len(out_degrees): - return False - - for idx in range(0, len(in_degrees)): - i = in_degrees[idx] - o = out_degrees[idx] - V[(i, 0)] = V.get((i, 0), 0) + 1 - V[(o, 1)] = V.get((o, 1), 0) + 1 - - forbidden[(o, i)] = forbidden.get((o, i), 0) + 1 - - S = {} # number of edges going from in/out degree nodes. - for k in nkk: - for l in nkk[k]: - val = nkk[k][l] - if not float(val).is_integer(): # condition 1 - return False - - if val > 0: - S[(k, 1)] = S.get((k, 1), 0) + val - S[(l, 0)] = S.get((l, 0), 0) + val - # condition 3 - if val + forbidden.get((k, l), 0) > V[(k, 1)] * V[(l, 0)]: - return False - - for s in S: - if not float(S[s]) / s[0] == V[s]: # condition 2 - return False - - # if all conditions abive have been satisfied then the input nkk is - # realizable as a simple graph. - return True - - -def _directed_neighbor_switch(G, w, unsat, h_node_residual_out, chords, - h_partition_in, partition): - """ Releases one free stub for node w, while preserving joint degree in G. - - Parameters - ---------- - G : networkx directed graph - graph within which the edge swap will take place. - w : integer - node id for which we need to perform a neighbor switch. - unsat: set of integers - set of node ids that have the same degree as w and are unsaturated. - h_node_residual_out: dict of integers - for a given node, keeps track of the remaining stubs to be added. - chords: set of tuples - keeps track of available positions to add edges. - h_partition_in: dict of integers - for a given node, keeps track of its partition id (in degree). - partition: integer - partition id to check if chords have to be updated. - - Notes - ----- - First, it selects node w_prime that (1) has the same degree as w and - (2) is unsaturated. Then, it selects node v, a neighbor of w, that is - not connected to w_prime and does an edge swap i.e. removes (w,v) and - adds (w_prime,v). If neighbor switch is not possible for w using - w_prime and v, then return w_prime; in [1] it's proven that - such unsaturated nodes can be used. - - References - ---------- - [1] B. Tillman, A. Markopoulou, C. T. Butts & M. Gjoka, - "Construction of Directed 2K Graphs". In Proc. of KDD 2017. - """ - w_prime = unsat.pop() - unsat.add(w_prime) - # select node t, a neighbor of w, that is not connected to w_prime - w_neighbs = list(G.successors(w)) - # slightly faster declaring this variable - w_prime_neighbs = list(G.successors(w_prime)) - - for v in w_neighbs: - if (v not in w_prime_neighbs) and w_prime != v: - # removes (w,v), add (w_prime,v) and update data structures - G.remove_edge(w, v) - G.add_edge(w_prime, v) - - if h_partition_in[v] == partition: - chords.add((w, v)) - chords.discard((w_prime, v)) - - h_node_residual_out[w] += 1 - h_node_residual_out[w_prime] -= 1 - if h_node_residual_out[w_prime] == 0: - unsat.remove(w_prime) - return None - - # If neighbor switch didn't work, use unsaturated node - return w_prime - - -def _directed_neighbor_switch_rev(G, w, unsat, h_node_residual_in, chords, - h_partition_out, partition): - """ The reverse of directed_neighbor_switch. - - Parameters - ---------- - G : networkx directed graph - graph within which the edge swap will take place. - w : integer - node id for which we need to perform a neighbor switch. - unsat: set of integers - set of node ids that have the same degree as w and are unsaturated. - h_node_residual_in: dict of integers - for a given node, keeps track of the remaining stubs to be added. - chords: set of tuples - keeps track of available positions to add edges. - h_partition_out: dict of integers - for a given node, keeps track of its partition id (out degree). - partition: integer - partition id to check if chords have to be updated. - - Notes - ----- - Same operation as directed_neighbor_switch except it handles this operation - for incoming edges instead of outgoing. - """ - w_prime = unsat.pop() - unsat.add(w_prime) - # slightly faster declaring these as variables. - w_neighbs = list(G.predecessors(w)) - w_prime_neighbs = list(G.predecessors(w_prime)) - # select node v, a neighbor of w, that is not connected to w_prime. - for v in w_neighbs: - if (v not in w_prime_neighbs) and w_prime != v: - # removes (v,w), add (v,w_prime) and update data structures. - G.remove_edge(v, w) - G.add_edge(v, w_prime) - if h_partition_out[v] == partition: - chords.add((v, w)) - chords.discard((v, w_prime)) - - h_node_residual_in[w] += 1 - h_node_residual_in[w_prime] -= 1 - if h_node_residual_in[w_prime] == 0: - unsat.remove(w_prime) - return None - - # If neighbor switch didn't work, use the unsaturated node. - return w_prime - - -@py_random_state(3) -def directed_joint_degree_graph(in_degrees, out_degrees, nkk, seed=None): - """ Generates a random simple directed graph with the joint degree. - - Parameters - ---------- - degree_seq : list of tuples (of size 3) - degree sequence contains tuples of nodes with node id, in degree and - out degree. - nkk : dictionary of dictionary of integers - directed joint degree dictionary, for nodes of out degree k (first - level of dict) and nodes of in degree l (second level of dict) - describes the number of edges. - seed : hashable object, optional - Seed for random number generator. - - Returns - ------- - G : Graph - A directed graph with the specified inputs. - - Raises - ------ - NetworkXError - If degree_seq and nkk are not realizable as a simple directed graph. - - - Notes - ----- - Similarly to the undirected version: - In each iteration of the "while loop" the algorithm picks two disconnected - nodes v and w, of degree k and l correspondingly, for which nkk[k][l] has - not reached its target yet i.e. (for given k,l): n_edges_add < nkk[k][l]. - It then adds edge (v,w) and always increases the number of edges in graph G - by one. - - The intelligence of the algorithm lies in the fact that it is always - possible to add an edge between disconnected nodes v and w, for which - nkk[degree(v)][degree(w)] has not reached its target, even if one or both - nodes do not have free stubs. If either node v or w does not have a free - stub, we perform a "neighbor switch", an edge rewiring move that releases a - free stub while keeping nkk the same. - - The difference for the directed version lies in the fact that neighbor - switches might not be able to rewire, but in these cases unsaturated nodes - can be reassigned to use instead, see [1] for detailed description and - proofs. - - The algorithm continues for E (number of edges in the graph) iterations of - the "while loop", at which point all entries of the given nkk[k][l] have - reached their target values and the construction is complete. - - References - ---------- - [1] B. Tillman, A. Markopoulou, C. T. Butts & M. Gjoka, - "Construction of Directed 2K Graphs". In Proc. of KDD 2017. - - Examples - -------- - >>> import networkx as nx - >>> in_degrees = [0, 1, 1, 2] - >>> out_degrees = [1, 1, 1, 1] - >>> nkk = {1:{1:2,2:2}} - >>> G=nx.directed_joint_degree_graph(in_degrees, out_degrees, nkk) - >>> - """ - if not is_valid_directed_joint_degree(in_degrees, out_degrees, nkk): - msg = 'Input is not realizable as a simple graph' - raise nx.NetworkXError(msg) - - # start with an empty directed graph. - G = nx.DiGraph() - - # for a given group, keep the list of all node ids. - h_degree_nodelist_in = {} - h_degree_nodelist_out = {} - # for a given group, keep the list of all unsaturated node ids. - h_degree_nodelist_in_unsat = {} - h_degree_nodelist_out_unsat = {} - # for a given node, keep track of the remaining stubs to be added. - h_node_residual_out = {} - h_node_residual_in = {} - # for a given node, keep track of the partition id. - h_partition_out = {} - h_partition_in = {} - # keep track of non-chords between pairs of partition ids. - non_chords = {} - - # populate data structures - for idx, i in enumerate(in_degrees): - idx = int(idx) - if i > 0: - h_degree_nodelist_in.setdefault(i, []) - h_degree_nodelist_in_unsat.setdefault(i, set()) - h_degree_nodelist_in[i].append(idx) - h_degree_nodelist_in_unsat[i].add(idx) - h_node_residual_in[idx] = i - h_partition_in[idx] = i - - for idx, o in enumerate(out_degrees): - o = out_degrees[idx] - non_chords[(o, in_degrees[idx])] = non_chords.get((o, in_degrees[idx]), - 0) + 1 - idx = int(idx) - if o > 0: - h_degree_nodelist_out.setdefault(o, []) - h_degree_nodelist_out_unsat.setdefault(o, set()) - h_degree_nodelist_out[o].append(idx) - h_degree_nodelist_out_unsat[o].add(idx) - h_node_residual_out[idx] = o - h_partition_out[idx] = o - - G.add_node(idx) - - nk_in = {} - nk_out = {} - for p in h_degree_nodelist_in: - nk_in[p] = len(h_degree_nodelist_in[p]) - for p in h_degree_nodelist_out: - nk_out[p] = len(h_degree_nodelist_out[p]) - - # iterate over every degree pair (k,l) and add the number of edges given - # for each pair. - for k in nkk: - for l in nkk[k]: - n_edges_add = nkk[k][l] - - if (n_edges_add > 0): - # chords contains a random set of potential edges. - chords = set() - - k_len = nk_out[k] - l_len = nk_in[l] - chords_sample = seed.sample(range(k_len * l_len), n_edges_add - + non_chords.get((k, l), 0)) - - num = 0 - while len(chords) < n_edges_add: - i = h_degree_nodelist_out[k][chords_sample[num] % k_len] - j = h_degree_nodelist_in[l][chords_sample[num] // k_len] - num += 1 - if i != j: - chords.add((i, j)) - - # k_unsat and l_unsat consist of nodes of in/out degree k and l - # that are unsaturated i.e. those nodes that have at least one - # available stub - k_unsat = h_degree_nodelist_out_unsat[k] - l_unsat = h_degree_nodelist_in_unsat[l] - - while n_edges_add > 0: - v, w = chords.pop() - chords.add((v, w)) - - # if node v has no free stubs then do neighbor switch. - if h_node_residual_out[v] == 0: - _v = _directed_neighbor_switch(G, v, k_unsat, - h_node_residual_out, - chords, h_partition_in, - l) - if _v is not None: - v = _v - - # if node w has no free stubs then do neighbor switch. - if h_node_residual_in[w] == 0: - _w = _directed_neighbor_switch_rev(G, w, l_unsat, - h_node_residual_in, - chords, - h_partition_out, k) - if _w is not None: - w = _w - - # add edge (v,w) and update data structures. - G.add_edge(v, w) - h_node_residual_out[v] -= 1 - h_node_residual_in[w] -= 1 - n_edges_add -= 1 - chords.discard((v, w)) - - if h_node_residual_out[v] == 0: - k_unsat.discard(v) - if h_node_residual_in[w] == 0: - l_unsat.discard(w) - return G diff --git a/extensions/fablabchemnitz/networkx/generators/lattice.py b/extensions/fablabchemnitz/networkx/generators/lattice.py deleted file mode 100644 index 07eb9a7f..00000000 --- a/extensions/fablabchemnitz/networkx/generators/lattice.py +++ /dev/null @@ -1,361 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg (hagberg@lanl.gov) -# Pieter Swart (swart@lanl.gov) -# Joel Miller (jmiller@lanl.gov) -# Dan Schult (dschult@lanl.gov) -"""Functions for generating grid graphs and lattices - -The :func:`grid_2d_graph`, :func:`triangular_lattice_graph`, and -:func:`hexagonal_lattice_graph` functions correspond to the three -`regular tilings of the plane`_, the square, triangular, and hexagonal -tilings, respectively. :func:`grid_graph` and :func:`hypercube_graph` -are similar for arbitrary dimensions. Useful relevant discussion can -be found about `Triangular Tiling`_, and `Square, Hex and Triangle Grids`_ - -.. _regular tilings of the plane: https://en.wikipedia.org/wiki/List_of_regular_polytopes_and_compounds#Euclidean_tilings -.. _Square, Hex and Triangle Grids: http://www-cs-students.stanford.edu/~amitp/game-programming/grids/ -.. _Triangular Tiling: https://en.wikipedia.org/wiki/Triangular_tiling - -""" - -from math import sqrt - -from networkx.classes import Graph -from networkx.classes import set_node_attributes -from networkx.algorithms.minors import contracted_nodes -from networkx.algorithms.operators.product import cartesian_product -from networkx.exception import NetworkXError -from networkx.relabel import relabel_nodes -from networkx.utils import flatten -from networkx.utils import nodes_or_number -from networkx.utils import pairwise -from networkx.generators.classic import cycle_graph -from networkx.generators.classic import empty_graph -from networkx.generators.classic import path_graph - -__all__ = ['grid_2d_graph', 'grid_graph', 'hypercube_graph', - 'triangular_lattice_graph', 'hexagonal_lattice_graph'] - - -@nodes_or_number([0, 1]) -def grid_2d_graph(m, n, periodic=False, create_using=None): - """Returns the two-dimensional grid graph. - - The grid graph has each node connected to its four nearest neighbors. - - Parameters - ---------- - m, n : int or iterable container of nodes - If an integer, nodes are from `range(n)`. - If a container, elements become the coordinate of the nodes. - - periodic : bool (default: False) - If this is ``True`` the nodes on the grid boundaries are joined - to the corresponding nodes on the opposite grid boundaries. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - NetworkX graph - The (possibly periodic) grid graph of the specified dimensions. - - """ - G = empty_graph(0, create_using) - row_name, rows = m - col_name, cols = n - G.add_nodes_from((i, j) for i in rows for j in cols) - G.add_edges_from(((i, j), (pi, j)) - for pi, i in pairwise(rows) for j in cols) - G.add_edges_from(((i, j), (i, pj)) - for i in rows for pj, j in pairwise(cols)) - if periodic is True: - if len(rows) > 2: - first = rows[0] - last = rows[-1] - G.add_edges_from(((first, j), (last, j)) for j in cols) - if len(cols) > 2: - first = cols[0] - last = cols[-1] - G.add_edges_from(((i, first), (i, last)) for i in rows) - # both directions for directed - if G.is_directed(): - G.add_edges_from((v, u) for u, v in G.edges()) - return G - - -def grid_graph(dim, periodic=False): - """Returns the *n*-dimensional grid graph. - - The dimension *n* is the length of the list `dim` and the size in - each dimension is the value of the corresponding list element. - - Parameters - ---------- - dim : list or tuple of numbers or iterables of nodes - 'dim' is a tuple or list with, for each dimension, either a number - that is the size of that dimension or an iterable of nodes for - that dimension. The dimension of the grid_graph is the length - of `dim`. - - periodic : bool - If `periodic is True` the nodes on the grid boundaries are joined - to the corresponding nodes on the opposite grid boundaries. - - Returns - ------- - NetworkX graph - The (possibly periodic) grid graph of the specified dimensions. - - Examples - -------- - To produce a 2 by 3 by 4 grid graph, a graph on 24 nodes: - - >>> from networkx import grid_graph - >>> G = grid_graph(dim=[2, 3, 4]) - >>> len(G) - 24 - >>> G = grid_graph(dim=[range(7, 9), range(3, 6)]) - >>> len(G) - 6 - """ - dlabel = "%s" % dim - if not dim: - return empty_graph(0) - - func = cycle_graph if periodic else path_graph - G = func(dim[0]) - for current_dim in dim[1:]: - Gnew = func(current_dim) - G = cartesian_product(Gnew, G) - # graph G is done but has labels of the form (1, (2, (3, 1))) so relabel - H = relabel_nodes(G, flatten) - return H - - -def hypercube_graph(n): - """Returns the *n*-dimensional hypercube graph. - - The nodes are the integers between 0 and ``2 ** n - 1``, inclusive. - - For more information on the hypercube graph, see the Wikipedia - article `Hypercube graph`_. - - .. _Hypercube graph: https://en.wikipedia.org/wiki/Hypercube_graph - - Parameters - ---------- - n : int - The dimension of the hypercube. - The number of nodes in the graph will be ``2 ** n``. - - Returns - ------- - NetworkX graph - The hypercube graph of dimension *n*. - """ - dim = n * [2] - G = grid_graph(dim) - return G - - -def triangular_lattice_graph(m, n, periodic=False, with_positions=True, - create_using=None): - r"""Returns the $m$ by $n$ triangular lattice graph. - - The `triangular lattice graph`_ is a two-dimensional `grid graph`_ in - which each square unit has a diagonal edge (each grid unit has a chord). - - The returned graph has $m$ rows and $n$ columns of triangles. Rows and - columns include both triangles pointing up and down. Rows form a strip - of constant height. Columns form a series of diamond shapes, staggered - with the columns on either side. Another way to state the size is that - the nodes form a grid of `m+1` rows and `(n + 1) // 2` columns. - The odd row nodes are shifted horizontally relative to the even rows. - - Directed graph types have edges pointed up or right. - - Positions of nodes are computed by default or `with_positions is True`. - The position of each node (embedded in a euclidean plane) is stored in - the graph using equilateral triangles with sidelength 1. - The height between rows of nodes is thus $\sqrt(3)/2$. - Nodes lie in the first quadrant with the node $(0, 0)$ at the origin. - - .. _triangular lattice graph: http://mathworld.wolfram.com/TriangularGrid.html - .. _grid graph: http://www-cs-students.stanford.edu/~amitp/game-programming/grids/ - .. _Triangular Tiling: https://en.wikipedia.org/wiki/Triangular_tiling - - Parameters - ---------- - m : int - The number of rows in the lattice. - - n : int - The number of columns in the lattice. - - periodic : bool (default: False) - If True, join the boundary vertices of the grid using periodic - boundary conditions. The join between boundaries is the final row - and column of triangles. This means there is one row and one column - fewer nodes for the periodic lattice. Periodic lattices require - `m >= 3`, `n >= 5` and are allowed but misaligned if `m` or `n` are odd - - with_positions : bool (default: True) - Store the coordinates of each node in the graph node attribute 'pos'. - The coordinates provide a lattice with equilateral triangles. - Periodic positions shift the nodes vertically in a nonlinear way so - the edges don't overlap so much. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - NetworkX graph - The *m* by *n* triangular lattice graph. - """ - H = empty_graph(0, create_using) - if n == 0 or m == 0: - return H - if periodic: - if n < 5 or m < 3: - msg = "m > 2 and n > 4 required for periodic. m={}, n={}" - raise NetworkXError(msg.format(m, n)) - - N = (n + 1) // 2 # number of nodes in row - rows = range(m + 1) - cols = range(N + 1) - # Make grid - H.add_edges_from(((i, j), (i + 1, j)) for j in rows for i in cols[:N]) - H.add_edges_from(((i, j), (i, j + 1)) for j in rows[:m] for i in cols) - # add diagonals - H.add_edges_from(((i, j), (i + 1, j + 1)) - for j in rows[1:m:2] for i in cols[:N]) - H.add_edges_from(((i + 1, j), (i, j + 1)) - for j in rows[:m:2] for i in cols[:N]) - # identify boundary nodes if periodic - if periodic is True: - for i in cols: - H = contracted_nodes(H, (i, 0), (i, m)) - for j in rows[:m]: - H = contracted_nodes(H, (0, j), (N, j)) - elif n % 2: - # remove extra nodes - H.remove_nodes_from(((N, j) for j in rows[1::2])) - - # Add position node attributes - if with_positions: - ii = (i for i in cols for j in rows) - jj = (j for i in cols for j in rows) - xx = (0.5 * (j % 2) + i for i in cols for j in rows) - h = sqrt(3) / 2 - if periodic: - yy = (h * j + .01 * i * i for i in cols for j in rows) - else: - yy = (h * j for i in cols for j in rows) - pos = {(i, j): (x, y) for i, j, x, y in zip(ii, jj, xx, yy) - if (i, j) in H} - set_node_attributes(H, pos, 'pos') - return H - - -def hexagonal_lattice_graph(m, n, periodic=False, with_positions=True, - create_using=None): - """Returns an `m` by `n` hexagonal lattice graph. - - The *hexagonal lattice graph* is a graph whose nodes and edges are - the `hexagonal tiling`_ of the plane. - - The returned graph will have `m` rows and `n` columns of hexagons. - `Odd numbered columns`_ are shifted up relative to even numbered columns. - - Positions of nodes are computed by default or `with_positions is True`. - Node positions creating the standard embedding in the plane - with sidelength 1 and are stored in the node attribute 'pos'. - `pos = nx.get_node_attributes(G, 'pos')` creates a dict ready for drawing. - - .. _hexagonal tiling: https://en.wikipedia.org/wiki/Hexagonal_tiling - .. _Odd numbered columns: http://www-cs-students.stanford.edu/~amitp/game-programming/grids/ - - Parameters - ---------- - m : int - The number of rows of hexagons in the lattice. - - n : int - The number of columns of hexagons in the lattice. - - periodic : bool - Whether to make a periodic grid by joining the boundary vertices. - For this to work `n` must be odd and both `n > 1` and `m > 1`. - The periodic connections create another row and column of hexagons - so these graphs have fewer nodes as boundary nodes are identified. - - with_positions : bool (default: True) - Store the coordinates of each node in the graph node attribute 'pos'. - The coordinates provide a lattice with vertical columns of hexagons - offset to interleave and cover the plane. - Periodic positions shift the nodes vertically in a nonlinear way so - the edges don't overlap so much. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - If graph is directed, edges will point up or right. - - Returns - ------- - NetworkX graph - The *m* by *n* hexagonal lattice graph. - """ - G = empty_graph(0, create_using) - if m == 0 or n == 0: - return G - if periodic and (n % 2 == 1 or m < 2 or n < 2): - msg = "periodic hexagonal lattice needs m > 1, n > 1 and even n" - raise NetworkXError(msg) - - M = 2 * m # twice as many nodes as hexagons vertically - rows = range(M + 2) - cols = range(n + 1) - # make lattice - col_edges = (((i, j), (i, j + 1)) for i in cols for j in rows[:M + 1]) - row_edges = (((i, j), (i + 1, j)) for i in cols[:n] for j in rows - if i % 2 == j % 2) - G.add_edges_from(col_edges) - G.add_edges_from(row_edges) - # Remove corner nodes with one edge - G.remove_node((0, M + 1)) - G.remove_node((n, (M + 1) * (n % 2))) - - # identify boundary nodes if periodic - if periodic: - for i in cols[:n]: - G = contracted_nodes(G, (i, 0), (i, M)) - for i in cols[1:]: - G = contracted_nodes(G, (i, 1), (i, M + 1)) - for j in rows[1:M]: - G = contracted_nodes(G, (0, j), (n, j)) - G.remove_node((n, M)) - - # calc position in embedded space - ii = (i for i in cols for j in rows) - jj = (j for i in cols for j in rows) - xx = (0.5 + i + i // 2 + (j % 2) * ((i % 2) - .5) - for i in cols for j in rows) - h = sqrt(3) / 2 - if periodic: - yy = (h * j + .01 * i * i for i in cols for j in rows) - else: - yy = (h * j for i in cols for j in rows) - # exclude nodes not in G - pos = {(i, j): (x, y) for i, j, x, y in zip(ii, jj, xx, yy) if (i, j) in G} - set_node_attributes(G, pos, 'pos') - return G diff --git a/extensions/fablabchemnitz/networkx/generators/line.py b/extensions/fablabchemnitz/networkx/generators/line.py deleted file mode 100644 index be7c8d61..00000000 --- a/extensions/fablabchemnitz/networkx/generators/line.py +++ /dev/null @@ -1,528 +0,0 @@ -# Copyright (C) 2013-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: James Clough -# Aric Hagberg -# Pieter Swart -# Dan Schult -# chebee7i -"""Functions for generating line graphs.""" -from itertools import combinations -from collections import defaultdict - -import networkx as nx -from networkx.utils import arbitrary_element, generate_unique_node -from networkx.utils.decorators import * - -__all__ = ['line_graph', 'inverse_line_graph'] - - -def line_graph(G, create_using=None): - r"""Returns the line graph of the graph or digraph `G`. - - The line graph of a graph `G` has a node for each edge in `G` and an - edge joining those nodes if the two edges in `G` share a common node. For - directed graphs, nodes are adjacent exactly when the edges they represent - form a directed path of length two. - - The nodes of the line graph are 2-tuples of nodes in the original graph (or - 3-tuples for multigraphs, with the key of the edge as the third element). - - For information about self-loops and more discussion, see the **Notes** - section below. - - Parameters - ---------- - G : graph - A NetworkX Graph, DiGraph, MultiGraph, or MultiDigraph. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Returns - ------- - L : graph - The line graph of G. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.star_graph(3) - >>> L = nx.line_graph(G) - >>> print(sorted(map(sorted, L.edges()))) # makes a 3-clique, K3 - [[(0, 1), (0, 2)], [(0, 1), (0, 3)], [(0, 2), (0, 3)]] - - Notes - ----- - Graph, node, and edge data are not propagated to the new graph. For - undirected graphs, the nodes in G must be sortable, otherwise the - constructed line graph may not be correct. - - *Self-loops in undirected graphs* - - For an undirected graph `G` without multiple edges, each edge can be - written as a set `\{u, v\}`. Its line graph `L` has the edges of `G` as - its nodes. If `x` and `y` are two nodes in `L`, then `\{x, y\}` is an edge - in `L` if and only if the intersection of `x` and `y` is nonempty. Thus, - the set of all edges is determined by the set of all pairwise intersections - of edges in `G`. - - Trivially, every edge in G would have a nonzero intersection with itself, - and so every node in `L` should have a self-loop. This is not so - interesting, and the original context of line graphs was with simple - graphs, which had no self-loops or multiple edges. The line graph was also - meant to be a simple graph and thus, self-loops in `L` are not part of the - standard definition of a line graph. In a pairwise intersection matrix, - this is analogous to excluding the diagonal entries from the line graph - definition. - - Self-loops and multiple edges in `G` add nodes to `L` in a natural way, and - do not require any fundamental changes to the definition. It might be - argued that the self-loops we excluded before should now be included. - However, the self-loops are still "trivial" in some sense and thus, are - usually excluded. - - *Self-loops in directed graphs* - - For a directed graph `G` without multiple edges, each edge can be written - as a tuple `(u, v)`. Its line graph `L` has the edges of `G` as its - nodes. If `x` and `y` are two nodes in `L`, then `(x, y)` is an edge in `L` - if and only if the tail of `x` matches the head of `y`, for example, if `x - = (a, b)` and `y = (b, c)` for some vertices `a`, `b`, and `c` in `G`. - - Due to the directed nature of the edges, it is no longer the case that - every edge in `G` should have a self-loop in `L`. Now, the only time - self-loops arise is if a node in `G` itself has a self-loop. So such - self-loops are no longer "trivial" but instead, represent essential - features of the topology of `G`. For this reason, the historical - development of line digraphs is such that self-loops are included. When the - graph `G` has multiple edges, once again only superficial changes are - required to the definition. - - References - ---------- - * Harary, Frank, and Norman, Robert Z., "Some properties of line digraphs", - Rend. Circ. Mat. Palermo, II. Ser. 9 (1960), 161--168. - * Hemminger, R. L.; Beineke, L. W. (1978), "Line graphs and line digraphs", - in Beineke, L. W.; Wilson, R. J., Selected Topics in Graph Theory, - Academic Press Inc., pp. 271--305. - - """ - if G.is_directed(): - L = _lg_directed(G, create_using=create_using) - else: - L = _lg_undirected(G, selfloops=False, create_using=create_using) - return L - - -def _node_func(G): - """Returns a function which returns a sorted node for line graphs. - - When constructing a line graph for undirected graphs, we must normalize - the ordering of nodes as they appear in the edge. - - """ - if G.is_multigraph(): - def sorted_node(u, v, key): - return (u, v, key) if u <= v else (v, u, key) - else: - def sorted_node(u, v): - return (u, v) if u <= v else (v, u) - return sorted_node - - -def _edge_func(G): - """Returns the edges from G, handling keys for multigraphs as necessary. - - """ - if G.is_multigraph(): - def get_edges(nbunch=None): - return G.edges(nbunch, keys=True) - else: - def get_edges(nbunch=None): - return G.edges(nbunch) - return get_edges - - -def _sorted_edge(u, v): - """Returns a sorted edge. - - During the construction of a line graph for undirected graphs, the data - structure can be a multigraph even though the line graph will never have - multiple edges between its nodes. For this reason, we must make sure not - to add any edge more than once. This requires that we build up a list of - edges to add and then remove all duplicates. And so, we must normalize - the representation of the edges. - - """ - return (u, v) if u <= v else (v, u) - - -def _lg_directed(G, create_using=None): - """Returns the line graph L of the (multi)digraph G. - - Edges in G appear as nodes in L, represented as tuples of the form (u,v) - or (u,v,key) if G is a multidigraph. A node in L corresponding to the edge - (u,v) is connected to every node corresponding to an edge (v,w). - - Parameters - ---------- - G : digraph - A directed graph or directed multigraph. - create_using : NetworkX graph constructor, optional - Graph type to create. If graph instance, then cleared before populated. - Default is to use the same graph class as `G`. - - """ - L = nx.empty_graph(0, create_using, default=G.__class__) - - # Create a graph specific edge function. - get_edges = _edge_func(G) - - for from_node in get_edges(): - # from_node is: (u,v) or (u,v,key) - L.add_node(from_node) - for to_node in get_edges(from_node[1]): - L.add_edge(from_node, to_node) - - return L - - -def _lg_undirected(G, selfloops=False, create_using=None): - """Returns the line graph L of the (multi)graph G. - - Edges in G appear as nodes in L, represented as sorted tuples of the form - (u,v), or (u,v,key) if G is a multigraph. A node in L corresponding to - the edge {u,v} is connected to every node corresponding to an edge that - involves u or v. - - Parameters - ---------- - G : graph - An undirected graph or multigraph. - selfloops : bool - If `True`, then self-loops are included in the line graph. If `False`, - they are excluded. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - Notes - ----- - The standard algorithm for line graphs of undirected graphs does not - produce self-loops. - - """ - L = nx.empty_graph(0, create_using, default=G.__class__) - - # Graph specific functions for edges and sorted nodes. - get_edges = _edge_func(G) - sorted_node = _node_func(G) - - # Determine if we include self-loops or not. - shift = 0 if selfloops else 1 - - edges = set([]) - for u in G: - # Label nodes as a sorted tuple of nodes in original graph. - nodes = [sorted_node(*x) for x in get_edges(u)] - - if len(nodes) == 1: - # Then the edge will be an isolated node in L. - L.add_node(nodes[0]) - - # Add a clique of `nodes` to graph. To prevent double adding edges, - # especially important for multigraphs, we store the edges in - # canonical form in a set. - for i, a in enumerate(nodes): - edges.update([_sorted_edge(a, b) for b in nodes[i + shift:]]) - - L.add_edges_from(edges) - return L - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def inverse_line_graph(G): - """ Returns the inverse line graph of graph G. - - If H is a graph, and G is the line graph of H, such that H = L(G). - Then H is the inverse line graph of G. - - Not all graphs are line graphs and these do not have an inverse line graph. - In these cases this generator returns a NetworkXError. - - Parameters - ---------- - G : graph - A NetworkX Graph - - Returns - ------- - H : graph - The inverse line graph of G. - - Raises - ------ - NetworkXNotImplemented - If G is directed or a multigraph - - NetworkXError - If G is not a line graph - - Notes - ----- - This is an implementation of the Roussopoulos algorithm. - - If G consists of multiple components, then the algorithm doesn't work. - You should invert every component seperately: - - >>> K5 = nx.complete_graph(5) - >>> P4 = nx.Graph([('a', 'b'), ('b', 'c'), ('c', 'd')]) - >>> G = nx.union(K5, P4) - >>> root_graphs = [] - >>> for comp in nx.connected_components(G): - ... root_graphs.append(nx.inverse_line_graph(G.subgraph(comp))) - >>> len(root_graphs) - 2 - - References - ---------- - * Roussopolous, N, "A max {m, n} algorithm for determining the graph H from - its line graph G", Information Processing Letters 2, (1973), 108--112. - - """ - if G.number_of_nodes() == 0: - a = generate_unique_node() - H = nx.Graph() - H.add_node(a) - return H - elif G.number_of_nodes() == 1: - v = list(G)[0] - a = (v, 0) - b = (v, 1) - H = nx.Graph([(a,b)]) - return H - elif G.number_of_nodes() > 1 and G.number_of_edges() == 0: - msg = ( - "inverse_line_graph() doesn't work on an edgeless graph. " - "Please use this function on each component seperately." - ) - raise nx.NetworkXError(msg) - - starting_cell = _select_starting_cell(G) - P = _find_partition(G, starting_cell) - # count how many times each vertex appears in the partition set - P_count = {u: 0 for u in G.nodes()} - for p in P: - for u in p: - P_count[u] += 1 - - if max(P_count.values()) > 2: - msg = "G is not a line graph (vertex found in more " \ - "than two partition cells)" - raise nx.NetworkXError(msg) - W = tuple([(u,) for u in P_count if P_count[u] == 1]) - H = nx.Graph() - H.add_nodes_from(P) - H.add_nodes_from(W) - for a, b in combinations(H.nodes(), 2): - if len(set(a).intersection(set(b))) > 0: - H.add_edge(a, b) - return H - - -def _triangles(G, e): - """ Return list of all triangles containing edge e""" - u, v = e - if u not in G: - raise nx.NetworkXError("Vertex %s not in graph" % u) - if v not in G[u]: - raise nx.NetworkXError("Edge (%s, %s) not in graph" % (u, v)) - triangle_list = [] - for x in G[u]: - if x in G[v]: - triangle_list.append((u, v, x)) - return triangle_list - - -def _odd_triangle(G, T): - """ Test whether T is an odd triangle in G - - Parameters - ---------- - G : NetworkX Graph - T : 3-tuple of vertices forming triangle in G - - Returns - ------- - True is T is an odd triangle - False otherwise - - Raises - ------ - NetworkXError - T is not a triangle in G - - Notes - ----- - An odd triangle is one in which there exists another vertex in G which is - adjacent to either exactly one or exactly all three of the vertices in the - triangle. - - """ - for u in T: - if u not in G.nodes(): - raise nx.NetworkXError("Vertex %s not in graph" % u) - for e in list(combinations(T, 2)): - if e[0] not in G[e[1]]: - raise nx.NetworkXError("Edge (%s, %s) not in graph" % (e[0], e[1])) - - T_neighbors = defaultdict(int) - for t in T: - for v in G[t]: - if v not in T: - T_neighbors[v] += 1 - for v in T_neighbors: - if T_neighbors[v] in [1, 3]: - return True - return False - - -def _find_partition(G, starting_cell): - """ Find a partition of the vertices of G into cells of complete graphs - - Parameters - ---------- - G : NetworkX Graph - starting_cell : tuple of vertices in G which form a cell - - Returns - ------- - List of tuples of vertices of G - - Raises - ------ - NetworkXError - If a cell is not a complete subgraph then G is not a line graph - """ - G_partition = G.copy() - P = [starting_cell] # partition set - G_partition.remove_edges_from(list(combinations(starting_cell, 2))) - # keep list of partitioned nodes which might have an edge in G_partition - partitioned_vertices = list(starting_cell) - while G_partition.number_of_edges() > 0: - # there are still edges left and so more cells to be made - u = partitioned_vertices[-1] - deg_u = len(G_partition[u]) - if deg_u == 0: - # if u has no edges left in G_partition then we have found - # all of its cells so we do not need to keep looking - partitioned_vertices.pop() - else: - # if u still has edges then we need to find its other cell - # this other cell must be a complete subgraph or else G is - # not a line graph - new_cell = [u] + list(G_partition[u]) - for u in new_cell: - for v in new_cell: - if (u != v) and (v not in G_partition[u]): - msg = "G is not a line graph" \ - "(partition cell not a complete subgraph)" - raise nx.NetworkXError(msg) - P.append(tuple(new_cell)) - G_partition.remove_edges_from(list(combinations(new_cell, 2))) - partitioned_vertices += new_cell - return P - - -def _select_starting_cell(G, starting_edge=None): - """ Select a cell to initiate _find_partition - - Parameters - ---------- - G : NetworkX Graph - starting_edge: an edge to build the starting cell from - - Returns - ------- - Tuple of vertices in G - - Raises - ------ - NetworkXError - If it is determined that G is not a line graph - - Notes - ----- - If starting edge not specified then pick an arbitrary edge - doesn't - matter which. However, this function may call itself requiring a - specific starting edge. Note that the r, s notation for counting - triangles is the same as in the Roussopoulos paper cited above. - """ - if starting_edge is None: - e = arbitrary_element(list(G.edges())) - else: - e = starting_edge - if e[0] not in G[e[1]]: - msg = 'starting_edge (%s, %s) is not in the Graph' - raise nx.NetworkXError(msg % e) - e_triangles = _triangles(G, e) - r = len(e_triangles) - if r == 0: - # there are no triangles containing e, so the starting cell is just e - starting_cell = e - elif r == 1: - # there is exactly one triangle, T, containing e. If other 2 edges - # of T belong only to this triangle then T is starting cell - T = e_triangles[0] - a, b, c = T - # ab was original edge so check the other 2 edges - ac_edges = [x for x in _triangles(G, (a, c))] - bc_edges = [x for x in _triangles(G, (b, c))] - if len(ac_edges) == 1: - if len(bc_edges) == 1: - starting_cell = T - else: - return _select_starting_cell(G, starting_edge=(b, c)) - else: - return _select_starting_cell(G, starting_edge=(a, c)) - else: - # r >= 2 so we need to count the number of odd triangles, s - s = 0 - odd_triangles = [] - for T in e_triangles: - if _odd_triangle(G, T): - s += 1 - odd_triangles.append(T) - if r == 2 and s == 0: - # in this case either triangle works, so just use T - starting_cell = T - elif r - 1 <= s <= r: - # check if odd triangles containing e form complete subgraph - # there must be exactly s+2 of them - # and they must all be connected - triangle_nodes = set([]) - for T in odd_triangles: - for x in T: - triangle_nodes.add(x) - if len(triangle_nodes) == s + 2: - for u in triangle_nodes: - for v in triangle_nodes: - if u != v and (v not in G[u]): - msg = "G is not a line graph (odd triangles " \ - "do not form complete subgraph)" - raise nx.NetworkXError(msg) - # otherwise then we can use this as the starting cell - starting_cell = tuple(triangle_nodes) - else: - msg = "G is not a line graph (odd triangles " \ - "do not form complete subgraph)" - raise nx.NetworkXError(msg) - else: - msg = "G is not a line graph (incorrect number of " \ - "odd triangles around starting edge)" - raise nx.NetworkXError(msg) - return starting_cell diff --git a/extensions/fablabchemnitz/networkx/generators/mycielski.py b/extensions/fablabchemnitz/networkx/generators/mycielski.py deleted file mode 100644 index 5814850e..00000000 --- a/extensions/fablabchemnitz/networkx/generators/mycielski.py +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright (C) 2010-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. - -"""Functions related to the Mycielski Operation and the Mycielskian family -of graphs. - -""" - -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ['mycielskian', 'mycielski_graph'] - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def mycielskian(G, iterations=1): - r"""Returns the Mycielskian of a simple, undirected graph G - - The Mycielskian of graph preserves a graph's triangle free - property while increasing the chromatic number by 1. - - The Mycielski Operation on a graph, :math:`G=(V, E)`, constructs a new - graph with :math:`2|V| + 1` nodes and :math:`3|E| + |V|` edges. - - The construction is as follows: - - Let :math:`V = {0, ..., n-1}`. Construct another vertex set - :math:`U = {n, ..., 2n}` and a vertex, `w`. - Construct a new graph, `M`, with vertices :math:`U \bigcup V \bigcup w`. - For edges, :math:`(u, v) \in E` add edges :math:`(u, v), (u, v + n)`, and - :math:`(u + n, v)` to M. Finally, for all vertices :math:`u \in U`, add - edge :math:`(u, w)` to M. - - The Mycielski Operation can be done multiple times by repeating the above - process iteratively. - - More information can be found at https://en.wikipedia.org/wiki/Mycielskian - - Parameters - ---------- - G : graph - A simple, undirected NetworkX graph - iterations : int - The number of iterations of the Mycielski operation to - perform on G. Defaults to 1. Must be a non-negative integer. - - Returns - ------- - M : graph - The Mycielskian of G after the specified number of iterations. - - Notes - ------ - Graph, node, and edge data are not necessarily propagated to the new graph. - - """ - - n = G.number_of_nodes() - M = nx.convert_node_labels_to_integers(G) - - for i in range(iterations): - n = M.number_of_nodes() - M.add_nodes_from(range(n, 2 * n)) - old_edges = list(M.edges()) - M.add_edges_from((u, v + n) for u, v in old_edges) - M.add_edges_from((u + n, v) for u, v in old_edges) - M.add_node(2 * n) - M.add_edges_from((u + n, 2 * n) for u in range(n)) - - return M - - -def mycielski_graph(n): - """Generator for the n_th Mycielski Graph. - - The Mycielski family of graphs is an infinite set of graphs. - :math:`M_1` is the singleton graph, :math:`M_2` is two vertices with an - edge, and, for :math:`i > 2`, :math:`M_i` is the Mycielskian of - :math:`M_{i-1}`. - - More information can be found at - http://mathworld.wolfram.com/MycielskiGraph.html - - Parameters - ---------- - n : int - The desired Mycielski Graph. - - Returns - ------- - M : graph - The n_th Mycielski Graph - - Notes - ----- - The first graph in the Mycielski sequence is the singleton graph. - The Mycielskian of this graph is not the :math:`P_2` graph, but rather the - :math:`P_2` graph with an extra, isolated vertex. The second Mycielski - graph is the :math:`P_2` graph, so the first two are hard coded. - The remaining graphs are generated using the Mycielski operation. - - """ - - if n < 1: - raise nx.NetworkXError("must satisfy n >= 0") - - if n == 1: - return nx.empty_graph(1) - - else: - return mycielskian(nx.path_graph(2), n - 2) diff --git a/extensions/fablabchemnitz/networkx/generators/nonisomorphic_trees.py b/extensions/fablabchemnitz/networkx/generators/nonisomorphic_trees.py deleted file mode 100644 index c8ce122f..00000000 --- a/extensions/fablabchemnitz/networkx/generators/nonisomorphic_trees.py +++ /dev/null @@ -1,200 +0,0 @@ -""" -Implementation of the Wright, Richmond, Odlyzko and McKay (WROM) -algorithm for the enumeration of all non-isomorphic free trees of a -given order. Rooted trees are represented by level sequences, i.e., -lists in which the i-th element specifies the distance of vertex i to -the root. - -""" -# Copyright (C) 2013 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -__author__ = "\n".join(["Aric Hagberg (hagberg@lanl.gov)", - "Mridul Seth (seth.mridul@gmail.com)"]) - -__all__ = ['nonisomorphic_trees', - 'number_of_nonisomorphic_trees'] - -import networkx as nx - - -def nonisomorphic_trees(order, create="graph"): - """Returns a list of nonisomporphic trees - - Parameters - ---------- - order : int - order of the desired tree(s) - - create : graph or matrix (default="Graph) - If graph is selected a list of trees will be returned, - if matrix is selected a list of adjancency matrix will - be returned - - Returns - ------- - G : List of NetworkX Graphs - - M : List of Adjacency matrices - - References - ---------- - - """ - - if order < 2: - raise ValueError - # start at the path graph rooted at its center - layout = list(range(order // 2 + 1)) + list(range(1, (order + 1) // 2)) - - while layout is not None: - layout = _next_tree(layout) - if layout is not None: - if create == "graph": - yield _layout_to_graph(layout) - elif create == "matrix": - yield _layout_to_matrix(layout) - layout = _next_rooted_tree(layout) - - -def number_of_nonisomorphic_trees(order): - """Returns the number of nonisomorphic trees - - Parameters - ---------- - order : int - order of the desired tree(s) - - Returns - ------- - length : Number of nonisomorphic graphs for the given order - - References - ---------- - - """ - return sum(1 for _ in nonisomorphic_trees(order)) - - -def _next_rooted_tree(predecessor, p=None): - """One iteration of the Beyer-Hedetniemi algorithm.""" - - if p is None: - p = len(predecessor) - 1 - while predecessor[p] == 1: - p -= 1 - if p == 0: - return None - - q = p - 1 - while predecessor[q] != predecessor[p] - 1: - q -= 1 - result = list(predecessor) - for i in range(p, len(result)): - result[i] = result[i - p + q] - return result - - -def _next_tree(candidate): - """One iteration of the Wright, Richmond, Odlyzko and McKay - algorithm.""" - - # valid representation of a free tree if: - # there are at least two vertices at layer 1 - # (this is always the case because we start at the path graph) - left, rest = _split_tree(candidate) - - # and the left subtree of the root - # is less high than the tree with the left subtree removed - left_height = max(left) - rest_height = max(rest) - valid = rest_height >= left_height - - if valid and rest_height == left_height: - # and, if left and rest are of the same height, - # if left does not encompass more vertices - if len(left) > len(rest): - valid = False - # and, if they have the same number or vertices, - # if left does not come after rest lexicographically - elif len(left) == len(rest) and left > rest: - valid = False - - if valid: - return candidate - else: - # jump to the next valid free tree - p = len(left) - new_candidate = _next_rooted_tree(candidate, p) - if candidate[p] > 2: - new_left, new_rest = _split_tree(new_candidate) - new_left_height = max(new_left) - suffix = range(1, new_left_height + 2) - new_candidate[-len(suffix):] = suffix - return new_candidate - - -def _split_tree(layout): - """Returns a tuple of two layouts, one containing the left - subtree of the root vertex, and one containing the original tree - with the left subtree removed.""" - - one_found = False - m = None - for i in range(len(layout)): - if layout[i] == 1: - if one_found: - m = i - break - else: - one_found = True - - if m is None: - m = len(layout) - - left = [layout[i] - 1 for i in range(1, m)] - rest = [0] + [layout[i] for i in range(m, len(layout))] - return (left, rest) - - -def _layout_to_matrix(layout): - """Create the adjacency matrix for the tree specified by the - given layout (level sequence).""" - - result = [[0] * len(layout) for i in range(len(layout))] - stack = [] - for i in range(len(layout)): - i_level = layout[i] - if stack: - j = stack[-1] - j_level = layout[j] - while j_level >= i_level: - stack.pop() - j = stack[-1] - j_level = layout[j] - result[i][j] = result[j][i] = 1 - stack.append(i) - return result - - -def _layout_to_graph(layout): - """Create a NetworkX Graph for the tree specified by the - given layout(level sequence)""" - result = [[0] * len(layout) for i in range(len(layout))] - G = nx.Graph() - stack = [] - for i in range(len(layout)): - i_level = layout[i] - if stack: - j = stack[-1] - j_level = layout[j] - while j_level >= i_level: - stack.pop() - j = stack[-1] - j_level = layout[j] - G.add_edge(i, j) - stack.append(i) - return G diff --git a/extensions/fablabchemnitz/networkx/generators/random_clustered.py b/extensions/fablabchemnitz/networkx/generators/random_clustered.py deleted file mode 100644 index 0041c10b..00000000 --- a/extensions/fablabchemnitz/networkx/generators/random_clustered.py +++ /dev/null @@ -1,125 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# Authors: Aric Hagberg (hagberg@lanl.gov) -# Joel Miller (joel.c.miller.research@gmail.com) -"""Generate graphs with given degree and triangle sequence. -""" -import networkx as nx -from networkx.utils import py_random_state - -__all__ = ['random_clustered_graph'] - - -@py_random_state(2) -def random_clustered_graph(joint_degree_sequence, create_using=None, seed=None): - r"""Generate a random graph with the given joint independent edge degree and - triangle degree sequence. - - This uses a configuration model-like approach to generate a random graph - (with parallel edges and self-loops) by randomly assigning edges to match - the given joint degree sequence. - - The joint degree sequence is a list of pairs of integers of the form - $[(d_{1,i}, d_{1,t}), \dotsc, (d_{n,i}, d_{n,t})]$. According to this list, - vertex $u$ is a member of $d_{u,t}$ triangles and has $d_{u, i}$ other - edges. The number $d_{u,t}$ is the *triangle degree* of $u$ and the number - $d_{u,i}$ is the *independent edge degree*. - - Parameters - ---------- - joint_degree_sequence : list of integer pairs - Each list entry corresponds to the independent edge degree and - triangle degree of a node. - create_using : NetworkX graph constructor, optional (default MultiGraph) - Graph type to create. If graph instance, then cleared before populated. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : MultiGraph - A graph with the specified degree sequence. Nodes are labeled - starting at 0 with an index corresponding to the position in - deg_sequence. - - Raises - ------ - NetworkXError - If the independent edge degree sequence sum is not even - or the triangle degree sequence sum is not divisible by 3. - - Notes - ----- - As described by Miller [1]_ (see also Newman [2]_ for an equivalent - description). - - A non-graphical degree sequence (not realizable by some simple - graph) is allowed since this function returns graphs with self - loops and parallel edges. An exception is raised if the - independent degree sequence does not have an even sum or the - triangle degree sequence sum is not divisible by 3. - - This configuration model-like construction process can lead to - duplicate edges and loops. You can remove the self-loops and - parallel edges (see below) which will likely result in a graph - that doesn't have the exact degree sequence specified. This - "finite-size effect" decreases as the size of the graph increases. - - References - ---------- - .. [1] Joel C. Miller. "Percolation and epidemics in random clustered - networks". In: Physical review. E, Statistical, nonlinear, and soft - matter physics 80 (2 Part 1 August 2009). - .. [2] M. E. J. Newman. "Random Graphs with Clustering". - In: Physical Review Letters 103 (5 July 2009) - - Examples - -------- - >>> deg = [(1, 0), (1, 0), (1, 0), (2, 0), (1, 0), (2, 1), (0, 1), (0, 1)] - >>> G = nx.random_clustered_graph(deg) - - To remove parallel edges: - - >>> G = nx.Graph(G) - - To remove self loops: - - >>> G.remove_edges_from(nx.selfloop_edges(G)) - - """ - # In Python 3, zip() returns an iterator. Make this into a list. - joint_degree_sequence = list(joint_degree_sequence) - - N = len(joint_degree_sequence) - G = nx.empty_graph(N, create_using, default=nx.MultiGraph) - if G.is_directed(): - raise nx.NetworkXError("Directed Graph not supported") - - ilist = [] - tlist = [] - for n in G: - degrees = joint_degree_sequence[n] - for icount in range(degrees[0]): - ilist.append(n) - for tcount in range(degrees[1]): - tlist.append(n) - - if len(ilist) % 2 != 0 or len(tlist) % 3 != 0: - raise nx.NetworkXError('Invalid degree sequence') - - seed.shuffle(ilist) - seed.shuffle(tlist) - while ilist: - G.add_edge(ilist.pop(), ilist.pop()) - while tlist: - n1 = tlist.pop() - n2 = tlist.pop() - n3 = tlist.pop() - G.add_edges_from([(n1, n2), (n1, n3), (n2, n3)]) - return G diff --git a/extensions/fablabchemnitz/networkx/generators/random_graphs.py b/extensions/fablabchemnitz/networkx/generators/random_graphs.py deleted file mode 100644 index 78b2dd81..00000000 --- a/extensions/fablabchemnitz/networkx/generators/random_graphs.py +++ /dev/null @@ -1,1273 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -""" -Generators for random graphs. - -""" - -import itertools -import math - -import networkx as nx -from networkx.utils import py_random_state -from .classic import empty_graph, path_graph, complete_graph -from .degree_seq import degree_sequence_tree -from collections import defaultdict - -__all__ = ['fast_gnp_random_graph', - 'gnp_random_graph', - 'dense_gnm_random_graph', - 'gnm_random_graph', - 'erdos_renyi_graph', - 'binomial_graph', - 'newman_watts_strogatz_graph', - 'watts_strogatz_graph', - 'connected_watts_strogatz_graph', - 'random_regular_graph', - 'barabasi_albert_graph', - 'dual_barabasi_albert_graph', - 'extended_barabasi_albert_graph', - 'powerlaw_cluster_graph', - 'random_lobster', - 'random_shell_graph', - 'random_powerlaw_tree', - 'random_powerlaw_tree_sequence', - 'random_kernel_graph'] - - -#------------------------------------------------------------------------- -# Some Famous Random Graphs -#------------------------------------------------------------------------- - - -@py_random_state(2) -def fast_gnp_random_graph(n, p, seed=None, directed=False): - """Returns a $G_{n,p}$ random graph, also known as an Erdős-Rényi graph or - a binomial graph. - - Parameters - ---------- - n : int - The number of nodes. - p : float - Probability for edge creation. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - directed : bool, optional (default=False) - If True, this function returns a directed graph. - - Notes - ----- - The $G_{n,p}$ graph algorithm chooses each of the $[n (n - 1)] / 2$ - (undirected) or $n (n - 1)$ (directed) possible edges with probability $p$. - - This algorithm [1]_ runs in $O(n + m)$ time, where `m` is the expected number of - edges, which equals $p n (n - 1) / 2$. This should be faster than - :func:`gnp_random_graph` when $p$ is small and the expected number of edges - is small (that is, the graph is sparse). - - See Also - -------- - gnp_random_graph - - References - ---------- - .. [1] Vladimir Batagelj and Ulrik Brandes, - "Efficient generation of large random networks", - Phys. Rev. E, 71, 036113, 2005. - """ - G = empty_graph(n) - - if p <= 0 or p >= 1: - return nx.gnp_random_graph(n, p, seed=seed, directed=directed) - - w = -1 - lp = math.log(1.0 - p) - - if directed: - G = nx.DiGraph(G) - # Nodes in graph are from 0,n-1 (start with v as the first node index). - v = 0 - while v < n: - lr = math.log(1.0 - seed.random()) - w = w + 1 + int(lr / lp) - if v == w: # avoid self loops - w = w + 1 - while v < n <= w: - w = w - n - v = v + 1 - if v == w: # avoid self loops - w = w + 1 - if v < n: - G.add_edge(v, w) - else: - # Nodes in graph are from 0,n-1 (start with v as the second node index). - v = 1 - while v < n: - lr = math.log(1.0 - seed.random()) - w = w + 1 + int(lr / lp) - while w >= v and v < n: - w = w - v - v = v + 1 - if v < n: - G.add_edge(v, w) - return G - - -@py_random_state(2) -def gnp_random_graph(n, p, seed=None, directed=False): - """Returns a $G_{n,p}$ random graph, also known as an Erdős-Rényi graph - or a binomial graph. - - The $G_{n,p}$ model chooses each of the possible edges with probability $p$. - - The functions :func:`binomial_graph` and :func:`erdos_renyi_graph` are - aliases of this function. - - Parameters - ---------- - n : int - The number of nodes. - p : float - Probability for edge creation. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - directed : bool, optional (default=False) - If True, this function returns a directed graph. - - See Also - -------- - fast_gnp_random_graph - - Notes - ----- - This algorithm [2]_ runs in $O(n^2)$ time. For sparse graphs (that is, for - small values of $p$), :func:`fast_gnp_random_graph` is a faster algorithm. - - References - ---------- - .. [1] P. Erdős and A. Rényi, On Random Graphs, Publ. Math. 6, 290 (1959). - .. [2] E. N. Gilbert, Random Graphs, Ann. Math. Stat., 30, 1141 (1959). - """ - if directed: - edges = itertools.permutations(range(n), 2) - G = nx.DiGraph() - else: - edges = itertools.combinations(range(n), 2) - G = nx.Graph() - G.add_nodes_from(range(n)) - if p <= 0: - return G - if p >= 1: - return complete_graph(n, create_using=G) - - for e in edges: - if seed.random() < p: - G.add_edge(*e) - return G - - -# add some aliases to common names -binomial_graph = gnp_random_graph -erdos_renyi_graph = gnp_random_graph - - -@py_random_state(2) -def dense_gnm_random_graph(n, m, seed=None): - """Returns a $G_{n,m}$ random graph. - - In the $G_{n,m}$ model, a graph is chosen uniformly at random from the set - of all graphs with $n$ nodes and $m$ edges. - - This algorithm should be faster than :func:`gnm_random_graph` for dense - graphs. - - Parameters - ---------- - n : int - The number of nodes. - m : int - The number of edges. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - See Also - -------- - gnm_random_graph() - - Notes - ----- - Algorithm by Keith M. Briggs Mar 31, 2006. - Inspired by Knuth's Algorithm S (Selection sampling technique), - in section 3.4.2 of [1]_. - - References - ---------- - .. [1] Donald E. Knuth, The Art of Computer Programming, - Volume 2/Seminumerical algorithms, Third Edition, Addison-Wesley, 1997. - """ - mmax = n * (n - 1) / 2 - if m >= mmax: - G = complete_graph(n) - else: - G = empty_graph(n) - - if n == 1 or m >= mmax: - return G - - u = 0 - v = 1 - t = 0 - k = 0 - while True: - if seed.randrange(mmax - t) < m - k: - G.add_edge(u, v) - k += 1 - if k == m: - return G - t += 1 - v += 1 - if v == n: # go to next row of adjacency matrix - u += 1 - v = u + 1 - - -@py_random_state(2) -def gnm_random_graph(n, m, seed=None, directed=False): - """Returns a $G_{n,m}$ random graph. - - In the $G_{n,m}$ model, a graph is chosen uniformly at random from the set - of all graphs with $n$ nodes and $m$ edges. - - This algorithm should be faster than :func:`dense_gnm_random_graph` for - sparse graphs. - - Parameters - ---------- - n : int - The number of nodes. - m : int - The number of edges. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - directed : bool, optional (default=False) - If True return a directed graph - - See also - -------- - dense_gnm_random_graph - - """ - if directed: - G = nx.DiGraph() - else: - G = nx.Graph() - G.add_nodes_from(range(n)) - - if n == 1: - return G - max_edges = n * (n - 1) - if not directed: - max_edges /= 2.0 - if m >= max_edges: - return complete_graph(n, create_using=G) - - nlist = list(G) - edge_count = 0 - while edge_count < m: - # generate random edge,u,v - u = seed.choice(nlist) - v = seed.choice(nlist) - if u == v or G.has_edge(u, v): - continue - else: - G.add_edge(u, v) - edge_count = edge_count + 1 - return G - - -@py_random_state(3) -def newman_watts_strogatz_graph(n, k, p, seed=None): - """Returns a Newman–Watts–Strogatz small-world graph. - - Parameters - ---------- - n : int - The number of nodes. - k : int - Each node is joined with its `k` nearest neighbors in a ring - topology. - p : float - The probability of adding a new edge for each edge. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Notes - ----- - First create a ring over $n$ nodes [1]_. Then each node in the ring is - connected with its $k$ nearest neighbors (or $k - 1$ neighbors if $k$ - is odd). Then shortcuts are created by adding new edges as follows: for - each edge $(u, v)$ in the underlying "$n$-ring with $k$ nearest - neighbors" with probability $p$ add a new edge $(u, w)$ with - randomly-chosen existing node $w$. In contrast with - :func:`watts_strogatz_graph`, no edges are removed. - - See Also - -------- - watts_strogatz_graph() - - References - ---------- - .. [1] M. E. J. Newman and D. J. Watts, - Renormalization group analysis of the small-world network model, - Physics Letters A, 263, 341, 1999. - https://doi.org/10.1016/S0375-9601(99)00757-4 - """ - if k > n: - raise nx.NetworkXError("k>=n, choose smaller k or larger n") - - #If k == n the graph return is a complete graph - if k == n: - return nx.complete_graph(n) - - G = empty_graph(n) - nlist = list(G.nodes()) - fromv = nlist - # connect the k/2 neighbors - for j in range(1, k // 2 + 1): - tov = fromv[j:] + fromv[0:j] # the first j are now last - for i in range(len(fromv)): - G.add_edge(fromv[i], tov[i]) - # for each edge u-v, with probability p, randomly select existing - # node w and add new edge u-w - e = list(G.edges()) - for (u, v) in e: - if seed.random() < p: - w = seed.choice(nlist) - # no self-loops and reject if edge u-w exists - # is that the correct NWS model? - while w == u or G.has_edge(u, w): - w = seed.choice(nlist) - if G.degree(u) >= n - 1: - break # skip this rewiring - else: - G.add_edge(u, w) - return G - - -@py_random_state(3) -def watts_strogatz_graph(n, k, p, seed=None): - """Returns a Watts–Strogatz small-world graph. - - Parameters - ---------- - n : int - The number of nodes - k : int - Each node is joined with its `k` nearest neighbors in a ring - topology. - p : float - The probability of rewiring each edge - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - See Also - -------- - newman_watts_strogatz_graph() - connected_watts_strogatz_graph() - - Notes - ----- - First create a ring over $n$ nodes [1]_. Then each node in the ring is joined - to its $k$ nearest neighbors (or $k - 1$ neighbors if $k$ is odd). - Then shortcuts are created by replacing some edges as follows: for each - edge $(u, v)$ in the underlying "$n$-ring with $k$ nearest neighbors" - with probability $p$ replace it with a new edge $(u, w)$ with uniformly - random choice of existing node $w$. - - In contrast with :func:`newman_watts_strogatz_graph`, the random rewiring - does not increase the number of edges. The rewired graph is not guaranteed - to be connected as in :func:`connected_watts_strogatz_graph`. - - References - ---------- - .. [1] Duncan J. Watts and Steven H. Strogatz, - Collective dynamics of small-world networks, - Nature, 393, pp. 440--442, 1998. - """ - if k > n: - raise nx.NetworkXError("k>n, choose smaller k or larger n") - - #If k == n, the graph is complete not Watts-Strogatz - if k == n: - return nx.complete_graph(n) - - G = nx.Graph() - nodes = list(range(n)) # nodes are labeled 0 to n-1 - # connect each node to k/2 neighbors - for j in range(1, k // 2 + 1): - targets = nodes[j:] + nodes[0:j] # first j nodes are now last in list - G.add_edges_from(zip(nodes, targets)) - # rewire edges from each node - # loop over all nodes in order (label) and neighbors in order (distance) - # no self loops or multiple edges allowed - for j in range(1, k // 2 + 1): # outer loop is neighbors - targets = nodes[j:] + nodes[0:j] # first j nodes are now last in list - # inner loop in node order - for u, v in zip(nodes, targets): - if seed.random() < p: - w = seed.choice(nodes) - # Enforce no self-loops or multiple edges - while w == u or G.has_edge(u, w): - w = seed.choice(nodes) - if G.degree(u) >= n - 1: - break # skip this rewiring - else: - G.remove_edge(u, v) - G.add_edge(u, w) - return G - - -@py_random_state(4) -def connected_watts_strogatz_graph(n, k, p, tries=100, seed=None): - """Returns a connected Watts–Strogatz small-world graph. - - Attempts to generate a connected graph by repeated generation of - Watts–Strogatz small-world graphs. An exception is raised if the maximum - number of tries is exceeded. - - Parameters - ---------- - n : int - The number of nodes - k : int - Each node is joined with its `k` nearest neighbors in a ring - topology. - p : float - The probability of rewiring each edge - tries : int - Number of attempts to generate a connected graph. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Notes - ----- - First create a ring over $n$ nodes [1]_. Then each node in the ring is joined - to its $k$ nearest neighbors (or $k - 1$ neighbors if $k$ is odd). - Then shortcuts are created by replacing some edges as follows: for each - edge $(u, v)$ in the underlying "$n$-ring with $k$ nearest neighbors" - with probability $p$ replace it with a new edge $(u, w)$ with uniformly - random choice of existing node $w$. - The entire process is repeated until a connected graph results. - - See Also - -------- - newman_watts_strogatz_graph() - watts_strogatz_graph() - - References - ---------- - .. [1] Duncan J. Watts and Steven H. Strogatz, - Collective dynamics of small-world networks, - Nature, 393, pp. 440--442, 1998. - """ - for i in range(tries): - # seed is an RNG so should change sequence each call - G = watts_strogatz_graph(n, k, p, seed) - if nx.is_connected(G): - return G - raise nx.NetworkXError('Maximum number of tries exceeded') - - -@py_random_state(2) -def random_regular_graph(d, n, seed=None): - r"""Returns a random $d$-regular graph on $n$ nodes. - - The resulting graph has no self-loops or parallel edges. - - Parameters - ---------- - d : int - The degree of each node. - n : integer - The number of nodes. The value of $n \times d$ must be even. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Notes - ----- - The nodes are numbered from $0$ to $n - 1$. - - Kim and Vu's paper [2]_ shows that this algorithm samples in an - asymptotically uniform way from the space of random graphs when - $d = O(n^{1 / 3 - \epsilon})$. - - Raises - ------ - - NetworkXError - If $n \times d$ is odd or $d$ is greater than or equal to $n$. - - References - ---------- - .. [1] A. Steger and N. Wormald, - Generating random regular graphs quickly, - Probability and Computing 8 (1999), 377-396, 1999. - http://citeseer.ist.psu.edu/steger99generating.html - - .. [2] Jeong Han Kim and Van H. Vu, - Generating random regular graphs, - Proceedings of the thirty-fifth ACM symposium on Theory of computing, - San Diego, CA, USA, pp 213--222, 2003. - http://portal.acm.org/citation.cfm?id=780542.780576 - """ - if (n * d) % 2 != 0: - raise nx.NetworkXError("n * d must be even") - - if not 0 <= d < n: - raise nx.NetworkXError("the 0 <= d < n inequality must be satisfied") - - if d == 0: - return empty_graph(n) - - def _suitable(edges, potential_edges): - # Helper subroutine to check if there are suitable edges remaining - # If False, the generation of the graph has failed - if not potential_edges: - return True - for s1 in potential_edges: - for s2 in potential_edges: - # Two iterators on the same dictionary are guaranteed - # to visit it in the same order if there are no - # intervening modifications. - if s1 == s2: - # Only need to consider s1-s2 pair one time - break - if s1 > s2: - s1, s2 = s2, s1 - if (s1, s2) not in edges: - return True - return False - - def _try_creation(): - # Attempt to create an edge set - - edges = set() - stubs = list(range(n)) * d - - while stubs: - potential_edges = defaultdict(lambda: 0) - seed.shuffle(stubs) - stubiter = iter(stubs) - for s1, s2 in zip(stubiter, stubiter): - if s1 > s2: - s1, s2 = s2, s1 - if s1 != s2 and ((s1, s2) not in edges): - edges.add((s1, s2)) - else: - potential_edges[s1] += 1 - potential_edges[s2] += 1 - - if not _suitable(edges, potential_edges): - return None # failed to find suitable edge set - - stubs = [node for node, potential in potential_edges.items() - for _ in range(potential)] - return edges - - # Even though a suitable edge set exists, - # the generation of such a set is not guaranteed. - # Try repeatedly to find one. - edges = _try_creation() - while edges is None: - edges = _try_creation() - - G = nx.Graph() - G.add_edges_from(edges) - - return G - - -def _random_subset(seq, m, rng): - """ Return m unique elements from seq. - - This differs from random.sample which can return repeated - elements if seq holds repeated elements. - - Note: rng is a random.Random or numpy.random.RandomState instance. - """ - targets = set() - while len(targets) < m: - x = rng.choice(seq) - targets.add(x) - return targets - - -@py_random_state(2) -def barabasi_albert_graph(n, m, seed=None): - """Returns a random graph according to the Barabási–Albert preferential - attachment model. - - A graph of $n$ nodes is grown by attaching new nodes each with $m$ - edges that are preferentially attached to existing nodes with high degree. - - Parameters - ---------- - n : int - Number of nodes - m : int - Number of edges to attach from a new node to existing nodes - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : Graph - - Raises - ------ - NetworkXError - If `m` does not satisfy ``1 <= m < n``. - - References - ---------- - .. [1] A. L. Barabási and R. Albert "Emergence of scaling in - random networks", Science 286, pp 509-512, 1999. - """ - - if m < 1 or m >= n: - raise nx.NetworkXError("Barabási–Albert network must have m >= 1" - " and m < n, m = %d, n = %d" % (m, n)) - - # Add m initial nodes (m0 in barabasi-speak) - G = empty_graph(m) - # Target nodes for new edges - targets = list(range(m)) - # List of existing nodes, with nodes repeated once for each adjacent edge - repeated_nodes = [] - # Start adding the other n-m nodes. The first node is m. - source = m - while source < n: - # Add edges to m nodes from the source. - G.add_edges_from(zip([source] * m, targets)) - # Add one node to the list for each new edge just created. - repeated_nodes.extend(targets) - # And the new node "source" has m edges to add to the list. - repeated_nodes.extend([source] * m) - # Now choose m unique nodes from the existing nodes - # Pick uniformly from repeated_nodes (preferential attachment) - targets = _random_subset(repeated_nodes, m, seed) - source += 1 - return G - - -@py_random_state(4) -def dual_barabasi_albert_graph(n, m1, m2, p, seed=None): - """Returns a random graph according to the dual Barabási–Albert preferential - attachment model. - - A graph of $n$ nodes is grown by attaching new nodes each with either $m_1$ - edges (with probability $p$) or $m_2$ edges (with probability $1-p$) that - are preferentially attached to existing nodes with high degree. - - Parameters - ---------- - n : int - Number of nodes - m1 : int - Number of edges to attach from a new node to existing nodes with probability $p$ - m2 : int - Number of edges to attach from a new node to existing nodes with probability $1-p$ - p : float - The probability of attaching $m_1$ edges (as opposed to $m_2$ edges) - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : Graph - - Raises - ------ - NetworkXError - If `m1` and `m2` do not satisfy ``1 <= m1,m2 < n`` or `p` does not satisfy ``0 <= p <= 1``. - - References - ---------- - .. [1] N. Moshiri "The dual-Barabasi-Albert model", arXiv:1810.10538. - """ - - if m1 < 1 or m1 >= n: - raise nx.NetworkXError("Dual Barabási–Albert network must have m1 >= 1" - " and m1 < n, m1 = %d, n = %d" % (m1, n)) - if m2 < 1 or m2 >= n: - raise nx.NetworkXError("Dual Barabási–Albert network must have m2 >= 1" - " and m2 < n, m2 = %d, n = %d" % (m2, n)) - if p < 0 or p > 1: - raise nx.NetworkXError("Dual Barabási–Albert network must have 0 <= p <= 1," - "p = %f" % p) - - # For simplicity, if p == 0 or 1, just return BA - if p == 1: - return barabasi_albert_graph(n, m1, seed) - elif p == 0: - return barabasi_albert_graph(n, m2, seed) - - # Add max(m1,m2) initial nodes (m0 in barabasi-speak) - G = empty_graph(max(m1,m2)) - # Target nodes for new edges - targets = list(range(max(m1,m2))) - # List of existing nodes, with nodes repeated once for each adjacent edge - repeated_nodes = [] - # Start adding the remaining nodes. - source = max(m1,m2) - # Pick which m to use first time (m1 or m2) - if seed.random() < p: - m = m1 - else: - m = m2 - while source < n: - # Add edges to m nodes from the source. - G.add_edges_from(zip([source] * m, targets)) - # Add one node to the list for each new edge just created. - repeated_nodes.extend(targets) - # And the new node "source" has m edges to add to the list. - repeated_nodes.extend([source] * m) - # Pick which m to use next time (m1 or m2) - if seed.random() < p: - m = m1 - else: - m = m2 - # Now choose m unique nodes from the existing nodes - # Pick uniformly from repeated_nodes (preferential attachment) - targets = _random_subset(repeated_nodes, m, seed) - source += 1 - return G - - -@py_random_state(4) -def extended_barabasi_albert_graph(n, m, p, q, seed=None): - """Returns an extended Barabási–Albert model graph. - - An extended Barabási–Albert model graph is a random graph constructed - using preferential attachment. The extended model allows new edges, - rewired edges or new nodes. Based on the probabilities $p$ and $q$ - with $p + q < 1$, the growing behavior of the graph is determined as: - - 1) With $p$ probability, $m$ new edges are added to the graph, - starting from randomly chosen existing nodes and attached preferentially at the other end. - - 2) With $q$ probability, $m$ existing edges are rewired - by randomly choosing an edge and rewiring one end to a preferentially chosen node. - - 3) With $(1 - p - q)$ probability, $m$ new nodes are added to the graph - with edges attached preferentially. - - When $p = q = 0$, the model behaves just like the Barabási–Alber mo - - Parameters - ---------- - n : int - Number of nodes - m : int - Number of edges with which a new node attaches to existing nodes - p : float - Probability value for adding an edge between existing nodes. p + q < 1 - q : float - Probability value of rewiring of existing edges. p + q < 1 - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - G : Graph - - Raises - ------ - NetworkXError - If `m` does not satisfy ``1 <= m < n`` or ``1 >= p + q`` - - References - ---------- - .. [1] Albert, R., & Barabási, A. L. (2000) - Topology of evolving networks: local events and universality - Physical review letters, 85(24), 5234. - """ - if m < 1 or m >= n: - msg = "Extended Barabasi-Albert network needs m>=1 and m= 1: - msg = "Extended Barabasi-Albert network needs p + q <= 1, p=%d, q=%d" - raise nx.NetworkXError(msg % (p, q)) - - # Add m initial nodes (m0 in barabasi-speak) - G = empty_graph(m) - - # List of nodes to represent the preferential attachment random selection. - # At the creation of the graph, all nodes are added to the list - # so that even nodes that are not connected have a chance to get selected, - # for rewiring and adding of edges. - # With each new edge, nodes at the ends of the edge are added to the list. - attachment_preference = [] - attachment_preference.extend(range(m)) - - # Start adding the other n-m nodes. The first node is m. - new_node = m - while new_node < n: - a_probability = seed.random() - - # Total number of edges of a Clique of all the nodes - clique_degree = len(G) - 1 - clique_size = (len(G) * clique_degree) / 2 - - # Adding m new edges, if there is room to add them - if a_probability < p and G.size() <= clique_size - m: - # Select the nodes where an edge can be added - elligible_nodes = [nd for nd, deg in G.degree() - if deg < clique_degree] - for i in range(m): - # Choosing a random source node from elligible_nodes - src_node = seed.choice(elligible_nodes) - - # Picking a possible node that is not 'src_node' or - # neighbor with 'src_node', with preferential attachment - prohibited_nodes = list(G[src_node]) - prohibited_nodes.append(src_node) - # This will raise an exception if the sequence is empty - dest_node = seed.choice([nd for nd in attachment_preference - if nd not in prohibited_nodes]) - # Adding the new edge - G.add_edge(src_node, dest_node) - - # Appending both nodes to add to their preferential attachment - attachment_preference.append(src_node) - attachment_preference.append(dest_node) - - # Adjusting the elligible nodes. Degree may be saturated. - if G.degree(src_node) == clique_degree: - elligible_nodes.remove(src_node) - if G.degree(dest_node) == clique_degree \ - and dest_node in elligible_nodes: - elligible_nodes.remove(dest_node) - - # Rewiring m edges, if there are enough edges - elif p <= a_probability < (p + q) and m <= G.size() < clique_size: - # Selecting nodes that have at least 1 edge but that are not - # fully connected to ALL other nodes (center of star). - # These nodes are the pivot nodes of the edges to rewire - elligible_nodes = [nd for nd, deg in G.degree() - if 0 < deg < clique_degree] - for i in range(m): - # Choosing a random source node - node = seed.choice(elligible_nodes) - - # The available nodes do have a neighbor at least. - neighbor_nodes = list(G[node]) - - # Choosing the other end that will get dettached - src_node = seed.choice(neighbor_nodes) - - # Picking a target node that is not 'node' or - # neighbor with 'node', with preferential attachment - neighbor_nodes.append(node) - dest_node = seed.choice([nd for nd in attachment_preference - if nd not in neighbor_nodes]) - # Rewire - G.remove_edge(node, src_node) - G.add_edge(node, dest_node) - - # Adjusting the preferential attachment list - attachment_preference.remove(src_node) - attachment_preference.append(dest_node) - - # Adjusting the elligible nodes. - # nodes may be saturated or isolated. - if G.degree(src_node) == 0 and src_node in elligible_nodes: - elligible_nodes.remove(src_node) - if dest_node in elligible_nodes: - if G.degree(dest_node) == clique_degree: - elligible_nodes.remove(dest_node) - else: - if G.degree(dest_node) == 1: - elligible_nodes.append(dest_node) - - # Adding new node with m edges - else: - # Select the edges' nodes by preferential attachment - targets = _random_subset(attachment_preference, m, seed) - G.add_edges_from(zip([new_node] * m, targets)) - - # Add one node to the list for each new edge just created. - attachment_preference.extend(targets) - # The new node has m edges to it, plus itself: m + 1 - attachment_preference.extend([new_node] * (m + 1)) - new_node += 1 - return G - - -@py_random_state(3) -def powerlaw_cluster_graph(n, m, p, seed=None): - """Holme and Kim algorithm for growing graphs with powerlaw - degree distribution and approximate average clustering. - - Parameters - ---------- - n : int - the number of nodes - m : int - the number of random edges to add for each new node - p : float, - Probability of adding a triangle after adding a random edge - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Notes - ----- - The average clustering has a hard time getting above a certain - cutoff that depends on `m`. This cutoff is often quite low. The - transitivity (fraction of triangles to possible triangles) seems to - decrease with network size. - - It is essentially the Barabási–Albert (BA) growth model with an - extra step that each random edge is followed by a chance of - making an edge to one of its neighbors too (and thus a triangle). - - This algorithm improves on BA in the sense that it enables a - higher average clustering to be attained if desired. - - It seems possible to have a disconnected graph with this algorithm - since the initial `m` nodes may not be all linked to a new node - on the first iteration like the BA model. - - Raises - ------ - NetworkXError - If `m` does not satisfy ``1 <= m <= n`` or `p` does not - satisfy ``0 <= p <= 1``. - - References - ---------- - .. [1] P. Holme and B. J. Kim, - "Growing scale-free networks with tunable clustering", - Phys. Rev. E, 65, 026107, 2002. - """ - - if m < 1 or n < m: - raise nx.NetworkXError( - "NetworkXError must have m>1 and m 1 or p < 0: - raise nx.NetworkXError( - "NetworkXError p must be in [0,1], p=%f" % (p)) - - G = empty_graph(m) # add m initial nodes (m0 in barabasi-speak) - repeated_nodes = list(G.nodes()) # list of existing nodes to sample from - # with nodes repeated once for each adjacent edge - source = m # next node is m - while source < n: # Now add the other n-1 nodes - possible_targets = _random_subset(repeated_nodes, m, seed) - # do one preferential attachment for new node - target = possible_targets.pop() - G.add_edge(source, target) - repeated_nodes.append(target) # add one node to list for each new link - count = 1 - while count < m: # add m-1 more new links - if seed.random() < p: # clustering step: add triangle - neighborhood = [nbr for nbr in G.neighbors(target) - if not G.has_edge(source, nbr) - and not nbr == source] - if neighborhood: # if there is a neighbor without a link - nbr = seed.choice(neighborhood) - G.add_edge(source, nbr) # add triangle - repeated_nodes.append(nbr) - count = count + 1 - continue # go to top of while loop - # else do preferential attachment step if above fails - target = possible_targets.pop() - G.add_edge(source, target) - repeated_nodes.append(target) - count = count + 1 - - repeated_nodes.extend([source] * m) # add source node to list m times - source += 1 - return G - - -@py_random_state(3) -def random_lobster(n, p1, p2, seed=None): - """Returns a random lobster graph. - - A lobster is a tree that reduces to a caterpillar when pruning all - leaf nodes. A caterpillar is a tree that reduces to a path graph - when pruning all leaf nodes; setting `p2` to zero produces a caterpillar. - - Parameters - ---------- - n : int - The expected number of nodes in the backbone - p1 : float - Probability of adding an edge to the backbone - p2 : float - Probability of adding an edge one level beyond backbone - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - """ - # a necessary ingredient in any self-respecting graph library - llen = int(2 * seed.random() * n + 0.5) - L = path_graph(llen) - # build caterpillar: add edges to path graph with probability p1 - current_node = llen - 1 - for n in range(llen): - if seed.random() < p1: # add fuzzy caterpillar parts - current_node += 1 - L.add_edge(n, current_node) - if seed.random() < p2: # add crunchy lobster bits - current_node += 1 - L.add_edge(current_node - 1, current_node) - return L # voila, un lobster! - - -@py_random_state(1) -def random_shell_graph(constructor, seed=None): - """Returns a random shell graph for the constructor given. - - Parameters - ---------- - constructor : list of three-tuples - Represents the parameters for a shell, starting at the center - shell. Each element of the list must be of the form `(n, m, - d)`, where `n` is the number of nodes in the shell, `m` is - the number of edges in the shell, and `d` is the ratio of - inter-shell (next) edges to intra-shell edges. If `d` is zero, - there will be no intra-shell edges, and if `d` is one there - will be all possible intra-shell edges. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Examples - -------- - >>> constructor = [(10, 20, 0.8), (20, 40, 0.8)] - >>> G = nx.random_shell_graph(constructor) - - """ - G = empty_graph(0) - - glist = [] - intra_edges = [] - nnodes = 0 - # create gnm graphs for each shell - for (n, m, d) in constructor: - inter_edges = int(m * d) - intra_edges.append(m - inter_edges) - g = nx.convert_node_labels_to_integers( - gnm_random_graph(n, inter_edges, seed=seed), - first_label=nnodes) - glist.append(g) - nnodes += n - G = nx.operators.union(G, g) - - # connect the shells randomly - for gi in range(len(glist) - 1): - nlist1 = list(glist[gi]) - nlist2 = list(glist[gi + 1]) - total_edges = intra_edges[gi] - edge_count = 0 - while edge_count < total_edges: - u = seed.choice(nlist1) - v = seed.choice(nlist2) - if u == v or G.has_edge(u, v): - continue - else: - G.add_edge(u, v) - edge_count = edge_count + 1 - return G - - -@py_random_state(2) -def random_powerlaw_tree(n, gamma=3, seed=None, tries=100): - """Returns a tree with a power law degree distribution. - - Parameters - ---------- - n : int - The number of nodes. - gamma : float - Exponent of the power law. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - tries : int - Number of attempts to adjust the sequence to make it a tree. - - Raises - ------ - NetworkXError - If no valid sequence is found within the maximum number of - attempts. - - Notes - ----- - A trial power law degree sequence is chosen and then elements are - swapped with new elements from a powerlaw distribution until the - sequence makes a tree (by checking, for example, that the number of - edges is one smaller than the number of nodes). - - """ - # This call may raise a NetworkXError if the number of tries is succeeded. - seq = random_powerlaw_tree_sequence(n, gamma=gamma, seed=seed, tries=tries) - G = degree_sequence_tree(seq) - return G - - -@py_random_state(2) -def random_powerlaw_tree_sequence(n, gamma=3, seed=None, tries=100): - """Returns a degree sequence for a tree with a power law distribution. - - Parameters - ---------- - n : int, - The number of nodes. - gamma : float - Exponent of the power law. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - tries : int - Number of attempts to adjust the sequence to make it a tree. - - Raises - ------ - NetworkXError - If no valid sequence is found within the maximum number of - attempts. - - Notes - ----- - A trial power law degree sequence is chosen and then elements are - swapped with new elements from a power law distribution until - the sequence makes a tree (by checking, for example, that the number of - edges is one smaller than the number of nodes). - - """ - # get trial sequence - z = nx.utils.powerlaw_sequence(n, exponent=gamma, seed=seed) - # round to integer values in the range [0,n] - zseq = [min(n, max(int(round(s)), 0)) for s in z] - - # another sequence to swap values from - z = nx.utils.powerlaw_sequence(tries, exponent=gamma, seed=seed) - # round to integer values in the range [0,n] - swap = [min(n, max(int(round(s)), 0)) for s in z] - - for deg in swap: - # If this degree sequence can be the degree sequence of a tree, return - # it. It can be a tree if the number of edges is one fewer than the - # number of nodes, or in other words, `n - sum(zseq) / 2 == 1`. We - # use an equivalent condition below that avoids floating point - # operations. - if 2 * n - sum(zseq) == 2: - return zseq - index = seed.randint(0, n - 1) - zseq[index] = swap.pop() - - raise nx.NetworkXError('Exceeded max (%d) attempts for a valid tree' - ' sequence.' % tries) - - -@py_random_state(3) -def random_kernel_graph(n, kernel_integral, kernel_root=None, seed=None): - r"""Returns an random graph based on the specified kernel. - - The algorithm chooses each of the $[n(n-1)]/2$ possible edges with - probability specified by a kernel $\kappa(x,y)$ [1]_. The kernel - $\kappa(x,y)$ must be a symmetric (in $x,y$), non-negative, - bounded function. - - Parameters - ---------- - n : int - The number of nodes - kernal_integral : function - Function that returns the definite integral of the kernel $\kappa(x,y)$, - $F(y,a,b) := \int_a^b \kappa(x,y)dx$ - kernel_root: function (optional) - Function that returns the root $b$ of the equation $F(y,a,b) = r$. - If None, the root is found using :func:`scipy.optimize.brentq` - (this requires SciPy). - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Notes - ----- - The kernel is specified through its definite integral which must be - provided as one of the arguments. If the integral and root of the - kernel integral can be found in $O(1)$ time then this algorithm runs in - time $O(n+m)$ where m is the expected number of edges [2]_. - - The nodes are set to integers from $0$ to $n-1$. - - Examples - -------- - Generate an Erdős–Rényi random graph $G(n,c/n)$, with kernel - $\kappa(x,y)=c$ where $c$ is the mean expected degree. - - >>> def integral(u, w, z): - ... return c * (z - w) - >>> def root(u, w, r): - ... return r / c + w - >>> c = 1 - >>> graph = nx.random_kernel_graph(1000, integral, root) - - See Also - -------- - gnp_random_graph - expected_degree_graph - - References - ---------- - .. [1] Bollobás, Béla, Janson, S. and Riordan, O. - "The phase transition in inhomogeneous random graphs", - *Random Structures Algorithms*, 31, 3--122, 2007. - - .. [2] Hagberg A, Lemons N (2015), - "Fast Generation of Sparse Random Kernel Graphs". - PLoS ONE 10(9): e0135177, 2015. doi:10.1371/journal.pone.0135177 - """ - if kernel_root is None: - import scipy.optimize as optimize - - def kernel_root(y, a, r): - def my_function(b): - return kernel_integral(y, a, b) - r - return optimize.brentq(my_function, a, 1) - graph = nx.Graph() - graph.add_nodes_from(range(n)) - (i, j) = (1, 1) - while i < n: - r = -math.log(1 - seed.random()) # (1-seed.random()) in (0, 1] - if kernel_integral(i / n, j / n, 1) <= r: - i, j = i + 1, i + 1 - else: - j = int(math.ceil(n * kernel_root(i / n, j / n, r))) - graph.add_edge(i - 1, j - 1) - return graph diff --git a/extensions/fablabchemnitz/networkx/generators/small.py b/extensions/fablabchemnitz/networkx/generators/small.py deleted file mode 100644 index bac92de0..00000000 --- a/extensions/fablabchemnitz/networkx/generators/small.py +++ /dev/null @@ -1,450 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Various small and named graphs, together with some compact generators. - -""" -__author__ = """Aric Hagberg (hagberg@lanl.gov)\nPieter Swart (swart@lanl.gov)""" -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. - -__all__ = ['make_small_graph', - 'LCF_graph', - 'bull_graph', - 'chvatal_graph', - 'cubical_graph', - 'desargues_graph', - 'diamond_graph', - 'dodecahedral_graph', - 'frucht_graph', - 'heawood_graph', - 'hoffman_singleton_graph', - 'house_graph', - 'house_x_graph', - 'icosahedral_graph', - 'krackhardt_kite_graph', - 'moebius_kantor_graph', - 'octahedral_graph', - 'pappus_graph', - 'petersen_graph', - 'sedgewick_maze_graph', - 'tetrahedral_graph', - 'truncated_cube_graph', - 'truncated_tetrahedron_graph', - 'tutte_graph'] - -import networkx as nx -from networkx.generators.classic import empty_graph, cycle_graph, path_graph, complete_graph -from networkx.exception import NetworkXError - -#------------------------------------------------------------------------------ -# Tools for creating small graphs -#------------------------------------------------------------------------------ - - -def make_small_undirected_graph(graph_description, create_using=None): - """ - Return a small undirected graph described by graph_description. - - See make_small_graph. - """ - G = empty_graph(0, create_using) - if G.is_directed(): - raise NetworkXError("Directed Graph not supported") - return make_small_graph(graph_description, G) - - -def make_small_graph(graph_description, create_using=None): - """ - Return the small graph described by graph_description. - - graph_description is a list of the form [ltype,name,n,xlist] - - Here ltype is one of "adjacencylist" or "edgelist", - name is the name of the graph and n the number of nodes. - This constructs a graph of n nodes with integer labels 0,..,n-1. - - If ltype="adjacencylist" then xlist is an adjacency list - with exactly n entries, in with the j'th entry (which can be empty) - specifies the nodes connected to vertex j. - e.g. the "square" graph C_4 can be obtained by - - >>> G=nx.make_small_graph(["adjacencylist","C_4",4,[[2,4],[1,3],[2,4],[1,3]]]) - - or, since we do not need to add edges twice, - - >>> G=nx.make_small_graph(["adjacencylist","C_4",4,[[2,4],[3],[4],[]]]) - - If ltype="edgelist" then xlist is an edge list - written as [[v1,w2],[v2,w2],...,[vk,wk]], - where vj and wj integers in the range 1,..,n - e.g. the "square" graph C_4 can be obtained by - - >>> G=nx.make_small_graph(["edgelist","C_4",4,[[1,2],[3,4],[2,3],[4,1]]]) - - Use the create_using argument to choose the graph class/type. - """ - ltype = graph_description[0] - name = graph_description[1] - n = graph_description[2] - - G = empty_graph(n, create_using) - nodes = G.nodes() - - if ltype == "adjacencylist": - adjlist = graph_description[3] - if len(adjlist) != n: - raise NetworkXError("invalid graph_description") - G.add_edges_from([(u - 1, v) for v in nodes for u in adjlist[v]]) - elif ltype == "edgelist": - edgelist = graph_description[3] - for e in edgelist: - v1 = e[0] - 1 - v2 = e[1] - 1 - if v1 < 0 or v1 > n - 1 or v2 < 0 or v2 > n - 1: - raise NetworkXError("invalid graph_description") - else: - G.add_edge(v1, v2) - G.name = name - return G - - -def LCF_graph(n, shift_list, repeats, create_using=None): - """ - Return the cubic graph specified in LCF notation. - - LCF notation (LCF=Lederberg-Coxeter-Fruchte) is a compressed - notation used in the generation of various cubic Hamiltonian - graphs of high symmetry. See, for example, dodecahedral_graph, - desargues_graph, heawood_graph and pappus_graph below. - - n (number of nodes) - The starting graph is the n-cycle with nodes 0,...,n-1. - (The null graph is returned if n < 0.) - - shift_list = [s1,s2,..,sk], a list of integer shifts mod n, - - repeats - integer specifying the number of times that shifts in shift_list - are successively applied to each v_current in the n-cycle - to generate an edge between v_current and v_current+shift mod n. - - For v1 cycling through the n-cycle a total of k*repeats - with shift cycling through shiftlist repeats times connect - v1 with v1+shift mod n - - The utility graph $K_{3,3}$ - - >>> G = nx.LCF_graph(6, [3, -3], 3) - - The Heawood graph - - >>> G = nx.LCF_graph(14, [5, -5], 7) - - See http://mathworld.wolfram.com/LCFNotation.html for a description - and references. - - """ - if n <= 0: - return empty_graph(0, create_using) - - # start with the n-cycle - G = cycle_graph(n, create_using) - if G.is_directed(): - raise NetworkXError("Directed Graph not supported") - G.name = "LCF_graph" - nodes = sorted(list(G)) - - n_extra_edges = repeats * len(shift_list) - # edges are added n_extra_edges times - # (not all of these need be new) - if n_extra_edges < 1: - return G - - for i in range(n_extra_edges): - shift = shift_list[i % len(shift_list)] # cycle through shift_list - v1 = nodes[i % n] # cycle repeatedly through nodes - v2 = nodes[(i + shift) % n] - G.add_edge(v1, v2) - return G - - -#------------------------------------------------------------------------------- -# Various small and named graphs -#------------------------------------------------------------------------------- - -def bull_graph(create_using=None): - """Returns the Bull graph. """ - description = [ - "adjacencylist", - "Bull Graph", - 5, - [[2, 3], [1, 3, 4], [1, 2, 5], [2], [3]] - ] - G = make_small_undirected_graph(description, create_using) - return G - - -def chvatal_graph(create_using=None): - """Returns the Chvátal graph.""" - description = [ - "adjacencylist", - "Chvatal Graph", - 12, - [[2, 5, 7, 10], [3, 6, 8], [4, 7, 9], [5, 8, 10], - [6, 9], [11, 12], [11, 12], [9, 12], - [11], [11, 12], [], []] - ] - G = make_small_undirected_graph(description, create_using) - return G - - -def cubical_graph(create_using=None): - """Returns the 3-regular Platonic Cubical graph.""" - description = [ - "adjacencylist", - "Platonic Cubical Graph", - 8, - [[2, 4, 5], [1, 3, 8], [2, 4, 7], [1, 3, 6], - [1, 6, 8], [4, 5, 7], [3, 6, 8], [2, 5, 7]] - ] - G = make_small_undirected_graph(description, create_using) - return G - - -def desargues_graph(create_using=None): - """ Return the Desargues graph.""" - G = LCF_graph(20, [5, -5, 9, -9], 5, create_using) - G.name = "Desargues Graph" - return G - - -def diamond_graph(create_using=None): - """Returns the Diamond graph. """ - description = [ - "adjacencylist", - "Diamond Graph", - 4, - [[2, 3], [1, 3, 4], [1, 2, 4], [2, 3]] - ] - G = make_small_undirected_graph(description, create_using) - return G - - -def dodecahedral_graph(create_using=None): - """ Return the Platonic Dodecahedral graph. """ - G = LCF_graph(20, [10, 7, 4, -4, -7, 10, -4, 7, -7, 4], 2, create_using) - G.name = "Dodecahedral Graph" - return G - - -def frucht_graph(create_using=None): - """Returns the Frucht Graph. - - The Frucht Graph is the smallest cubical graph whose - automorphism group consists only of the identity element. - - """ - G = cycle_graph(7, create_using) - G.add_edges_from([[0, 7], [1, 7], [2, 8], [3, 9], [4, 9], [5, 10], [6, 10], - [7, 11], [8, 11], [8, 9], [10, 11]]) - - G.name = "Frucht Graph" - return G - - -def heawood_graph(create_using=None): - """ Return the Heawood graph, a (3,6) cage. """ - G = LCF_graph(14, [5, -5], 7, create_using) - G.name = "Heawood Graph" - return G - - -def hoffman_singleton_graph(): - '''Return the Hoffman-Singleton Graph.''' - G = nx.Graph() - for i in range(5): - for j in range(5): - G.add_edge(('pentagon', i, j), ('pentagon', i, (j - 1) % 5)) - G.add_edge(('pentagon', i, j), ('pentagon', i, (j + 1) % 5)) - G.add_edge(('pentagram', i, j), ('pentagram', i, (j - 2) % 5)) - G.add_edge(('pentagram', i, j), ('pentagram', i, (j + 2) % 5)) - for k in range(5): - G.add_edge(('pentagon', i, j), - ('pentagram', k, (i * k + j) % 5)) - G = nx.convert_node_labels_to_integers(G) - G.name = 'Hoffman-Singleton Graph' - return G - - -def house_graph(create_using=None): - """Returns the House graph (square with triangle on top).""" - description = [ - "adjacencylist", - "House Graph", - 5, - [[2, 3], [1, 4], [1, 4, 5], [2, 3, 5], [3, 4]] - ] - G = make_small_undirected_graph(description, create_using) - return G - - -def house_x_graph(create_using=None): - """Returns the House graph with a cross inside the house square.""" - description = [ - "adjacencylist", - "House-with-X-inside Graph", - 5, - [[2, 3, 4], [1, 3, 4], [1, 2, 4, 5], [1, 2, 3, 5], [3, 4]] - ] - G = make_small_undirected_graph(description, create_using) - return G - - -def icosahedral_graph(create_using=None): - """Returns the Platonic Icosahedral graph.""" - description = [ - "adjacencylist", - "Platonic Icosahedral Graph", - 12, - [[2, 6, 8, 9, 12], [3, 6, 7, 9], [4, 7, 9, 10], [5, 7, 10, 11], - [6, 7, 11, 12], [7, 12], [], [9, 10, 11, 12], - [10], [11], [12], []] - ] - G = make_small_undirected_graph(description, create_using) - return G - - -def krackhardt_kite_graph(create_using=None): - """ - Return the Krackhardt Kite Social Network. - - A 10 actor social network introduced by David Krackhardt - to illustrate: degree, betweenness, centrality, closeness, etc. - The traditional labeling is: - Andre=1, Beverley=2, Carol=3, Diane=4, - Ed=5, Fernando=6, Garth=7, Heather=8, Ike=9, Jane=10. - - """ - description = [ - "adjacencylist", - "Krackhardt Kite Social Network", - 10, - [[2, 3, 4, 6], [1, 4, 5, 7], [1, 4, 6], [1, 2, 3, 5, 6, 7], [2, 4, 7], - [1, 3, 4, 7, 8], [2, 4, 5, 6, 8], [6, 7, 9], [8, 10], [9]] - ] - G = make_small_undirected_graph(description, create_using) - return G - - -def moebius_kantor_graph(create_using=None): - """Returns the Moebius-Kantor graph.""" - G = LCF_graph(16, [5, -5], 8, create_using) - G.name = "Moebius-Kantor Graph" - return G - - -def octahedral_graph(create_using=None): - """Returns the Platonic Octahedral graph.""" - description = [ - "adjacencylist", - "Platonic Octahedral Graph", - 6, - [[2, 3, 4, 5], [3, 4, 6], [5, 6], [5, 6], [6], []] - ] - G = make_small_undirected_graph(description, create_using) - return G - - -def pappus_graph(): - """ Return the Pappus graph.""" - G = LCF_graph(18, [5, 7, -7, 7, -7, -5], 3) - G.name = "Pappus Graph" - return G - - -def petersen_graph(create_using=None): - """Returns the Petersen graph.""" - description = [ - "adjacencylist", - "Petersen Graph", - 10, - [[2, 5, 6], [1, 3, 7], [2, 4, 8], [3, 5, 9], [4, 1, 10], [1, 8, 9], [2, 9, 10], - [3, 6, 10], [4, 6, 7], [5, 7, 8]] - ] - G = make_small_undirected_graph(description, create_using) - return G - - -def sedgewick_maze_graph(create_using=None): - """ - Return a small maze with a cycle. - - This is the maze used in Sedgewick,3rd Edition, Part 5, Graph - Algorithms, Chapter 18, e.g. Figure 18.2 and following. - Nodes are numbered 0,..,7 - """ - G = empty_graph(0, create_using) - G.add_nodes_from(range(8)) - G.add_edges_from([[0, 2], [0, 7], [0, 5]]) - G.add_edges_from([[1, 7], [2, 6]]) - G.add_edges_from([[3, 4], [3, 5]]) - G.add_edges_from([[4, 5], [4, 7], [4, 6]]) - G.name = "Sedgewick Maze" - return G - - -def tetrahedral_graph(create_using=None): - """ Return the 3-regular Platonic Tetrahedral graph.""" - G = complete_graph(4, create_using) - G.name = "Platonic Tetrahedral graph" - return G - - -def truncated_cube_graph(create_using=None): - """Returns the skeleton of the truncated cube.""" - description = [ - "adjacencylist", - "Truncated Cube Graph", - 24, - [[2, 3, 5], [12, 15], [4, 5], [7, 9], - [6], [17, 19], [8, 9], [11, 13], - [10], [18, 21], [12, 13], [15], - [14], [22, 23], [16], [20, 24], - [18, 19], [21], [20], [24], - [22], [23], [24], []] - ] - G = make_small_undirected_graph(description, create_using) - return G - - -def truncated_tetrahedron_graph(create_using=None): - """Returns the skeleton of the truncated Platonic tetrahedron.""" - G = path_graph(12, create_using) -# G.add_edges_from([(1,3),(1,10),(2,7),(4,12),(5,12),(6,8),(9,11)]) - G.add_edges_from([(0, 2), (0, 9), (1, 6), (3, 11), (4, 11), (5, 7), (8, 10)]) - G.name = "Truncated Tetrahedron Graph" - return G - - -def tutte_graph(create_using=None): - """Returns the Tutte graph.""" - description = [ - "adjacencylist", - "Tutte's Graph", - 46, - [[2, 3, 4], [5, 27], [11, 12], [19, 20], [6, 34], - [7, 30], [8, 28], [9, 15], [10, 39], [11, 38], - [40], [13, 40], [14, 36], [15, 16], [35], - [17, 23], [18, 45], [19, 44], [46], [21, 46], - [22, 42], [23, 24], [41], [25, 28], [26, 33], - [27, 32], [34], [29], [30, 33], [31], - [32, 34], [33], [], [], [36, 39], - [37], [38, 40], [39], [], [], - [42, 45], [43], [44, 46], [45], [], []] - ] - G = make_small_undirected_graph(description, create_using) - return G diff --git a/extensions/fablabchemnitz/networkx/generators/social.py b/extensions/fablabchemnitz/networkx/generators/social.py deleted file mode 100644 index 0c7934eb..00000000 --- a/extensions/fablabchemnitz/networkx/generators/social.py +++ /dev/null @@ -1,537 +0,0 @@ -""" -Famous social networks. -""" -import networkx as nx -__author__ = """\n""".join(['Jordi Torrents ', - 'Katy Bold ', - 'Aric Hagberg ']) - -__all__ = ['karate_club_graph', 'davis_southern_women_graph', - 'florentine_families_graph', 'les_miserables_graph'] - - -def karate_club_graph(): - """Returns Zachary's Karate Club graph. - - Each node in the returned graph has a node attribute 'club' that - indicates the name of the club to which the member represented by that node - belongs, either 'Mr. Hi' or 'Officer'. - - Examples - -------- - To get the name of the club to which a node belongs:: - - >>> import networkx as nx - >>> G = nx.karate_club_graph() - >>> G.nodes[5]['club'] - 'Mr. Hi' - >>> G.nodes[9]['club'] - 'Officer' - - References - ---------- - .. [1] Zachary, Wayne W. - "An Information Flow Model for Conflict and Fission in Small Groups." - *Journal of Anthropological Research*, 33, 452--473, (1977). - - .. [2] Data file from: - http://vlado.fmf.uni-lj.si/pub/networks/data/Ucinet/UciData.htm - """ - # Create the set of all members, and the members of each club. - all_members = set(range(34)) - club1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 16, 17, 19, 21} - # club2 = all_members - club1 - - G = nx.Graph() - G.add_nodes_from(all_members) - G.name = "Zachary's Karate Club" - - zacharydat = """\ -0 1 1 1 1 1 1 1 1 0 1 1 1 1 0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 -1 0 1 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 -1 1 0 1 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 -1 1 1 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 -0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 0 1 1 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 -0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 -0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 -0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 1 -0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 -1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1 0 0 0 1 1 -0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 1 0 0 1 0 1 0 1 1 0 0 0 0 0 1 1 1 0 1 -0 0 0 0 0 0 0 0 1 1 0 0 0 1 1 1 0 0 1 1 1 0 1 1 0 0 1 1 1 1 1 1 1 0""" - - for row, line in enumerate(zacharydat.split('\n')): - thisrow = [int(b) for b in line.split()] - for col, entry in enumerate(thisrow): - if entry == 1: - G.add_edge(row, col) - - # Add the name of each member's club as a node attribute. - for v in G: - G.nodes[v]['club'] = 'Mr. Hi' if v in club1 else 'Officer' - return G - - -def davis_southern_women_graph(): - """Returns Davis Southern women social network. - - This is a bipartite graph. - - References - ---------- - .. [1] A. Davis, Gardner, B. B., Gardner, M. R., 1941. Deep South. - University of Chicago Press, Chicago, IL. - """ - G = nx.Graph() - # Top nodes - women = ["Evelyn Jefferson", - "Laura Mandeville", - "Theresa Anderson", - "Brenda Rogers", - "Charlotte McDowd", - "Frances Anderson", - "Eleanor Nye", - "Pearl Oglethorpe", - "Ruth DeSand", - "Verne Sanderson", - "Myra Liddel", - "Katherina Rogers", - "Sylvia Avondale", - "Nora Fayette", - "Helen Lloyd", - "Dorothy Murchison", - "Olivia Carleton", - "Flora Price"] - G.add_nodes_from(women, bipartite=0) - # Bottom nodes - events = ["E1", - "E2", - "E3", - "E4", - "E5", - "E6", - "E7", - "E8", - "E9", - "E10", - "E11", - "E12", - "E13", - "E14"] - G.add_nodes_from(events, bipartite=1) - - G.add_edges_from([("Evelyn Jefferson", "E1"), - ("Evelyn Jefferson", "E2"), - ("Evelyn Jefferson", "E3"), - ("Evelyn Jefferson", "E4"), - ("Evelyn Jefferson", "E5"), - ("Evelyn Jefferson", "E6"), - ("Evelyn Jefferson", "E8"), - ("Evelyn Jefferson", "E9"), - ("Laura Mandeville", "E1"), - ("Laura Mandeville", "E2"), - ("Laura Mandeville", "E3"), - ("Laura Mandeville", "E5"), - ("Laura Mandeville", "E6"), - ("Laura Mandeville", "E7"), - ("Laura Mandeville", "E8"), - ("Theresa Anderson", "E2"), - ("Theresa Anderson", "E3"), - ("Theresa Anderson", "E4"), - ("Theresa Anderson", "E5"), - ("Theresa Anderson", "E6"), - ("Theresa Anderson", "E7"), - ("Theresa Anderson", "E8"), - ("Theresa Anderson", "E9"), - ("Brenda Rogers", "E1"), - ("Brenda Rogers", "E3"), - ("Brenda Rogers", "E4"), - ("Brenda Rogers", "E5"), - ("Brenda Rogers", "E6"), - ("Brenda Rogers", "E7"), - ("Brenda Rogers", "E8"), - ("Charlotte McDowd", "E3"), - ("Charlotte McDowd", "E4"), - ("Charlotte McDowd", "E5"), - ("Charlotte McDowd", "E7"), - ("Frances Anderson", "E3"), - ("Frances Anderson", "E5"), - ("Frances Anderson", "E6"), - ("Frances Anderson", "E8"), - ("Eleanor Nye", "E5"), - ("Eleanor Nye", "E6"), - ("Eleanor Nye", "E7"), - ("Eleanor Nye", "E8"), - ("Pearl Oglethorpe", "E6"), - ("Pearl Oglethorpe", "E8"), - ("Pearl Oglethorpe", "E9"), - ("Ruth DeSand", "E5"), - ("Ruth DeSand", "E7"), - ("Ruth DeSand", "E8"), - ("Ruth DeSand", "E9"), - ("Verne Sanderson", "E7"), - ("Verne Sanderson", "E8"), - ("Verne Sanderson", "E9"), - ("Verne Sanderson", "E12"), - ("Myra Liddel", "E8"), - ("Myra Liddel", "E9"), - ("Myra Liddel", "E10"), - ("Myra Liddel", "E12"), - ("Katherina Rogers", "E8"), - ("Katherina Rogers", "E9"), - ("Katherina Rogers", "E10"), - ("Katherina Rogers", "E12"), - ("Katherina Rogers", "E13"), - ("Katherina Rogers", "E14"), - ("Sylvia Avondale", "E7"), - ("Sylvia Avondale", "E8"), - ("Sylvia Avondale", "E9"), - ("Sylvia Avondale", "E10"), - ("Sylvia Avondale", "E12"), - ("Sylvia Avondale", "E13"), - ("Sylvia Avondale", "E14"), - ("Nora Fayette", "E6"), - ("Nora Fayette", "E7"), - ("Nora Fayette", "E9"), - ("Nora Fayette", "E10"), - ("Nora Fayette", "E11"), - ("Nora Fayette", "E12"), - ("Nora Fayette", "E13"), - ("Nora Fayette", "E14"), - ("Helen Lloyd", "E7"), - ("Helen Lloyd", "E8"), - ("Helen Lloyd", "E10"), - ("Helen Lloyd", "E11"), - ("Helen Lloyd", "E12"), - ("Dorothy Murchison", "E8"), - ("Dorothy Murchison", "E9"), - ("Olivia Carleton", "E9"), - ("Olivia Carleton", "E11"), - ("Flora Price", "E9"), - ("Flora Price", "E11")]) - G.graph['top'] = women - G.graph['bottom'] = events - return G - - -def florentine_families_graph(): - """Returns Florentine families graph. - - References - ---------- - .. [1] Ronald L. Breiger and Philippa E. Pattison - Cumulated social roles: The duality of persons and their algebras,1 - Social Networks, Volume 8, Issue 3, September 1986, Pages 215-256 - """ - G = nx.Graph() - G.add_edge('Acciaiuoli', 'Medici') - G.add_edge('Castellani', 'Peruzzi') - G.add_edge('Castellani', 'Strozzi') - G.add_edge('Castellani', 'Barbadori') - G.add_edge('Medici', 'Barbadori') - G.add_edge('Medici', 'Ridolfi') - G.add_edge('Medici', 'Tornabuoni') - G.add_edge('Medici', 'Albizzi') - G.add_edge('Medici', 'Salviati') - G.add_edge('Salviati', 'Pazzi') - G.add_edge('Peruzzi', 'Strozzi') - G.add_edge('Peruzzi', 'Bischeri') - G.add_edge('Strozzi', 'Ridolfi') - G.add_edge('Strozzi', 'Bischeri') - G.add_edge('Ridolfi', 'Tornabuoni') - G.add_edge('Tornabuoni', 'Guadagni') - G.add_edge('Albizzi', 'Ginori') - G.add_edge('Albizzi', 'Guadagni') - G.add_edge('Bischeri', 'Guadagni') - G.add_edge('Guadagni', 'Lamberteschi') - return G - - -def les_miserables_graph(): - """Returns coappearance network of characters in the novel Les Miserables. - - References - ---------- - .. [1] D. E. Knuth, 1993. - The Stanford GraphBase: a platform for combinatorial computing, - pp. 74-87. New York: AcM Press. - """ - G = nx.Graph() - G.add_edge('Napoleon', 'Myriel', weight=1) - G.add_edge('MlleBaptistine', 'Myriel', weight=8) - G.add_edge('MmeMagloire', 'Myriel', weight=10) - G.add_edge('MmeMagloire', 'MlleBaptistine', weight=6) - G.add_edge('CountessDeLo', 'Myriel', weight=1) - G.add_edge('Geborand', 'Myriel', weight=1) - G.add_edge('Champtercier', 'Myriel', weight=1) - G.add_edge('Cravatte', 'Myriel', weight=1) - G.add_edge('Count', 'Myriel', weight=2) - G.add_edge('OldMan', 'Myriel', weight=1) - G.add_edge('Valjean', 'Labarre', weight=1) - G.add_edge('Valjean', 'MmeMagloire', weight=3) - G.add_edge('Valjean', 'MlleBaptistine', weight=3) - G.add_edge('Valjean', 'Myriel', weight=5) - G.add_edge('Marguerite', 'Valjean', weight=1) - G.add_edge('MmeDeR', 'Valjean', weight=1) - G.add_edge('Isabeau', 'Valjean', weight=1) - G.add_edge('Gervais', 'Valjean', weight=1) - G.add_edge('Listolier', 'Tholomyes', weight=4) - G.add_edge('Fameuil', 'Tholomyes', weight=4) - G.add_edge('Fameuil', 'Listolier', weight=4) - G.add_edge('Blacheville', 'Tholomyes', weight=4) - G.add_edge('Blacheville', 'Listolier', weight=4) - G.add_edge('Blacheville', 'Fameuil', weight=4) - G.add_edge('Favourite', 'Tholomyes', weight=3) - G.add_edge('Favourite', 'Listolier', weight=3) - G.add_edge('Favourite', 'Fameuil', weight=3) - G.add_edge('Favourite', 'Blacheville', weight=4) - G.add_edge('Dahlia', 'Tholomyes', weight=3) - G.add_edge('Dahlia', 'Listolier', weight=3) - G.add_edge('Dahlia', 'Fameuil', weight=3) - G.add_edge('Dahlia', 'Blacheville', weight=3) - G.add_edge('Dahlia', 'Favourite', weight=5) - G.add_edge('Zephine', 'Tholomyes', weight=3) - G.add_edge('Zephine', 'Listolier', weight=3) - G.add_edge('Zephine', 'Fameuil', weight=3) - G.add_edge('Zephine', 'Blacheville', weight=3) - G.add_edge('Zephine', 'Favourite', weight=4) - G.add_edge('Zephine', 'Dahlia', weight=4) - G.add_edge('Fantine', 'Tholomyes', weight=3) - G.add_edge('Fantine', 'Listolier', weight=3) - G.add_edge('Fantine', 'Fameuil', weight=3) - G.add_edge('Fantine', 'Blacheville', weight=3) - G.add_edge('Fantine', 'Favourite', weight=4) - G.add_edge('Fantine', 'Dahlia', weight=4) - G.add_edge('Fantine', 'Zephine', weight=4) - G.add_edge('Fantine', 'Marguerite', weight=2) - G.add_edge('Fantine', 'Valjean', weight=9) - G.add_edge('MmeThenardier', 'Fantine', weight=2) - G.add_edge('MmeThenardier', 'Valjean', weight=7) - G.add_edge('Thenardier', 'MmeThenardier', weight=13) - G.add_edge('Thenardier', 'Fantine', weight=1) - G.add_edge('Thenardier', 'Valjean', weight=12) - G.add_edge('Cosette', 'MmeThenardier', weight=4) - G.add_edge('Cosette', 'Valjean', weight=31) - G.add_edge('Cosette', 'Tholomyes', weight=1) - G.add_edge('Cosette', 'Thenardier', weight=1) - G.add_edge('Javert', 'Valjean', weight=17) - G.add_edge('Javert', 'Fantine', weight=5) - G.add_edge('Javert', 'Thenardier', weight=5) - G.add_edge('Javert', 'MmeThenardier', weight=1) - G.add_edge('Javert', 'Cosette', weight=1) - G.add_edge('Fauchelevent', 'Valjean', weight=8) - G.add_edge('Fauchelevent', 'Javert', weight=1) - G.add_edge('Bamatabois', 'Fantine', weight=1) - G.add_edge('Bamatabois', 'Javert', weight=1) - G.add_edge('Bamatabois', 'Valjean', weight=2) - G.add_edge('Perpetue', 'Fantine', weight=1) - G.add_edge('Simplice', 'Perpetue', weight=2) - G.add_edge('Simplice', 'Valjean', weight=3) - G.add_edge('Simplice', 'Fantine', weight=2) - G.add_edge('Simplice', 'Javert', weight=1) - G.add_edge('Scaufflaire', 'Valjean', weight=1) - G.add_edge('Woman1', 'Valjean', weight=2) - G.add_edge('Woman1', 'Javert', weight=1) - G.add_edge('Judge', 'Valjean', weight=3) - G.add_edge('Judge', 'Bamatabois', weight=2) - G.add_edge('Champmathieu', 'Valjean', weight=3) - G.add_edge('Champmathieu', 'Judge', weight=3) - G.add_edge('Champmathieu', 'Bamatabois', weight=2) - G.add_edge('Brevet', 'Judge', weight=2) - G.add_edge('Brevet', 'Champmathieu', weight=2) - G.add_edge('Brevet', 'Valjean', weight=2) - G.add_edge('Brevet', 'Bamatabois', weight=1) - G.add_edge('Chenildieu', 'Judge', weight=2) - G.add_edge('Chenildieu', 'Champmathieu', weight=2) - G.add_edge('Chenildieu', 'Brevet', weight=2) - G.add_edge('Chenildieu', 'Valjean', weight=2) - G.add_edge('Chenildieu', 'Bamatabois', weight=1) - G.add_edge('Cochepaille', 'Judge', weight=2) - G.add_edge('Cochepaille', 'Champmathieu', weight=2) - G.add_edge('Cochepaille', 'Brevet', weight=2) - G.add_edge('Cochepaille', 'Chenildieu', weight=2) - G.add_edge('Cochepaille', 'Valjean', weight=2) - G.add_edge('Cochepaille', 'Bamatabois', weight=1) - G.add_edge('Pontmercy', 'Thenardier', weight=1) - G.add_edge('Boulatruelle', 'Thenardier', weight=1) - G.add_edge('Eponine', 'MmeThenardier', weight=2) - G.add_edge('Eponine', 'Thenardier', weight=3) - G.add_edge('Anzelma', 'Eponine', weight=2) - G.add_edge('Anzelma', 'Thenardier', weight=2) - G.add_edge('Anzelma', 'MmeThenardier', weight=1) - G.add_edge('Woman2', 'Valjean', weight=3) - G.add_edge('Woman2', 'Cosette', weight=1) - G.add_edge('Woman2', 'Javert', weight=1) - G.add_edge('MotherInnocent', 'Fauchelevent', weight=3) - G.add_edge('MotherInnocent', 'Valjean', weight=1) - G.add_edge('Gribier', 'Fauchelevent', weight=2) - G.add_edge('MmeBurgon', 'Jondrette', weight=1) - G.add_edge('Gavroche', 'MmeBurgon', weight=2) - G.add_edge('Gavroche', 'Thenardier', weight=1) - G.add_edge('Gavroche', 'Javert', weight=1) - G.add_edge('Gavroche', 'Valjean', weight=1) - G.add_edge('Gillenormand', 'Cosette', weight=3) - G.add_edge('Gillenormand', 'Valjean', weight=2) - G.add_edge('Magnon', 'Gillenormand', weight=1) - G.add_edge('Magnon', 'MmeThenardier', weight=1) - G.add_edge('MlleGillenormand', 'Gillenormand', weight=9) - G.add_edge('MlleGillenormand', 'Cosette', weight=2) - G.add_edge('MlleGillenormand', 'Valjean', weight=2) - G.add_edge('MmePontmercy', 'MlleGillenormand', weight=1) - G.add_edge('MmePontmercy', 'Pontmercy', weight=1) - G.add_edge('MlleVaubois', 'MlleGillenormand', weight=1) - G.add_edge('LtGillenormand', 'MlleGillenormand', weight=2) - G.add_edge('LtGillenormand', 'Gillenormand', weight=1) - G.add_edge('LtGillenormand', 'Cosette', weight=1) - G.add_edge('Marius', 'MlleGillenormand', weight=6) - G.add_edge('Marius', 'Gillenormand', weight=12) - G.add_edge('Marius', 'Pontmercy', weight=1) - G.add_edge('Marius', 'LtGillenormand', weight=1) - G.add_edge('Marius', 'Cosette', weight=21) - G.add_edge('Marius', 'Valjean', weight=19) - G.add_edge('Marius', 'Tholomyes', weight=1) - G.add_edge('Marius', 'Thenardier', weight=2) - G.add_edge('Marius', 'Eponine', weight=5) - G.add_edge('Marius', 'Gavroche', weight=4) - G.add_edge('BaronessT', 'Gillenormand', weight=1) - G.add_edge('BaronessT', 'Marius', weight=1) - G.add_edge('Mabeuf', 'Marius', weight=1) - G.add_edge('Mabeuf', 'Eponine', weight=1) - G.add_edge('Mabeuf', 'Gavroche', weight=1) - G.add_edge('Enjolras', 'Marius', weight=7) - G.add_edge('Enjolras', 'Gavroche', weight=7) - G.add_edge('Enjolras', 'Javert', weight=6) - G.add_edge('Enjolras', 'Mabeuf', weight=1) - G.add_edge('Enjolras', 'Valjean', weight=4) - G.add_edge('Combeferre', 'Enjolras', weight=15) - G.add_edge('Combeferre', 'Marius', weight=5) - G.add_edge('Combeferre', 'Gavroche', weight=6) - G.add_edge('Combeferre', 'Mabeuf', weight=2) - G.add_edge('Prouvaire', 'Gavroche', weight=1) - G.add_edge('Prouvaire', 'Enjolras', weight=4) - G.add_edge('Prouvaire', 'Combeferre', weight=2) - G.add_edge('Feuilly', 'Gavroche', weight=2) - G.add_edge('Feuilly', 'Enjolras', weight=6) - G.add_edge('Feuilly', 'Prouvaire', weight=2) - G.add_edge('Feuilly', 'Combeferre', weight=5) - G.add_edge('Feuilly', 'Mabeuf', weight=1) - G.add_edge('Feuilly', 'Marius', weight=1) - G.add_edge('Courfeyrac', 'Marius', weight=9) - G.add_edge('Courfeyrac', 'Enjolras', weight=17) - G.add_edge('Courfeyrac', 'Combeferre', weight=13) - G.add_edge('Courfeyrac', 'Gavroche', weight=7) - G.add_edge('Courfeyrac', 'Mabeuf', weight=2) - G.add_edge('Courfeyrac', 'Eponine', weight=1) - G.add_edge('Courfeyrac', 'Feuilly', weight=6) - G.add_edge('Courfeyrac', 'Prouvaire', weight=3) - G.add_edge('Bahorel', 'Combeferre', weight=5) - G.add_edge('Bahorel', 'Gavroche', weight=5) - G.add_edge('Bahorel', 'Courfeyrac', weight=6) - G.add_edge('Bahorel', 'Mabeuf', weight=2) - G.add_edge('Bahorel', 'Enjolras', weight=4) - G.add_edge('Bahorel', 'Feuilly', weight=3) - G.add_edge('Bahorel', 'Prouvaire', weight=2) - G.add_edge('Bahorel', 'Marius', weight=1) - G.add_edge('Bossuet', 'Marius', weight=5) - G.add_edge('Bossuet', 'Courfeyrac', weight=12) - G.add_edge('Bossuet', 'Gavroche', weight=5) - G.add_edge('Bossuet', 'Bahorel', weight=4) - G.add_edge('Bossuet', 'Enjolras', weight=10) - G.add_edge('Bossuet', 'Feuilly', weight=6) - G.add_edge('Bossuet', 'Prouvaire', weight=2) - G.add_edge('Bossuet', 'Combeferre', weight=9) - G.add_edge('Bossuet', 'Mabeuf', weight=1) - G.add_edge('Bossuet', 'Valjean', weight=1) - G.add_edge('Joly', 'Bahorel', weight=5) - G.add_edge('Joly', 'Bossuet', weight=7) - G.add_edge('Joly', 'Gavroche', weight=3) - G.add_edge('Joly', 'Courfeyrac', weight=5) - G.add_edge('Joly', 'Enjolras', weight=5) - G.add_edge('Joly', 'Feuilly', weight=5) - G.add_edge('Joly', 'Prouvaire', weight=2) - G.add_edge('Joly', 'Combeferre', weight=5) - G.add_edge('Joly', 'Mabeuf', weight=1) - G.add_edge('Joly', 'Marius', weight=2) - G.add_edge('Grantaire', 'Bossuet', weight=3) - G.add_edge('Grantaire', 'Enjolras', weight=3) - G.add_edge('Grantaire', 'Combeferre', weight=1) - G.add_edge('Grantaire', 'Courfeyrac', weight=2) - G.add_edge('Grantaire', 'Joly', weight=2) - G.add_edge('Grantaire', 'Gavroche', weight=1) - G.add_edge('Grantaire', 'Bahorel', weight=1) - G.add_edge('Grantaire', 'Feuilly', weight=1) - G.add_edge('Grantaire', 'Prouvaire', weight=1) - G.add_edge('MotherPlutarch', 'Mabeuf', weight=3) - G.add_edge('Gueulemer', 'Thenardier', weight=5) - G.add_edge('Gueulemer', 'Valjean', weight=1) - G.add_edge('Gueulemer', 'MmeThenardier', weight=1) - G.add_edge('Gueulemer', 'Javert', weight=1) - G.add_edge('Gueulemer', 'Gavroche', weight=1) - G.add_edge('Gueulemer', 'Eponine', weight=1) - G.add_edge('Babet', 'Thenardier', weight=6) - G.add_edge('Babet', 'Gueulemer', weight=6) - G.add_edge('Babet', 'Valjean', weight=1) - G.add_edge('Babet', 'MmeThenardier', weight=1) - G.add_edge('Babet', 'Javert', weight=2) - G.add_edge('Babet', 'Gavroche', weight=1) - G.add_edge('Babet', 'Eponine', weight=1) - G.add_edge('Claquesous', 'Thenardier', weight=4) - G.add_edge('Claquesous', 'Babet', weight=4) - G.add_edge('Claquesous', 'Gueulemer', weight=4) - G.add_edge('Claquesous', 'Valjean', weight=1) - G.add_edge('Claquesous', 'MmeThenardier', weight=1) - G.add_edge('Claquesous', 'Javert', weight=1) - G.add_edge('Claquesous', 'Eponine', weight=1) - G.add_edge('Claquesous', 'Enjolras', weight=1) - G.add_edge('Montparnasse', 'Javert', weight=1) - G.add_edge('Montparnasse', 'Babet', weight=2) - G.add_edge('Montparnasse', 'Gueulemer', weight=2) - G.add_edge('Montparnasse', 'Claquesous', weight=2) - G.add_edge('Montparnasse', 'Valjean', weight=1) - G.add_edge('Montparnasse', 'Gavroche', weight=1) - G.add_edge('Montparnasse', 'Eponine', weight=1) - G.add_edge('Montparnasse', 'Thenardier', weight=1) - G.add_edge('Toussaint', 'Cosette', weight=2) - G.add_edge('Toussaint', 'Javert', weight=1) - G.add_edge('Toussaint', 'Valjean', weight=1) - G.add_edge('Child1', 'Gavroche', weight=2) - G.add_edge('Child2', 'Gavroche', weight=2) - G.add_edge('Child2', 'Child1', weight=3) - G.add_edge('Brujon', 'Babet', weight=3) - G.add_edge('Brujon', 'Gueulemer', weight=3) - G.add_edge('Brujon', 'Thenardier', weight=3) - G.add_edge('Brujon', 'Gavroche', weight=1) - G.add_edge('Brujon', 'Eponine', weight=1) - G.add_edge('Brujon', 'Claquesous', weight=1) - G.add_edge('Brujon', 'Montparnasse', weight=1) - G.add_edge('MmeHucheloup', 'Bossuet', weight=1) - G.add_edge('MmeHucheloup', 'Joly', weight=1) - G.add_edge('MmeHucheloup', 'Grantaire', weight=1) - G.add_edge('MmeHucheloup', 'Bahorel', weight=1) - G.add_edge('MmeHucheloup', 'Courfeyrac', weight=1) - G.add_edge('MmeHucheloup', 'Gavroche', weight=1) - G.add_edge('MmeHucheloup', 'Enjolras', weight=1) - return G diff --git a/extensions/fablabchemnitz/networkx/generators/spectral_graph_forge.py b/extensions/fablabchemnitz/networkx/generators/spectral_graph_forge.py deleted file mode 100644 index af470b42..00000000 --- a/extensions/fablabchemnitz/networkx/generators/spectral_graph_forge.py +++ /dev/null @@ -1,203 +0,0 @@ -# Copyright (C) 2017-2019 by -# Luca Baldesi -# BSD license. -# -# Author: Luca Baldesi (luca.baldesi@unitn.it) -"""Generates graphs with a given eigenvector structure""" - - -import networkx as nx -from networkx.utils import np_random_state - -__all__ = ['spectral_graph_forge'] - - -def _truncate(x): - """ Returns the truncated value of x in the interval [0,1] - """ - - if x < 0: - return 0 - if x > 1: - return 1 - return x - - -def _mat_spect_approx(A, level, sorteigs=True, reverse=False, absolute=True): - """ Returns the low-rank approximation of the given matrix A - - Parameters - ---------- - A : numpy matrix - level : integer - It represents the fixed rank for the output approximation matrix - sorteigs : boolean - Whether eigenvectors should be sorted according to their associated - eigenvalues before removing the firsts of them - reverse : boolean - Whether eigenvectors list should be reversed before removing the firsts - of them - absolute : boolean - Whether eigenvectors should be sorted considering the absolute values - of the corresponding eigenvalues - - Returns - ------- - B : numpy matrix - low-rank approximation of A - - Notes - ----- - Low-rank matrix approximation is about finding a fixed rank matrix close - enough to the input one with respect to a given norm (distance). - In the case of real symmetric input matrix and euclidean distance, the best - low-rank approximation is given by the sum of first eigenvector matrices. - - References - ---------- - .. [1] G. Eckart and G. Young, The approximation of one matrix by another - of lower rank - .. [2] L. Mirsky, Symmetric gauge functions and unitarily invariant norms - - """ - - import numpy as np - - d, V = np.linalg.eigh(A) - d = np.ravel(d) - n = len(d) - if sorteigs: - if absolute: - k = np.argsort(np.abs(d)) - else: - k = np.argsort(d) - # ordered from the lowest to the highest - else: - k = range(n) - if not reverse: - k = np.flipud(k) - - z = np.zeros((n, 1)) - for i in range(level, n): - V[:, k[i]] = z - - B = V*np.diag(d)*np.transpose(V) - return B - - -@np_random_state(3) -def spectral_graph_forge(G, alpha, transformation='identity', seed=None): - """Returns a random simple graph with spectrum resembling that of `G` - - This algorithm, called Spectral Graph Forge (SGF), computes the - eigenvectors of a given graph adjacency matrix, filters them and - builds a random graph with a similar eigenstructure. - SGF has been proved to be particularly useful for synthesizing - realistic social networks and it can also be used to anonymize - graph sensitive data. - - Parameters - ---------- - G : Graph - alpha : float - Ratio representing the percentage of eigenvectors of G to consider, - values in [0,1]. - transformation : string, optional - Represents the intended matrix linear transformation, possible values - are 'identity' and 'modularity' - seed : integer, random_state, or None (default) - Indicator of numpy random number generation state. - See :ref:`Randomness`. - - Returns - ------- - H : Graph - A graph with a similar eigenvector structure of the input one. - - Raises - ------ - NetworkXError - If transformation has a value different from 'identity' or 'modularity' - - Notes - ----- - Spectral Graph Forge (SGF) generates a random simple graph resembling the - global properties of the given one. - It leverages the low-rank approximation of the associated adjacency matrix - driven by the *alpha* precision parameter. - SGF preserves the number of nodes of the input graph and their ordering. - This way, nodes of output graphs resemble the properties of the input one - and attributes can be directly mapped. - - It considers the graph adjacency matrices which can optionally be - transformed to other symmetric real matrices (currently transformation - options include *identity* and *modularity*). - The *modularity* transformation, in the sense of Newman's modularity matrix - allows the focusing on community structure related properties of the graph. - - SGF applies a low-rank approximation whose fixed rank is computed from the - ratio *alpha* of the input graph adjacency matrix dimension. - This step performs a filtering on the input eigenvectors similar to the low - pass filtering common in telecommunications. - - The filtered values (after truncation) are used as input to a Bernoulli - sampling for constructing a random adjacency matrix. - - References - ---------- - .. [1] L. Baldesi, C. T. Butts, A. Markopoulou, "Spectral Graph Forge: - Graph Generation Targeting Modularity", IEEE Infocom, '18. - https://arxiv.org/abs/1801.01715 - .. [2] M. Newman, "Networks: an introduction", Oxford university press, - 2010 - - Examples - -------- - >>> import networkx as nx - >>> G = nx.karate_club_graph() - >>> H = nx.spectral_graph_forge(G, 0.3) - >>> - """ - - import numpy as np - import scipy.stats as stats - - available_transformations = ['identity', 'modularity'] - alpha = _truncate(alpha) - A = nx.to_numpy_matrix(G) - n = A.shape[1] - level = int(round(n*alpha)) - - if transformation not in available_transformations: - msg = '\'{0}\' is not a valid transformation. '.format(transformation) - msg += 'Transformations: {0}'.format(available_transformations) - raise nx.NetworkXError(msg) - - K = np.ones((1, n)) * A - - B = A - if (transformation == 'modularity'): - B -= np.transpose(K) * K / float(sum(np.ravel(K))) - - B = _mat_spect_approx(B, level, sorteigs=True, absolute=True) - - if (transformation == 'modularity'): - B += np.transpose(K) * K / float(sum(np.ravel(K))) - - B = np.vectorize(_truncate, otypes=[np.float])(B) - np.fill_diagonal(B, np.zeros((1, n))) - - for i in range(n-1): - B[i, i+1:] = stats.bernoulli.rvs(B[i, i+1:], random_state=seed) - B[i+1:, i] = np.transpose(B[i, i+1:]) - - H = nx.from_numpy_matrix(B) - - return H - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/generators/stochastic.py b/extensions/fablabchemnitz/networkx/generators/stochastic.py deleted file mode 100644 index d99854b0..00000000 --- a/extensions/fablabchemnitz/networkx/generators/stochastic.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright (C) 2010-2013 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -"""Functions for generating stochastic graphs from a given weighted directed -graph. - -""" - -from networkx.classes import DiGraph -from networkx.classes import MultiDiGraph -from networkx.utils import not_implemented_for - -__author__ = "Aric Hagberg " -__all__ = ['stochastic_graph'] - - -@not_implemented_for('undirected') -def stochastic_graph(G, copy=True, weight='weight'): - """Returns a right-stochastic representation of directed graph `G`. - - A right-stochastic graph is a weighted digraph in which for each - node, the sum of the weights of all the out-edges of that node is - 1. If the graph is already weighted (for example, via a 'weight' - edge attribute), the reweighting takes that into account. - - Parameters - ---------- - G : directed graph - A :class:`~networkx.DiGraph` or :class:`~networkx.MultiDiGraph`. - - copy : boolean, optional - If this is True, then this function returns a new graph with - the stochastic reweighting. Otherwise, the original graph is - modified in-place (and also returned, for convenience). - - weight : edge attribute key (optional, default='weight') - Edge attribute key used for reading the existing weight and - setting the new weight. If no attribute with this key is found - for an edge, then the edge weight is assumed to be 1. If an edge - has a weight, it must be a a positive number. - - """ - if copy: - G = MultiDiGraph(G) if G.is_multigraph() else DiGraph(G) - # There is a tradeoff here: the dictionary of node degrees may - # require a lot of memory, whereas making a call to `G.out_degree` - # inside the loop may be costly in computation time. - degree = dict(G.out_degree(weight=weight)) - for u, v, d in G.edges(data=True): - if degree[u] == 0: - d[weight] = 0 - else: - d[weight] = d.get(weight, 1) / degree[u] - return G diff --git a/extensions/fablabchemnitz/networkx/generators/tests/__init__.py b/extensions/fablabchemnitz/networkx/generators/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_atlas.py b/extensions/fablabchemnitz/networkx/generators/tests/test_atlas.py deleted file mode 100644 index 85ff1795..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_atlas.py +++ /dev/null @@ -1,77 +0,0 @@ -from itertools import groupby - -import pytest - -import networkx as nx -from networkx.testing import * -from networkx import graph_atlas -from networkx import graph_atlas_g -from networkx.generators.atlas import NUM_GRAPHS -from networkx.utils import pairwise - - -class TestAtlasGraph(object): - """Unit tests for the :func:`~networkx.graph_atlas` function.""" - - def test_index_too_small(self): - with pytest.raises(ValueError): - graph_atlas(-1) - - def test_index_too_large(self): - with pytest.raises(ValueError): - graph_atlas(NUM_GRAPHS) - - def test_graph(self): - G = graph_atlas(6) - assert_nodes_equal(G.nodes(), range(3)) - assert_edges_equal(G.edges(), [(0, 1), (0, 2)]) - - -class TestAtlasGraphG(object): - """Unit tests for the :func:`~networkx.graph_atlas_g` function.""" - - @classmethod - def setup_class(cls): - cls.GAG = graph_atlas_g() - - def test_sizes(self): - G = self.GAG[0] - assert G.number_of_nodes() == 0 - assert G.number_of_edges() == 0 - - G = self.GAG[7] - assert G.number_of_nodes() == 3 - assert G.number_of_edges() == 3 - - def test_names(self): - for i, G in enumerate(self.GAG): - assert int(G.name[1:]) == i - - def test_nondecreasing_nodes(self): - # check for nondecreasing number of nodes - for n1, n2 in pairwise(map(len, self.GAG)): - assert n2 <= n1 + 1 - - def test_nondecreasing_edges(self): - # check for nondecreasing number of edges (for fixed number of - # nodes) - for n, group in groupby(self.GAG, key=nx.number_of_nodes): - for m1, m2 in pairwise(map(nx.number_of_edges, group)): - assert m2 <= m1 + 1 - - def test_nondecreasing_degree_sequence(self): - # Check for lexicographically nondecreasing degree sequences - # (for fixed number of nodes and edges). - # - # There are three exceptions to this rule in the order given in - # the "Atlas of Graphs" book, so we need to manually exclude - # those. - exceptions = [('G55', 'G56'), ('G1007', 'G1008'), ('G1012', 'G1013')] - for n, group in groupby(self.GAG, key=nx.number_of_nodes): - for m, group in groupby(group, key=nx.number_of_edges): - for G1, G2 in pairwise(group): - if (G1.name, G2.name) in exceptions: - continue - d1 = sorted(d for v, d in G1.degree()) - d2 = sorted(d for v, d in G2.degree()) - assert d1 <= d2 diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_classic.py b/extensions/fablabchemnitz/networkx/generators/tests/test_classic.py deleted file mode 100644 index a605cb6a..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_classic.py +++ /dev/null @@ -1,458 +0,0 @@ -#!/usr/bin/env python -""" -==================== -Generators - Classic -==================== - -Unit tests for various classic graph generators in generators/classic.py -""" -import itertools - -import pytest -import networkx as nx -from networkx.algorithms.isomorphism.isomorph import graph_could_be_isomorphic -from networkx.testing import assert_edges_equal -from networkx.testing import assert_nodes_equal - -is_isomorphic = graph_could_be_isomorphic - - -class TestGeneratorClassic(): - def test_balanced_tree(self): - # balanced_tree(r,h) is a tree with (r**(h+1)-1)/(r-1) edges - for r, h in [(2, 2), (3, 3), (6, 2)]: - t = nx.balanced_tree(r, h) - order = t.order() - assert order == (r**(h + 1) - 1) / (r - 1) - assert nx.is_connected(t) - assert t.size() == order - 1 - dh = nx.degree_histogram(t) - assert dh[0] == 0 # no nodes of 0 - assert dh[1] == r**h # nodes of degree 1 are leaves - assert dh[r] == 1 # root is degree r - assert dh[r + 1] == order - r**h - 1 # everyone else is degree r+1 - assert len(dh) == r + 2 - - def test_balanced_tree_star(self): - # balanced_tree(r,1) is the r-star - t = nx.balanced_tree(r=2, h=1) - assert is_isomorphic(t, nx.star_graph(2)) - t = nx.balanced_tree(r=5, h=1) - assert is_isomorphic(t, nx.star_graph(5)) - t = nx.balanced_tree(r=10, h=1) - assert is_isomorphic(t, nx.star_graph(10)) - - def test_balanced_tree_path(self): - """Tests that the balanced tree with branching factor one is the - path graph. - - """ - # A tree of height four has five levels. - T = nx.balanced_tree(1, 4) - P = nx.path_graph(5) - assert is_isomorphic(T, P) - - def test_full_rary_tree(self): - r = 2 - n = 9 - t = nx.full_rary_tree(r, n) - assert t.order() == n - assert nx.is_connected(t) - dh = nx.degree_histogram(t) - assert dh[0] == 0 # no nodes of 0 - assert dh[1] == 5 # nodes of degree 1 are leaves - assert dh[r] == 1 # root is degree r - assert dh[r + 1] == 9 - 5 - 1 # everyone else is degree r+1 - assert len(dh) == r + 2 - - def test_full_rary_tree_balanced(self): - t = nx.full_rary_tree(2, 15) - th = nx.balanced_tree(2, 3) - assert is_isomorphic(t, th) - - def test_full_rary_tree_path(self): - t = nx.full_rary_tree(1, 10) - assert is_isomorphic(t, nx.path_graph(10)) - - def test_full_rary_tree_empty(self): - t = nx.full_rary_tree(0, 10) - assert is_isomorphic(t, nx.empty_graph(10)) - t = nx.full_rary_tree(3, 0) - assert is_isomorphic(t, nx.empty_graph(0)) - - def test_full_rary_tree_3_20(self): - t = nx.full_rary_tree(3, 20) - assert t.order() == 20 - - def test_barbell_graph(self): - # number of nodes = 2*m1 + m2 (2 m1-complete graphs + m2-path + 2 edges) - # number of edges = 2*(nx.number_of_edges(m1-complete graph) + m2 + 1 - m1 = 3 - m2 = 5 - b = nx.barbell_graph(m1, m2) - assert nx.number_of_nodes(b) == 2 * m1 + m2 - assert nx.number_of_edges(b) == m1 * (m1 - 1) + m2 + 1 - - m1 = 4 - m2 = 10 - b = nx.barbell_graph(m1, m2) - assert nx.number_of_nodes(b) == 2 * m1 + m2 - assert nx.number_of_edges(b) == m1 * (m1 - 1) + m2 + 1 - - m1 = 3 - m2 = 20 - b = nx.barbell_graph(m1, m2) - assert nx.number_of_nodes(b) == 2 * m1 + m2 - assert nx.number_of_edges(b) == m1 * (m1 - 1) + m2 + 1 - - # Raise NetworkXError if m1<2 - m1 = 1 - m2 = 20 - pytest.raises(nx.NetworkXError, nx.barbell_graph, m1, m2) - - # Raise NetworkXError if m2<0 - m1 = 5 - m2 = -2 - pytest.raises(nx.NetworkXError, nx.barbell_graph, m1, m2) - - # nx.barbell_graph(2,m) = nx.path_graph(m+4) - m1 = 2 - m2 = 5 - b = nx.barbell_graph(m1, m2) - assert is_isomorphic(b, nx.path_graph(m2 + 4)) - - m1 = 2 - m2 = 10 - b = nx.barbell_graph(m1, m2) - assert is_isomorphic(b, nx.path_graph(m2 + 4)) - - m1 = 2 - m2 = 20 - b = nx.barbell_graph(m1, m2) - assert is_isomorphic(b, nx.path_graph(m2 + 4)) - - pytest.raises(nx.NetworkXError, nx.barbell_graph, m1, m2, - create_using=nx.DiGraph()) - - mb = nx.barbell_graph(m1, m2, create_using=nx.MultiGraph()) - assert_edges_equal(mb.edges(), b.edges()) - - def test_binomial_tree(self): - for n in range(0,4): - b = nx.binomial_tree(n) - assert nx.number_of_nodes(b) == 2**n - assert nx.number_of_edges(b) == (2**n - 1) - - def test_complete_graph(self): - # complete_graph(m) is a connected graph with - # m nodes and m*(m+1)/2 edges - for m in [0, 1, 3, 5]: - g = nx.complete_graph(m) - assert nx.number_of_nodes(g) == m - assert nx.number_of_edges(g) == m * (m - 1) // 2 - - mg = nx.complete_graph(m, create_using=nx.MultiGraph) - assert_edges_equal(mg.edges(), g.edges()) - - g = nx.complete_graph("abc") - assert_nodes_equal(g.nodes(), ['a', 'b', 'c']) - assert g.size() == 3 - - def test_complete_digraph(self): - # complete_graph(m) is a connected graph with - # m nodes and m*(m+1)/2 edges - for m in [0, 1, 3, 5]: - g = nx.complete_graph(m, create_using=nx.DiGraph) - assert nx.number_of_nodes(g) == m - assert nx.number_of_edges(g) == m * (m - 1) - - g = nx.complete_graph("abc", create_using=nx.DiGraph) - assert len(g) == 3 - assert g.size() == 6 - assert g.is_directed() - - def test_circular_ladder_graph(self): - G = nx.circular_ladder_graph(5) - pytest.raises(nx.NetworkXError, nx.circular_ladder_graph, - 5, create_using=nx.DiGraph) - mG = nx.circular_ladder_graph(5, create_using=nx.MultiGraph) - assert_edges_equal(mG.edges(), G.edges()) - - def test_circulant_graph(self): - # Ci_n(1) is the cycle graph for all n - Ci6_1 = nx.circulant_graph(6, [1]) - C6 = nx.cycle_graph(6) - assert_edges_equal(Ci6_1.edges(), C6.edges()) - - # Ci_n(1, 2, ..., n div 2) is the complete graph for all n - Ci7 = nx.circulant_graph(7, [1, 2, 3]) - K7 = nx.complete_graph(7) - assert_edges_equal(Ci7.edges(), K7.edges()) - - # Ci_6(1, 3) is K_3,3 i.e. the utility graph - Ci6_1_3 = nx.circulant_graph(6, [1, 3]) - K3_3 = nx.complete_bipartite_graph(3, 3) - assert is_isomorphic(Ci6_1_3, K3_3) - - def test_cycle_graph(self): - G = nx.cycle_graph(4) - assert_edges_equal(G.edges(), [(0, 1), (0, 3), (1, 2), (2, 3)]) - mG = nx.cycle_graph(4, create_using=nx.MultiGraph) - assert_edges_equal(mG.edges(), [(0, 1), (0, 3), (1, 2), (2, 3)]) - G = nx.cycle_graph(4, create_using=nx.DiGraph) - assert not G.has_edge(2, 1) - assert G.has_edge(1, 2) - assert G.is_directed() - - G = nx.cycle_graph("abc") - assert len(G) == 3 - assert G.size() == 3 - g = nx.cycle_graph("abc", nx.DiGraph) - assert len(g) == 3 - assert g.size() == 3 - assert g.is_directed() - - def test_dorogovtsev_goltsev_mendes_graph(self): - G = nx.dorogovtsev_goltsev_mendes_graph(0) - assert_edges_equal(G.edges(), [(0, 1)]) - assert_nodes_equal(list(G), [0, 1]) - G = nx.dorogovtsev_goltsev_mendes_graph(1) - assert_edges_equal(G.edges(), [(0, 1), (0, 2), (1, 2)]) - assert nx.average_clustering(G) == 1.0 - assert sorted(nx.triangles(G).values()) == [1, 1, 1] - G = nx.dorogovtsev_goltsev_mendes_graph(10) - assert nx.number_of_nodes(G) == 29526 - assert nx.number_of_edges(G) == 59049 - assert G.degree(0) == 1024 - assert G.degree(1) == 1024 - assert G.degree(2) == 1024 - - pytest.raises(nx.NetworkXError, - nx.dorogovtsev_goltsev_mendes_graph, 7, - create_using=nx.DiGraph) - pytest.raises(nx.NetworkXError, - nx.dorogovtsev_goltsev_mendes_graph, 7, - create_using=nx.MultiGraph) - - def test_create_using(self): - G = nx.empty_graph() - assert isinstance(G, nx.Graph) - pytest.raises(TypeError, nx.empty_graph, create_using=0.0) - pytest.raises(TypeError, nx.empty_graph, create_using="Graph") - - G = nx.empty_graph(create_using=nx.MultiGraph) - assert isinstance(G, nx.MultiGraph) - G = nx.empty_graph(create_using=nx.DiGraph) - assert isinstance(G, nx.DiGraph) - - G = nx.empty_graph(create_using=nx.DiGraph, default=nx.MultiGraph) - assert isinstance(G, nx.DiGraph) - G = nx.empty_graph(create_using=None, default=nx.MultiGraph) - assert isinstance(G, nx.MultiGraph) - G = nx.empty_graph(default=nx.MultiGraph) - assert isinstance(G, nx.MultiGraph) - - G = nx.path_graph(5) - H = nx.empty_graph(create_using=G) - assert not H.is_multigraph() - assert not H.is_directed() - assert len(H) == 0 - assert G is H - - H = nx.empty_graph(create_using=nx.MultiGraph()) - assert H.is_multigraph() - assert not H.is_directed() - assert G is not H - - def test_empty_graph(self): - G = nx.empty_graph() - assert nx.number_of_nodes(G) == 0 - G = nx.empty_graph(42) - assert nx.number_of_nodes(G) == 42 - assert nx.number_of_edges(G) == 0 - - G = nx.empty_graph("abc") - assert len(G) == 3 - assert G.size() == 0 - - # create empty digraph - G = nx.empty_graph(42, create_using=nx.DiGraph(name="duh")) - assert nx.number_of_nodes(G) == 42 - assert nx.number_of_edges(G) == 0 - assert isinstance(G, nx.DiGraph) - - # create empty multigraph - G = nx.empty_graph(42, create_using=nx.MultiGraph(name="duh")) - assert nx.number_of_nodes(G) == 42 - assert nx.number_of_edges(G) == 0 - assert isinstance(G, nx.MultiGraph) - - # create empty graph from another - pete = nx.petersen_graph() - G = nx.empty_graph(42, create_using=pete) - assert nx.number_of_nodes(G) == 42 - assert nx.number_of_edges(G) == 0 - assert isinstance(G, nx.Graph) - - def test_ladder_graph(self): - for i, G in [(0, nx.empty_graph(0)), (1, nx.path_graph(2)), - (2, nx.hypercube_graph(2)), (10, nx.grid_graph([2, 10]))]: - assert is_isomorphic(nx.ladder_graph(i), G) - - pytest.raises(nx.NetworkXError, - nx.ladder_graph, 2, create_using=nx.DiGraph) - - g = nx.ladder_graph(2) - mg = nx.ladder_graph(2, create_using=nx.MultiGraph) - assert_edges_equal(mg.edges(), g.edges()) - - def test_lollipop_graph(self): - # number of nodes = m1 + m2 - # number of edges = nx.number_of_edges(nx.complete_graph(m1)) + m2 - for m1, m2 in [(3, 5), (4, 10), (3, 20)]: - b = nx.lollipop_graph(m1, m2) - assert nx.number_of_nodes(b) == m1 + m2 - assert nx.number_of_edges(b) == m1 * (m1 - 1) / 2 + m2 - - # Raise NetworkXError if m<2 - pytest.raises(nx.NetworkXError, - nx.lollipop_graph, 1, 20) - - # Raise NetworkXError if n<0 - pytest.raises(nx.NetworkXError, - nx.lollipop_graph, 5, -2) - - # lollipop_graph(2,m) = path_graph(m+2) - for m1, m2 in [(2, 5), (2, 10), (2, 20)]: - b = nx.lollipop_graph(m1, m2) - assert is_isomorphic(b, nx.path_graph(m2 + 2)) - - pytest.raises(nx.NetworkXError, - nx.lollipop_graph, m1, m2, create_using=nx.DiGraph) - - mb = nx.lollipop_graph(m1, m2, create_using=nx.MultiGraph) - assert_edges_equal(mb.edges(), b.edges()) - - g = nx.lollipop_graph([1, 2, 3, 4], "abc") - assert len(g) == 7 - assert g.size() == 9 - - def test_null_graph(self): - assert nx.number_of_nodes(nx.null_graph()) == 0 - - def test_path_graph(self): - p = nx.path_graph(0) - assert is_isomorphic(p, nx.null_graph()) - - p = nx.path_graph(1) - assert is_isomorphic(p, nx.empty_graph(1)) - - p = nx.path_graph(10) - assert nx.is_connected(p) - assert (sorted(d for n, d in p.degree()) == - [1, 1, 2, 2, 2, 2, 2, 2, 2, 2]) - assert p.order() - 1 == p.size() - - dp = nx.path_graph(3, create_using=nx.DiGraph) - assert dp.has_edge(0, 1) - assert not dp.has_edge(1, 0) - - mp = nx.path_graph(10, create_using=nx.MultiGraph) - assert_edges_equal(mp.edges(), p.edges()) - - G = nx.path_graph("abc") - assert len(G) == 3 - assert G.size() == 2 - g = nx.path_graph("abc", nx.DiGraph) - assert len(g) == 3 - assert g.size() == 2 - assert g.is_directed() - - def test_star_graph(self): - star_graph = nx.star_graph - assert is_isomorphic(star_graph(0), nx.empty_graph(1)) - assert is_isomorphic(star_graph(1), nx.path_graph(2)) - assert is_isomorphic(star_graph(2), nx.path_graph(3)) - assert is_isomorphic(star_graph(5), nx.complete_bipartite_graph(1, 5)) - - s = star_graph(10) - assert (sorted(d for n, d in s.degree()) == - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 10]) - - pytest.raises(nx.NetworkXError, - star_graph, 10, create_using=nx.DiGraph) - - ms = star_graph(10, create_using=nx.MultiGraph) - assert_edges_equal(ms.edges(), s.edges()) - - G = star_graph("abcdefg") - assert len(G) == 7 - assert G.size() == 6 - - def test_trivial_graph(self): - assert nx.number_of_nodes(nx.trivial_graph()) == 1 - - def test_turan_graph(self): - assert nx.number_of_edges(nx.turan_graph(13, 4)) == 63 - assert is_isomorphic(nx.turan_graph(13, 4), - nx.complete_multipartite_graph(3, 4, 3, 3)) - - def test_wheel_graph(self): - for n, G in [(0, nx.null_graph()), (1, nx.empty_graph(1)), - (2, nx.path_graph(2)), (3, nx.complete_graph(3)), - (4, nx.complete_graph(4))]: - g = nx.wheel_graph(n) - assert is_isomorphic(g, G) - - g = nx.wheel_graph(10) - assert (sorted(d for n, d in g.degree()) == - [3, 3, 3, 3, 3, 3, 3, 3, 3, 9]) - - pytest.raises(nx.NetworkXError, - nx.wheel_graph, 10, create_using=nx.DiGraph) - - mg = nx.wheel_graph(10, create_using=nx.MultiGraph()) - assert_edges_equal(mg.edges(), g.edges()) - - G = nx.wheel_graph("abc") - assert len(G) == 3 - assert G.size() == 3 - - def test_complete_0_partite_graph(self): - """Tests that the complete 0-partite graph is the null graph.""" - G = nx.complete_multipartite_graph() - H = nx.null_graph() - assert_nodes_equal(G, H) - assert_edges_equal(G.edges(), H.edges()) - - def test_complete_1_partite_graph(self): - """Tests that the complete 1-partite graph is the empty graph.""" - G = nx.complete_multipartite_graph(3) - H = nx.empty_graph(3) - assert_nodes_equal(G, H) - assert_edges_equal(G.edges(), H.edges()) - - def test_complete_2_partite_graph(self): - """Tests that the complete 2-partite graph is the complete bipartite - graph. - - """ - G = nx.complete_multipartite_graph(2, 3) - H = nx.complete_bipartite_graph(2, 3) - assert_nodes_equal(G, H) - assert_edges_equal(G.edges(), H.edges()) - - def test_complete_multipartite_graph(self): - """Tests for generating the complete multipartite graph.""" - G = nx.complete_multipartite_graph(2, 3, 4) - blocks = [(0, 1), (2, 3, 4), (5, 6, 7, 8)] - # Within each block, no two vertices should be adjacent. - for block in blocks: - for u, v in itertools.combinations_with_replacement(block, 2): - assert v not in G[u] - assert G.nodes[u] == G.nodes[v] - # Across blocks, all vertices should be adjacent. - for (block1, block2) in itertools.combinations(blocks, 2): - for u, v in itertools.product(block1, block2): - assert v in G[u] - assert G.nodes[u] != G.nodes[v] diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_cographs.py b/extensions/fablabchemnitz/networkx/generators/tests/test_cographs.py deleted file mode 100644 index 6e0ce7ca..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_cographs.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- encoding: utf-8 -*- -# test_cographs.py - unit tests for cograph generators -# -# Copyright 2010-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.generators.cographs` module. - -""" - -import networkx as nx - - -def test_random_cograph(): - n = 3 - G = nx.random_cograph(n) - - assert len(G) == 2 ** n - - #Every connected subgraph of G has diameter <= 2 - if nx.is_connected(G): - assert nx.diameter(G) <= 2 - else: - components = nx.connected_components(G) - for component in components: - assert nx.diameter(G.subgraph(component)) <= 2 diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_community.py b/extensions/fablabchemnitz/networkx/generators/tests/test_community.py deleted file mode 100644 index b62bcc6d..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_community.py +++ /dev/null @@ -1,271 +0,0 @@ -import networkx as nx -import pytest - - -def test_random_partition_graph(): - G = nx.random_partition_graph([3, 3, 3], 1, 0, seed=42) - C = G.graph['partition'] - assert C == [set([0, 1, 2]), set([3, 4, 5]), set([6, 7, 8])] - assert len(G) == 9 - assert len(list(G.edges())) == 9 - - G = nx.random_partition_graph([3, 3, 3], 0, 1) - C = G.graph['partition'] - assert C == [set([0, 1, 2]), set([3, 4, 5]), set([6, 7, 8])] - assert len(G) == 9 - assert len(list(G.edges())) == 27 - - G = nx.random_partition_graph([3, 3, 3], 1, 0, directed=True) - C = G.graph['partition'] - assert C == [set([0, 1, 2]), set([3, 4, 5]), set([6, 7, 8])] - assert len(G) == 9 - assert len(list(G.edges())) == 18 - - G = nx.random_partition_graph([3, 3, 3], 0, 1, directed=True) - C = G.graph['partition'] - assert C == [set([0, 1, 2]), set([3, 4, 5]), set([6, 7, 8])] - assert len(G) == 9 - assert len(list(G.edges())) == 54 - - G = nx.random_partition_graph([1, 2, 3, 4, 5], 0.5, 0.1) - C = G.graph['partition'] - assert C == [set([0]), set([1, 2]), set([3, 4, 5]), - set([6, 7, 8, 9]), set([10, 11, 12, 13, 14])] - assert len(G) == 15 - - rpg = nx.random_partition_graph - pytest.raises(nx.NetworkXError, rpg, [1, 2, 3], 1.1, 0.1) - pytest.raises(nx.NetworkXError, rpg, [1, 2, 3], -0.1, 0.1) - pytest.raises(nx.NetworkXError, rpg, [1, 2, 3], 0.1, 1.1) - pytest.raises(nx.NetworkXError, rpg, [1, 2, 3], 0.1, -0.1) - - -def test_planted_partition_graph(): - G = nx.planted_partition_graph(4, 3, 1, 0, seed=42) - C = G.graph['partition'] - assert len(C) == 4 - assert len(G) == 12 - assert len(list(G.edges())) == 12 - - G = nx.planted_partition_graph(4, 3, 0, 1) - C = G.graph['partition'] - assert len(C) == 4 - assert len(G) == 12 - assert len(list(G.edges())) == 54 - - G = nx.planted_partition_graph(10, 4, .5, .1, seed=42) - C = G.graph['partition'] - assert len(C) == 10 - assert len(G) == 40 - - G = nx.planted_partition_graph(4, 3, 1, 0, directed=True) - C = G.graph['partition'] - assert len(C) == 4 - assert len(G) == 12 - assert len(list(G.edges())) == 24 - - G = nx.planted_partition_graph(4, 3, 0, 1, directed=True) - C = G.graph['partition'] - assert len(C) == 4 - assert len(G) == 12 - assert len(list(G.edges())) == 108 - - G = nx.planted_partition_graph(10, 4, .5, .1, seed=42, directed=True) - C = G.graph['partition'] - assert len(C) == 10 - assert len(G) == 40 - - ppg = nx.planted_partition_graph - pytest.raises(nx.NetworkXError, ppg, 3, 3, 1.1, 0.1) - pytest.raises(nx.NetworkXError, ppg, 3, 3, -0.1, 0.1) - pytest.raises(nx.NetworkXError, ppg, 3, 3, 0.1, 1.1) - pytest.raises(nx.NetworkXError, ppg, 3, 3, 0.1, -0.1) - - -def test_relaxed_caveman_graph(): - G = nx.relaxed_caveman_graph(4, 3, 0) - assert len(G) == 12 - G = nx.relaxed_caveman_graph(4, 3, 1) - assert len(G) == 12 - G = nx.relaxed_caveman_graph(4, 3, 0.5) - assert len(G) == 12 - G = nx.relaxed_caveman_graph(4, 3, 0.5, seed=42) - assert len(G) == 12 - - -def test_connected_caveman_graph(): - G = nx.connected_caveman_graph(4, 3) - assert len(G) == 12 - - G = nx.connected_caveman_graph(1, 5) - K5 = nx.complete_graph(5) - K5.remove_edge(3, 4) - assert nx.is_isomorphic(G, K5) - - -def test_caveman_graph(): - G = nx.caveman_graph(4, 3) - assert len(G) == 12 - - G = nx.caveman_graph(1, 5) - K5 = nx.complete_graph(5) - assert nx.is_isomorphic(G, K5) - - -def test_gaussian_random_partition_graph(): - G = nx.gaussian_random_partition_graph(100, 10, 10, 0.3, 0.01) - assert len(G) == 100 - G = nx.gaussian_random_partition_graph(100, 10, 10, 0.3, 0.01, - directed=True) - assert len(G) == 100 - G = nx.gaussian_random_partition_graph(100, 10, 10, 0.3, 0.01, - directed=False, seed=42) - assert len(G) == 100 - G = nx.gaussian_random_partition_graph(100, 10, 10, 0.3, 0.01, - directed=True, seed=42) - assert len(G) == 100 - pytest.raises(nx.NetworkXError, - nx.gaussian_random_partition_graph, 100, 101, 10, 1, 0) - - -def test_ring_of_cliques(): - for i in range(2, 20, 3): - for j in range(2, 20, 3): - G = nx.ring_of_cliques(i, j) - assert G.number_of_nodes() == i * j - if i != 2 or j != 1: - expected_num_edges = i * (((j * (j - 1)) // 2) + 1) - else: - # the edge that already exists cannot be duplicated - expected_num_edges = i * (((j * (j - 1)) // 2) + 1) - 1 - assert G.number_of_edges() == expected_num_edges - pytest.raises(nx.NetworkXError, nx.ring_of_cliques, 1, 5) - pytest.raises(nx.NetworkXError, nx.ring_of_cliques, 3, 0) - - -def test_windmill_graph(): - for n in range(2, 20, 3): - for k in range(2, 20, 3): - G = nx.windmill_graph(n, k) - assert G.number_of_nodes() == (k - 1) * n + 1 - assert G.number_of_edges() == n * k * (k - 1) / 2 - assert G.degree(0) == G.number_of_nodes() - 1 - for i in range(1, G.number_of_nodes()): - assert G.degree(i) == k - 1 - pytest.raises(nx.NetworkXError, nx.ring_of_cliques, 1, 3) - pytest.raises(nx.NetworkXError, nx.ring_of_cliques, 15, 0) - - -def test_stochastic_block_model(): - sizes = [75, 75, 300] - probs = [[0.25, 0.05, 0.02], - [0.05, 0.35, 0.07], - [0.02, 0.07, 0.40]] - G = nx.stochastic_block_model(sizes, probs, seed=0) - C = G.graph['partition'] - assert len(C) == 3 - assert len(G) == 450 - assert G.size() == 22160 - - GG = nx.stochastic_block_model(sizes, probs, range(450), seed=0) - assert G.nodes == GG.nodes - - # Test Exceptions - sbm = nx.stochastic_block_model - badnodelist = list(range(400)) # not enough nodes to match sizes - badprobs1 = [[0.25, 0.05, 1.02], - [0.05, 0.35, 0.07], - [0.02, 0.07, 0.40]] - badprobs2 = [[0.25, 0.05, 0.02], - [0.05, -0.35, 0.07], - [0.02, 0.07, 0.40]] - probs_rect1 = [[0.25, 0.05, 0.02], - [0.05, -0.35, 0.07]] - probs_rect2 = [[0.25, 0.05], - [0.05, -0.35], - [0.02, 0.07]] - asymprobs = [[0.25, 0.05, 0.01], - [0.05, -0.35, 0.07], - [0.02, 0.07, 0.40]] - pytest.raises(nx.NetworkXException, sbm, sizes, badprobs1) - pytest.raises(nx.NetworkXException, sbm, sizes, badprobs2) - pytest.raises(nx.NetworkXException, sbm, sizes, probs_rect1, directed=True) - pytest.raises(nx.NetworkXException, sbm, sizes, probs_rect2, directed=True) - pytest.raises(nx.NetworkXException, sbm, sizes, asymprobs, directed=False) - pytest.raises(nx.NetworkXException, sbm, sizes, probs, badnodelist) - nodelist = [0] + list(range(449)) # repeated node name in nodelist - pytest.raises(nx.NetworkXException, sbm, sizes, probs, nodelist) - - # Extra keyword arguments test - GG = nx.stochastic_block_model(sizes, probs, seed=0, selfloops=True) - assert G.nodes == GG.nodes - GG = nx.stochastic_block_model(sizes, probs, selfloops=True, directed=True) - assert G.nodes == GG.nodes - GG = nx.stochastic_block_model(sizes, probs, seed=0, sparse=False) - assert G.nodes == GG.nodes - - -def test_generator(): - n = 250 - tau1 = 3 - tau2 = 1.5 - mu = 0.1 - G = nx.LFR_benchmark_graph(n, tau1, tau2, mu, average_degree=5, - min_community=20, seed=10) - assert len(G) == 250 - C = {frozenset(G.nodes[v]['community']) for v in G} - assert nx.community.is_partition(G.nodes(), C) - - -def test_invalid_tau1(): - with pytest.raises(nx.NetworkXError): - n = 100 - tau1 = 2 - tau2 = 1 - mu = 0.1 - nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2) - - -def test_invalid_tau2(): - with pytest.raises(nx.NetworkXError): - n = 100 - tau1 = 1 - tau2 = 2 - mu = 0.1 - nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2) - - -def test_mu_too_large(): - with pytest.raises(nx.NetworkXError): - n = 100 - tau1 = 2 - tau2 = 2 - mu = 1.1 - nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2) - - -def test_mu_too_small(): - with pytest.raises(nx.NetworkXError): - n = 100 - tau1 = 2 - tau2 = 2 - mu = -1 - nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2) - - -def test_both_degrees_none(): - with pytest.raises(nx.NetworkXError): - n = 100 - tau1 = 2 - tau2 = 2 - mu = -1 - nx.LFR_benchmark_graph(n, tau1, tau2, mu) - - -def test_neither_degrees_none(): - with pytest.raises(nx.NetworkXError): - n = 100 - tau1 = 2 - tau2 = 2 - mu = -1 - nx.LFR_benchmark_graph(n, tau1, tau2, mu, min_degree=2, average_degree=5) diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_degree_seq.py b/extensions/fablabchemnitz/networkx/generators/tests/test_degree_seq.py deleted file mode 100644 index 70062775..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_degree_seq.py +++ /dev/null @@ -1,212 +0,0 @@ -import pytest - -import networkx as nx - - -class TestConfigurationModel(object): - """Unit tests for the :func:`~networkx.configuration_model` - function. - - """ - - def test_empty_degree_sequence(self): - """Tests that an empty degree sequence yields the null graph.""" - G = nx.configuration_model([]) - assert len(G) == 0 - - def test_degree_zero(self): - """Tests that a degree sequence of all zeros yields the empty - graph. - - """ - G = nx.configuration_model([0, 0, 0]) - assert len(G) == 3 - assert G.number_of_edges() == 0 - - def test_degree_sequence(self): - """Tests that the degree sequence of the generated graph matches - the input degree sequence. - - """ - deg_seq = [5, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - G = nx.configuration_model(deg_seq, seed=12345678) - assert (sorted((d for n, d in G.degree()), reverse=True) == - [5, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1]) - assert (sorted((d for n, d in G.degree(range(len(deg_seq)))), - reverse=True) == - [5, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1]) - - def test_random_seed(self): - """Tests that each call with the same random seed generates the - same graph. - - """ - deg_seq = [3] * 12 - G1 = nx.configuration_model(deg_seq, seed=1000) - G2 = nx.configuration_model(deg_seq, seed=1000) - assert nx.is_isomorphic(G1, G2) - G1 = nx.configuration_model(deg_seq, seed=10) - G2 = nx.configuration_model(deg_seq, seed=10) - assert nx.is_isomorphic(G1, G2) - - def test_directed_disallowed(self): - """Tests that attempting to create a configuration model graph - using a directed graph yields an exception. - - """ - with pytest.raises(nx.NetworkXNotImplemented): - nx.configuration_model([], create_using=nx.DiGraph()) - - def test_odd_degree_sum(self): - """Tests that a degree sequence whose sum is odd yields an - exception. - - """ - with pytest.raises(nx.NetworkXError): - nx.configuration_model([1, 2]) - - -def test_directed_configuation_raise_unequal(): - with pytest.raises(nx.NetworkXError): - zin = [5, 3, 3, 3, 3, 2, 2, 2, 1, 1] - zout = [5, 3, 3, 3, 3, 2, 2, 2, 1, 2] - nx.directed_configuration_model(zin, zout) - - -def test_directed_configuation_model(): - G = nx.directed_configuration_model([], [], seed=0) - assert len(G) == 0 - - -def test_simple_directed_configuation_model(): - G = nx.directed_configuration_model([1, 1], [1, 1], seed=0) - assert len(G) == 2 - - -def test_expected_degree_graph_empty(): - # empty graph has empty degree sequence - deg_seq = [] - G = nx.expected_degree_graph(deg_seq) - assert dict(G.degree()) == {} - - -def test_expected_degree_graph(): - # test that fixed seed delivers the same graph - deg_seq = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] - G1 = nx.expected_degree_graph(deg_seq, seed=1000) - assert len(G1) == 12 - - G2 = nx.expected_degree_graph(deg_seq, seed=1000) - assert nx.is_isomorphic(G1, G2) - - G1 = nx.expected_degree_graph(deg_seq, seed=10) - G2 = nx.expected_degree_graph(deg_seq, seed=10) - assert nx.is_isomorphic(G1, G2) - - -def test_expected_degree_graph_selfloops(): - deg_seq = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3] - G1 = nx.expected_degree_graph(deg_seq, seed=1000, selfloops=False) - G2 = nx.expected_degree_graph(deg_seq, seed=1000, selfloops=False) - assert nx.is_isomorphic(G1, G2) - assert len(G1) == 12 - - -def test_expected_degree_graph_skew(): - deg_seq = [10, 2, 2, 2, 2] - G1 = nx.expected_degree_graph(deg_seq, seed=1000) - G2 = nx.expected_degree_graph(deg_seq, seed=1000) - assert nx.is_isomorphic(G1, G2) - assert len(G1) == 5 - - -def test_havel_hakimi_construction(): - G = nx.havel_hakimi_graph([]) - assert len(G) == 0 - - z = [1000, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - pytest.raises(nx.NetworkXError, nx.havel_hakimi_graph, z) - z = ["A", 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - pytest.raises(nx.NetworkXError, nx.havel_hakimi_graph, z) - - z = [5, 4, 3, 3, 3, 2, 2, 2] - G = nx.havel_hakimi_graph(z) - G = nx.configuration_model(z) - z = [6, 5, 4, 4, 2, 1, 1, 1] - pytest.raises(nx.NetworkXError, nx.havel_hakimi_graph, z) - - z = [10, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2] - - G = nx.havel_hakimi_graph(z) - - pytest.raises(nx.NetworkXError, nx.havel_hakimi_graph, z, - create_using=nx.DiGraph()) - - -def test_directed_havel_hakimi(): - # Test range of valid directed degree sequences - n, r = 100, 10 - p = 1.0 / r - for i in range(r): - G1 = nx.erdos_renyi_graph(n, p * (i + 1), None, True) - din1 = list(d for n, d in G1.in_degree()) - dout1 = list(d for n, d in G1.out_degree()) - G2 = nx.directed_havel_hakimi_graph(din1, dout1) - din2 = list(d for n, d in G2.in_degree()) - dout2 = list(d for n, d in G2.out_degree()) - assert sorted(din1) == sorted(din2) - assert sorted(dout1) == sorted(dout2) - - # Test non-graphical sequence - dout = [1000, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1] - din = [103, 102, 102, 102, 102, 102, 102, 102, 102, 102] - pytest.raises(nx.exception.NetworkXError, - nx.directed_havel_hakimi_graph, din, dout) - # Test valid sequences - dout = [1, 1, 1, 1, 1, 2, 2, 2, 3, 4] - din = [2, 2, 2, 2, 2, 2, 2, 2, 0, 2] - G2 = nx.directed_havel_hakimi_graph(din, dout) - dout2 = (d for n, d in G2.out_degree()) - din2 = (d for n, d in G2.in_degree()) - assert sorted(dout) == sorted(dout2) - assert sorted(din) == sorted(din2) - # Test unequal sums - din = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2] - pytest.raises(nx.exception.NetworkXError, - nx.directed_havel_hakimi_graph, din, dout) - # Test for negative values - din = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, -2] - pytest.raises(nx.exception.NetworkXError, - nx.directed_havel_hakimi_graph, din, dout) - - -def test_degree_sequence_tree(): - z = [1, 1, 1, 1, 1, 2, 2, 2, 3, 4] - G = nx.degree_sequence_tree(z) - assert len(G) == len(z) - assert len(list(G.edges())) == sum(z) / 2 - - pytest.raises(nx.NetworkXError, nx.degree_sequence_tree, z, - create_using=nx.DiGraph()) - - z = [1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4] - pytest.raises(nx.NetworkXError, nx.degree_sequence_tree, z) - - -def test_random_degree_sequence_graph(): - d = [1, 2, 2, 3] - G = nx.random_degree_sequence_graph(d, seed=42) - assert d == sorted(d for n, d in G.degree()) - - -def test_random_degree_sequence_graph_raise(): - z = [1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 4] - pytest.raises(nx.NetworkXUnfeasible, nx.random_degree_sequence_graph, z) - - -def test_random_degree_sequence_large(): - G1 = nx.fast_gnp_random_graph(100, 0.1, seed=42) - d1 = (d for n, d in G1.degree()) - G2 = nx.random_degree_sequence_graph(d1, seed=42) - d2 = (d for n, d in G2.degree()) - assert sorted(d1) == sorted(d2) diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_directed.py b/extensions/fablabchemnitz/networkx/generators/tests/test_directed.py deleted file mode 100644 index 5a8a9b03..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_directed.py +++ /dev/null @@ -1,117 +0,0 @@ -"""Generators - Directed Graphs ----------------------------- -""" -import pytest - -import networkx as nx -from networkx.classes import Graph -from networkx.classes import MultiDiGraph -from networkx.generators.directed import gn_graph -from networkx.generators.directed import gnr_graph -from networkx.generators.directed import gnc_graph -from networkx.generators.directed import random_k_out_graph -from networkx.generators.directed import random_uniform_k_out_graph -from networkx.generators.directed import scale_free_graph - - -class TestGeneratorsDirected(object): - def test_smoke_test_random_graphs(self): - gn_graph(100) - gnr_graph(100, 0.5) - gnc_graph(100) - scale_free_graph(100) - - gn_graph(100, seed=42) - gnr_graph(100, 0.5, seed=42) - gnc_graph(100, seed=42) - scale_free_graph(100, seed=42) - - def test_create_using_keyword_arguments(self): - pytest.raises(nx.NetworkXError, - gn_graph, 100, create_using=Graph()) - pytest.raises(nx.NetworkXError, - gnr_graph, 100, 0.5, create_using=Graph()) - pytest.raises(nx.NetworkXError, - gnc_graph, 100, create_using=Graph()) - pytest.raises(nx.NetworkXError, - scale_free_graph, 100, create_using=Graph()) - G = gn_graph(100, seed=1) - MG = gn_graph(100, create_using=MultiDiGraph(), seed=1) - assert sorted(G.edges()) == sorted(MG.edges()) - G = gnr_graph(100, 0.5, seed=1) - MG = gnr_graph(100, 0.5, create_using=MultiDiGraph(), seed=1) - assert sorted(G.edges()) == sorted(MG.edges()) - G = gnc_graph(100, seed=1) - MG = gnc_graph(100, create_using=MultiDiGraph(), seed=1) - assert sorted(G.edges()) == sorted(MG.edges()) - - G = scale_free_graph(100, alpha=0.3, beta=0.4, gamma=0.3, - delta_in=0.3, delta_out=0.1, - create_using=MultiDiGraph, seed=1) - pytest.raises(ValueError, scale_free_graph, 100, 0.5, 0.4, 0.3) - pytest.raises(ValueError, scale_free_graph, 100, alpha=-0.3) - pytest.raises(ValueError, scale_free_graph, 100, beta=-0.3) - pytest.raises(ValueError, scale_free_graph, 100, gamma=-0.3) - - -class TestRandomKOutGraph(object): - """Unit tests for the - :func:`~networkx.generators.directed.random_k_out_graph` function. - - """ - - def test_regularity(self): - """Tests that the generated graph is `k`-out-regular.""" - n = 10 - k = 3 - alpha = 1 - G = random_k_out_graph(n, k, alpha) - assert all(d == k for v, d in G.out_degree()) - G = random_k_out_graph(n, k, alpha, seed=42) - assert all(d == k for v, d in G.out_degree()) - - def test_no_self_loops(self): - """Tests for forbidding self-loops.""" - n = 10 - k = 3 - alpha = 1 - G = random_k_out_graph(n, k, alpha, self_loops=False) - assert nx.number_of_selfloops(G) == 0 - - -class TestUniformRandomKOutGraph(object): - """Unit tests for the - :func:`~networkx.generators.directed.random_uniform_k_out_graph` - function. - - """ - def test_regularity(self): - """Tests that the generated graph is `k`-out-regular.""" - n = 10 - k = 3 - G = random_uniform_k_out_graph(n, k) - assert all(d == k for v, d in G.out_degree()) - G = random_uniform_k_out_graph(n, k, seed=42) - assert all(d == k for v, d in G.out_degree()) - - def test_no_self_loops(self): - """Tests for forbidding self-loops.""" - n = 10 - k = 3 - G = random_uniform_k_out_graph(n, k, self_loops=False) - assert nx.number_of_selfloops(G) == 0 - assert all(d == k for v, d in G.out_degree()) - - def test_with_replacement(self): - n = 10 - k = 3 - G = random_uniform_k_out_graph(n, k, with_replacement=True) - assert G.is_multigraph() - assert all(d == k for v, d in G.out_degree()) - - def test_without_replacement(self): - n = 10 - k = 3 - G = random_uniform_k_out_graph(n, k, with_replacement=False) - assert not G.is_multigraph() - assert all(d == k for v, d in G.out_degree()) diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_duplication.py b/extensions/fablabchemnitz/networkx/generators/tests/test_duplication.py deleted file mode 100644 index d74d35af..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_duplication.py +++ /dev/null @@ -1,81 +0,0 @@ -# -*- encoding: utf-8 -*- -# test_duplication.py - unit tests for the generators.duplication module -# -# Copyright 2010-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.generators.duplication` module. - -""" -import pytest - -from networkx.exception import NetworkXError -from networkx.generators.duplication import duplication_divergence_graph -from networkx.generators.duplication import partial_duplication_graph - - -class TestDuplicationDivergenceGraph(object): - """Unit tests for the - :func:`networkx.generators.duplication.duplication_divergence_graph` - function. - - """ - - def test_final_size(self): - G = duplication_divergence_graph(3, 1) - assert len(G) == 3 - G = duplication_divergence_graph(3, 1, seed=42) - assert len(G) == 3 - - def test_probability_too_large(self): - with pytest.raises(NetworkXError): - duplication_divergence_graph(3, 2) - - def test_probability_too_small(self): - with pytest.raises(NetworkXError): - duplication_divergence_graph(3, -1) - - -class TestPartialDuplicationGraph(object): - """Unit tests for the - :func:`networkx.generators.duplication.partial_duplication_graph` - function. - - """ - - def test_final_size(self): - N = 10 - n = 5 - p = 0.5 - q = 0.5 - G = partial_duplication_graph(N, n, p, q) - assert len(G) == N - G = partial_duplication_graph(N, n, p, q, seed=42) - assert len(G) == N - - def test_initial_clique_size(self): - N = 10 - n = 10 - p = 0.5 - q = 0.5 - G = partial_duplication_graph(N, n, p, q) - assert len(G) == n - - def test_invalid_initial_size(self): - with pytest.raises(NetworkXError): - N = 5 - n = 10 - p = 0.5 - q = 0.5 - G = partial_duplication_graph(N, n, p, q) - assert len(G) == n - - def test_invalid_probabilities(self): - N = 1 - n = 1 - for p, q in [(0.5, 2), (0.5, -1), (2, 0.5), (-1, 0.5)]: - args = (N, n, p, q) - pytest.raises(NetworkXError, partial_duplication_graph, *args) diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_ego.py b/extensions/fablabchemnitz/networkx/generators/tests/test_ego.py deleted file mode 100644 index 9744e49a..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_ego.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python -""" -ego graph ---------- -""" - -import networkx as nx -from networkx.testing.utils import * - - -class TestGeneratorEgo(): - def test_ego(self): - G = nx.star_graph(3) - H = nx.ego_graph(G, 0) - assert nx.is_isomorphic(G, H) - G.add_edge(1, 11) - G.add_edge(2, 22) - G.add_edge(3, 33) - H = nx.ego_graph(G, 0) - assert nx.is_isomorphic(nx.star_graph(3), H) - G = nx.path_graph(3) - H = nx.ego_graph(G, 0) - assert_edges_equal(H.edges(), [(0, 1)]) - H = nx.ego_graph(G, 0, undirected=True) - assert_edges_equal(H.edges(), [(0, 1)]) - H = nx.ego_graph(G, 0, center=False) - assert_edges_equal(H.edges(), []) - - def test_ego_distance(self): - G = nx.Graph() - G.add_edge(0, 1, weight=2, distance=1) - G.add_edge(1, 2, weight=2, distance=2) - G.add_edge(2, 3, weight=2, distance=1) - assert_nodes_equal(nx.ego_graph(G, 0, radius=3).nodes(), [0, 1, 2, 3]) - eg = nx.ego_graph(G, 0, radius=3, distance='weight') - assert_nodes_equal(eg.nodes(), [0, 1]) - eg = nx.ego_graph(G, 0, radius=3, distance='weight', undirected=True) - assert_nodes_equal(eg.nodes(), [0, 1]) - eg = nx.ego_graph(G, 0, radius=3, distance='distance') - assert_nodes_equal(eg.nodes(), [0, 1, 2]) diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_expanders.py b/extensions/fablabchemnitz/networkx/generators/tests/test_expanders.py deleted file mode 100644 index 38b989b2..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_expanders.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2014 "cheebee7i". -# Copyright 2014 "alexbrc". -# Copyright 2014 Jeffrey Finkelstein . -"""Unit tests for the :mod:`networkx.generators.expanders` module. - -""" - -import networkx as nx -from networkx import adjacency_matrix -from networkx import number_of_nodes -from networkx.generators.expanders import chordal_cycle_graph -from networkx.generators.expanders import margulis_gabber_galil_graph - -import pytest - - -def test_margulis_gabber_galil_graph(): - for n in 2, 3, 5, 6, 10: - g = margulis_gabber_galil_graph(n) - assert number_of_nodes(g) == n * n - for node in g: - assert g.degree(node) == 8 - assert len(node) == 2 - for i in node: - assert int(i) == i - assert 0 <= i < n - - np = pytest.importorskip("numpy") - scipy = pytest.importorskip("scipy") - scipy.linalg = pytest.importorskip("scipy.linalg") - # Eigenvalues are already sorted using the scipy eigvalsh, - # but the implementation in numpy does not guarantee order. - w = sorted(scipy.linalg.eigvalsh(adjacency_matrix(g).A)) - assert w[-2] < 5 * np.sqrt(2) - - -def test_chordal_cycle_graph(): - """Test for the :func:`networkx.chordal_cycle_graph` function.""" - primes = [3, 5, 7, 11] - for p in primes: - G = chordal_cycle_graph(p) - assert len(G) == p - # TODO The second largest eigenvalue should be smaller than a constant, - # independent of the number of nodes in the graph: - # - # eigs = sorted(scipy.linalg.eigvalsh(adjacency_matrix(G).A)) - # assert_less(eigs[-2], ...) - # - - -def test_margulis_gabber_galil_graph_badinput(): - pytest.raises(nx.NetworkXError, margulis_gabber_galil_graph, 3, - nx.DiGraph()) - pytest.raises(nx.NetworkXError, margulis_gabber_galil_graph, 3, - nx.Graph()) diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_geometric.py b/extensions/fablabchemnitz/networkx/generators/tests/test_geometric.py deleted file mode 100644 index 497db74c..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_geometric.py +++ /dev/null @@ -1,334 +0,0 @@ -from itertools import combinations -from math import sqrt -import random - - -import networkx as nx -from networkx.generators.geometric import euclidean - - -def l1dist(x, y): - return sum(abs(a - b) for a, b in zip(x, y)) - - -class TestRandomGeometricGraph(object): - """Unit tests for the :func:`~networkx.random_geometric_graph` - function. - - """ - - def test_number_of_nodes(self): - G = nx.random_geometric_graph(50, 0.25, seed=42) - assert len(G) == 50 - G = nx.random_geometric_graph(range(50), 0.25, seed=42) - assert len(G) == 50 - - def test_distances(self): - """Tests that pairs of vertices adjacent if and only if they are - within the prescribed radius. - - """ - # Use the Euclidean metric, the default according to the - # documentation. - dist = euclidean - G = nx.random_geometric_graph(50, 0.25) - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert dist(G.nodes[u]['pos'], G.nodes[v]['pos']) <= 0.25 - # Nonadjacent vertices must be at greater distance. - else: - assert not dist(G.nodes[u]['pos'], G.nodes[v]['pos']) <= 0.25 - - def test_p(self): - """Tests for providing an alternate distance metric to the - generator. - - """ - # Use the L1 metric. - dist = l1dist - G = nx.random_geometric_graph(50, 0.25, p=1) - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert dist(G.nodes[u]['pos'], G.nodes[v]['pos']) <= 0.25 - # Nonadjacent vertices must be at greater distance. - else: - assert not dist(G.nodes[u]['pos'], G.nodes[v]['pos']) <= 0.25 - - def test_node_names(self): - """Tests using values other than sequential numbers as node IDs. - - """ - import string - nodes = list(string.ascii_lowercase) - G = nx.random_geometric_graph(nodes, 0.25) - assert len(G) == len(nodes) - - dist = euclidean - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert dist(G.nodes[u]['pos'], G.nodes[v]['pos']) <= 0.25 - # Nonadjacent vertices must be at greater distance. - else: - assert not dist(G.nodes[u]['pos'], G.nodes[v]['pos']) <= 0.25 - - -class TestSoftRandomGeometricGraph(object): - """Unit tests for the :func:`~networkx.soft_random_geometric_graph` - function. - - """ - - def test_number_of_nodes(self): - G = nx.soft_random_geometric_graph(50, 0.25, seed=42) - assert len(G) == 50 - G = nx.soft_random_geometric_graph(range(50), 0.25, seed=42) - assert len(G) == 50 - - def test_distances(self): - """Tests that pairs of vertices adjacent if and only if they are - within the prescribed radius. - - """ - # Use the Euclidean metric, the default according to the - # documentation. - def dist(x, y): return sqrt(sum((a - b) ** 2 for a, b in zip(x, y))) - G = nx.soft_random_geometric_graph(50, 0.25) - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert dist(G.nodes[u]['pos'], G.nodes[v]['pos']) <= 0.25 - - def test_p(self): - """Tests for providing an alternate distance metric to the - generator. - - """ - # Use the L1 metric. - def dist(x, y): return sum(abs(a - b) for a, b in zip(x, y)) - G = nx.soft_random_geometric_graph(50, 0.25, p=1) - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert dist(G.nodes[u]['pos'], G.nodes[v]['pos']) <= 0.25 - - def test_node_names(self): - """Tests using values other than sequential numbers as node IDs. - - """ - import string - nodes = list(string.ascii_lowercase) - G = nx.soft_random_geometric_graph(nodes, 0.25) - assert len(G) == len(nodes) - - def dist(x, y): return sqrt(sum((a - b) ** 2 for a, b in zip(x, y))) - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert dist(G.nodes[u]['pos'], G.nodes[v]['pos']) <= 0.25 - - def test_p_dist_default(self): - """Tests default p_dict = 0.5 returns graph with edge count <= RGG with - same n, radius, dim and positions - - """ - nodes = 50 - dim = 2 - pos = {v: [random.random() for i in range(dim)] for v in range(nodes)} - RGG = nx.random_geometric_graph(50, 0.25, pos=pos) - SRGG = nx.soft_random_geometric_graph(50, 0.25, pos=pos) - assert len(SRGG.edges()) <= len(RGG.edges()) - - def test_p_dist_zero(self): - """Tests if p_dict = 0 returns disconencted graph with 0 edges - - """ - def p_dist(dist): - return 0 - - G = nx.soft_random_geometric_graph(50, 0.25, p_dist=p_dist) - assert len(G.edges) == 0 - - -def join(G, u, v, theta, alpha, metric): - """Returns ``True`` if and only if the nodes whose attributes are - ``du`` and ``dv`` should be joined, according to the threshold - condition for geographical threshold graphs. - - ``G`` is an undirected NetworkX graph, and ``u`` and ``v`` are nodes - in that graph. The nodes must have node attributes ``'pos'`` and - ``'weight'``. - - ``metric`` is a distance metric. - - """ - du, dv = G.nodes[u], G.nodes[v] - u_pos, v_pos = du['pos'], dv['pos'] - u_weight, v_weight = du['weight'], dv['weight'] - return (u_weight + v_weight) * metric(u_pos, v_pos) ** alpha >= theta - - -class TestGeographicalThresholdGraph(object): - """Unit tests for the :func:`~networkx.geographical_threshold_graph` - function. - - """ - - def test_number_of_nodes(self): - G = nx.geographical_threshold_graph(50, 100, seed=42) - assert len(G) == 50 - G = nx.geographical_threshold_graph(range(50), 100, seed=42) - assert len(G) == 50 - - def test_distances(self): - """Tests that pairs of vertices adjacent if and only if their - distances meet the given threshold. - - """ - # Use the Euclidean metric and alpha = -2 - # the default according to the documentation. - dist = euclidean - G = nx.geographical_threshold_graph(50, 10) - for u, v in combinations(G, 2): - # Adjacent vertices must exceed the threshold. - if v in G[u]: - assert join(G, u, v, 10, -2, dist) - # Nonadjacent vertices must not exceed the threshold. - else: - assert not join(G, u, v, 10, -2, dist) - - def test_metric(self): - """Tests for providing an alternate distance metric to the - generator. - - """ - # Use the L1 metric. - dist = l1dist - G = nx.geographical_threshold_graph(50, 10, metric=dist) - for u, v in combinations(G, 2): - # Adjacent vertices must exceed the threshold. - if v in G[u]: - assert join(G, u, v, 10, -2, dist) - # Nonadjacent vertices must not exceed the threshold. - else: - assert not join(G, u, v, 10, -2, dist) - - def test_p_dist_zero(self): - """Tests if p_dict = 0 returns disconencted graph with 0 edges - - """ - def p_dist(dist): - return 0 - - G = nx.geographical_threshold_graph(50, 1, p_dist=p_dist) - assert len(G.edges) == 0 - - -class TestWaxmanGraph(object): - """Unit tests for the :func:`~networkx.waxman_graph` function.""" - - def test_number_of_nodes_1(self): - G = nx.waxman_graph(50, 0.5, 0.1, seed=42) - assert len(G) == 50 - G = nx.waxman_graph(range(50), 0.5, 0.1, seed=42) - assert len(G) == 50 - - def test_number_of_nodes_2(self): - G = nx.waxman_graph(50, 0.5, 0.1, L=1) - assert len(G) == 50 - G = nx.waxman_graph(range(50), 0.5, 0.1, L=1) - assert len(G) == 50 - - def test_metric(self): - """Tests for providing an alternate distance metric to the - generator. - - """ - # Use the L1 metric. - dist = l1dist - G = nx.waxman_graph(50, 0.5, 0.1, metric=dist) - assert len(G) == 50 - - -class TestNavigableSmallWorldGraph(object): - - def test_navigable_small_world(self): - G = nx.navigable_small_world_graph(5, p=1, q=0, seed=42) - gg = nx.grid_2d_graph(5, 5).to_directed() - assert nx.is_isomorphic(G, gg) - - G = nx.navigable_small_world_graph(5, p=1, q=0, dim=3) - gg = nx.grid_graph([5, 5, 5]).to_directed() - assert nx.is_isomorphic(G, gg) - - G = nx.navigable_small_world_graph(5, p=1, q=0, dim=1) - gg = nx.grid_graph([5]).to_directed() - assert nx.is_isomorphic(G, gg) - - -class TestThresholdedRandomGeometricGraph(object): - """Unit tests for the :func:`~networkx.thresholded_random_geometric_graph` - function. - - """ - - def test_number_of_nodes(self): - G = nx.thresholded_random_geometric_graph(50, 0.2, 0.1, seed=42) - assert len(G) == 50 - G = nx.thresholded_random_geometric_graph(range(50), 0.2, 0.1) - assert len(G) == 50 - - def test_distances(self): - """Tests that pairs of vertices adjacent if and only if they are - within the prescribed radius. - - """ - # Use the Euclidean metric, the default according to the - # documentation. - def dist(x, y): return sqrt(sum((a - b) ** 2 for a, b in zip(x, y))) - G = nx.thresholded_random_geometric_graph(50, 0.25, 0.1) - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert dist(G.nodes[u]['pos'], G.nodes[v]['pos']) <= 0.25 - - def test_p(self): - """Tests for providing an alternate distance metric to the - generator. - - """ - # Use the L1 metric. - def dist(x, y): return sum(abs(a - b) for a, b in zip(x, y)) - G = nx.thresholded_random_geometric_graph(50, 0.25, 0.1, p=1) - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert dist(G.nodes[u]['pos'], G.nodes[v]['pos']) <= 0.25 - - def test_node_names(self): - """Tests using values other than sequential numbers as node IDs. - - """ - import string - nodes = list(string.ascii_lowercase) - G = nx.thresholded_random_geometric_graph(nodes, 0.25, 0.1) - assert len(G) == len(nodes) - - def dist(x, y): return sqrt(sum((a - b) ** 2 for a, b in zip(x, y))) - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert dist(G.nodes[u]['pos'], G.nodes[v]['pos']) <= 0.25 - - def test_theta(self): - """Tests that pairs of vertices adjacent if and only if their sum - weights exceeds the threshold parameter theta. - """ - G = nx.thresholded_random_geometric_graph(50, 0.25, 0.1) - - for u, v in combinations(G, 2): - # Adjacent vertices must be within the given distance. - if v in G[u]: - assert (G.nodes[u]['weight'] + G.nodes[v]['weight']) >= 0.1 diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_harary_graph.py b/extensions/fablabchemnitz/networkx/generators/tests/test_harary_graph.py deleted file mode 100644 index 51fbbf80..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_harary_graph.py +++ /dev/null @@ -1,133 +0,0 @@ -"""Unit tests for the :mod:`networkx.generators.harary_graph` module. -""" - -import pytest - -import networkx as nx -from networkx.generators.harary_graph import hnm_harary_graph -from networkx.generators.harary_graph import hkn_harary_graph -from networkx.algorithms.isomorphism.isomorph import is_isomorphic - - -class TestHararyGraph: - """ - Suppose n nodes, m >= n-1 edges, d = 2m // n, r = 2m % n - """ - def test_hnm_harary_graph(self): - # When d is even and r = 0, the hnm_harary_graph(n,m) is - # the circulant_graph(n, list(range(1,d/2+1))) - for (n, m) in [(5, 5), (6, 12), (7, 14)]: - G1 = hnm_harary_graph(n, m) - d = 2*m // n - G2 = nx.circulant_graph(n, list(range(1, d//2 + 1))) - assert is_isomorphic(G1, G2) - - # When d is even and r > 0, the hnm_harary_graph(n,m) is - # the circulant_graph(n, list(range(1,d/2+1))) - # with r edges added arbitrarily - for (n, m) in [(5, 7), (6, 13), (7, 16)]: - G1 = hnm_harary_graph(n, m) - d = 2*m // n - G2 = nx.circulant_graph(n, list(range(1, d//2 + 1))) - assert set(G2.edges) < set(G1.edges) - assert G1.number_of_edges() == m - - # When d is odd and n is even and r = 0, the hnm_harary_graph(n,m) - # is the circulant_graph(n, list(range(1,(d+1)/2) plus [n//2]) - for (n, m) in [(6, 9), (8, 12), (10, 15)]: - G1 = hnm_harary_graph(n, m) - d = 2*m // n - L = list(range(1, (d+1)//2)) - L.append(n//2) - G2 = nx.circulant_graph(n, L) - assert is_isomorphic(G1, G2) - - # When d is odd and n is even and r > 0, the hnm_harary_graph(n,m) - # is the circulant_graph(n, list(range(1,(d+1)/2) plus [n//2]) - # with r edges added arbitrarily - for (n, m) in [(6, 10), (8, 13), (10, 17)]: - G1 = hnm_harary_graph(n, m) - d = 2*m // n - L = list(range(1, (d+1)//2)) - L.append(n//2) - G2 = nx.circulant_graph(n, L) - assert set(G2.edges) < set(G1.edges) - assert G1.number_of_edges() == m - - # When d is odd and n is odd, the hnm_harary_graph(n,m) is - # the circulant_graph(n, list(range(1,(d+1)/2)) - # with m - n*(d-1)/2 edges added arbitrarily - for (n, m) in [(5, 4), (7, 12), (9, 14)]: - G1 = hnm_harary_graph(n, m) - d = 2*m // n - L = list(range(1, (d+1)//2)) - G2 = nx.circulant_graph(n, L) - assert set(G2.edges) < set(G1.edges) - assert G1.number_of_edges() == m - - # Raise NetworkXError if n<1 - n = 0 - m = 0 - pytest.raises(nx.NetworkXError, hnm_harary_graph, n, m) - - # Raise NetworkXError if m < n-1 - n = 6 - m = 4 - pytest.raises(nx.NetworkXError, hnm_harary_graph, n, m) - - # Raise NetworkXError if m > n(n-1)/2 - n = 6 - m = 16 - pytest.raises(nx.NetworkXError, hnm_harary_graph, n, m) - - """ - Suppose connectivity k, number of nodes n - """ - def test_hkn_harary_graph(self): - # When k == 1, the hkn_harary_graph(k,n) is - # the path_graph(n) - for (k, n) in [(1, 6), (1, 7)]: - G1 = hkn_harary_graph(k, n) - G2 = nx.path_graph(n) - assert is_isomorphic(G1, G2) - - # When k is even, the hkn_harary_graph(k,n) is - # the circulant_graph(n, list(range(1,k/2+1))) - for (k, n) in [(2, 6), (2, 7), (4, 6), (4, 7)]: - G1 = hkn_harary_graph(k, n) - G2 = nx.circulant_graph(n, list(range(1, k//2 + 1))) - assert is_isomorphic(G1, G2) - - # When k is odd and n is even, the hkn_harary_graph(k,n) is - # the circulant_graph(n, list(range(1,(k+1)/2)) plus [n/2]) - for (k, n) in [(3, 6), (5, 8), (7, 10)]: - G1 = hkn_harary_graph(k, n) - L = list(range(1, (k+1)//2)) - L.append(n//2) - G2 = nx.circulant_graph(n, L) - assert is_isomorphic(G1, G2) - - # When k is odd and n is odd, the hkn_harary_graph(k,n) is - # the circulant_graph(n, list(range(1,(k+1)/2))) with - # n//2+1 edges added between node i and node i+n//2+1 - for (k, n) in [(3, 5), (5, 9), (7, 11)]: - G1 = hkn_harary_graph(k, n) - G2 = nx.circulant_graph(n, list(range(1, (k+1)//2))) - eSet1 = set(G1.edges) - eSet2 = set(G2.edges) - eSet3 = set() - half = n // 2 - for i in range(0, half+1): - # add half+1 edges between i and i+half - eSet3.add((i, (i+half) % n)) - assert eSet1 == eSet2 | eSet3 - - # Raise NetworkXError if k<1 - k = 0 - n = 0 - pytest.raises(nx.NetworkXError, hkn_harary_graph, k, n) - - # Raise NetworkXError if ndegree_count[1]*degree_count[4] - joint_degrees_3 = {1: {4: 2}, - 2: {2: 2, 3: 2, 4: 2}, - 3: {2: 2, 4: 1}, - 4: {1: 2, 2: 2, 3: 1}} - assert not is_valid_joint_degree(joint_degrees_3) - - # test condition 5 - # joint_degrees_5[1][1] not even - joint_degrees_5 = {1: {1: 9}} - assert not is_valid_joint_degree(joint_degrees_5) - - -def test_joint_degree_graph(ntimes=10): - for _ in range(ntimes): - seed = int(time.time()) - - n, m, p = 20, 10, 1 - # generate random graph with model powerlaw_cluster and calculate - # its joint degree - g = powerlaw_cluster_graph(n, m, p, seed=seed) - joint_degrees_g = degree_mixing_dict(g, normalized=False) - - # generate simple undirected graph with given joint degree - # joint_degrees_g - G = joint_degree_graph(joint_degrees_g) - joint_degrees_G = degree_mixing_dict(G, normalized=False) - - # assert that the given joint degree is equal to the generated - # graph's joint degree - assert joint_degrees_g == joint_degrees_G - - -def test_is_valid_directed_joint_degree(): - - in_degrees = [0, 1, 1, 2] - out_degrees = [1, 1, 1, 1] - nkk = {1: {1: 2, 2: 2}} - assert is_valid_directed_joint_degree(in_degrees, out_degrees, nkk) - - # not realizable, values are not integers. - nkk = {1: {1: 1.5, 2: 2.5}} - assert not is_valid_directed_joint_degree(in_degrees, out_degrees, nkk) - - # not realizable, number of edges between 1-2 are insufficient. - nkk = {1: {1: 2, 2: 1}} - assert not is_valid_directed_joint_degree(in_degrees, out_degrees, nkk) - - # not realizable, in/out degree sequences have different number of nodes. - out_degrees = [1, 1, 1] - nkk = {1: {1: 2, 2: 2}} - assert not is_valid_directed_joint_degree(in_degrees, out_degrees, nkk) - - # not realizable, degree seqeunces have fewer than required nodes. - in_degrees = [0, 1, 2] - assert not is_valid_directed_joint_degree(in_degrees, out_degrees, nkk) - - -def test_directed_joint_degree_graph(n=15, m=100, ntimes=1000): - for _ in range(ntimes): - - # generate gnm random graph and calculate its joint degree. - g = gnm_random_graph(n, m, None, directed=True) - - # in-degree seqeunce of g as a list of integers. - in_degrees = list(dict(g.in_degree()).values()) - # out-degree sequence of g as a list of integers. - out_degrees = list(dict(g.out_degree()).values()) - nkk = degree_mixing_dict(g) - - # generate simple directed graph with given degree sequence and joint - # degree matrix. - G = directed_joint_degree_graph(in_degrees, out_degrees, nkk) - - # assert degree sequence correctness. - assert in_degrees == list(dict(G.in_degree()).values()) - assert out_degrees == list(dict(G.out_degree()).values()) - # assert joint degree matrix correctness. - assert nkk == degree_mixing_dict(G) diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_lattice.py b/extensions/fablabchemnitz/networkx/generators/tests/test_lattice.py deleted file mode 100644 index dfa2e543..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_lattice.py +++ /dev/null @@ -1,211 +0,0 @@ -"""Unit tests for the :mod:`networkx.generators.lattice` module.""" - -import pytest - -import networkx as nx -from networkx.testing import assert_edges_equal - - -class TestGrid2DGraph: - """Unit tests for :func:`networkx.generators.lattice.grid_2d_graph`""" - - def test_number_of_vertices(self): - m, n = 5, 6 - G = nx.grid_2d_graph(m, n) - assert len(G) == m * n - - def test_degree_distribution(self): - m, n = 5, 6 - G = nx.grid_2d_graph(m, n) - expected_histogram = [0, 0, 4, 2 * (m + n) - 8, (m - 2) * (n - 2)] - assert nx.degree_histogram(G) == expected_histogram - - def test_directed(self): - m, n = 5, 6 - G = nx.grid_2d_graph(m, n) - H = nx.grid_2d_graph(m, n, create_using=nx.DiGraph()) - assert H.succ == G.adj - assert H.pred == G.adj - - def test_multigraph(self): - m, n = 5, 6 - G = nx.grid_2d_graph(m, n) - H = nx.grid_2d_graph(m, n, create_using=nx.MultiGraph()) - assert list(H.edges()) == list(G.edges()) - - def test_periodic(self): - G = nx.grid_2d_graph(0, 0, periodic=True) - assert dict(G.degree()) == {} - - for m, n, H in [(2, 2, nx.cycle_graph(4)), (1, 7, nx.cycle_graph(7)), - (7, 1, nx.cycle_graph(7)), - (2, 5, nx.circular_ladder_graph(5)), - (5, 2, nx.circular_ladder_graph(5)), - (2, 4, nx.cubical_graph()), - (4, 2, nx.cubical_graph())]: - G = nx.grid_2d_graph(m, n, periodic=True) - assert nx.could_be_isomorphic(G, H) - - def test_periodic_directed(self): - G = nx.grid_2d_graph(4, 2, periodic=True) - H = nx.grid_2d_graph(4, 2, periodic=True, create_using=nx.DiGraph()) - assert H.succ == G.adj - assert H.pred == G.adj - - def test_periodic_multigraph(self): - G = nx.grid_2d_graph(4, 2, periodic=True) - H = nx.grid_2d_graph(4, 2, periodic=True, create_using=nx.MultiGraph()) - assert list(G.edges()) == list(H.edges()) - - def test_node_input(self): - G = nx.grid_2d_graph(4, 2, periodic=True) - H = nx.grid_2d_graph(range(4), range(2), periodic=True) - assert nx.is_isomorphic(H, G) - H = nx.grid_2d_graph("abcd", "ef", periodic=True) - assert nx.is_isomorphic(H, G) - G = nx.grid_2d_graph(5, 6) - H = nx.grid_2d_graph(range(5), range(6)) - assert_edges_equal(H, G) - - -class TestGridGraph: - """Unit tests for :func:`networkx.generators.lattice.grid_graph`""" - - def test_grid_graph(self): - """grid_graph([n,m]) is a connected simple graph with the - following properties: - number_of_nodes = n*m - degree_histogram = [0,0,4,2*(n+m)-8,(n-2)*(m-2)] - """ - for n, m in [(3, 5), (5, 3), (4, 5), (5, 4)]: - dim = [n, m] - g = nx.grid_graph(dim) - assert len(g) == n * m - assert nx.degree_histogram(g) == [0, 0, 4, 2 * (n + m) - 8, - (n - 2) * (m - 2)] - - for n, m in [(1, 5), (5, 1)]: - dim = [n, m] - g = nx.grid_graph(dim) - assert len(g) == n * m - assert nx.is_isomorphic(g, nx.path_graph(5)) - -# mg = nx.grid_graph([n,m], create_using=MultiGraph()) -# assert_equal(mg.edges(), g.edges()) - - def test_node_input(self): - G = nx.grid_graph([range(7, 9), range(3, 6)]) - assert len(G) == 2 * 3 - assert nx.is_isomorphic(G, nx.grid_graph([2, 3])) - - -class TestHypercubeGraph: - """Unit tests for :func:`networkx.generators.lattice.hypercube_graph`""" - - def test_special_cases(self): - for n, H in [(0, nx.null_graph()), (1, nx.path_graph(2)), - (2, nx.cycle_graph(4)), (3, nx.cubical_graph())]: - G = nx.hypercube_graph(n) - assert nx.could_be_isomorphic(G, H) - - def test_degree_distribution(self): - for n in range(1, 10): - G = nx.hypercube_graph(n) - expected_histogram = [0] * n + [2 ** n] - assert nx.degree_histogram(G) == expected_histogram - - -class TestTriangularLatticeGraph: - "Tests for :func:`networkx.generators.lattice.triangular_lattice_graph`" - - def test_lattice_points(self): - """Tests that the graph is really a triangular lattice.""" - for m, n in [(2, 3), (2, 2), (2, 1), (3, 3), (3, 2), (3, 4)]: - G = nx.triangular_lattice_graph(m, n) - N = (n + 1) // 2 - assert len(G) == (m + 1) * (1 + N) - (n % 2) * ((m + 1) // 2) - for (i, j) in G.nodes(): - nbrs = G[(i, j)] - if i < N: - assert (i + 1, j) in nbrs - if j < m: - assert (i, j + 1) in nbrs - if j < m and (i > 0 or j % 2) and (i < N or (j + 1) % 2): - assert (i + 1, j + 1) in nbrs or (i - 1, j + 1) in nbrs - - def test_directed(self): - """Tests for creating a directed triangular lattice.""" - G = nx.triangular_lattice_graph(3, 4, create_using=nx.Graph()) - H = nx.triangular_lattice_graph(3, 4, create_using=nx.DiGraph()) - assert H.is_directed() - for u, v in H.edges(): - assert v[1] >= u[1] - if v[1] == u[1]: - assert v[0] > u[0] - - def test_multigraph(self): - """Tests for creating a triangular lattice multigraph.""" - G = nx.triangular_lattice_graph(3, 4, create_using=nx.Graph()) - H = nx.triangular_lattice_graph(3, 4, create_using=nx.MultiGraph()) - assert list(H.edges()) == list(G.edges()) - - def test_periodic(self): - G = nx.triangular_lattice_graph(4, 6, periodic=True) - assert len(G) == 12 - assert G.size() == 36 - # all degrees are 6 - assert len([n for n, d in G.degree() if d != 6]) == 0 - G = nx.triangular_lattice_graph(5, 7, periodic=True) - TLG = nx.triangular_lattice_graph - pytest.raises(nx.NetworkXError, TLG, 2, 4, periodic=True) - pytest.raises(nx.NetworkXError, TLG, 4, 4, periodic=True) - pytest.raises(nx.NetworkXError, TLG, 2, 6, periodic=True) - - -class TestHexagonalLatticeGraph: - "Tests for :func:`networkx.generators.lattice.hexagonal_lattice_graph`" - - def test_lattice_points(self): - """Tests that the graph is really a hexagonal lattice.""" - for m, n in [(4, 5), (4, 4), (4, 3), (3, 2), (3, 3), (3, 5)]: - G = nx.hexagonal_lattice_graph(m, n) - assert len(G) == 2 * (m + 1) * (n + 1) - 2 - C_6 = nx.cycle_graph(6) - hexagons = [ - [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)], - [(0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4)], - [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3)], - [(2, 0), (2, 1), (2, 2), (3, 0), (3, 1), (3, 2)], - [(2, 2), (2, 3), (2, 4), (3, 2), (3, 3), (3, 4)], - ] - for hexagon in hexagons: - assert nx.is_isomorphic(G.subgraph(hexagon), C_6) - - def test_directed(self): - """Tests for creating a directed hexagonal lattice.""" - G = nx.hexagonal_lattice_graph(3, 5, create_using=nx.Graph()) - H = nx.hexagonal_lattice_graph(3, 5, create_using=nx.DiGraph()) - assert H.is_directed() - pos = nx.get_node_attributes(H, 'pos') - for u, v in H.edges(): - assert pos[v][1] >= pos[u][1] - if pos[v][1] == pos[u][1]: - assert pos[v][0] > pos[u][0] - - def test_multigraph(self): - """Tests for creating a hexagonal lattice multigraph.""" - G = nx.hexagonal_lattice_graph(3, 5, create_using=nx.Graph()) - H = nx.hexagonal_lattice_graph(3, 5, create_using=nx.MultiGraph()) - assert list(H.edges()) == list(G.edges()) - - def test_periodic(self): - G = nx.hexagonal_lattice_graph(4, 6, periodic=True) - assert len(G) == 48 - assert G.size() == 72 - # all degrees are 3 - assert len([n for n, d in G.degree() if d != 3]) == 0 - G = nx.hexagonal_lattice_graph(5, 8, periodic=True) - HLG = nx.hexagonal_lattice_graph - pytest.raises(nx.NetworkXError, HLG, 2, 7, periodic=True) - pytest.raises(nx.NetworkXError, HLG, 1, 4, periodic=True) - pytest.raises(nx.NetworkXError, HLG, 2, 1, periodic=True) diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_line.py b/extensions/fablabchemnitz/networkx/generators/tests/test_line.py deleted file mode 100644 index 23fe0398..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_line.py +++ /dev/null @@ -1,237 +0,0 @@ -import networkx as nx -import pytest - -import networkx.generators.line as line -from networkx.testing.utils import * - - -def test_node_func(): - # graph - G = nx.Graph() - G.add_edge(1, 2) - nf = line._node_func(G) - assert nf(1, 2) == (1, 2) - assert nf(2, 1) == (1, 2) - - # multigraph - G = nx.MultiGraph() - G.add_edge(1, 2) - G.add_edge(1, 2) - nf = line._node_func(G) - assert nf(1, 2, 0) == (1, 2, 0) - assert nf(2, 1, 0) == (1, 2, 0) - - -def test_edge_func(): - # graph - G = nx.Graph() - G.add_edge(1, 2) - G.add_edge(2, 3) - ef = line._edge_func(G) - expected = [(1, 2), (2, 3)] - assert_edges_equal(ef(), expected) - - # digraph - G = nx.MultiDiGraph() - G.add_edge(1, 2) - G.add_edge(2, 3) - G.add_edge(2, 3) - ef = line._edge_func(G) - expected = [(1, 2, 0), (2, 3, 0), (2, 3, 1)] - result = sorted(ef()) - assert expected == result - - -def test_sorted_edge(): - assert (1, 2) == line._sorted_edge(1, 2) - assert (1, 2) == line._sorted_edge(2, 1) - - -class TestGeneratorLine(): - def test_star(self): - G = nx.star_graph(5) - L = nx.line_graph(G) - assert nx.is_isomorphic(L, nx.complete_graph(5)) - - def test_path(self): - G = nx.path_graph(5) - L = nx.line_graph(G) - assert nx.is_isomorphic(L, nx.path_graph(4)) - - def test_cycle(self): - G = nx.cycle_graph(5) - L = nx.line_graph(G) - assert nx.is_isomorphic(L, G) - - def test_digraph1(self): - G = nx.DiGraph() - G.add_edges_from([(0, 1), (0, 2), (0, 3)]) - L = nx.line_graph(G) - # no edge graph, but with nodes - assert L.adj == {(0, 1): {}, (0, 2): {}, (0, 3): {}} - - def test_digraph2(self): - G = nx.DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3)]) - L = nx.line_graph(G) - assert_edges_equal(L.edges(), [((0, 1), (1, 2)), ((1, 2), (2, 3))]) - - def test_create1(self): - G = nx.DiGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3)]) - L = nx.line_graph(G, create_using=nx.Graph()) - assert_edges_equal(L.edges(), [((0, 1), (1, 2)), ((1, 2), (2, 3))]) - - def test_create2(self): - G = nx.Graph() - G.add_edges_from([(0, 1), (1, 2), (2, 3)]) - L = nx.line_graph(G, create_using=nx.DiGraph()) - assert_edges_equal(L.edges(), [((0, 1), (1, 2)), ((1, 2), (2, 3))]) - - -class TestGeneratorInverseLine(): - def test_example(self): - G = nx.Graph() - G_edges = [[1, 2], [1, 3], [1, 4], [1, 5], [2, 3], [2, 5], [2, 6], - [2, 7], [3, 4], [3, 5], [6, 7], [6, 8], [7, 8]] - G.add_edges_from(G_edges) - H = nx.inverse_line_graph(G) - solution = nx.Graph() - solution_edges = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('a', 'e'), - ('c', 'd'), ('e', 'f'), ('e', 'g'), ('f', 'g')] - solution.add_edges_from(solution_edges) - assert nx.is_isomorphic(H, solution) - - def test_example_2(self): - G = nx.Graph() - G_edges = [[1, 2], [1, 3], [2, 3], - [3, 4], [3, 5], [4, 5]] - G.add_edges_from(G_edges) - H = nx.inverse_line_graph(G) - solution = nx.Graph() - solution_edges = [('a', 'c'), ('b', 'c'), ('c', 'd'), - ('d', 'e'), ('d', 'f')] - solution.add_edges_from(solution_edges) - assert nx.is_isomorphic(H, solution) - - def test_pair(self): - G = nx.path_graph(2) - H = nx.inverse_line_graph(G) - solution = nx.path_graph(3) - assert nx.is_isomorphic(H, solution) - - def test_line(self): - G = nx.path_graph(5) - solution = nx.path_graph(6) - H = nx.inverse_line_graph(G) - assert nx.is_isomorphic(H, solution) - - def test_triangle_graph(self): - G = nx.complete_graph(3) - H = nx.inverse_line_graph(G) - alternative_solution = nx.Graph() - alternative_solution.add_edges_from([[0, 1], [0, 2], [0, 3]]) - # there are two alternative inverse line graphs for this case - # so long as we get one of them the test should pass - assert (nx.is_isomorphic(H, G) or - nx.is_isomorphic(H, alternative_solution)) - - def test_cycle(self): - G = nx.cycle_graph(5) - H = nx.inverse_line_graph(G) - assert nx.is_isomorphic(H, G) - - def test_empty(self): - G = nx.Graph() - H = nx.inverse_line_graph(G) - assert nx.is_isomorphic(H, nx.complete_graph(1)) - - def test_K1(self): - G = nx.complete_graph(1) - H = nx.inverse_line_graph(G) - solution = nx.path_graph(2) - assert nx.is_isomorphic(H, solution) - - def test_claw(self): - # This is the simplest non-line graph - G = nx.Graph() - G_edges = [[0, 1], [0, 2], [0, 3]] - G.add_edges_from(G_edges) - pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G) - - def test_non_line_graph(self): - # These are other non-line graphs - - # wheel graph with 6 nodes - G = nx.Graph() - G_edges = [[0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [1, 2], - [2, 3], [3, 4], [4, 5], [5, 1]] - G.add_edges_from(G_edges) - pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G) - - # 3---4---5 - # / \ / \ / - # 0---1---2 - G = nx.Graph() - G_edges = [[0, 1], [1, 2], [3, 4], [4, 5], [0, 3], [1, 3], - [1, 4], [2, 4], [2, 5]] - G.add_edges_from(G_edges) - pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G) - - # K_5 minus an edge - K5me = nx.complete_graph(5) - K5me.remove_edge(0,1) - pytest.raises(nx.NetworkXError, nx.inverse_line_graph, K5me) - - def test_wrong_graph_type(self): - G = nx.DiGraph() - G_edges = [[0, 1], [0, 2], [0, 3]] - G.add_edges_from(G_edges) - pytest.raises(nx.NetworkXNotImplemented, nx.inverse_line_graph, G) - - G = nx.MultiGraph() - G_edges = [[0, 1], [0, 2], [0, 3]] - G.add_edges_from(G_edges) - pytest.raises(nx.NetworkXNotImplemented, nx.inverse_line_graph, G) - - def test_line_inverse_line_complete(self): - G = nx.complete_graph(10) - H = nx.line_graph(G) - J = nx.inverse_line_graph(H) - assert nx.is_isomorphic(G, J) - - def test_line_inverse_line_path(self): - G = nx.path_graph(10) - H = nx.line_graph(G) - J = nx.inverse_line_graph(H) - assert nx.is_isomorphic(G, J) - - def test_line_inverse_line_hypercube(self): - G = nx.hypercube_graph(5) - H = nx.line_graph(G) - J = nx.inverse_line_graph(H) - assert nx.is_isomorphic(G, J) - - def test_line_inverse_line_cycle(self): - G = nx.cycle_graph(10) - H = nx.line_graph(G) - J = nx.inverse_line_graph(H) - assert nx.is_isomorphic(G, J) - - def test_line_inverse_line_star(self): - G = nx.star_graph(20) - H = nx.line_graph(G) - J = nx.inverse_line_graph(H) - assert nx.is_isomorphic(G, J) - - def test_line_inverse_line_multipartite(self): - G = nx.complete_multipartite_graph(3, 4, 5) - H = nx.line_graph(G) - J = nx.inverse_line_graph(H) - assert nx.is_isomorphic(G, J) - - def test_line_inverse_line_dgm(self): - G = nx.dorogovtsev_goltsev_mendes_graph(4) - H = nx.line_graph(G) - J = nx.inverse_line_graph(H) - assert nx.is_isomorphic(G, J) diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_mycielski.py b/extensions/fablabchemnitz/networkx/generators/tests/test_mycielski.py deleted file mode 100644 index 20ac1d7e..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_mycielski.py +++ /dev/null @@ -1,36 +0,0 @@ -# test_mycielski.py - unit tests for the mycielski module -# -# Copyright 2010, 2011, 2012, 2013, 2014, 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. - -"""Unit tests for the :mod:`networkx.generators.mycielski` module.""" - -import networkx as nx - - -class TestMycielski(object): - - def test_construction(self): - G = nx.path_graph(2) - M = nx.mycielskian(G) - assert nx.is_isomorphic(M, nx.cycle_graph(5)) - - def test_size(self): - G = nx.path_graph(2) - M = nx.mycielskian(G, 2) - assert len(M) == 11 - assert M.size() == 20 - - def test_mycielski_graph_generator(self): - G = nx.mycielski_graph(1) - assert nx.is_isomorphic(G, nx.empty_graph(1)) - G = nx.mycielski_graph(2) - assert nx.is_isomorphic(G, nx.path_graph(2)) - G = nx.mycielski_graph(3) - assert nx.is_isomorphic(G, nx.cycle_graph(5)) - G = nx.mycielski_graph(4) - assert nx.is_isomorphic(G, nx.mycielskian(nx.cycle_graph(5))) diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_nonisomorphic_trees.py b/extensions/fablabchemnitz/networkx/generators/tests/test_nonisomorphic_trees.py deleted file mode 100644 index 4cd701d7..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_nonisomorphic_trees.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python -""" -==================== -Generators - Non Isomorphic Trees -==================== - -Unit tests for WROM algorithm generator in generators/nonisomorphic_trees.py -""" -import networkx as nx -from networkx.testing import assert_edges_equal - - -class TestGeneratorNonIsomorphicTrees(): - - def test_tree_structure(self): - # test for tree structure for nx.nonisomorphic_trees() - def f(x): return list(nx.nonisomorphic_trees(x)) - for i in f(6): - assert nx.is_tree(i) - for i in f(8): - assert nx.is_tree(i) - - def test_nonisomorphism(self): - # test for nonisomorphism of trees for nx.nonisomorphic_trees() - def f(x): return list(nx.nonisomorphic_trees(x)) - trees = f(6) - for i in range(len(trees)): - for j in range(i + 1, len(trees)): - assert not nx.is_isomorphic(trees[i], trees[j]) - trees = f(8) - for i in range(len(trees)): - for j in range(i + 1, len(trees)): - assert not nx.is_isomorphic(trees[i], trees[j]) - - def test_number_of_nonisomorphic_trees(self): - # http://oeis.org/A000055 - assert nx.number_of_nonisomorphic_trees(2) == 1 - assert nx.number_of_nonisomorphic_trees(3) == 1 - assert nx.number_of_nonisomorphic_trees(4) == 2 - assert nx.number_of_nonisomorphic_trees(5) == 3 - assert nx.number_of_nonisomorphic_trees(6) == 6 - assert nx.number_of_nonisomorphic_trees(7) == 11 - assert nx.number_of_nonisomorphic_trees(8) == 23 - - def test_nonisomorphic_trees(self): - def f(x): return list(nx.nonisomorphic_trees(x)) - assert_edges_equal(f(3)[0].edges(), [(0, 1), (0, 2)]) - assert_edges_equal(f(4)[0].edges(), [(0, 1), (0, 3), (1, 2)]) - assert_edges_equal(f(4)[1].edges(), [(0, 1), (0, 2), (0, 3)]) - - def test_nonisomorphic_trees_matrix(self): - trees_2 = [[[0, 1], [1, 0]]] - assert list(nx.nonisomorphic_trees(2, create="matrix")) == trees_2 - trees_3 = [[[0, 1, 1], [1, 0, 0], [1, 0, 0]]] - assert list(nx.nonisomorphic_trees(3, create="matrix")) == trees_3 - trees_4 = [[[0, 1, 0, 1], [1, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]], - [[0, 1, 1, 1], [1, 0, 0, 0], [1, 0, 0, 0], [1, 0, 0, 0]]] - assert list(nx.nonisomorphic_trees(4, create="matrix")) == trees_4 diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_random_clustered.py b/extensions/fablabchemnitz/networkx/generators/tests/test_random_clustered.py deleted file mode 100644 index 2483799d..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_random_clustered.py +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env python -import pytest -import networkx - - -class TestRandomClusteredGraph: - - def test_valid(self): - node = [1, 1, 1, 2, 1, 2, 0, 0] - tri = [0, 0, 0, 0, 0, 1, 1, 1] - joint_degree_sequence = zip(node, tri) - G = networkx.random_clustered_graph(joint_degree_sequence) - assert G.number_of_nodes() == 8 - assert G.number_of_edges() == 7 - - def test_valid2(self): - G = networkx.random_clustered_graph( - [(1, 2), (2, 1), (1, 1), (1, 1), (1, 1), (2, 0)]) - assert G.number_of_nodes() == 6 - assert G.number_of_edges() == 10 - - def test_invalid1(self): - pytest.raises((TypeError, networkx.NetworkXError), - networkx.random_clustered_graph, [[1, 1], [2, 1], [0, 1]]) - - def test_invalid2(self): - pytest.raises((TypeError, networkx.NetworkXError), - networkx.random_clustered_graph, [[1, 1], [1, 2], [0, 1]]) diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_random_graphs.py b/extensions/fablabchemnitz/networkx/generators/tests/test_random_graphs.py deleted file mode 100644 index a81bd00d..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_random_graphs.py +++ /dev/null @@ -1,273 +0,0 @@ -# -*- encoding: utf-8 -*- -# test_random_graphs.py - unit tests for random graph generators -# -# Copyright 2010-2019 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.generators.random_graphs` module. - -""" -import pytest - -from networkx.exception import NetworkXError -from networkx.generators.random_graphs import barabasi_albert_graph -from networkx.generators.random_graphs import dual_barabasi_albert_graph -from networkx.generators.random_graphs import extended_barabasi_albert_graph -from networkx.generators.random_graphs import binomial_graph -from networkx.generators.random_graphs import connected_watts_strogatz_graph -from networkx.generators.random_graphs import dense_gnm_random_graph -from networkx.generators.random_graphs import erdos_renyi_graph -from networkx.generators.random_graphs import fast_gnp_random_graph -from networkx.generators.random_graphs import gnm_random_graph -from networkx.generators.random_graphs import gnp_random_graph -from networkx.generators.random_graphs import newman_watts_strogatz_graph -from networkx.generators.random_graphs import powerlaw_cluster_graph -from networkx.generators.random_graphs import random_kernel_graph -from networkx.generators.random_graphs import random_lobster -from networkx.generators.random_graphs import random_powerlaw_tree -from networkx.generators.random_graphs import random_powerlaw_tree_sequence -from networkx.generators.random_graphs import random_regular_graph -from networkx.generators.random_graphs import random_shell_graph -from networkx.generators.random_graphs import watts_strogatz_graph - - -class TestGeneratorsRandom(object): - - def smoke_test_random_graph(self): - seed = 42 - G = gnp_random_graph(100, 0.25, seed) - G = gnp_random_graph(100, 0.25, seed, directed=True) - G = binomial_graph(100, 0.25, seed) - G = erdos_renyi_graph(100, 0.25, seed) - G = fast_gnp_random_graph(100, 0.25, seed) - G = fast_gnp_random_graph(100, 0.25, seed, directed=True) - G = gnm_random_graph(100, 20, seed) - G = gnm_random_graph(100, 20, seed, directed=True) - G = dense_gnm_random_graph(100, 20, seed) - - G = watts_strogatz_graph(10, 2, 0.25, seed) - assert len(G) == 10 - assert G.number_of_edges() == 10 - - G = connected_watts_strogatz_graph(10, 2, 0.1, tries=10, seed=seed) - assert len(G) == 10 - assert G.number_of_edges() == 10 - pytest.raises(NetworkXError, connected_watts_strogatz_graph, \ - 10, 2, 0.1, tries=0) - - G = watts_strogatz_graph(10, 4, 0.25, seed) - assert len(G) == 10 - assert G.number_of_edges() == 20 - - G = newman_watts_strogatz_graph(10, 2, 0.0, seed) - assert len(G) == 10 - assert G.number_of_edges() == 10 - - G = newman_watts_strogatz_graph(10, 4, 0.25, seed) - assert len(G) == 10 - assert G.number_of_edges() >= 20 - - G = barabasi_albert_graph(100, 1, seed) - G = barabasi_albert_graph(100, 3, seed) - assert G.number_of_edges() == (97 * 3) - - G = extended_barabasi_albert_graph(100, 1, 0, 0, seed) - assert G.number_of_edges() == 99 - G = extended_barabasi_albert_graph(100, 3, 0, 0, seed) - assert G.number_of_edges() == 97 * 3 - G = extended_barabasi_albert_graph(100, 1, 0, 0.5, seed) - assert G.number_of_edges() == 99 - G = extended_barabasi_albert_graph(100, 2, 0.5, 0, seed) - assert G.number_of_edges() > 100 * 3 - assert G.number_of_edges() < 100 * 4 - - G = extended_barabasi_albert_graph(100, 2, 0.3, 0.3, seed) - assert G.number_of_edges() > 100 * 2 - assert G.number_of_edges() < 100 * 4 - - G = powerlaw_cluster_graph(100, 1, 1.0, seed) - G = powerlaw_cluster_graph(100, 3, 0.0, seed) - assert G.number_of_edges() == (97 * 3) - - G = random_regular_graph(10, 20, seed) - - pytest.raises(NetworkXError, random_regular_graph, 3, 21) - pytest.raises(NetworkXError, random_regular_graph, 33, 21) - - constructor = [(10, 20, 0.8), (20, 40, 0.8)] - G = random_shell_graph(constructor, seed) - - G = random_lobster(10, 0.1, 0.5, seed) - - # difficult to find seed that requires few tries - seq = random_powerlaw_tree_sequence(10, 3, seed=14, tries=1) - G = random_powerlaw_tree(10, 3, seed=14, tries=1) - - def test_dual_barabasi_albert(self, m1=1, m2=4, p=0.5): - """ - Tests that the dual BA random graph generated behaves consistently. - - Tests the exceptions are raised as expected. - - The graphs generation are repeated several times to prevent lucky shots - - """ - seed = 42 - repeats = 2 - - while repeats: - repeats -= 1 - - # This should be BA with m = m1 - BA1 = barabasi_albert_graph(100, m1, seed) - DBA1 = dual_barabasi_albert_graph(100, m1, m2, 1, seed) - assert BA1.size() == DBA1.size() - - # This should be BA with m = m2 - BA2 = barabasi_albert_graph(100, m2, seed) - DBA2 = dual_barabasi_albert_graph(100, m1, m2, 0, seed) - assert BA2.size() == DBA2.size() - - # Testing exceptions - dbag = dual_barabasi_albert_graph - pytest.raises(NetworkXError, dbag, m1, m1, m2, 0) - pytest.raises(NetworkXError, dbag, m2, m1, m2, 0) - pytest.raises(NetworkXError, dbag, 100, m1, m2, -0.5) - pytest.raises(NetworkXError, dbag, 100, m1, m2, 1.5) - - def test_extended_barabasi_albert(self, m=2): - """ - Tests that the extended BA random graph generated behaves consistently. - - Tests the exceptions are raised as expected. - - The graphs generation are repeated several times to prevent lucky-shots - - """ - seed = 42 - repeats = 2 - BA_model = barabasi_albert_graph(100, m, seed) - BA_model_edges = BA_model.number_of_edges() - - while repeats: - repeats -= 1 - - # This behaves just like BA, the number of edges must be the same - G1 = extended_barabasi_albert_graph(100, m, 0, 0, seed) - assert G1.size() == BA_model_edges - - # More than twice more edges should have been added - G1 = extended_barabasi_albert_graph(100, m, 0.8, 0, seed) - assert G1.size() > BA_model_edges * 2 - - # Only edge rewiring, so the number of edges less than original - G2 = extended_barabasi_albert_graph(100, m, 0, 0.8, seed) - assert G2.size() == BA_model_edges - - # Mixed scenario: less edges than G1 and more edges than G2 - G3 = extended_barabasi_albert_graph(100, m, 0.3, 0.3, seed) - assert G3.size() > G2.size() - assert G3.size() < G1.size() - - # Testing exceptions - ebag = extended_barabasi_albert_graph - pytest.raises(NetworkXError, ebag, m, m, 0, 0) - pytest.raises(NetworkXError, ebag, 1, 0.5, 0, 0) - pytest.raises(NetworkXError, ebag, 100, 2, 0.5, 0.5) - - def test_random_zero_regular_graph(self): - """Tests that a 0-regular graph has the correct number of nodes and - edges. - - """ - seed = 42 - G = random_regular_graph(0, 10, seed) - assert len(G) == 10 - assert sum(1 for _ in G.edges()) == 0 - - def test_gnp(self): - for generator in [gnp_random_graph, binomial_graph, erdos_renyi_graph, - fast_gnp_random_graph]: - G = generator(10, -1.1) - assert len(G) == 10 - assert sum(1 for _ in G.edges()) == 0 - - G = generator(10, 0.1) - assert len(G) == 10 - - G = generator(10, 0.1, seed=42) - assert len(G) == 10 - - G = generator(10, 1.1) - assert len(G) == 10 - assert sum(1 for _ in G.edges()) == 45 - - G = generator(10, -1.1, directed=True) - assert G.is_directed() - assert len(G) == 10 - assert sum(1 for _ in G.edges()) == 0 - - G = generator(10, 0.1, directed=True) - assert G.is_directed() - assert len(G) == 10 - - G = generator(10, 1.1, directed=True) - assert G.is_directed() - assert len(G) == 10 - assert sum(1 for _ in G.edges()) == 90 - - # assert that random graphs generate all edges for p close to 1 - edges = 0 - runs = 100 - for i in range(runs): - edges += sum(1 for _ in generator(10, 0.99999, directed=True).edges()) - assert abs(edges / float(runs) - 90) <= runs * 2.0 / 100 - - def test_gnm(self): - G = gnm_random_graph(10, 3) - assert len(G) == 10 - assert sum(1 for _ in G.edges()) == 3 - - G = gnm_random_graph(10, 3, seed=42) - assert len(G) == 10 - assert sum(1 for _ in G.edges()) == 3 - - G = gnm_random_graph(10, 100) - assert len(G) == 10 - assert sum(1 for _ in G.edges()) == 45 - - G = gnm_random_graph(10, 100, directed=True) - assert len(G) == 10 - assert sum(1 for _ in G.edges()) == 90 - - G = gnm_random_graph(10, -1.1) - assert len(G) == 10 - assert sum(1 for _ in G.edges()) == 0 - - def test_watts_strogatz_big_k(self): - #Test to make sure than n <= k - pytest.raises(NetworkXError, watts_strogatz_graph, 10, 11, 0.25) - pytest.raises(NetworkXError, newman_watts_strogatz_graph, 10, 11, 0.25) - - # could create an infinite loop, now doesn't - # infinite loop used to occur when a node has degree n-1 and needs to rewire - watts_strogatz_graph(10, 9, 0.25, seed=0) - newman_watts_strogatz_graph(10, 9, 0.5, seed=0) - - #Test k==n scenario - watts_strogatz_graph(10, 10, 0.25, seed=0) - newman_watts_strogatz_graph(10, 10, 0.25, seed=0) - - def test_random_kernel_graph(self): - def integral(u, w, z): - return c * (z - w) - - def root(u, w, r): - return r / c + w - c = 1 - graph = random_kernel_graph(1000, integral, root) - graph = random_kernel_graph(1000, integral, root, seed=42) - assert len(graph) == 1000 diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_small.py b/extensions/fablabchemnitz/networkx/generators/tests/test_small.py deleted file mode 100644 index 43c22aa5..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_small.py +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env python - -import pytest -import networkx as nx -from networkx.algorithms.isomorphism.isomorph import graph_could_be_isomorphic -is_isomorphic = graph_could_be_isomorphic - -"""Generators - Small -===================== - -Some small graphs -""" - -null = nx.null_graph() - - -class TestGeneratorsSmall(): - def test_make_small_graph(self): - d = ["adjacencylist", "Bull Graph", 5, [[2, 3], [1, 3, 4], [1, 2, 5], [2], [3]]] - G = nx.make_small_graph(d) - assert is_isomorphic(G, nx.bull_graph()) - - def test__LCF_graph(self): - # If n<=0, then return the null_graph - G = nx.LCF_graph(-10, [1, 2], 100) - assert is_isomorphic(G, null) - G = nx.LCF_graph(0, [1, 2], 3) - assert is_isomorphic(G, null) - G = nx.LCF_graph(0, [1, 2], 10) - assert is_isomorphic(G, null) - - # Test that LCF(n,[],0) == cycle_graph(n) - for a, b, c in [(5, [], 0), (10, [], 0), (5, [], 1), (10, [], 10)]: - G = nx.LCF_graph(a, b, c) - assert is_isomorphic(G, nx.cycle_graph(a)) - - # Generate the utility graph K_{3,3} - G = nx.LCF_graph(6, [3, -3], 3) - utility_graph = nx.complete_bipartite_graph(3, 3) - assert is_isomorphic(G, utility_graph) - - def test_properties_named_small_graphs(self): - G = nx.bull_graph() - assert G.number_of_nodes() == 5 - assert G.number_of_edges() == 5 - assert sorted(d for n, d in G.degree()) == [1, 1, 2, 3, 3] - assert nx.diameter(G) == 3 - assert nx.radius(G) == 2 - - G = nx.chvatal_graph() - assert G.number_of_nodes() == 12 - assert G.number_of_edges() == 24 - assert list(d for n, d in G.degree()) == 12 * [4] - assert nx.diameter(G) == 2 - assert nx.radius(G) == 2 - - G = nx.cubical_graph() - assert G.number_of_nodes() == 8 - assert G.number_of_edges() == 12 - assert list(d for n, d in G.degree()) == 8 * [3] - assert nx.diameter(G) == 3 - assert nx.radius(G) == 3 - - G = nx.desargues_graph() - assert G.number_of_nodes() == 20 - assert G.number_of_edges() == 30 - assert list(d for n, d in G.degree()) == 20 * [3] - - G = nx.diamond_graph() - assert G.number_of_nodes() == 4 - assert sorted(d for n, d in G.degree()) == [2, 2, 3, 3] - assert nx.diameter(G) == 2 - assert nx.radius(G) == 1 - - G = nx.dodecahedral_graph() - assert G.number_of_nodes() == 20 - assert G.number_of_edges() == 30 - assert list(d for n, d in G.degree()) == 20 * [3] - assert nx.diameter(G) == 5 - assert nx.radius(G) == 5 - - G = nx.frucht_graph() - assert G.number_of_nodes() == 12 - assert G.number_of_edges() == 18 - assert list(d for n, d in G.degree()) == 12 * [3] - assert nx.diameter(G) == 4 - assert nx.radius(G) == 3 - - G = nx.heawood_graph() - assert G.number_of_nodes() == 14 - assert G.number_of_edges() == 21 - assert list(d for n, d in G.degree()) == 14 * [3] - assert nx.diameter(G) == 3 - assert nx.radius(G) == 3 - - G = nx.hoffman_singleton_graph() - assert G.number_of_nodes() == 50 - assert G.number_of_edges() == 175 - assert list(d for n, d in G.degree()) == 50 * [7] - assert nx.diameter(G) == 2 - assert nx.radius(G) == 2 - - G = nx.house_graph() - assert G.number_of_nodes() == 5 - assert G.number_of_edges() == 6 - assert sorted(d for n, d in G.degree()) == [2, 2, 2, 3, 3] - assert nx.diameter(G) == 2 - assert nx.radius(G) == 2 - - G = nx.house_x_graph() - assert G.number_of_nodes() == 5 - assert G.number_of_edges() == 8 - assert sorted(d for n, d in G.degree()) == [2, 3, 3, 4, 4] - assert nx.diameter(G) == 2 - assert nx.radius(G) == 1 - - G = nx.icosahedral_graph() - assert G.number_of_nodes() == 12 - assert G.number_of_edges() == 30 - assert (list(d for n, d in G.degree()) == - [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5]) - assert nx.diameter(G) == 3 - assert nx.radius(G) == 3 - - G = nx.krackhardt_kite_graph() - assert G.number_of_nodes() == 10 - assert G.number_of_edges() == 18 - assert (sorted(d for n, d in G.degree()) == - [1, 2, 3, 3, 3, 4, 4, 5, 5, 6]) - - G = nx.moebius_kantor_graph() - assert G.number_of_nodes() == 16 - assert G.number_of_edges() == 24 - assert list(d for n, d in G.degree()) == 16 * [3] - assert nx.diameter(G) == 4 - - G = nx.octahedral_graph() - assert G.number_of_nodes() == 6 - assert G.number_of_edges() == 12 - assert list(d for n, d in G.degree()) == 6 * [4] - assert nx.diameter(G) == 2 - assert nx.radius(G) == 2 - - G = nx.pappus_graph() - assert G.number_of_nodes() == 18 - assert G.number_of_edges() == 27 - assert list(d for n, d in G.degree()) == 18 * [3] - assert nx.diameter(G) == 4 - - G = nx.petersen_graph() - assert G.number_of_nodes() == 10 - assert G.number_of_edges() == 15 - assert list(d for n, d in G.degree()) == 10 * [3] - assert nx.diameter(G) == 2 - assert nx.radius(G) == 2 - - G = nx.sedgewick_maze_graph() - assert G.number_of_nodes() == 8 - assert G.number_of_edges() == 10 - assert sorted(d for n, d in G.degree()) == [1, 2, 2, 2, 3, 3, 3, 4] - - G = nx.tetrahedral_graph() - assert G.number_of_nodes() == 4 - assert G.number_of_edges() == 6 - assert list(d for n, d in G.degree()) == [3, 3, 3, 3] - assert nx.diameter(G) == 1 - assert nx.radius(G) == 1 - - G = nx.truncated_cube_graph() - assert G.number_of_nodes() == 24 - assert G.number_of_edges() == 36 - assert list(d for n, d in G.degree()) == 24 * [3] - - G = nx.truncated_tetrahedron_graph() - assert G.number_of_nodes() == 12 - assert G.number_of_edges() == 18 - assert list(d for n, d in G.degree()) == 12 * [3] - - G = nx.tutte_graph() - assert G.number_of_nodes() == 46 - assert G.number_of_edges() == 69 - assert list(d for n, d in G.degree()) == 46 * [3] - - # Test create_using with directed or multigraphs on small graphs - pytest.raises(nx.NetworkXError, nx.tutte_graph, - create_using=nx.DiGraph) - MG = nx.tutte_graph(create_using=nx.MultiGraph) - assert sorted(MG.edges()) == sorted(G.edges()) diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_spectral_graph_forge.py b/extensions/fablabchemnitz/networkx/generators/tests/test_spectral_graph_forge.py deleted file mode 100644 index f1da0a0c..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_spectral_graph_forge.py +++ /dev/null @@ -1,48 +0,0 @@ -import pytest - -from networkx import is_isomorphic -from networkx.exception import NetworkXError -from networkx.testing import assert_nodes_equal -from networkx.generators.spectral_graph_forge import spectral_graph_forge -from networkx.generators import karate_club_graph - - -def test_spectral_graph_forge(): - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') - - G = karate_club_graph() - - seed = 54321 - - # common cases, just checking node number preserving and difference - # between identity and modularity cases - H = spectral_graph_forge(G, 0.1, transformation='identity', seed=seed) - assert_nodes_equal(G, H) - - I = spectral_graph_forge(G, 0.1, transformation='identity', seed=seed) - assert_nodes_equal(G, H) - assert is_isomorphic(I, H) - - I = spectral_graph_forge(G, 0.1, transformation='modularity', seed=seed) - assert_nodes_equal(G, I) - - assert not is_isomorphic(I, H) - - # with all the eigenvectors, output graph is identical to the input one - H = spectral_graph_forge(G, 1, transformation='modularity', seed=seed) - assert_nodes_equal(G, H) - assert is_isomorphic(G, H) - - # invalid alpha input value, it is silently truncated in [0,1] - H = spectral_graph_forge(G, -1, transformation='identity', seed=seed) - assert_nodes_equal(G, H) - - H = spectral_graph_forge(G, 10, transformation='identity', seed=seed) - assert_nodes_equal(G, H) - assert is_isomorphic(G, H) - - # invalid transformation mode, checking the error raising - pytest.raises(NetworkXError, - spectral_graph_forge, G, 0.1, transformation='unknown', - seed=seed) diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_stochastic.py b/extensions/fablabchemnitz/networkx/generators/tests/test_stochastic.py deleted file mode 100644 index 1cedd0a5..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_stochastic.py +++ /dev/null @@ -1,61 +0,0 @@ -# test_stochastic.py - unit tests for the stochastic module -# -# Copyright 2010, 2011, 2012, 2013, 2014, 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.generators.stochastic` module.""" -import pytest -import networkx as nx - - -class TestStochasticGraph(object): - """Unit tests for the :func:`~networkx.stochastic_graph` function. - - """ - - def test_default_weights(self): - G = nx.DiGraph() - G.add_edge(0, 1) - G.add_edge(0, 2) - S = nx.stochastic_graph(G) - assert nx.is_isomorphic(G, S) - assert (sorted(S.edges(data=True)) == - [(0, 1, {'weight': 0.5}), (0, 2, {'weight': 0.5})]) - - def test_in_place(self): - """Tests for an in-place reweighting of the edges of the graph. - - """ - G = nx.DiGraph() - G.add_edge(0, 1, weight=1) - G.add_edge(0, 2, weight=1) - nx.stochastic_graph(G, copy=False) - assert (sorted(G.edges(data=True)) == - [(0, 1, {'weight': 0.5}), (0, 2, {'weight': 0.5})]) - - def test_arbitrary_weights(self): - G = nx.DiGraph() - G.add_edge(0, 1, weight=1) - G.add_edge(0, 2, weight=1) - S = nx.stochastic_graph(G) - assert (sorted(S.edges(data=True)) == - [(0, 1, {'weight': 0.5}), (0, 2, {'weight': 0.5})]) - - def test_multidigraph(self): - G = nx.MultiDiGraph() - G.add_edges_from([(0, 1), (0, 1), (0, 2), (0, 2)]) - S = nx.stochastic_graph(G) - d = dict(weight=0.25) - assert (sorted(S.edges(data=True)) == - [(0, 1, d), (0, 1, d), (0, 2, d), (0, 2, d)]) - - def test_graph_disallowed(self): - with pytest.raises(nx.NetworkXNotImplemented): - nx.stochastic_graph(nx.Graph()) - - def test_multigraph_disallowed(self): - with pytest.raises(nx.NetworkXNotImplemented): - nx.stochastic_graph(nx.MultiGraph()) diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_trees.py b/extensions/fablabchemnitz/networkx/generators/tests/test_trees.py deleted file mode 100644 index 1d150cd2..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_trees.py +++ /dev/null @@ -1,74 +0,0 @@ - -import networkx as nx -from networkx.generators.trees import NIL -from networkx.utils import arbitrary_element - - -class TestPrefixTree(object): - """Unit tests for the prefix tree generator function.""" - - def test_basic(self): - # This example is from the Wikipedia article "Trie" - # . - strings = ['a', 'to', 'tea', 'ted', 'ten', 'i', 'in', 'inn'] - T, root = nx.prefix_tree(strings) - - def source_label(v): return T.nodes[v]['source'] - - # First, we check that the tree has the expected - # structure. Recall that each node that corresponds to one of - # the input strings has an edge to the NIL node. - # - # Consider the three children at level 1 in the trie. - a, i, t = sorted(T[root], key=source_label) - # Check the 'a' branch. - assert len(T[a]) == 1 - nil = arbitrary_element(T[a]) - assert len(T[nil]) == 0 - # Check the 'i' branch. - assert len(T[i]) == 2 - nil, in_ = sorted(T[i], key=source_label) - assert len(T[nil]) == 0 - assert len(T[in_]) == 2 - nil, inn = sorted(T[in_], key=source_label) - assert len(T[nil]) == 0 - assert len(T[inn]) == 1 - nil = arbitrary_element(T[inn]) - assert len(T[nil]) == 0 - # Check the 't' branch. - te, to = sorted(T[t], key=source_label) - assert len(T[to]) == 1 - nil = arbitrary_element(T[to]) - assert len(T[nil]) == 0 - tea, ted, ten = sorted(T[te], key=source_label) - assert len(T[tea]) == 1 - assert len(T[ted]) == 1 - assert len(T[ten]) == 1 - nil = arbitrary_element(T[tea]) - assert len(T[nil]) == 0 - nil = arbitrary_element(T[ted]) - assert len(T[nil]) == 0 - nil = arbitrary_element(T[ten]) - assert len(T[nil]) == 0 - - # Next, we check that the "sources" of each of the nodes is the - # rightmost letter in the string corresponding to the path to - # that node. - assert source_label(root) == None - assert source_label(a) == 'a' - assert source_label(i) == 'i' - assert source_label(t) == 't' - assert source_label(in_) == 'n' - assert source_label(inn) == 'n' - assert source_label(to) == 'o' - assert source_label(te) == 'e' - assert source_label(tea) == 'a' - assert source_label(ted) == 'd' - assert source_label(ten) == 'n' - assert source_label(NIL) == NIL - - -def test_random_tree(): - """Tests that a random tree is in fact a tree.""" - T = nx.random_tree(10, seed=1234) - assert nx.is_tree(T) diff --git a/extensions/fablabchemnitz/networkx/generators/tests/test_triads.py b/extensions/fablabchemnitz/networkx/generators/tests/test_triads.py deleted file mode 100644 index 2474c3ab..00000000 --- a/extensions/fablabchemnitz/networkx/generators/tests/test_triads.py +++ /dev/null @@ -1,22 +0,0 @@ -# test_triads.py - unit tests for the triads module -# -# Copyright 2015 NetworkX developers. -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Unit tests for the :mod:`networkx.generators.triads` module.""" -import pytest - -from networkx import triad_graph - - -def test_triad_graph(): - G = triad_graph('030T') - assert [tuple(e) for e in ('ab', 'ac', 'cb')] == sorted(G.edges()) - - -def test_invalid_name(): - with pytest.raises(ValueError): - triad_graph('bogus') diff --git a/extensions/fablabchemnitz/networkx/generators/trees.py b/extensions/fablabchemnitz/networkx/generators/trees.py deleted file mode 100644 index 37c6ffe5..00000000 --- a/extensions/fablabchemnitz/networkx/generators/trees.py +++ /dev/null @@ -1,201 +0,0 @@ -# -*- encoding: utf-8 -*- -# Copyright (C) 2015-2019 by -# Jeffrey Finkelstein -# NetworkX developers -# All rights reserved. -# BSD license. -# -# Authors: Jeffrey Finkelstein -"""Functions for generating trees.""" -from collections import defaultdict - -import networkx as nx -from networkx.utils import generate_unique_node -from networkx.utils import py_random_state - -__all__ = ['prefix_tree', 'random_tree'] - -#: The nil node, the only leaf node in a prefix tree. -#: -#: Each predecessor of the nil node corresponds to the end of a path -#: used to generate the prefix tree. -NIL = 'NIL' - - -def prefix_tree(paths): - """Creates a directed prefix tree from the given list of iterables. - - Parameters - ---------- - paths: iterable of lists - An iterable over "paths", which are themselves lists of - nodes. Common prefixes among these paths are converted into - common initial segments in the generated tree. - - Most commonly, this may be an iterable over lists of integers, - or an iterable over Python strings. - - Returns - ------- - T: DiGraph - A directed graph representing an arborescence consisting of the - prefix tree generated by `paths`. Nodes are directed "downward", - from parent to child. A special "synthetic" root node is added - to be the parent of the first node in each path. A special - "synthetic" leaf node, the "nil" node, is added to be the child - of all nodes representing the last element in a path. (The - addition of this nil node technically makes this not an - arborescence but a directed acyclic graph; removing the nil node - makes it an arborescence.) - - Each node has an attribute 'source' whose value is the original - element of the path to which this node corresponds. The 'source' - of the root node is None, and the 'source' of the nil node is - :data:`.NIL`. - - The root node is the only node of in-degree zero in the graph, - and the nil node is the only node of out-degree zero. For - convenience, the nil node can be accessed via the :data:`.NIL` - attribute; for example:: - - >>> from networkx.generators.trees import NIL - >>> paths = ['ab', 'abs', 'ad'] - >>> T, root = nx.prefix_tree(paths) - >>> T.predecessors(NIL) # doctest: +SKIP - - root : string - The randomly generated uuid of the root node. - - Notes - ----- - The prefix tree is also known as a *trie*. - - Examples - -------- - Create a prefix tree from a list of strings with some common - prefixes:: - - >>> strings = ['ab', 'abs', 'ad'] - >>> T, root = nx.prefix_tree(strings) - - Continuing the above example, to recover the original paths that - generated the prefix tree, traverse up the tree from the - :data:`.NIL` node to the root:: - - >>> from networkx.generators.trees import NIL - >>> - >>> strings = ['ab', 'abs', 'ad'] - >>> T, root = nx.prefix_tree(strings) - >>> recovered = [] - >>> for v in T.predecessors(NIL): - ... s = '' - ... while v != root: - ... # Prepend the character `v` to the accumulator `s`. - ... s = str(T.nodes[v]['source']) + s - ... # Each non-nil, non-root node has exactly one parent. - ... v = next(T.predecessors(v)) - ... recovered.append(s) - >>> sorted(recovered) - ['ab', 'abs', 'ad'] - - """ - def _helper(paths, root, B): - """Recursively create a trie from the given list of paths. - - `paths` is a list of paths, each of which is itself a list of - nodes, relative to the given `root` (but not including it). This - list of paths will be interpreted as a tree-like structure, in - which two paths that share a prefix represent two branches of - the tree with the same initial segment. - - `root` is the parent of the node at index 0 in each path. - - `B` is the "accumulator", the :class:`networkx.DiGraph` - representing the branching to which the new nodes and edges will - be added. - - """ - # Create a mapping from each head node to the list of tail paths - # remaining beneath that node. - children = defaultdict(list) - for path in paths: - # If the path is the empty list, that represents the empty - # string, so we add an edge to the NIL node. - if not path: - B.add_edge(root, NIL) - continue - # TODO In Python 3, this should be `child, *rest = path`. - child, rest = path[0], path[1:] - # `child` may exist as the head of more than one path in `paths`. - children[child].append(rest) - # Add a node for each child found above and add edges from the - # root to each child. In this loop, `head` is the child and - # `tails` is the list of remaining paths under that child. - for head, tails in children.items(): - # We need to relabel each child with a unique name. To do - # this we simply change each key in the dictionary to be a - # (key, uuid) pair. - new_head = generate_unique_node() - # Ensure the new child knows the name of the old child so - # that the user can recover the mapping to the original - # nodes. - B.add_node(new_head, source=head) - B.add_edge(root, new_head) - _helper(tails, new_head, B) - - # Initialize the prefix tree with a root node and a nil node. - T = nx.DiGraph() - root = generate_unique_node() - T.add_node(root, source=None) - T.add_node(NIL, source=NIL) - # Populate the tree. - _helper(paths, root, T) - return T, root - - -# From the Wikipedia article on Prüfer sequences: -# -# > Generating uniformly distributed random Prüfer sequences and -# > converting them into the corresponding trees is a straightforward -# > method of generating uniformly distributed random labelled trees. -# -@py_random_state(1) -def random_tree(n, seed=None): - """Returns a uniformly random tree on `n` nodes. - - Parameters - ---------- - n : int - A positive integer representing the number of nodes in the tree. - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - NetworkX graph - A tree, given as an undirected graph, whose nodes are numbers in - the set {0, …, *n* - 1}. - - Raises - ------ - NetworkXPointlessConcept - If `n` is zero (because the null graph is not a tree). - - Notes - ----- - The current implementation of this function generates a uniformly - random Prüfer sequence then converts that to a tree via the - :func:`~networkx.from_prufer_sequence` function. Since there is a - bijection between Prüfer sequences of length *n* - 2 and trees on - *n* nodes, the tree is chosen uniformly at random from the set of - all trees on *n* nodes. - - """ - if n == 0: - raise nx.NetworkXPointlessConcept('the null graph is not a tree') - # Cannot create a Prüfer sequence unless `n` is at least two. - if n == 1: - return nx.empty_graph(1) - sequence = [seed.choice(range(n)) for i in range(n - 2)] - return nx.from_prufer_sequence(sequence) diff --git a/extensions/fablabchemnitz/networkx/generators/triads.py b/extensions/fablabchemnitz/networkx/generators/triads.py deleted file mode 100644 index f5e83c2a..00000000 --- a/extensions/fablabchemnitz/networkx/generators/triads.py +++ /dev/null @@ -1,79 +0,0 @@ -# triads.py - generators for triad graphs -# -# Copyright 2015 NetworkX developers. -# Copyright 2011 Reya Group -# Copyright 2011 Alex Levenson -# Copyright 2011 Diederik van Liere -# -# This file is part of NetworkX. -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -"""Functions that generate the triad graphs, that is, the possible -digraphs on three nodes. - -""" -from networkx.classes import DiGraph - -__all__ = ['triad_graph'] - -#: Dictionary mapping triad name to list of directed edges in the -#: digraph representation of that triad (with nodes 'a', 'b', and 'c'). -TRIAD_EDGES = {'003': [], - '012': ['ab'], - '102': ['ab', 'ba'], - '021D': ['ba', 'bc'], - '021U': ['ab', 'cb'], - '021C': ['ab', 'bc'], - '111D': ['ac', 'ca', 'bc'], - '111U': ['ac', 'ca', 'cb'], - '030T': ['ab', 'cb', 'ac'], - '030C': ['ba', 'cb', 'ac'], - '201': ['ab', 'ba', 'ac', 'ca'], - '120D': ['bc', 'ba', 'ac', 'ca'], - '120U': ['ab', 'cb', 'ac', 'ca'], - '120C': ['ab', 'bc', 'ac', 'ca'], - '210': ['ab', 'bc', 'cb', 'ac', 'ca'], - '300': ['ab', 'ba', 'bc', 'cb', 'ac', 'ca'] - } - - -def triad_graph(triad_name): - """Returns the triad graph with the given name. - - Each string in the following tuple is a valid triad name:: - - ('003', '012', '102', '021D', '021U', '021C', '111D', '111U', - '030T', '030C', '201', '120D', '120U', '120C', '210', '300') - - Each triad name corresponds to one of the possible valid digraph on - three nodes. - - Parameters - ---------- - triad_name : string - The name of a triad, as described above. - - Returns - ------- - :class:`~networkx.DiGraph` - The digraph on three nodes with the given name. The nodes of the - graph are the single-character strings 'a', 'b', and 'c'. - - Raises - ------ - :exc:`ValueError` - If `triad_name` is not the name of a triad. - - See also - -------- - triadic_census - - """ - if triad_name not in TRIAD_EDGES: - raise ValueError('unknown triad name "{}"; use one of the triad names' - ' in the TRIAD_NAMES constant'.format(triad_name)) - G = DiGraph() - G.add_nodes_from('abc') - G.add_edges_from(TRIAD_EDGES[triad_name]) - return G diff --git a/extensions/fablabchemnitz/networkx/linalg/__init__.py b/extensions/fablabchemnitz/networkx/linalg/__init__.py deleted file mode 100644 index f09b4023..00000000 --- a/extensions/fablabchemnitz/networkx/linalg/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -from networkx.linalg.attrmatrix import * -import networkx.linalg.attrmatrix -from networkx.linalg.spectrum import * -import networkx.linalg.spectrum -from networkx.linalg.graphmatrix import * -import networkx.linalg.graphmatrix -from networkx.linalg.laplacianmatrix import * -import networkx.linalg.laplacianmatrix -from networkx.linalg.algebraicconnectivity import * -from networkx.linalg.modularitymatrix import * -import networkx.linalg.modularitymatrix -from networkx.linalg.bethehessianmatrix import * -import networkx.linalg.bethehessianmatrix diff --git a/extensions/fablabchemnitz/networkx/linalg/algebraicconnectivity.py b/extensions/fablabchemnitz/networkx/linalg/algebraicconnectivity.py deleted file mode 100644 index ff7fc0a5..00000000 --- a/extensions/fablabchemnitz/networkx/linalg/algebraicconnectivity.py +++ /dev/null @@ -1,592 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2014 ysitu -# All rights reserved. -# BSD license. -# -# Author: ysitu -""" -Algebraic connectivity and Fiedler vectors of undirected graphs. -""" -from functools import partial -import networkx as nx -from networkx.utils import not_implemented_for -from networkx.utils import reverse_cuthill_mckee_ordering -from networkx.utils import random_state - -try: - from numpy import array, asmatrix, asarray, dot, ndarray, ones, sqrt, zeros - from numpy.linalg import norm, qr - from numpy.random import normal - from scipy.linalg import eigh, inv - from scipy.sparse import csc_matrix, spdiags - from scipy.sparse.linalg import eigsh, lobpcg - __all__ = ['algebraic_connectivity', 'fiedler_vector', 'spectral_ordering'] -except ImportError: - __all__ = [] - -try: - from scipy.linalg.blas import dasum, daxpy, ddot -except ImportError: - if __all__: - # Make sure the imports succeeded. - # Use minimal replacements if BLAS is unavailable from SciPy. - dasum = partial(norm, ord=1) - ddot = dot - - def daxpy(x, y, a): - y += a * x - return y - - -class _PCGSolver(object): - """Preconditioned conjugate gradient method. - - To solve Ax = b: - M = A.diagonal() # or some other preconditioner - solver = _PCGSolver(lambda x: A * x, lambda x: M * x) - x = solver.solve(b) - - The inputs A and M are functions which compute - matrix multiplication on the argument. - A - multiply by the matrix A in Ax=b - M - multiply by M, the preconditioner surragate for A - - Warning: There is no limit on number of iterations. - """ - - def __init__(self, A, M): - self._A = A - self._M = M or (lambda x: x.copy()) - - def solve(self, B, tol): - B = asarray(B) - X = ndarray(B.shape, order='F') - for j in range(B.shape[1]): - X[:, j] = self._solve(B[:, j], tol) - return X - - def _solve(self, b, tol): - A = self._A - M = self._M - tol *= dasum(b) - # Initialize. - x = zeros(b.shape) - r = b.copy() - z = M(r) - rz = ddot(r, z) - p = z.copy() - # Iterate. - while True: - Ap = A(p) - alpha = rz / ddot(p, Ap) - x = daxpy(p, x, a=alpha) - r = daxpy(Ap, r, a=-alpha) - if dasum(r) < tol: - return x - z = M(r) - beta = ddot(r, z) - beta, rz = beta / rz, beta - p = daxpy(p, z, a=beta) - - -class _CholeskySolver(object): - """Cholesky factorization. - - To solve Ax = b: - solver = _CholeskySolver(A) - x = solver.solve(b) - - optional argument `tol` on solve method is ignored but included - to match _PCGsolver API. - """ - - def __init__(self, A): - if not self._cholesky: - raise nx.NetworkXError('Cholesky solver unavailable.') - self._chol = self._cholesky(A) - - def solve(self, B, tol=None): - return self._chol(B) - - try: - from scikits.sparse.cholmod import cholesky - _cholesky = cholesky - except ImportError: - _cholesky = None - - -class _LUSolver(object): - """LU factorization. - - To solve Ax = b: - solver = _LUSolver(A) - x = solver.solve(b) - - optional argument `tol` on solve method is ignored but included - to match _PCGsolver API. - """ - - def __init__(self, A): - if not self._splu: - raise nx.NetworkXError('LU solver unavailable.') - self._LU = self._splu(A) - - def solve(self, B, tol=None): - B = asarray(B) - X = ndarray(B.shape, order='F') - for j in range(B.shape[1]): - X[:, j] = self._LU.solve(B[:, j]) - return X - - try: - from scipy.sparse.linalg import splu - _splu = partial(splu, permc_spec='MMD_AT_PLUS_A', diag_pivot_thresh=0., - options={'Equil': True, 'SymmetricMode': True}) - except ImportError: - _splu = None - - -def _preprocess_graph(G, weight): - """Compute edge weights and eliminate zero-weight edges. - """ - if G.is_directed(): - H = nx.MultiGraph() - H.add_nodes_from(G) - H.add_weighted_edges_from(((u, v, e.get(weight, 1.)) - for u, v, e in G.edges(data=True) - if u != v), weight=weight) - G = H - if not G.is_multigraph(): - edges = ((u, v, abs(e.get(weight, 1.))) - for u, v, e in G.edges(data=True) if u != v) - else: - edges = ((u, v, sum(abs(e.get(weight, 1.)) for e in G[u][v].values())) - for u, v in G.edges() if u != v) - H = nx.Graph() - H.add_nodes_from(G) - H.add_weighted_edges_from((u, v, e) for u, v, e in edges if e != 0) - return H - - -def _rcm_estimate(G, nodelist): - """Estimate the Fiedler vector using the reverse Cuthill-McKee ordering. - """ - G = G.subgraph(nodelist) - order = reverse_cuthill_mckee_ordering(G) - n = len(nodelist) - index = dict(zip(nodelist, range(n))) - x = ndarray(n, dtype=float) - for i, u in enumerate(order): - x[index[u]] = i - x -= (n - 1) / 2. - return x - - -def _tracemin_fiedler(L, X, normalized, tol, method): - """Compute the Fiedler vector of L using the TraceMIN-Fiedler algorithm. - - The Fiedler vector of a connected undirected graph is the eigenvector - corresponding to the second smallest eigenvalue of the Laplacian matrix of - of the graph. This function starts with the Laplacian L, not the Graph. - - Parameters - ---------- - L : Laplacian of a possibly weighted or normalized, but undirected graph - - X : Initial guess for a solution. Usually a matrix of random numbers. - This function allows more than one column in X to identify more than - one eigenvector if desired. - - normalized : bool - Whether the normalized Laplacian matrix is used. - - tol : float - Tolerance of relative residual in eigenvalue computation. - Warning: There is no limit on number of iterations. - - method : string - Should be 'tracemin_pcg', 'tracemin_chol' or 'tracemin_lu'. - Otherwise exception is raised. - - Returns - ------- - sigma, X : Two NumPy arrays of floats. - The lowest eigenvalues and corresponding eigenvectors of L. - The size of input X determines the size of these outputs. - As this is for Fiedler vectors, the zero eigenvalue (and - constant eigenvector) are avoided. - """ - n = X.shape[0] - - if normalized: - # Form the normalized Laplacian matrix and determine the eigenvector of - # its nullspace. - e = sqrt(L.diagonal()) - D = spdiags(1. / e, [0], n, n, format='csr') - L = D * L * D - e *= 1. / norm(e, 2) - - if normalized: - def project(X): - """Make X orthogonal to the nullspace of L. - """ - X = asarray(X) - for j in range(X.shape[1]): - X[:, j] -= dot(X[:, j], e) * e - else: - def project(X): - """Make X orthogonal to the nullspace of L. - """ - X = asarray(X) - for j in range(X.shape[1]): - X[:, j] -= X[:, j].sum() / n - - if method == 'tracemin_pcg': - D = L.diagonal().astype(float) - solver = _PCGSolver(lambda x: L * x, lambda x: D * x) - elif method == 'tracemin_chol' or method == 'tracemin_lu': - # Convert A to CSC to suppress SparseEfficiencyWarning. - A = csc_matrix(L, dtype=float, copy=True) - # Force A to be nonsingular. Since A is the Laplacian matrix of a - # connected graph, its rank deficiency is one, and thus one diagonal - # element needs to modified. Changing to infinity forces a zero in the - # corresponding element in the solution. - i = (A.indptr[1:] - A.indptr[:-1]).argmax() - A[i, i] = float('inf') - if method == 'tracemin_chol': - solver = _CholeskySolver(A) - else: - solver = _LUSolver(A) - else: - raise nx.NetworkXError('Unknown linear system solver: ' + method) - - # Initialize. - Lnorm = abs(L).sum(axis=1).flatten().max() - project(X) - W = asmatrix(ndarray(X.shape, order='F')) - - while True: - # Orthonormalize X. - X = qr(X)[0] - # Compute iteration matrix H. - W[:, :] = L * X - H = X.T * W - sigma, Y = eigh(H, overwrite_a=True) - # Compute the Ritz vectors. - X *= Y - # Test for convergence exploiting the fact that L * X == W * Y. - res = dasum(W * asmatrix(Y)[:, 0] - sigma[0] * X[:, 0]) / Lnorm - if res < tol: - break - # Compute X = L \ X / (X' * (L \ X)). - # L \ X can have an arbitrary projection on the nullspace of L, - # which will be eliminated. - W[:, :] = solver.solve(X, tol) - X = (inv(W.T * X) * W.T).T # Preserves Fortran storage order. - project(X) - - return sigma, asarray(X) - - -def _get_fiedler_func(method): - """Returns a function that solves the Fiedler eigenvalue problem. - """ - if method == "tracemin": # old style keyword `. - - Returns - ------- - algebraic_connectivity : float - Algebraic connectivity. - - Raises - ------ - NetworkXNotImplemented - If G is directed. - - NetworkXError - If G has less than two nodes. - - Notes - ----- - Edge weights are interpreted by their absolute values. For MultiGraph's, - weights of parallel edges are summed. Zero-weighted edges are ignored. - - To use Cholesky factorization in the TraceMIN algorithm, the - :samp:`scikits.sparse` package must be installed. - - See Also - -------- - laplacian_matrix - """ - if len(G) < 2: - raise nx.NetworkXError('graph has less than two nodes.') - G = _preprocess_graph(G, weight) - if not nx.is_connected(G): - return 0. - - L = nx.laplacian_matrix(G) - if L.shape[0] == 2: - return 2. * L[0, 0] if not normalized else 2. - - find_fiedler = _get_fiedler_func(method) - x = None if method != 'lobpcg' else _rcm_estimate(G, G) - sigma, fiedler = find_fiedler(L, x, normalized, tol, seed) - return sigma - - -@random_state(5) -@not_implemented_for('directed') -def fiedler_vector(G, weight='weight', normalized=False, tol=1e-8, - method='tracemin_pcg', seed=None): - """Returns the Fiedler vector of a connected undirected graph. - - The Fiedler vector of a connected undirected graph is the eigenvector - corresponding to the second smallest eigenvalue of the Laplacian matrix of - of the graph. - - Parameters - ---------- - G : NetworkX graph - An undirected graph. - - weight : object, optional (default: None) - The data key used to determine the weight of each edge. If None, then - each edge has unit weight. - - normalized : bool, optional (default: False) - Whether the normalized Laplacian matrix is used. - - tol : float, optional (default: 1e-8) - Tolerance of relative residual in eigenvalue computation. - - method : string, optional (default: 'tracemin_pcg') - Method of eigenvalue computation. It must be one of the tracemin - options shown below (TraceMIN), 'lanczos' (Lanczos iteration) - or 'lobpcg' (LOBPCG). - - The TraceMIN algorithm uses a linear system solver. The following - values allow specifying the solver to be used. - - =============== ======================================== - Value Solver - =============== ======================================== - 'tracemin_pcg' Preconditioned conjugate gradient method - 'tracemin_chol' Cholesky factorization - 'tracemin_lu' LU factorization - =============== ======================================== - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - fiedler_vector : NumPy array of floats. - Fiedler vector. - - Raises - ------ - NetworkXNotImplemented - If G is directed. - - NetworkXError - If G has less than two nodes or is not connected. - - Notes - ----- - Edge weights are interpreted by their absolute values. For MultiGraph's, - weights of parallel edges are summed. Zero-weighted edges are ignored. - - To use Cholesky factorization in the TraceMIN algorithm, the - :samp:`scikits.sparse` package must be installed. - - See Also - -------- - laplacian_matrix - """ - if len(G) < 2: - raise nx.NetworkXError('graph has less than two nodes.') - G = _preprocess_graph(G, weight) - if not nx.is_connected(G): - raise nx.NetworkXError('graph is not connected.') - - if len(G) == 2: - return array([1., -1.]) - - find_fiedler = _get_fiedler_func(method) - L = nx.laplacian_matrix(G) - x = None if method != 'lobpcg' else _rcm_estimate(G, G) - sigma, fiedler = find_fiedler(L, x, normalized, tol, seed) - return fiedler - - -@random_state(5) -def spectral_ordering(G, weight='weight', normalized=False, tol=1e-8, - method='tracemin_pcg', seed=None): - """Compute the spectral_ordering of a graph. - - The spectral ordering of a graph is an ordering of its nodes where nodes - in the same weakly connected components appear contiguous and ordered by - their corresponding elements in the Fiedler vector of the component. - - Parameters - ---------- - G : NetworkX graph - A graph. - - weight : object, optional (default: None) - The data key used to determine the weight of each edge. If None, then - each edge has unit weight. - - normalized : bool, optional (default: False) - Whether the normalized Laplacian matrix is used. - - tol : float, optional (default: 1e-8) - Tolerance of relative residual in eigenvalue computation. - - method : string, optional (default: 'tracemin_pcg') - Method of eigenvalue computation. It must be one of the tracemin - options shown below (TraceMIN), 'lanczos' (Lanczos iteration) - or 'lobpcg' (LOBPCG). - - The TraceMIN algorithm uses a linear system solver. The following - values allow specifying the solver to be used. - - =============== ======================================== - Value Solver - =============== ======================================== - 'tracemin_pcg' Preconditioned conjugate gradient method - 'tracemin_chol' Cholesky factorization - 'tracemin_lu' LU factorization - =============== ======================================== - - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - spectral_ordering : NumPy array of floats. - Spectral ordering of nodes. - - Raises - ------ - NetworkXError - If G is empty. - - Notes - ----- - Edge weights are interpreted by their absolute values. For MultiGraph's, - weights of parallel edges are summed. Zero-weighted edges are ignored. - - To use Cholesky factorization in the TraceMIN algorithm, the - :samp:`scikits.sparse` package must be installed. - - See Also - -------- - laplacian_matrix - """ - if len(G) == 0: - raise nx.NetworkXError('graph is empty.') - G = _preprocess_graph(G, weight) - - find_fiedler = _get_fiedler_func(method) - order = [] - for component in nx.connected_components(G): - size = len(component) - if size > 2: - L = nx.laplacian_matrix(G, component) - x = None if method != 'lobpcg' else _rcm_estimate(G, component) - sigma, fiedler = find_fiedler(L, x, normalized, tol, seed) - sort_info = zip(fiedler, range(size), component) - order.extend(u for x, c, u in sorted(sort_info)) - else: - order.extend(component) - - return order - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy.sparse = pytest.importorskip('scipy.sparse') diff --git a/extensions/fablabchemnitz/networkx/linalg/attrmatrix.py b/extensions/fablabchemnitz/networkx/linalg/attrmatrix.py deleted file mode 100644 index 641aeae7..00000000 --- a/extensions/fablabchemnitz/networkx/linalg/attrmatrix.py +++ /dev/null @@ -1,455 +0,0 @@ -""" - Functions for constructing matrix-like objects from graph attributes. -""" - -__all__ = ['attr_matrix', 'attr_sparse_matrix'] - -import networkx as nx - - -def _node_value(G, node_attr): - """Returns a function that returns a value from G.nodes[u]. - - We return a function expecting a node as its sole argument. Then, in the - simplest scenario, the returned function will return G.nodes[u][node_attr]. - However, we also handle the case when `node_attr` is None or when it is a - function itself. - - Parameters - ---------- - G : graph - A NetworkX graph - - node_attr : {None, str, callable} - Specification of how the value of the node attribute should be obtained - from the node attribute dictionary. - - Returns - ------- - value : function - A function expecting a node as its sole argument. The function will - returns a value from G.nodes[u] that depends on `edge_attr`. - - """ - if node_attr is None: - def value(u): return u - elif not hasattr(node_attr, '__call__'): - # assume it is a key for the node attribute dictionary - def value(u): return G.nodes[u][node_attr] - else: - # Advanced: Allow users to specify something else. - # - # For example, - # node_attr = lambda u: G.nodes[u].get('size', .5) * 3 - # - value = node_attr - - return value - - -def _edge_value(G, edge_attr): - """Returns a function that returns a value from G[u][v]. - - Suppose there exists an edge between u and v. Then we return a function - expecting u and v as arguments. For Graph and DiGraph, G[u][v] is - the edge attribute dictionary, and the function (essentially) returns - G[u][v][edge_attr]. However, we also handle cases when `edge_attr` is None - and when it is a function itself. For MultiGraph and MultiDiGraph, G[u][v] - is a dictionary of all edges between u and v. In this case, the returned - function sums the value of `edge_attr` for every edge between u and v. - - Parameters - ---------- - G : graph - A NetworkX graph - - edge_attr : {None, str, callable} - Specification of how the value of the edge attribute should be obtained - from the edge attribute dictionary, G[u][v]. For multigraphs, G[u][v] - is a dictionary of all the edges between u and v. This allows for - special treatment of multiedges. - - Returns - ------- - value : function - A function expecting two nodes as parameters. The nodes should - represent the from- and to- node of an edge. The function will - return a value from G[u][v] that depends on `edge_attr`. - - """ - - if edge_attr is None: - # topological count of edges - - if G.is_multigraph(): - def value(u, v): return len(G[u][v]) - else: - def value(u, v): return 1 - - elif not hasattr(edge_attr, '__call__'): - # assume it is a key for the edge attribute dictionary - - if edge_attr == 'weight': - # provide a default value - if G.is_multigraph(): - def value(u, v): return sum([d.get(edge_attr, 1) for d in G[u][v].values()]) - else: - def value(u, v): return G[u][v].get(edge_attr, 1) - else: - # otherwise, the edge attribute MUST exist for each edge - if G.is_multigraph(): - def value(u, v): return sum([d[edge_attr] for d in G[u][v].values()]) - else: - def value(u, v): return G[u][v][edge_attr] - - else: - # Advanced: Allow users to specify something else. - # - # Alternative default value: - # edge_attr = lambda u,v: G[u][v].get('thickness', .5) - # - # Function on an attribute: - # edge_attr = lambda u,v: abs(G[u][v]['weight']) - # - # Handle Multi(Di)Graphs differently: - # edge_attr = lambda u,v: numpy.prod([d['size'] for d in G[u][v].values()]) - # - # Ignore multiple edges - # edge_attr = lambda u,v: 1 if len(G[u][v]) else 0 - # - value = edge_attr - - return value - - -def attr_matrix(G, edge_attr=None, node_attr=None, normalized=False, - rc_order=None, dtype=None, order=None): - """Returns a NumPy matrix using attributes from G. - - If only `G` is passed in, then the adjacency matrix is constructed. - - Let A be a discrete set of values for the node attribute `node_attr`. Then - the elements of A represent the rows and columns of the constructed matrix. - Now, iterate through every edge e=(u,v) in `G` and consider the value - of the edge attribute `edge_attr`. If ua and va are the values of the - node attribute `node_attr` for u and v, respectively, then the value of - the edge attribute is added to the matrix element at (ua, va). - - Parameters - ---------- - G : graph - The NetworkX graph used to construct the NumPy matrix. - - edge_attr : str, optional - Each element of the matrix represents a running total of the - specified edge attribute for edges whose node attributes correspond - to the rows/cols of the matirx. The attribute must be present for - all edges in the graph. If no attribute is specified, then we - just count the number of edges whose node attributes correspond - to the matrix element. - - node_attr : str, optional - Each row and column in the matrix represents a particular value - of the node attribute. The attribute must be present for all nodes - in the graph. Note, the values of this attribute should be reliably - hashable. So, float values are not recommended. If no attribute is - specified, then the rows and columns will be the nodes of the graph. - - normalized : bool, optional - If True, then each row is normalized by the summation of its values. - - rc_order : list, optional - A list of the node attribute values. This list specifies the ordering - of rows and columns of the array. If no ordering is provided, then - the ordering will be random (and also, a return value). - - Other Parameters - ---------------- - dtype : NumPy data-type, optional - A valid NumPy dtype used to initialize the array. Keep in mind certain - dtypes can yield unexpected results if the array is to be normalized. - The parameter is passed to numpy.zeros(). If unspecified, the NumPy - default is used. - - order : {'C', 'F'}, optional - Whether to store multidimensional data in C- or Fortran-contiguous - (row- or column-wise) order in memory. This parameter is passed to - numpy.zeros(). If unspecified, the NumPy default is used. - - Returns - ------- - M : NumPy matrix - The attribute matrix. - - ordering : list - If `rc_order` was specified, then only the matrix is returned. - However, if `rc_order` was None, then the ordering used to construct - the matrix is returned as well. - - Examples - -------- - Construct an adjacency matrix: - - >>> G = nx.Graph() - >>> G.add_edge(0, 1, thickness=1, weight=3) - >>> G.add_edge(0, 2, thickness=2) - >>> G.add_edge(1, 2, thickness=3) - >>> nx.attr_matrix(G, rc_order=[0, 1, 2]) - matrix([[0., 1., 1.], - [1., 0., 1.], - [1., 1., 0.]]) - - Alternatively, we can obtain the matrix describing edge thickness. - - >>> nx.attr_matrix(G, edge_attr='thickness', rc_order=[0, 1, 2]) - matrix([[0., 1., 2.], - [1., 0., 3.], - [2., 3., 0.]]) - - We can also color the nodes and ask for the probability distribution over - all edges (u,v) describing: - - Pr(v has color Y | u has color X) - - >>> G.nodes[0]['color'] = 'red' - >>> G.nodes[1]['color'] = 'red' - >>> G.nodes[2]['color'] = 'blue' - >>> rc = ['red', 'blue'] - >>> nx.attr_matrix(G, node_attr='color', normalized=True, rc_order=rc) - matrix([[0.33333333, 0.66666667], - [1. , 0. ]]) - - For example, the above tells us that for all edges (u,v): - - Pr( v is red | u is red) = 1/3 - Pr( v is blue | u is red) = 2/3 - - Pr( v is red | u is blue) = 1 - Pr( v is blue | u is blue) = 0 - - Finally, we can obtain the total weights listed by the node colors. - - >>> nx.attr_matrix(G, edge_attr='weight', node_attr='color', rc_order=rc) - matrix([[3., 2.], - [2., 0.]]) - - Thus, the total weight over all edges (u,v) with u and v having colors: - - (red, red) is 3 # the sole contribution is from edge (0,1) - (red, blue) is 2 # contributions from edges (0,2) and (1,2) - (blue, red) is 2 # same as (red, blue) since graph is undirected - (blue, blue) is 0 # there are no edges with blue endpoints - - """ - try: - import numpy as np - except ImportError: - raise ImportError( - "attr_matrix() requires numpy: http://scipy.org/ ") - - edge_value = _edge_value(G, edge_attr) - node_value = _node_value(G, node_attr) - - if rc_order is None: - ordering = list(set([node_value(n) for n in G])) - else: - ordering = rc_order - - N = len(ordering) - undirected = not G.is_directed() - index = dict(zip(ordering, range(N))) - M = np.zeros((N, N), dtype=dtype, order=order) - - seen = set([]) - for u, nbrdict in G.adjacency(): - for v in nbrdict: - # Obtain the node attribute values. - i, j = index[node_value(u)], index[node_value(v)] - if v not in seen: - M[i, j] += edge_value(u, v) - if undirected: - M[j, i] = M[i, j] - - if undirected: - seen.add(u) - - if normalized: - M /= M.sum(axis=1).reshape((N, 1)) - - M = np.asmatrix(M) - - if rc_order is None: - return M, ordering - else: - return M - - -def attr_sparse_matrix(G, edge_attr=None, node_attr=None, - normalized=False, rc_order=None, dtype=None): - """Returns a SciPy sparse matrix using attributes from G. - - If only `G` is passed in, then the adjacency matrix is constructed. - - Let A be a discrete set of values for the node attribute `node_attr`. Then - the elements of A represent the rows and columns of the constructed matrix. - Now, iterate through every edge e=(u,v) in `G` and consider the value - of the edge attribute `edge_attr`. If ua and va are the values of the - node attribute `node_attr` for u and v, respectively, then the value of - the edge attribute is added to the matrix element at (ua, va). - - Parameters - ---------- - G : graph - The NetworkX graph used to construct the NumPy matrix. - - edge_attr : str, optional - Each element of the matrix represents a running total of the - specified edge attribute for edges whose node attributes correspond - to the rows/cols of the matirx. The attribute must be present for - all edges in the graph. If no attribute is specified, then we - just count the number of edges whose node attributes correspond - to the matrix element. - - node_attr : str, optional - Each row and column in the matrix represents a particular value - of the node attribute. The attribute must be present for all nodes - in the graph. Note, the values of this attribute should be reliably - hashable. So, float values are not recommended. If no attribute is - specified, then the rows and columns will be the nodes of the graph. - - normalized : bool, optional - If True, then each row is normalized by the summation of its values. - - rc_order : list, optional - A list of the node attribute values. This list specifies the ordering - of rows and columns of the array. If no ordering is provided, then - the ordering will be random (and also, a return value). - - Other Parameters - ---------------- - dtype : NumPy data-type, optional - A valid NumPy dtype used to initialize the array. Keep in mind certain - dtypes can yield unexpected results if the array is to be normalized. - The parameter is passed to numpy.zeros(). If unspecified, the NumPy - default is used. - - Returns - ------- - M : SciPy sparse matrix - The attribute matrix. - - ordering : list - If `rc_order` was specified, then only the matrix is returned. - However, if `rc_order` was None, then the ordering used to construct - the matrix is returned as well. - - Examples - -------- - Construct an adjacency matrix: - - >>> G = nx.Graph() - >>> G.add_edge(0,1,thickness=1,weight=3) - >>> G.add_edge(0,2,thickness=2) - >>> G.add_edge(1,2,thickness=3) - >>> M = nx.attr_sparse_matrix(G, rc_order=[0,1,2]) - >>> M.todense() - matrix([[0., 1., 1.], - [1., 0., 1.], - [1., 1., 0.]]) - - Alternatively, we can obtain the matrix describing edge thickness. - - >>> M = nx.attr_sparse_matrix(G, edge_attr='thickness', rc_order=[0,1,2]) - >>> M.todense() - matrix([[0., 1., 2.], - [1., 0., 3.], - [2., 3., 0.]]) - - We can also color the nodes and ask for the probability distribution over - all edges (u,v) describing: - - Pr(v has color Y | u has color X) - - >>> G.nodes[0]['color'] = 'red' - >>> G.nodes[1]['color'] = 'red' - >>> G.nodes[2]['color'] = 'blue' - >>> rc = ['red', 'blue'] - >>> M = nx.attr_sparse_matrix(G, node_attr='color', \ - normalized=True, rc_order=rc) - >>> M.todense() - matrix([[0.33333333, 0.66666667], - [1. , 0. ]]) - - For example, the above tells us that for all edges (u,v): - - Pr( v is red | u is red) = 1/3 - Pr( v is blue | u is red) = 2/3 - - Pr( v is red | u is blue) = 1 - Pr( v is blue | u is blue) = 0 - - Finally, we can obtain the total weights listed by the node colors. - - >>> M = nx.attr_sparse_matrix(G, edge_attr='weight',\ - node_attr='color', rc_order=rc) - >>> M.todense() - matrix([[3., 2.], - [2., 0.]]) - - Thus, the total weight over all edges (u,v) with u and v having colors: - - (red, red) is 3 # the sole contribution is from edge (0,1) - (red, blue) is 2 # contributions from edges (0,2) and (1,2) - (blue, red) is 2 # same as (red, blue) since graph is undirected - (blue, blue) is 0 # there are no edges with blue endpoints - - """ - try: - import numpy as np - from scipy import sparse - except ImportError: - raise ImportError( - "attr_sparse_matrix() requires scipy: http://scipy.org/ ") - - edge_value = _edge_value(G, edge_attr) - node_value = _node_value(G, node_attr) - - if rc_order is None: - ordering = list(set([node_value(n) for n in G])) - else: - ordering = rc_order - - N = len(ordering) - undirected = not G.is_directed() - index = dict(zip(ordering, range(N))) - M = sparse.lil_matrix((N, N), dtype=dtype) - - seen = set([]) - for u, nbrdict in G.adjacency(): - for v in nbrdict: - # Obtain the node attribute values. - i, j = index[node_value(u)], index[node_value(v)] - if v not in seen: - M[i, j] += edge_value(u, v) - if undirected: - M[j, i] = M[i, j] - - if undirected: - seen.add(u) - - if normalized: - norms = np.asarray(M.sum(axis=1)).ravel() - for i, norm in enumerate(norms): - M[i, :] /= norm - - if rc_order is None: - return M, ordering - else: - return M - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/linalg/bethehessianmatrix.py b/extensions/fablabchemnitz/networkx/linalg/bethehessianmatrix.py deleted file mode 100644 index f6b0d8e3..00000000 --- a/extensions/fablabchemnitz/networkx/linalg/bethehessianmatrix.py +++ /dev/null @@ -1,92 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# Jean-Gabriel Young -# All rights reserved. -# BSD license. -# -# Authors: Jean-Gabriel Young (jeangabriel.young@gmail.com) -"""Bethe Hessian or deformed Laplacian matrix of graphs.""" -import networkx as nx -from networkx.utils import not_implemented_for - -__all__ = ['bethe_hessian_matrix'] - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def bethe_hessian_matrix(G, r=None, nodelist=None): - r"""Returns the Bethe Hessian matrix of G. - - The Bethe Hessian is a family of matrices parametrized by r, defined as - H(r) = (r^2 - 1) I - r A + D where A is the adjacency matrix, D is the - diagonal matrix of node degrees, and I is the identify matrix. It is equal - to the graph laplacian when the regularizer r = 1. - - The default choice of regularizer should be the ratio [2] - - .. math:: - r_m = \left(\sum k_i \right)^{-1}\left(\sum k_i^2 \right) - 1 - - Parameters - ---------- - G : Graph - A NetworkX graph - - r : float - Regularizer parameter - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - - Returns - ------- - H : Numpy matrix - The Bethe Hessian matrix of G, with paramter r. - - Examples - -------- - >>> import networkx as nx - >>> k =[3, 2, 2, 1, 0] - >>> G = nx.havel_hakimi_graph(k) - >>> H = nx.modularity_matrix(G) - - - See Also - -------- - bethe_hessian_spectrum - to_numpy_matrix - adjacency_matrix - laplacian_matrix - - References - ---------- - .. [1] A. Saade, F. Krzakala and L. Zdeborová - "Spectral clustering of graphs with the bethe hessian", - Advances in Neural Information Processing Systems. 2014. - .. [2] C. M. Lee, E. Levina - "Estimating the number of communities in networks by spectral methods" - arXiv:1507.00827, 2015. - """ - import scipy.sparse - if nodelist is None: - nodelist = list(G) - if r is None: - r = sum([d ** 2 for v, d in nx.degree(G)]) /\ - sum([d for v, d in nx.degree(G)]) - 1 - A = nx.to_scipy_sparse_matrix(G, nodelist=nodelist, format='csr') - n, m = A.shape - diags = A.sum(axis=1) - D = scipy.sparse.spdiags(diags.flatten(), [0], m, n, format='csr') - I = scipy.sparse.eye(m, n, format='csr') - return (r ** 2 - 1) * I - r * A + D - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') diff --git a/extensions/fablabchemnitz/networkx/linalg/graphmatrix.py b/extensions/fablabchemnitz/networkx/linalg/graphmatrix.py deleted file mode 100644 index 2d283138..00000000 --- a/extensions/fablabchemnitz/networkx/linalg/graphmatrix.py +++ /dev/null @@ -1,172 +0,0 @@ -""" -Adjacency matrix and incidence matrix of graphs. -""" -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -import networkx as nx -__author__ = "\n".join(['Aric Hagberg (hagberg@lanl.gov)', - 'Pieter Swart (swart@lanl.gov)', - 'Dan Schult(dschult@colgate.edu)']) - -__all__ = ['incidence_matrix', - 'adj_matrix', 'adjacency_matrix', - ] - - -def incidence_matrix(G, nodelist=None, edgelist=None, - oriented=False, weight=None): - """Returns incidence matrix of G. - - The incidence matrix assigns each row to a node and each column to an edge. - For a standard incidence matrix a 1 appears wherever a row's node is - incident on the column's edge. For an oriented incidence matrix each - edge is assigned an orientation (arbitrarily for undirected and aligning to - direction for directed). A -1 appears for the tail of an edge and 1 - for the head of the edge. The elements are zero otherwise. - - Parameters - ---------- - G : graph - A NetworkX graph - - nodelist : list, optional (default= all nodes in G) - The rows are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - edgelist : list, optional (default= all edges in G) - The columns are ordered according to the edges in edgelist. - If edgelist is None, then the ordering is produced by G.edges(). - - oriented: bool, optional (default=False) - If True, matrix elements are +1 or -1 for the head or tail node - respectively of each edge. If False, +1 occurs at both nodes. - - weight : string or None, optional (default=None) - The edge data key used to provide each value in the matrix. - If None, then each edge has weight 1. Edge weights, if used, - should be positive so that the orientation can provide the sign. - - Returns - ------- - A : SciPy sparse matrix - The incidence matrix of G. - - Notes - ----- - For MultiGraph/MultiDiGraph, the edges in edgelist should be - (u,v,key) 3-tuples. - - "Networks are the best discrete model for so many problems in - applied mathematics" [1]_. - - References - ---------- - .. [1] Gil Strang, Network applications: A = incidence matrix, - http://academicearth.org/lectures/network-applications-incidence-matrix - """ - import scipy.sparse - if nodelist is None: - nodelist = list(G) - if edgelist is None: - if G.is_multigraph(): - edgelist = list(G.edges(keys=True)) - else: - edgelist = list(G.edges()) - A = scipy.sparse.lil_matrix((len(nodelist), len(edgelist))) - node_index = dict((node, i) for i, node in enumerate(nodelist)) - for ei, e in enumerate(edgelist): - (u, v) = e[:2] - if u == v: - continue # self loops give zero column - try: - ui = node_index[u] - vi = node_index[v] - except KeyError: - raise nx.NetworkXError('node %s or %s in edgelist ' - 'but not in nodelist' % (u, v)) - if weight is None: - wt = 1 - else: - if G.is_multigraph(): - ekey = e[2] - wt = G[u][v][ekey].get(weight, 1) - else: - wt = G[u][v].get(weight, 1) - if oriented: - A[ui, ei] = -wt - A[vi, ei] = wt - else: - A[ui, ei] = wt - A[vi, ei] = wt - return A.asformat('csc') - - -def adjacency_matrix(G, nodelist=None, weight='weight'): - """Returns adjacency matrix of G. - - Parameters - ---------- - G : graph - A NetworkX graph - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : string or None, optional (default='weight') - The edge data key used to provide each value in the matrix. - If None, then each edge has weight 1. - - Returns - ------- - A : SciPy sparse matrix - Adjacency matrix representation of G. - - Notes - ----- - For directed graphs, entry i,j corresponds to an edge from i to j. - - If you want a pure Python adjacency matrix representation try - networkx.convert.to_dict_of_dicts which will return a - dictionary-of-dictionaries format that can be addressed as a - sparse matrix. - - For MultiGraph/MultiDiGraph with parallel edges the weights are summed. - See to_numpy_matrix for other options. - - The convention used for self-loop edges in graphs is to assign the - diagonal matrix entry value to the edge weight attribute - (or the number 1 if the edge has no weight attribute). If the - alternate convention of doubling the edge weight is desired the - resulting Scipy sparse matrix can be modified as follows: - - >>> import scipy as sp - >>> G = nx.Graph([(1,1)]) - >>> A = nx.adjacency_matrix(G) - >>> print(A.todense()) - [[1]] - >>> A.setdiag(A.diagonal()*2) - >>> print(A.todense()) - [[2]] - - See Also - -------- - to_numpy_matrix - to_scipy_sparse_matrix - to_dict_of_dicts - adjacency_spectrum - """ - return nx.to_scipy_sparse_matrix(G, nodelist=nodelist, weight=weight) - - -adj_matrix = adjacency_matrix - - -# fixture for pytest -def setup_module(module): - import pytest - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/linalg/laplacianmatrix.py b/extensions/fablabchemnitz/networkx/linalg/laplacianmatrix.py deleted file mode 100644 index babfff08..00000000 --- a/extensions/fablabchemnitz/networkx/linalg/laplacianmatrix.py +++ /dev/null @@ -1,375 +0,0 @@ -"""Laplacian matrix of graphs. -""" -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -import networkx as nx -from networkx.utils import not_implemented_for -__author__ = "\n".join(['Aric Hagberg ', - 'Pieter Swart (swart@lanl.gov)', - 'Dan Schult (dschult@colgate.edu)', - 'Alejandro Weinstein ']) -__all__ = ['laplacian_matrix', - 'normalized_laplacian_matrix', - 'directed_laplacian_matrix', - 'directed_combinatorial_laplacian_matrix'] - - -@not_implemented_for('directed') -def laplacian_matrix(G, nodelist=None, weight='weight'): - """Returns the Laplacian matrix of G. - - The graph Laplacian is the matrix L = D - A, where - A is the adjacency matrix and D is the diagonal matrix of node degrees. - - Parameters - ---------- - G : graph - A NetworkX graph - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : string or None, optional (default='weight') - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - Returns - ------- - L : SciPy sparse matrix - The Laplacian matrix of G. - - Notes - ----- - For MultiGraph/MultiDiGraph, the edges weights are summed. - - See Also - -------- - to_numpy_matrix - normalized_laplacian_matrix - laplacian_spectrum - """ - import scipy.sparse - if nodelist is None: - nodelist = list(G) - A = nx.to_scipy_sparse_matrix(G, nodelist=nodelist, weight=weight, - format='csr') - n, m = A.shape - diags = A.sum(axis=1) - D = scipy.sparse.spdiags(diags.flatten(), [0], m, n, format='csr') - return D - A - - -@not_implemented_for('directed') -def normalized_laplacian_matrix(G, nodelist=None, weight='weight'): - r"""Returns the normalized Laplacian matrix of G. - - The normalized graph Laplacian is the matrix - - .. math:: - - N = D^{-1/2} L D^{-1/2} - - where `L` is the graph Laplacian and `D` is the diagonal matrix of - node degrees. - - Parameters - ---------- - G : graph - A NetworkX graph - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : string or None, optional (default='weight') - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - Returns - ------- - N : NumPy matrix - The normalized Laplacian matrix of G. - - Notes - ----- - For MultiGraph/MultiDiGraph, the edges weights are summed. - See to_numpy_matrix for other options. - - If the Graph contains selfloops, D is defined as diag(sum(A,1)), where A is - the adjacency matrix [2]_. - - See Also - -------- - laplacian_matrix - normalized_laplacian_spectrum - - References - ---------- - .. [1] Fan Chung-Graham, Spectral Graph Theory, - CBMS Regional Conference Series in Mathematics, Number 92, 1997. - .. [2] Steve Butler, Interlacing For Weighted Graphs Using The Normalized - Laplacian, Electronic Journal of Linear Algebra, Volume 16, pp. 90-98, - March 2007. - """ - import scipy - import scipy.sparse - if nodelist is None: - nodelist = list(G) - A = nx.to_scipy_sparse_matrix(G, nodelist=nodelist, weight=weight, - format='csr') - n, m = A.shape - diags = A.sum(axis=1).flatten() - D = scipy.sparse.spdiags(diags, [0], m, n, format='csr') - L = D - A - with scipy.errstate(divide='ignore'): - diags_sqrt = 1.0 / scipy.sqrt(diags) - diags_sqrt[scipy.isinf(diags_sqrt)] = 0 - DH = scipy.sparse.spdiags(diags_sqrt, [0], m, n, format='csr') - return DH.dot(L.dot(DH)) - -############################################################################### -# Code based on -# https://bitbucket.org/bedwards/networkx-community/src/370bd69fc02f/networkx/algorithms/community/ - - -@not_implemented_for('undirected') -@not_implemented_for('multigraph') -def directed_laplacian_matrix(G, nodelist=None, weight='weight', - walk_type=None, alpha=0.95): - r"""Returns the directed Laplacian matrix of G. - - The graph directed Laplacian is the matrix - - .. math:: - - L = I - (\Phi^{1/2} P \Phi^{-1/2} + \Phi^{-1/2} P^T \Phi^{1/2} ) / 2 - - where `I` is the identity matrix, `P` is the transition matrix of the - graph, and `\Phi` a matrix with the Perron vector of `P` in the diagonal and - zeros elsewhere. - - Depending on the value of walk_type, `P` can be the transition matrix - induced by a random walk, a lazy random walk, or a random walk with - teleportation (PageRank). - - Parameters - ---------- - G : DiGraph - A NetworkX graph - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : string or None, optional (default='weight') - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - walk_type : string or None, optional (default=None) - If None, `P` is selected depending on the properties of the - graph. Otherwise is one of 'random', 'lazy', or 'pagerank' - - alpha : real - (1 - alpha) is the teleportation probability used with pagerank - - Returns - ------- - L : NumPy array - Normalized Laplacian of G. - - Notes - ----- - Only implemented for DiGraphs - - See Also - -------- - laplacian_matrix - - References - ---------- - .. [1] Fan Chung (2005). - Laplacians and the Cheeger inequality for directed graphs. - Annals of Combinatorics, 9(1), 2005 - """ - import scipy as sp - from scipy.sparse import spdiags, linalg - - P = _transition_matrix(G, nodelist=nodelist, weight=weight, - walk_type=walk_type, alpha=alpha) - - n, m = P.shape - - evals, evecs = linalg.eigs(P.T, k=1) - v = evecs.flatten().real - p = v / v.sum() - sqrtp = sp.sqrt(p) - Q = spdiags(sqrtp, [0], n, n) * P * spdiags(1.0 / sqrtp, [0], n, n) - I = sp.identity(len(G)) - - return I - (Q + Q.T) / 2.0 - - -@not_implemented_for('undirected') -@not_implemented_for('multigraph') -def directed_combinatorial_laplacian_matrix(G, nodelist=None, weight='weight', - walk_type=None, alpha=0.95): - r"""Return the directed combinatorial Laplacian matrix of G. - - The graph directed combinatorial Laplacian is the matrix - - .. math:: - - L = \Phi - (\Phi P + P^T \Phi) / 2 - - where `P` is the transition matrix of the graph and and `\Phi` a matrix - with the Perron vector of `P` in the diagonal and zeros elsewhere. - - Depending on the value of walk_type, `P` can be the transition matrix - induced by a random walk, a lazy random walk, or a random walk with - teleportation (PageRank). - - Parameters - ---------- - G : DiGraph - A NetworkX graph - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : string or None, optional (default='weight') - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - walk_type : string or None, optional (default=None) - If None, `P` is selected depending on the properties of the - graph. Otherwise is one of 'random', 'lazy', or 'pagerank' - - alpha : real - (1 - alpha) is the teleportation probability used with pagerank - - Returns - ------- - L : NumPy array - Combinatorial Laplacian of G. - - Notes - ----- - Only implemented for DiGraphs - - See Also - -------- - laplacian_matrix - - References - ---------- - .. [1] Fan Chung (2005). - Laplacians and the Cheeger inequality for directed graphs. - Annals of Combinatorics, 9(1), 2005 - """ - from scipy.sparse import spdiags, linalg - - P = _transition_matrix(G, nodelist=nodelist, weight=weight, - walk_type=walk_type, alpha=alpha) - - n, m = P.shape - - evals, evecs = linalg.eigs(P.T, k=1) - v = evecs.flatten().real - p = v / v.sum() - Phi = spdiags(p, [0], n, n) - - Phi = Phi.todense() - - return Phi - (Phi*P + P.T*Phi) / 2.0 - - -def _transition_matrix(G, nodelist=None, weight='weight', - walk_type=None, alpha=0.95): - """Returns the transition matrix of G. - - This is a row stochastic giving the transition probabilities while - performing a random walk on the graph. Depending on the value of walk_type, - P can be the transition matrix induced by a random walk, a lazy random walk, - or a random walk with teleportation (PageRank). - - Parameters - ---------- - G : DiGraph - A NetworkX graph - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : string or None, optional (default='weight') - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - walk_type : string or None, optional (default=None) - If None, `P` is selected depending on the properties of the - graph. Otherwise is one of 'random', 'lazy', or 'pagerank' - - alpha : real - (1 - alpha) is the teleportation probability used with pagerank - - Returns - ------- - P : NumPy array - transition matrix of G. - - Raises - ------ - NetworkXError - If walk_type not specified or alpha not in valid range - """ - - import scipy as sp - from scipy.sparse import identity, spdiags - if walk_type is None: - if nx.is_strongly_connected(G): - if nx.is_aperiodic(G): - walk_type = "random" - else: - walk_type = "lazy" - else: - walk_type = "pagerank" - - M = nx.to_scipy_sparse_matrix(G, nodelist=nodelist, weight=weight, - dtype=float) - n, m = M.shape - if walk_type in ["random", "lazy"]: - DI = spdiags(1.0 / sp.array(M.sum(axis=1).flat), [0], n, n) - if walk_type == "random": - P = DI * M - else: - I = identity(n) - P = (I + DI * M) / 2.0 - - elif walk_type == "pagerank": - if not (0 < alpha < 1): - raise nx.NetworkXError('alpha must be between 0 and 1') - # this is using a dense representation - M = M.todense() - # add constant to dangling nodes' row - dangling = sp.where(M.sum(axis=1) == 0) - for d in dangling[0]: - M[d] = 1.0 / n - # normalize - M = M / M.sum(axis=1) - P = alpha * M + (1 - alpha) / n - else: - raise nx.NetworkXError("walk_type must be random, lazy, or pagerank") - - return P - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') diff --git a/extensions/fablabchemnitz/networkx/linalg/modularitymatrix.py b/extensions/fablabchemnitz/networkx/linalg/modularitymatrix.py deleted file mode 100644 index ff1d5662..00000000 --- a/extensions/fablabchemnitz/networkx/linalg/modularitymatrix.py +++ /dev/null @@ -1,166 +0,0 @@ -"""Modularity matrix of graphs. -""" -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -import networkx as nx -from networkx.utils import not_implemented_for -__author__ = "\n".join(['Aric Hagberg ', - 'Pieter Swart (swart@lanl.gov)', - 'Dan Schult (dschult@colgate.edu)', - 'Jean-Gabriel Young (Jean.gabriel.young@gmail.com)']) -__all__ = ['modularity_matrix', 'directed_modularity_matrix'] - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def modularity_matrix(G, nodelist=None, weight=None): - r"""Returns the modularity matrix of G. - - The modularity matrix is the matrix B = A - , where A is the adjacency - matrix and is the average adjacency matrix, assuming that the graph - is described by the configuration model. - - More specifically, the element B_ij of B is defined as - - .. math:: - A_{ij} - {k_i k_j \over 2 m} - - where k_i is the degree of node i, and where m is the number of edges - in the graph. When weight is set to a name of an attribute edge, Aij, k_i, - k_j and m are computed using its value. - - Parameters - ---------- - G : Graph - A NetworkX graph - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used for - the edge weight. If None then all edge weights are 1. - - Returns - ------- - B : Numpy matrix - The modularity matrix of G. - - Examples - -------- - >>> import networkx as nx - >>> k =[3, 2, 2, 1, 0] - >>> G = nx.havel_hakimi_graph(k) - >>> B = nx.modularity_matrix(G) - - - See Also - -------- - to_numpy_matrix - modularity_spectrum - adjacency_matrix - directed_modularity_matrix - - References - ---------- - .. [1] M. E. J. Newman, "Modularity and community structure in networks", - Proc. Natl. Acad. Sci. USA, vol. 103, pp. 8577-8582, 2006. - """ - if nodelist is None: - nodelist = list(G) - A = nx.to_scipy_sparse_matrix(G, nodelist=nodelist, weight=weight, - format='csr') - k = A.sum(axis=1) - m = k.sum() * 0.5 - # Expected adjacency matrix - X = k * k.transpose() / (2 * m) - return A - X - - -@not_implemented_for('undirected') -@not_implemented_for('multigraph') -def directed_modularity_matrix(G, nodelist=None, weight=None): - """Returns the directed modularity matrix of G. - - The modularity matrix is the matrix B = A - , where A is the adjacency - matrix and is the expected adjacency matrix, assuming that the graph - is described by the configuration model. - - More specifically, the element B_ij of B is defined as - - .. math:: - B_{ij} = A_{ij} - k_i^{out} k_j^{in} / m - - where :math:`k_i^{in}` is the in degree of node i, and :math:`k_j^{out}` is the out degree - of node j, with m the number of edges in the graph. When weight is set - to a name of an attribute edge, Aij, k_i, k_j and m are computed using - its value. - - Parameters - ---------- - G : DiGraph - A NetworkX DiGraph - - nodelist : list, optional - The rows and columns are ordered according to the nodes in nodelist. - If nodelist is None, then the ordering is produced by G.nodes(). - - weight : string or None, optional (default=None) - The edge attribute that holds the numerical value used for - the edge weight. If None then all edge weights are 1. - - Returns - ------- - B : Numpy matrix - The modularity matrix of G. - - Examples - -------- - >>> import networkx as nx - >>> G = nx.DiGraph() - >>> G.add_edges_from(((1,2), (1,3), (3,1), (3,2), (3,5), (4,5), (4,6), - ... (5,4), (5,6), (6,4))) - >>> B = nx.directed_modularity_matrix(G) - - - Notes - ----- - NetworkX defines the element A_ij of the adjacency matrix as 1 if there - is a link going from node i to node j. Leicht and Newman use the opposite - definition. This explains the different expression for B_ij. - - See Also - -------- - to_numpy_matrix - modularity_spectrum - adjacency_matrix - modularity_matrix - - References - ---------- - .. [1] E. A. Leicht, M. E. J. Newman, - "Community structure in directed networks", - Phys. Rev Lett., vol. 100, no. 11, p. 118703, 2008. - """ - if nodelist is None: - nodelist = list(G) - A = nx.to_scipy_sparse_matrix(G, nodelist=nodelist, weight=weight, - format='csr') - k_in = A.sum(axis=0) - k_out = A.sum(axis=1) - m = k_in.sum() - # Expected adjacency matrix - X = k_out * k_in / m - return A - X - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') - scipy = pytest.importorskip('scipy') diff --git a/extensions/fablabchemnitz/networkx/linalg/spectrum.py b/extensions/fablabchemnitz/networkx/linalg/spectrum.py deleted file mode 100644 index 1bf68dda..00000000 --- a/extensions/fablabchemnitz/networkx/linalg/spectrum.py +++ /dev/null @@ -1,172 +0,0 @@ -""" -Eigenvalue spectrum of graphs. -""" -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -import networkx as nx -__author__ = "\n".join(['Aric Hagberg ', - 'Pieter Swart (swart@lanl.gov)', - 'Dan Schult(dschult@colgate.edu)', - 'Jean-Gabriel Young (jean.gabriel.young@gmail.com)']) - -__all__ = ['laplacian_spectrum', 'adjacency_spectrum', 'modularity_spectrum', - 'normalized_laplacian_spectrum', 'bethe_hessian_spectrum'] - - -def laplacian_spectrum(G, weight='weight'): - """Returns eigenvalues of the Laplacian of G - - Parameters - ---------- - G : graph - A NetworkX graph - - weight : string or None, optional (default='weight') - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - Returns - ------- - evals : NumPy array - Eigenvalues - - Notes - ----- - For MultiGraph/MultiDiGraph, the edges weights are summed. - See to_numpy_matrix for other options. - - See Also - -------- - laplacian_matrix - """ - from scipy.linalg import eigvalsh - return eigvalsh(nx.laplacian_matrix(G, weight=weight).todense()) - - -def normalized_laplacian_spectrum(G, weight='weight'): - """Return eigenvalues of the normalized Laplacian of G - - Parameters - ---------- - G : graph - A NetworkX graph - - weight : string or None, optional (default='weight') - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - Returns - ------- - evals : NumPy array - Eigenvalues - - Notes - ----- - For MultiGraph/MultiDiGraph, the edges weights are summed. - See to_numpy_matrix for other options. - - See Also - -------- - normalized_laplacian_matrix - """ - from scipy.linalg import eigvalsh - return eigvalsh(nx.normalized_laplacian_matrix(G, weight=weight).todense()) - - -def adjacency_spectrum(G, weight='weight'): - """Returns eigenvalues of the adjacency matrix of G. - - Parameters - ---------- - G : graph - A NetworkX graph - - weight : string or None, optional (default='weight') - The edge data key used to compute each value in the matrix. - If None, then each edge has weight 1. - - Returns - ------- - evals : NumPy array - Eigenvalues - - Notes - ----- - For MultiGraph/MultiDiGraph, the edges weights are summed. - See to_numpy_matrix for other options. - - See Also - -------- - adjacency_matrix - """ - from scipy.linalg import eigvals - return eigvals(nx.adjacency_matrix(G, weight=weight).todense()) - - -def modularity_spectrum(G): - """Returns eigenvalues of the modularity matrix of G. - - Parameters - ---------- - G : Graph - A NetworkX Graph or DiGraph - - Returns - ------- - evals : NumPy array - Eigenvalues - - See Also - -------- - modularity_matrix - - References - ---------- - .. [1] M. E. J. Newman, "Modularity and community structure in networks", - Proc. Natl. Acad. Sci. USA, vol. 103, pp. 8577-8582, 2006. - """ - from scipy.linalg import eigvals - if G.is_directed(): - return eigvals(nx.directed_modularity_matrix(G)) - else: - return eigvals(nx.modularity_matrix(G)) - - -def bethe_hessian_spectrum(G, r=None): - """Returns eigenvalues of the Bethe Hessian matrix of G. - - Parameters - ---------- - G : Graph - A NetworkX Graph or DiGraph - - r : float - Regularizer parameter - - Returns - ------- - evals : NumPy array - Eigenvalues - - See Also - -------- - bethe_hessian_matrix - - References - ---------- - .. [1] A. Saade, F. Krzakala and L. Zdeborová - "Spectral clustering of graphs with the bethe hessian", - Advances in Neural Information Processing Systems. 2014. - """ - from scipy.linalg import eigvalsh - return eigvalsh(nx.bethe_hessian_matrix(G, r).todense()) - - -# fixture for pytest -def setup_module(module): - import pytest - scipy.linalg = pytest.importorskip('scipy.linalg') diff --git a/extensions/fablabchemnitz/networkx/linalg/tests/__init__.py b/extensions/fablabchemnitz/networkx/linalg/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/linalg/tests/test_algebraic_connectivity.py b/extensions/fablabchemnitz/networkx/linalg/tests/test_algebraic_connectivity.py deleted file mode 100644 index d406d658..00000000 --- a/extensions/fablabchemnitz/networkx/linalg/tests/test_algebraic_connectivity.py +++ /dev/null @@ -1,284 +0,0 @@ -from math import sqrt - -import pytest -numpy = pytest.importorskip('numpy') -numpy.linalg = pytest.importorskip('numpy.linalg') -scipy = pytest.importorskip('scipy') -scipy.sparse = pytest.importorskip('scipy.sparse') - - - -import networkx as nx -from networkx.testing import almost_equal - -try: - from scikits.sparse.cholmod import cholesky - _cholesky = cholesky -except ImportError: - _cholesky = None - -if _cholesky is None: - methods = ('tracemin_pcg', 'tracemin_lu', 'lanczos', 'lobpcg') -else: - methods = ('tracemin_pcg', 'tracemin_chol', 'tracemin_lu', 'lanczos', 'lobpcg') - - -def check_eigenvector(A, l, x): - nx = numpy.linalg.norm(x) - # Check zeroness. - assert not almost_equal(nx, 0) - y = A * x - ny = numpy.linalg.norm(y) - # Check collinearity. - assert almost_equal(numpy.dot(x, y), nx * ny) - # Check eigenvalue. - assert almost_equal(ny, l * nx) - - -class TestAlgebraicConnectivity(object): - - def test_directed(self): - G = nx.DiGraph() - for method in self._methods: - pytest.raises(nx.NetworkXNotImplemented, nx.algebraic_connectivity, - G, method=method) - pytest.raises(nx.NetworkXNotImplemented, nx.fiedler_vector, G, - method=method) - - def test_null_and_singleton(self): - G = nx.Graph() - for method in self._methods: - pytest.raises(nx.NetworkXError, nx.algebraic_connectivity, G, - method=method) - pytest.raises(nx.NetworkXError, nx.fiedler_vector, G, - method=method) - G.add_edge(0, 0) - for method in self._methods: - pytest.raises(nx.NetworkXError, nx.algebraic_connectivity, G, - method=method) - pytest.raises(nx.NetworkXError, nx.fiedler_vector, G, - method=method) - - def test_disconnected(self): - G = nx.Graph() - G.add_nodes_from(range(2)) - for method in self._methods: - assert nx.algebraic_connectivity(G) == 0 - pytest.raises(nx.NetworkXError, nx.fiedler_vector, G, - method=method) - G.add_edge(0, 1, weight=0) - for method in self._methods: - assert nx.algebraic_connectivity(G) == 0 - pytest.raises(nx.NetworkXError, nx.fiedler_vector, G, - method=method) - - def test_unrecognized_method(self): - G = nx.path_graph(4) - pytest.raises(nx.NetworkXError, nx.algebraic_connectivity, G, - method='unknown') - pytest.raises(nx.NetworkXError, nx.fiedler_vector, G, method='unknown') - - def test_two_nodes(self): - G = nx.Graph() - G.add_edge(0, 1, weight=1) - A = nx.laplacian_matrix(G) - for method in self._methods: - assert almost_equal(nx.algebraic_connectivity( - G, tol=1e-12, method=method), 2) - x = nx.fiedler_vector(G, tol=1e-12, method=method) - check_eigenvector(A, 2, x) - G = nx.MultiGraph() - G.add_edge(0, 0, spam=1e8) - G.add_edge(0, 1, spam=1) - G.add_edge(0, 1, spam=-2) - A = -3 * nx.laplacian_matrix(G, weight='spam') - for method in self._methods: - assert almost_equal(nx.algebraic_connectivity( - G, weight='spam', tol=1e-12, method=method), 6) - x = nx.fiedler_vector(G, weight='spam', tol=1e-12, method=method) - check_eigenvector(A, 6, x) - - def test_abbreviation_of_method(self): - G = nx.path_graph(8) - A = nx.laplacian_matrix(G) - sigma = 2 - sqrt(2 + sqrt(2)) - ac = nx.algebraic_connectivity(G, tol=1e-12, method='tracemin') - assert almost_equal(ac, sigma) - x = nx.fiedler_vector(G, tol=1e-12, method='tracemin') - check_eigenvector(A, sigma, x) - - def test_path(self): - G = nx.path_graph(8) - A = nx.laplacian_matrix(G) - sigma = 2 - sqrt(2 + sqrt(2)) - for method in self._methods: - ac = nx.algebraic_connectivity(G, tol=1e-12, method=method) - assert almost_equal(ac, sigma) - x = nx.fiedler_vector(G, tol=1e-12, method=method) - check_eigenvector(A, sigma, x) - - def test_problematic_graph_issue_2381(self): - G = nx.path_graph(4) - G.add_edges_from([(4, 2), (5, 1)]) - A = nx.laplacian_matrix(G) - sigma = 0.438447187191 - for method in self._methods: - ac = nx.algebraic_connectivity(G, tol=1e-12, method=method) - assert almost_equal(ac, sigma) - x = nx.fiedler_vector(G, tol=1e-12, method=method) - check_eigenvector(A, sigma, x) - - def test_cycle(self): - G = nx.cycle_graph(8) - A = nx.laplacian_matrix(G) - sigma = 2 - sqrt(2) - for method in self._methods: - ac = nx.algebraic_connectivity(G, tol=1e-12, method=method) - assert almost_equal(ac, sigma) - x = nx.fiedler_vector(G, tol=1e-12, method=method) - check_eigenvector(A, sigma, x) - - def test_seed_argument(self): - G = nx.cycle_graph(8) - A = nx.laplacian_matrix(G) - sigma = 2 - sqrt(2) - for method in self._methods: - ac = nx.algebraic_connectivity(G, tol=1e-12, method=method, seed=1) - assert almost_equal(ac, sigma) - x = nx.fiedler_vector(G, tol=1e-12, method=method, seed=1) - check_eigenvector(A, sigma, x) - - def test_buckminsterfullerene(self): - G = nx.Graph( - [(1, 10), (1, 41), (1, 59), (2, 12), (2, 42), (2, 60), (3, 6), - (3, 43), (3, 57), (4, 8), (4, 44), (4, 58), (5, 13), (5, 56), - (5, 57), (6, 10), (6, 31), (7, 14), (7, 56), (7, 58), (8, 12), - (8, 32), (9, 23), (9, 53), (9, 59), (10, 15), (11, 24), (11, 53), - (11, 60), (12, 16), (13, 14), (13, 25), (14, 26), (15, 27), - (15, 49), (16, 28), (16, 50), (17, 18), (17, 19), (17, 54), - (18, 20), (18, 55), (19, 23), (19, 41), (20, 24), (20, 42), - (21, 31), (21, 33), (21, 57), (22, 32), (22, 34), (22, 58), - (23, 24), (25, 35), (25, 43), (26, 36), (26, 44), (27, 51), - (27, 59), (28, 52), (28, 60), (29, 33), (29, 34), (29, 56), - (30, 51), (30, 52), (30, 53), (31, 47), (32, 48), (33, 45), - (34, 46), (35, 36), (35, 37), (36, 38), (37, 39), (37, 49), - (38, 40), (38, 50), (39, 40), (39, 51), (40, 52), (41, 47), - (42, 48), (43, 49), (44, 50), (45, 46), (45, 54), (46, 55), - (47, 54), (48, 55)]) - for normalized in (False, True): - if not normalized: - A = nx.laplacian_matrix(G) - sigma = 0.2434017461399311 - else: - A = nx.normalized_laplacian_matrix(G) - sigma = 0.08113391537997749 - for method in methods: - try: - assert almost_equal(nx.algebraic_connectivity( - G, normalized=normalized, tol=1e-12, method=method), - sigma) - x = nx.fiedler_vector(G, normalized=normalized, tol=1e-12, - method=method) - check_eigenvector(A, sigma, x) - except nx.NetworkXError as e: - if e.args not in (('Cholesky solver unavailable.',), - ('LU solver unavailable.',)): - raise - - _methods = methods - - -class TestSpectralOrdering(object): - - def test_nullgraph(self): - for graph in (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph): - G = graph() - pytest.raises(nx.NetworkXError, nx.spectral_ordering, G) - - def test_singleton(self): - for graph in (nx.Graph, nx.DiGraph, nx.MultiGraph, nx.MultiDiGraph): - G = graph() - G.add_node('x') - assert nx.spectral_ordering(G) == ['x'] - G.add_edge('x', 'x', weight=33) - G.add_edge('x', 'x', weight=33) - assert nx.spectral_ordering(G) == ['x'] - - def test_unrecognized_method(self): - G = nx.path_graph(4) - pytest.raises(nx.NetworkXError, nx.spectral_ordering, G, - method='unknown') - - def test_three_nodes(self): - G = nx.Graph() - G.add_weighted_edges_from([(1, 2, 1), (1, 3, 2), (2, 3, 1)], - weight='spam') - for method in self._methods: - order = nx.spectral_ordering(G, weight='spam', method=method) - assert set(order) == set(G) - assert set([1, 3]) in (set(order[:-1]), set(order[1:])) - G = nx.MultiDiGraph() - G.add_weighted_edges_from([(1, 2, 1), (1, 3, 2), (2, 3, 1), (2, 3, 2)]) - for method in self._methods: - order = nx.spectral_ordering(G, method=method) - assert set(order) == set(G) - assert set([2, 3]) in (set(order[:-1]), set(order[1:])) - - def test_path(self): - # based on setup_class numpy is installed if we get here - from numpy.random import shuffle - path = list(range(10)) - shuffle(path) - G = nx.Graph() - nx.add_path(G, path) - for method in self._methods: - order = nx.spectral_ordering(G, method=method) - assert order in [path, list(reversed(path))] - - def test_seed_argument(self): - # based on setup_class numpy is installed if we get here - from numpy.random import shuffle - path = list(range(10)) - shuffle(path) - G = nx.Graph() - nx.add_path(G, path) - for method in self._methods: - order = nx.spectral_ordering(G, method=method, seed=1) - assert order in [path, list(reversed(path))] - - def test_disconnected(self): - G = nx.Graph() - nx.add_path(G, range(0, 10, 2)) - nx.add_path(G, range(1, 10, 2)) - for method in self._methods: - order = nx.spectral_ordering(G, method=method) - assert set(order) == set(G) - seqs = [list(range(0, 10, 2)), list(range(8, -1, -2)), - list(range(1, 10, 2)), list(range(9, -1, -2))] - assert order[:5] in seqs - assert order[5:] in seqs - - def test_cycle(self): - path = list(range(10)) - G = nx.Graph() - nx.add_path(G, path, weight=5) - G.add_edge(path[-1], path[0], weight=1) - A = nx.laplacian_matrix(G).todense() - for normalized in (False, True): - for method in methods: - try: - order = nx.spectral_ordering(G, normalized=normalized, - method=method) - except nx.NetworkXError as e: - if e.args not in (('Cholesky solver unavailable.',), - ('LU solver unavailable.',)): - raise - else: - if not normalized: - assert order in [[1, 2, 0, 3, 4, 5, 6, 9, 7, 8], - [8, 7, 9, 6, 5, 4, 3, 0, 2, 1]] - else: - assert order in [[1, 2, 3, 0, 4, 5, 9, 6, 7, 8], - [8, 7, 6, 9, 5, 4, 0, 3, 2, 1]] - - _methods = methods diff --git a/extensions/fablabchemnitz/networkx/linalg/tests/test_bethehessian.py b/extensions/fablabchemnitz/networkx/linalg/tests/test_bethehessian.py deleted file mode 100644 index a0f17eb9..00000000 --- a/extensions/fablabchemnitz/networkx/linalg/tests/test_bethehessian.py +++ /dev/null @@ -1,34 +0,0 @@ -import pytest -numpy = pytest.importorskip('numpy') -npt = pytest.importorskip('numpy.testing') -scipy = pytest.importorskip('scipy') - -import networkx as nx -from networkx.generators.degree_seq import havel_hakimi_graph - - -class TestBetheHessian(object): - - @classmethod - def setup_class(cls): - deg = [3, 2, 2, 1, 0] - cls.G = havel_hakimi_graph(deg) - cls.P = nx.path_graph(3) - - def test_bethe_hessian(self): - "Bethe Hessian matrix" - H = numpy.array([[ 4, -2, 0], - [-2, 5, -2], - [ 0, -2, 4]]) - permutation = [2, 0, 1] - # Bethe Hessian gives expected form - npt.assert_equal(nx.bethe_hessian_matrix(self.P, r=2).todense(), H) - # nodelist is correctly implemented - npt.assert_equal(nx.bethe_hessian_matrix(self.P, r=2, nodelist=permutation).todense(), - H[numpy.ix_(permutation, permutation)]) - # Equal to Laplacian matrix when r=1 - npt.assert_equal(nx.bethe_hessian_matrix(self.G, r=1).todense(), - nx.laplacian_matrix(self.G).todense()) - # Correct default for the regularizer r - npt.assert_equal(nx.bethe_hessian_matrix(self.G).todense(), - nx.bethe_hessian_matrix(self.G, r=1.25).todense()) diff --git a/extensions/fablabchemnitz/networkx/linalg/tests/test_graphmatrix.py b/extensions/fablabchemnitz/networkx/linalg/tests/test_graphmatrix.py deleted file mode 100644 index d1e06767..00000000 --- a/extensions/fablabchemnitz/networkx/linalg/tests/test_graphmatrix.py +++ /dev/null @@ -1,163 +0,0 @@ -import pytest -numpy = pytest.importorskip('numpy') -npt = pytest.importorskip('numpy.testing') -scipy = pytest.importorskip('scipy') - -import networkx as nx -from networkx.generators.degree_seq import havel_hakimi_graph - - -class TestGraphMatrix(object): - - @classmethod - def setup_class(cls): - deg = [3, 2, 2, 1, 0] - cls.G = havel_hakimi_graph(deg) - cls.OI = numpy.array([[-1, -1, -1, 0], - [1, 0, 0, -1], - [0, 1, 0, 1], - [0, 0, 1, 0], - [0, 0, 0, 0]]) - cls.A = numpy.array([[0, 1, 1, 1, 0], - [1, 0, 1, 0, 0], - [1, 1, 0, 0, 0], - [1, 0, 0, 0, 0], - [0, 0, 0, 0, 0]]) - cls.WG = havel_hakimi_graph(deg) - cls.WG.add_edges_from((u, v, {'weight': 0.5, 'other': 0.3}) - for (u, v) in cls.G.edges()) - cls.WA = numpy.array([[0, 0.5, 0.5, 0.5, 0], - [0.5, 0, 0.5, 0, 0], - [0.5, 0.5, 0, 0, 0], - [0.5, 0, 0, 0, 0], - [0, 0, 0, 0, 0]]) - cls.MG = nx.MultiGraph(cls.G) - cls.MG2 = cls.MG.copy() - cls.MG2.add_edge(0, 1) - cls.MG2A = numpy.array([[0, 2, 1, 1, 0], - [2, 0, 1, 0, 0], - [1, 1, 0, 0, 0], - [1, 0, 0, 0, 0], - [0, 0, 0, 0, 0]]) - cls.MGOI = numpy.array([[-1, -1, -1, -1, 0], - [1, 1, 0, 0, -1], - [0, 0, 1, 0, 1], - [0, 0, 0, 1, 0], - [0, 0, 0, 0, 0]]) - cls.no_edges_G = nx.Graph([(1, 2), (3, 2, {'weight': 8})]) - cls.no_edges_A = numpy.array([[0, 0], [0, 0]]) - - def test_incidence_matrix(self): - "Conversion to incidence matrix" - I = nx.incidence_matrix(self.G, - nodelist=sorted(self.G), - edgelist=sorted(self.G.edges()), - oriented=True).todense().astype(int) - npt.assert_equal(I, self.OI) - I = nx.incidence_matrix(self.G, - nodelist=sorted(self.G), - edgelist=sorted(self.G.edges()), - oriented=False).todense().astype(int) - npt.assert_equal(I, numpy.abs(self.OI)) - - I = nx.incidence_matrix(self.MG, - nodelist=sorted(self.MG), - edgelist=sorted(self.MG.edges()), - oriented=True).todense().astype(int) - npt.assert_equal(I, self.OI) - I = nx.incidence_matrix(self.MG, - nodelist=sorted(self.MG), - edgelist=sorted(self.MG.edges()), - oriented=False).todense().astype(int) - npt.assert_equal(I, numpy.abs(self.OI)) - - I = nx.incidence_matrix(self.MG2, - nodelist=sorted(self.MG2), - edgelist=sorted(self.MG2.edges()), - oriented=True).todense().astype(int) - npt.assert_equal(I, self.MGOI) - I = nx.incidence_matrix(self.MG2, - nodelist=sorted(self.MG), - edgelist=sorted(self.MG2.edges()), - oriented=False).todense().astype(int) - npt.assert_equal(I, numpy.abs(self.MGOI)) - - def test_weighted_incidence_matrix(self): - I = nx.incidence_matrix(self.WG, - nodelist=sorted(self.WG), - edgelist=sorted(self.WG.edges()), - oriented=True).todense().astype(int) - npt.assert_equal(I, self.OI) - I = nx.incidence_matrix(self.WG, - nodelist=sorted(self.WG), - edgelist=sorted(self.WG.edges()), - oriented=False).todense().astype(int) - npt.assert_equal(I, numpy.abs(self.OI)) - - # npt.assert_equal(nx.incidence_matrix(self.WG,oriented=True, - # weight='weight').todense(),0.5*self.OI) - # npt.assert_equal(nx.incidence_matrix(self.WG,weight='weight').todense(), - # numpy.abs(0.5*self.OI)) - # npt.assert_equal(nx.incidence_matrix(self.WG,oriented=True,weight='other').todense(), - # 0.3*self.OI) - - I = nx.incidence_matrix(self.WG, - nodelist=sorted(self.WG), - edgelist=sorted(self.WG.edges()), - oriented=True, - weight='weight').todense() - npt.assert_equal(I, 0.5 * self.OI) - I = nx.incidence_matrix(self.WG, - nodelist=sorted(self.WG), - edgelist=sorted(self.WG.edges()), - oriented=False, - weight='weight').todense() - npt.assert_equal(I, numpy.abs(0.5 * self.OI)) - I = nx.incidence_matrix(self.WG, - nodelist=sorted(self.WG), - edgelist=sorted(self.WG.edges()), - oriented=True, - weight='other').todense() - npt.assert_equal(I, 0.3 * self.OI) - - # WMG=nx.MultiGraph(self.WG) - # WMG.add_edge(0,1,weight=0.5,other=0.3) - # npt.assert_equal(nx.incidence_matrix(WMG,weight='weight').todense(), - # numpy.abs(0.5*self.MGOI)) - # npt.assert_equal(nx.incidence_matrix(WMG,weight='weight',oriented=True).todense(), - # 0.5*self.MGOI) - # npt.assert_equal(nx.incidence_matrix(WMG,weight='other',oriented=True).todense(), - # 0.3*self.MGOI) - - WMG = nx.MultiGraph(self.WG) - WMG.add_edge(0, 1, weight=0.5, other=0.3) - I = nx.incidence_matrix(WMG, - nodelist=sorted(WMG), - edgelist=sorted(WMG.edges(keys=True)), - oriented=True, - weight='weight').todense() - npt.assert_equal(I, 0.5 * self.MGOI) - I = nx.incidence_matrix(WMG, - nodelist=sorted(WMG), - edgelist=sorted(WMG.edges(keys=True)), - oriented=False, - weight='weight').todense() - npt.assert_equal(I, numpy.abs(0.5 * self.MGOI)) - I = nx.incidence_matrix(WMG, - nodelist=sorted(WMG), - edgelist=sorted(WMG.edges(keys=True)), - oriented=True, - weight='other').todense() - npt.assert_equal(I, 0.3 * self.MGOI) - - def test_adjacency_matrix(self): - "Conversion to adjacency matrix" - npt.assert_equal(nx.adj_matrix(self.G).todense(), self.A) - npt.assert_equal(nx.adj_matrix(self.MG).todense(), self.A) - npt.assert_equal(nx.adj_matrix(self.MG2).todense(), self.MG2A) - npt.assert_equal(nx.adj_matrix(self.G, nodelist=[0, 1]).todense(), self.A[:2, :2]) - npt.assert_equal(nx.adj_matrix(self.WG).todense(), self.WA) - npt.assert_equal(nx.adj_matrix(self.WG, weight=None).todense(), self.A) - npt.assert_equal(nx.adj_matrix(self.MG2, weight=None).todense(), self.MG2A) - npt.assert_equal(nx.adj_matrix(self.WG, weight='other').todense(), 0.6 * self.WA) - npt.assert_equal(nx.adj_matrix(self.no_edges_G, nodelist=[1, 3]).todense(), self.no_edges_A) diff --git a/extensions/fablabchemnitz/networkx/linalg/tests/test_laplacian.py b/extensions/fablabchemnitz/networkx/linalg/tests/test_laplacian.py deleted file mode 100644 index 003c3b36..00000000 --- a/extensions/fablabchemnitz/networkx/linalg/tests/test_laplacian.py +++ /dev/null @@ -1,149 +0,0 @@ -import pytest -numpy = pytest.importorskip('numpy') -npt = pytest.importorskip('numpy.testing') -scipy = pytest.importorskip('scipy') - -import networkx as nx -from networkx.generators.degree_seq import havel_hakimi_graph - - -class TestLaplacian(object): - - @classmethod - def setup_class(cls): - deg = [3, 2, 2, 1, 0] - cls.G = havel_hakimi_graph(deg) - cls.WG = nx.Graph((u, v, {'weight': 0.5, 'other': 0.3}) - for (u, v) in cls.G.edges()) - cls.WG.add_node(4) - cls.MG = nx.MultiGraph(cls.G) - - # Graph with clsloops - cls.Gsl = cls.G.copy() - for node in cls.Gsl.nodes(): - cls.Gsl.add_edge(node, node) - - def test_laplacian(self): - "Graph Laplacian" - NL = numpy.array([[3, -1, -1, -1, 0], - [-1, 2, -1, 0, 0], - [-1, -1, 2, 0, 0], - [-1, 0, 0, 1, 0], - [0, 0, 0, 0, 0]]) - WL = 0.5 * NL - OL = 0.3 * NL - npt.assert_equal(nx.laplacian_matrix(self.G).todense(), NL) - npt.assert_equal(nx.laplacian_matrix(self.MG).todense(), NL) - npt.assert_equal(nx.laplacian_matrix(self.G, nodelist=[0, 1]).todense(), - numpy.array([[1, -1], [-1, 1]])) - npt.assert_equal(nx.laplacian_matrix(self.WG).todense(), WL) - npt.assert_equal(nx.laplacian_matrix(self.WG, weight=None).todense(), NL) - npt.assert_equal(nx.laplacian_matrix(self.WG, weight='other').todense(), OL) - - def test_normalized_laplacian(self): - "Generalized Graph Laplacian" - GL = numpy.array([[1.00, -0.408, -0.408, -0.577, 0.00], - [-0.408, 1.00, -0.50, 0.00, 0.00], - [-0.408, -0.50, 1.00, 0.00, 0.00], - [-0.577, 0.00, 0.00, 1.00, 0.00], - [0.00, 0.00, 0.00, 0.00, 0.00]]) - Lsl = numpy.array([[0.75, -0.2887, -0.2887, -0.3536, 0.], - [-0.2887, 0.6667, -0.3333, 0., 0.], - [-0.2887, -0.3333, 0.6667, 0., 0.], - [-0.3536, 0., 0., 0.5, 0.], - [0., 0., 0., 0., 0.]]) - - npt.assert_almost_equal(nx.normalized_laplacian_matrix(self.G).todense(), - GL, decimal=3) - npt.assert_almost_equal(nx.normalized_laplacian_matrix(self.MG).todense(), - GL, decimal=3) - npt.assert_almost_equal(nx.normalized_laplacian_matrix(self.WG).todense(), - GL, decimal=3) - npt.assert_almost_equal(nx.normalized_laplacian_matrix(self.WG, weight='other').todense(), - GL, decimal=3) - npt.assert_almost_equal(nx.normalized_laplacian_matrix(self.Gsl).todense(), - Lsl, decimal=3) - - def test_directed_laplacian(self): - "Directed Laplacian" - # Graph used as an example in Sec. 4.1 of Langville and Meyer, - # "Google's PageRank and Beyond". The graph contains dangling nodes, so - # the pagerank random walk is selected by directed_laplacian - G = nx.DiGraph() - G.add_edges_from(((1, 2), (1, 3), (3, 1), (3, 2), (3, 5), (4, 5), (4, 6), - (5, 4), (5, 6), (6, 4))) - GL = numpy.array([[0.9833, -0.2941, -0.3882, -0.0291, -0.0231, -0.0261], - [-0.2941, 0.8333, -0.2339, -0.0536, -0.0589, -0.0554], - [-0.3882, -0.2339, 0.9833, -0.0278, -0.0896, -0.0251], - [-0.0291, -0.0536, -0.0278, 0.9833, -0.4878, -0.6675], - [-0.0231, -0.0589, -0.0896, -0.4878, 0.9833, -0.2078], - [-0.0261, -0.0554, -0.0251, -0.6675, -0.2078, 0.9833]]) - L = nx.directed_laplacian_matrix(G, alpha=0.9, nodelist=sorted(G)) - npt.assert_almost_equal(L, GL, decimal=3) - - # Make the graph strongly connected, so we can use a random and lazy walk - G.add_edges_from((((2, 5), (6, 1)))) - GL = numpy.array([[1., -0.3062, -0.4714, 0., 0., -0.3227], - [-0.3062, 1., -0.1443, 0., -0.3162, 0.], - [-0.4714, -0.1443, 1., 0., -0.0913, 0.], - [0., 0., 0., 1., -0.5, -0.5], - [0., -0.3162, -0.0913, -0.5, 1., -0.25], - [-0.3227, 0., 0., -0.5, -0.25, 1.]]) - L = nx.directed_laplacian_matrix(G, alpha=0.9, nodelist=sorted(G), walk_type='random') - npt.assert_almost_equal(L, GL, decimal=3) - - GL = numpy.array([[0.5, -0.1531, -0.2357, 0., 0., -0.1614], - [-0.1531, 0.5, -0.0722, 0., -0.1581, 0.], - [-0.2357, -0.0722, 0.5, 0., -0.0456, 0.], - [0., 0., 0., 0.5, -0.25, -0.25], - [0., -0.1581, -0.0456, -0.25, 0.5, -0.125], - [-0.1614, 0., 0., -0.25, -0.125, 0.5]]) - L = nx.directed_laplacian_matrix(G, alpha=0.9, nodelist=sorted(G), walk_type='lazy') - npt.assert_almost_equal(L, GL, decimal=3) - - def test_directed_combinatorial_laplacian(self): - "Directed combinatorial Laplacian" - # Graph used as an example in Sec. 4.1 of Langville and Meyer, - # "Google's PageRank and Beyond". The graph contains dangling nodes, so - # the pagerank random walk is selected by directed_laplacian - G = nx.DiGraph() - G.add_edges_from(((1, 2), (1, 3), (3, 1), (3, 2), (3, 5), (4, 5), (4, 6), - (5, 4), (5, 6), (6, 4))) - - GL = numpy.array([[0.0366, -0.0132, -0.0153, -0.0034, -0.0020, -0.0027], - [-0.0132, 0.0450, -0.0111, -0.0076, -0.0062, -0.0069], - [-0.0153, -0.0111, 0.0408, -0.0035, -0.0083, -0.0027], - [-0.0034, -0.0076, -0.0035, 0.3688, -0.1356, -0.2187], - [-0.0020, -0.0062, -0.0083, -0.1356, 0.2026, -0.0505], - [-0.0027, -0.0069, -0.0027, -0.2187, -0.0505, 0.2815]]) - - L = nx.directed_combinatorial_laplacian_matrix(G, alpha=0.9, - nodelist=sorted(G)) - npt.assert_almost_equal(L, GL, decimal=3) - - # Make the graph strongly connected, so we can use a random and lazy walk - G.add_edges_from((((2, 5), (6, 1)))) - - GL = numpy.array([[0.1395, -0.0349, -0.0465, 0, 0, -0.0581], - [-0.0349, 0.0930, -0.0116, 0, -0.0465, 0], - [-0.0465, -0.0116, 0.0698, 0, -0.0116, 0], - [0, 0, 0, 0.2326, -0.1163, -0.1163], - [0, -0.0465, -0.0116, -0.1163, 0.2326, -0.0581], - [-0.0581, 0, 0, -0.1163, -0.0581, 0.2326]]) - - L = nx.directed_combinatorial_laplacian_matrix(G, alpha=0.9, - nodelist=sorted(G), - walk_type='random') - npt.assert_almost_equal(L, GL, decimal=3) - - GL = numpy.array([[0.0698, -0.0174, -0.0233, 0, 0, -0.0291], - [-0.0174, 0.0465, -0.0058, 0, -0.0233, 0], - [-0.0233, -0.0058, 0.0349, 0, -0.0058, 0], - [0, 0, 0, 0.1163, -0.0581, -0.0581], - [0, -0.0233, -0.0058, -0.0581, 0.1163, -0.0291], - [-0.0291, 0, 0, -0.0581, -0.0291, 0.1163]]) - - L = nx.directed_combinatorial_laplacian_matrix(G, alpha=0.9, - nodelist=sorted(G), - walk_type='lazy') - npt.assert_almost_equal(L, GL, decimal=3) diff --git a/extensions/fablabchemnitz/networkx/linalg/tests/test_modularity.py b/extensions/fablabchemnitz/networkx/linalg/tests/test_modularity.py deleted file mode 100644 index 9adbe5c2..00000000 --- a/extensions/fablabchemnitz/networkx/linalg/tests/test_modularity.py +++ /dev/null @@ -1,65 +0,0 @@ -import pytest -numpy = pytest.importorskip('numpy') -npt = pytest.importorskip('numpy.testing') -scipy = pytest.importorskip('scipy') - -import networkx as nx -from networkx.generators.degree_seq import havel_hakimi_graph - - -class TestModularity(object): - - @classmethod - def setup_class(cls): - deg = [3, 2, 2, 1, 0] - cls.G = havel_hakimi_graph(deg) - # Graph used as an example in Sec. 4.1 of Langville and Meyer, - # "Google's PageRank and Beyond". (Used for test_directed_laplacian) - cls.DG = nx.DiGraph() - cls.DG.add_edges_from(((1, 2), (1, 3), (3, 1), (3, 2), (3, 5), (4, 5), (4, 6), - (5, 4), (5, 6), (6, 4))) - - def test_modularity(self): - "Modularity matrix" - B = numpy.matrix([[-1.125, 0.25, 0.25, 0.625, 0.], - [0.25, -0.5, 0.5, -0.25, 0.], - [0.25, 0.5, -0.5, -0.25, 0.], - [0.625, -0.25, -0.25, -0.125, 0.], - [0., 0., 0., 0., 0.]]) - - permutation = [4, 0, 1, 2, 3] - npt.assert_equal(nx.modularity_matrix(self.G), B) - npt.assert_equal(nx.modularity_matrix(self.G, nodelist=permutation), - B[numpy.ix_(permutation, permutation)]) - - def test_modularity_weight(self): - "Modularity matrix with weights" - B = numpy.matrix([[-1.125, 0.25, 0.25, 0.625, 0.], - [0.25, -0.5, 0.5, -0.25, 0.], - [0.25, 0.5, -0.5, -0.25, 0.], - [0.625, -0.25, -0.25, -0.125, 0.], - [0., 0., 0., 0., 0.]]) - - G_weighted = self.G.copy() - for n1, n2 in G_weighted.edges(): - G_weighted.edges[n1, n2]["weight"] = 0.5 - # The following test would fail in networkx 1.1 - npt.assert_equal(nx.modularity_matrix(G_weighted), B) - # The following test that the modularity matrix get rescaled accordingly - npt.assert_equal(nx.modularity_matrix(G_weighted, weight="weight"), 0.5 * B) - - def test_directed_modularity(self): - "Directed Modularity matrix" - B = numpy.matrix([[-0.2, 0.6, 0.8, -0.4, -0.4, -0.4], - [0., 0., 0., 0., 0., 0.], - [0.7, 0.4, -0.3, -0.6, 0.4, -0.6], - [-0.2, -0.4, -0.2, -0.4, 0.6, 0.6], - [-0.2, -0.4, -0.2, 0.6, -0.4, 0.6], - [-0.1, -0.2, -0.1, 0.8, -0.2, -0.2]]) - node_permutation = [5, 1, 2, 3, 4, 6] - idx_permutation = [4, 0, 1, 2, 3, 5] - mm = nx.directed_modularity_matrix(self.DG, nodelist=sorted(self.DG)) - npt.assert_equal(mm, B) - npt.assert_equal(nx.directed_modularity_matrix(self.DG, - nodelist=node_permutation), - B[numpy.ix_(idx_permutation, idx_permutation)]) diff --git a/extensions/fablabchemnitz/networkx/linalg/tests/test_spectrum.py b/extensions/fablabchemnitz/networkx/linalg/tests/test_spectrum.py deleted file mode 100644 index 63fdcf00..00000000 --- a/extensions/fablabchemnitz/networkx/linalg/tests/test_spectrum.py +++ /dev/null @@ -1,73 +0,0 @@ -import pytest -numpy = pytest.importorskip('numpy') -npt = pytest.importorskip('numpy.testing') -scipy = pytest.importorskip('scipy') - -import networkx as nx -from networkx.generators.degree_seq import havel_hakimi_graph - - -class TestSpectrum(object): - - @classmethod - def setup_class(cls): - deg = [3, 2, 2, 1, 0] - cls.G = havel_hakimi_graph(deg) - cls.P = nx.path_graph(3) - cls.WG = nx.Graph((u, v, {'weight': 0.5, 'other': 0.3}) - for (u, v) in cls.G.edges()) - cls.WG.add_node(4) - cls.DG = nx.DiGraph() - nx.add_path(cls.DG, [0, 1, 2]) - - def test_laplacian_spectrum(self): - "Laplacian eigenvalues" - evals = numpy.array([0, 0, 1, 3, 4]) - e = sorted(nx.laplacian_spectrum(self.G)) - npt.assert_almost_equal(e, evals) - e = sorted(nx.laplacian_spectrum(self.WG, weight=None)) - npt.assert_almost_equal(e, evals) - e = sorted(nx.laplacian_spectrum(self.WG)) - npt.assert_almost_equal(e, 0.5 * evals) - e = sorted(nx.laplacian_spectrum(self.WG, weight='other')) - npt.assert_almost_equal(e, 0.3 * evals) - - def test_normalized_laplacian_spectrum(self): - "Normalized Laplacian eigenvalues" - evals = numpy.array([0, 0, 0.7712864461218, 1.5, 1.7287135538781]) - e = sorted(nx.normalized_laplacian_spectrum(self.G)) - npt.assert_almost_equal(e, evals) - e = sorted(nx.normalized_laplacian_spectrum(self.WG, weight=None)) - npt.assert_almost_equal(e, evals) - e = sorted(nx.normalized_laplacian_spectrum(self.WG)) - npt.assert_almost_equal(e, evals) - e = sorted(nx.normalized_laplacian_spectrum(self.WG, weight='other')) - npt.assert_almost_equal(e, evals) - - - def test_adjacency_spectrum(self): - "Adjacency eigenvalues" - evals = numpy.array([-numpy.sqrt(2), 0, numpy.sqrt(2)]) - e = sorted(nx.adjacency_spectrum(self.P)) - npt.assert_almost_equal(e, evals) - - def test_modularity_spectrum(self): - "Modularity eigenvalues" - evals = numpy.array([-1.5, 0., 0.]) - e = sorted(nx.modularity_spectrum(self.P)) - npt.assert_almost_equal(e, evals) - # Directed modularity eigenvalues - evals = numpy.array([-0.5, 0., 0.]) - e = sorted(nx.modularity_spectrum(self.DG)) - npt.assert_almost_equal(e, evals) - - def test_bethe_hessian_spectrum(self): - "Bethe Hessian eigenvalues" - evals = numpy.array([0.5 * (9 - numpy.sqrt(33)), 4, - 0.5 * (9 + numpy.sqrt(33))]) - e = sorted(nx.bethe_hessian_spectrum(self.P, r=2)) - npt.assert_almost_equal(e, evals) - # Collapses back to Laplacian: - e1 = sorted(nx.bethe_hessian_spectrum(self.P, r=1)) - e2 = sorted(nx.laplacian_spectrum(self.P)) - npt.assert_almost_equal(e1, e2) diff --git a/extensions/fablabchemnitz/networkx/readwrite/__init__.py b/extensions/fablabchemnitz/networkx/readwrite/__init__.py deleted file mode 100644 index 7fa32dee..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -""" -A package for reading and writing graphs in various formats. - -""" -from networkx.readwrite.adjlist import * -from networkx.readwrite.multiline_adjlist import * -from networkx.readwrite.edgelist import * -from networkx.readwrite.gpickle import * -from networkx.readwrite.pajek import * -from networkx.readwrite.leda import * -from networkx.readwrite.sparse6 import * -from networkx.readwrite.graph6 import * -from networkx.readwrite.nx_yaml import * -from networkx.readwrite.gml import * -from networkx.readwrite.graphml import * -from networkx.readwrite.gexf import * -from networkx.readwrite.nx_shp import * -from networkx.readwrite.json_graph import * diff --git a/extensions/fablabchemnitz/networkx/readwrite/adjlist.py b/extensions/fablabchemnitz/networkx/readwrite/adjlist.py deleted file mode 100644 index a9e68222..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/adjlist.py +++ /dev/null @@ -1,304 +0,0 @@ -# -*- coding: utf-8 -*- -""" -************** -Adjacency List -************** -Read and write NetworkX graphs as adjacency lists. - -Adjacency list format is useful for graphs without data associated -with nodes or edges and for nodes that can be meaningfully represented -as strings. - -Format ------- -The adjacency list format consists of lines with node labels. The -first label in a line is the source node. Further labels in the line -are considered target nodes and are added to the graph along with an edge -between the source node and target node. - -The graph with edges a-b, a-c, d-e can be represented as the following -adjacency list (anything following the # in a line is a comment):: - - a b c # source target target - d e -""" -__author__ = '\n'.join(['Aric Hagberg ', - 'Dan Schult ', - 'Loïc Séguin-C. ']) -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. - -__all__ = ['generate_adjlist', - 'write_adjlist', - 'parse_adjlist', - 'read_adjlist'] - -from networkx.utils import make_str, open_file -import networkx as nx - - -def generate_adjlist(G, delimiter=' '): - """Generate a single line of the graph G in adjacency list format. - - Parameters - ---------- - G : NetworkX graph - - delimiter : string, optional - Separator for node labels - - Returns - ------- - lines : string - Lines of data in adjlist format. - - Examples - -------- - >>> G = nx.lollipop_graph(4, 3) - >>> for line in nx.generate_adjlist(G): - ... print(line) - 0 1 2 3 - 1 2 3 - 2 3 - 3 4 - 4 5 - 5 6 - 6 - - See Also - -------- - write_adjlist, read_adjlist - - """ - directed = G.is_directed() - seen = set() - for s, nbrs in G.adjacency(): - line = make_str(s) + delimiter - for t, data in nbrs.items(): - if not directed and t in seen: - continue - if G.is_multigraph(): - for d in data.values(): - line += make_str(t) + delimiter - else: - line += make_str(t) + delimiter - if not directed: - seen.add(s) - yield line[:-len(delimiter)] - - -@open_file(1, mode='wb') -def write_adjlist(G, path, comments="#", delimiter=' ', encoding='utf-8'): - """Write graph G in single-line adjacency-list format to path. - - - Parameters - ---------- - G : NetworkX graph - - path : string or file - Filename or file handle for data output. - Filenames ending in .gz or .bz2 will be compressed. - - comments : string, optional - Marker for comment lines - - delimiter : string, optional - Separator for node labels - - encoding : string, optional - Text encoding. - - Examples - -------- - >>> G=nx.path_graph(4) - >>> nx.write_adjlist(G,"test.adjlist") - - The path can be a filehandle or a string with the name of the file. If a - filehandle is provided, it has to be opened in 'wb' mode. - - >>> fh=open("test.adjlist",'wb') - >>> nx.write_adjlist(G, fh) - - Notes - ----- - This format does not store graph, node, or edge data. - - See Also - -------- - read_adjlist, generate_adjlist - """ - import sys - import time - pargs = comments + " ".join(sys.argv) + '\n' - header = (pargs - + comments + " GMT {}\n".format(time.asctime(time.gmtime())) - + comments + " {}\n".format(G.name)) - path.write(header.encode(encoding)) - - for line in generate_adjlist(G, delimiter): - line += '\n' - path.write(line.encode(encoding)) - - -def parse_adjlist(lines, comments='#', delimiter=None, - create_using=None, nodetype=None): - """Parse lines of a graph adjacency list representation. - - Parameters - ---------- - lines : list or iterator of strings - Input data in adjlist format - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - nodetype : Python type, optional - Convert nodes to this type. - - comments : string, optional - Marker for comment lines - - delimiter : string, optional - Separator for node labels. The default is whitespace. - - Returns - ------- - G: NetworkX graph - The graph corresponding to the lines in adjacency list format. - - Examples - -------- - >>> lines = ['1 2 5', - ... '2 3 4', - ... '3 5', - ... '4', - ... '5'] - >>> G = nx.parse_adjlist(lines, nodetype=int) - >>> nodes = [1, 2, 3, 4, 5] - >>> all(node in G for node in nodes) - True - >>> edges = [(1, 2), (1, 5), (2, 3), (2, 4), (3, 5)] - >>> all((u, v) in G.edges() or (v, u) in G.edges() for (u, v) in edges) - True - - See Also - -------- - read_adjlist - - """ - G = nx.empty_graph(0, create_using) - for line in lines: - p = line.find(comments) - if p >= 0: - line = line[:p] - if not len(line): - continue - vlist = line.strip().split(delimiter) - u = vlist.pop(0) - # convert types - if nodetype is not None: - try: - u = nodetype(u) - except: - raise TypeError("Failed to convert node ({}) to type {}" - .format(u, nodetype)) - G.add_node(u) - if nodetype is not None: - try: - vlist = map(nodetype, vlist) - except: - raise TypeError("Failed to convert nodes ({}) to type {}" - .format(','.join(vlist), nodetype)) - G.add_edges_from([(u, v) for v in vlist]) - return G - - -@open_file(0, mode='rb') -def read_adjlist(path, comments="#", delimiter=None, create_using=None, - nodetype=None, encoding='utf-8'): - """Read graph in adjacency list format from path. - - Parameters - ---------- - path : string or file - Filename or file handle to read. - Filenames ending in .gz or .bz2 will be uncompressed. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - nodetype : Python type, optional - Convert nodes to this type. - - comments : string, optional - Marker for comment lines - - delimiter : string, optional - Separator for node labels. The default is whitespace. - - Returns - ------- - G: NetworkX graph - The graph corresponding to the lines in adjacency list format. - - Examples - -------- - >>> G=nx.path_graph(4) - >>> nx.write_adjlist(G, "test.adjlist") - >>> G=nx.read_adjlist("test.adjlist") - - The path can be a filehandle or a string with the name of the file. If a - filehandle is provided, it has to be opened in 'rb' mode. - - >>> fh=open("test.adjlist", 'rb') - >>> G=nx.read_adjlist(fh) - - Filenames ending in .gz or .bz2 will be compressed. - - >>> nx.write_adjlist(G,"test.adjlist.gz") - >>> G=nx.read_adjlist("test.adjlist.gz") - - The optional nodetype is a function to convert node strings to nodetype. - - For example - - >>> G=nx.read_adjlist("test.adjlist", nodetype=int) - - will attempt to convert all nodes to integer type. - - Since nodes must be hashable, the function nodetype must return hashable - types (e.g. int, float, str, frozenset - or tuples of those, etc.) - - The optional create_using parameter indicates the type of NetworkX graph - created. The default is `nx.Graph`, an undirected graph. - To read the data as a directed graph use - - >>> G=nx.read_adjlist("test.adjlist", create_using=nx.DiGraph) - - Notes - ----- - This format does not store graph or node data. - - See Also - -------- - write_adjlist - """ - lines = (line.decode(encoding) for line in path) - return parse_adjlist(lines, - comments=comments, - delimiter=delimiter, - create_using=create_using, - nodetype=nodetype) - - -# fixture for pytest -def teardown_module(module): - import os - for fname in ['test.adjlist', 'test.adjlist.gz']: - if os.path.isfile(fname): - os.unlink(fname) diff --git a/extensions/fablabchemnitz/networkx/readwrite/edgelist.py b/extensions/fablabchemnitz/networkx/readwrite/edgelist.py deleted file mode 100644 index d8b53ea2..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/edgelist.py +++ /dev/null @@ -1,469 +0,0 @@ -""" -********** -Edge Lists -********** -Read and write NetworkX graphs as edge lists. - -The multi-line adjacency list format is useful for graphs with nodes -that can be meaningfully represented as strings. With the edgelist -format simple edge data can be stored but node or graph data is not. -There is no way of representing isolated nodes unless the node has a -self-loop edge. - -Format ------- -You can read or write three formats of edge lists with these functions. - -Node pairs with no data:: - - 1 2 - -Python dictionary as data:: - - 1 2 {'weight':7, 'color':'green'} - -Arbitrary data:: - - 1 2 7 green -""" -__author__ = """Aric Hagberg (hagberg@lanl.gov)\nDan Schult (dschult@colgate.edu)""" -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. - -__all__ = ['generate_edgelist', - 'write_edgelist', - 'parse_edgelist', - 'read_edgelist', - 'read_weighted_edgelist', - 'write_weighted_edgelist'] - -from networkx.utils import open_file, make_str -import networkx as nx - - -def generate_edgelist(G, delimiter=' ', data=True): - """Generate a single line of the graph G in edge list format. - - Parameters - ---------- - G : NetworkX graph - - delimiter : string, optional - Separator for node labels - - data : bool or list of keys - If False generate no edge data. If True use a dictionary - representation of edge data. If a list of keys use a list of data - values corresponding to the keys. - - Returns - ------- - lines : string - Lines of data in adjlist format. - - Examples - -------- - >>> G = nx.lollipop_graph(4, 3) - >>> G[1][2]['weight'] = 3 - >>> G[3][4]['capacity'] = 12 - >>> for line in nx.generate_edgelist(G, data=False): - ... print(line) - 0 1 - 0 2 - 0 3 - 1 2 - 1 3 - 2 3 - 3 4 - 4 5 - 5 6 - - >>> for line in nx.generate_edgelist(G): - ... print(line) - 0 1 {} - 0 2 {} - 0 3 {} - 1 2 {'weight': 3} - 1 3 {} - 2 3 {} - 3 4 {'capacity': 12} - 4 5 {} - 5 6 {} - - >>> for line in nx.generate_edgelist(G,data=['weight']): - ... print(line) - 0 1 - 0 2 - 0 3 - 1 2 3 - 1 3 - 2 3 - 3 4 - 4 5 - 5 6 - - See Also - -------- - write_adjlist, read_adjlist - """ - if data is True: - for u, v, d in G.edges(data=True): - e = u, v, dict(d) - yield delimiter.join(map(make_str, e)) - elif data is False: - for u, v in G.edges(data=False): - e = u, v - yield delimiter.join(map(make_str, e)) - else: - for u, v, d in G.edges(data=True): - e = [u, v] - try: - e.extend(d[k] for k in data) - except KeyError: - pass # missing data for this edge, should warn? - yield delimiter.join(map(make_str, e)) - - -@open_file(1, mode='wb') -def write_edgelist(G, path, comments="#", delimiter=' ', data=True, - encoding='utf-8'): - """Write graph as a list of edges. - - Parameters - ---------- - G : graph - A NetworkX graph - path : file or string - File or filename to write. If a file is provided, it must be - opened in 'wb' mode. Filenames ending in .gz or .bz2 will be compressed. - comments : string, optional - The character used to indicate the start of a comment - delimiter : string, optional - The string used to separate values. The default is whitespace. - data : bool or list, optional - If False write no edge data. - If True write a string representation of the edge data dictionary.. - If a list (or other iterable) is provided, write the keys specified - in the list. - encoding: string, optional - Specify which encoding to use when writing file. - - Examples - -------- - >>> G=nx.path_graph(4) - >>> nx.write_edgelist(G, "test.edgelist") - >>> G=nx.path_graph(4) - >>> fh=open("test.edgelist",'wb') - >>> nx.write_edgelist(G, fh) - >>> nx.write_edgelist(G, "test.edgelist.gz") - >>> nx.write_edgelist(G, "test.edgelist.gz", data=False) - - >>> G=nx.Graph() - >>> G.add_edge(1,2,weight=7,color='red') - >>> nx.write_edgelist(G,'test.edgelist',data=False) - >>> nx.write_edgelist(G,'test.edgelist',data=['color']) - >>> nx.write_edgelist(G,'test.edgelist',data=['color','weight']) - - See Also - -------- - read_edgelist - write_weighted_edgelist - """ - - for line in generate_edgelist(G, delimiter, data): - line += '\n' - path.write(line.encode(encoding)) - - -def parse_edgelist(lines, comments='#', delimiter=None, - create_using=None, nodetype=None, data=True): - """Parse lines of an edge list representation of a graph. - - Parameters - ---------- - lines : list or iterator of strings - Input data in edgelist format - comments : string, optional - Marker for comment lines - delimiter : string, optional - Separator for node labels - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - nodetype : Python type, optional - Convert nodes to this type. - data : bool or list of (label,type) tuples - If False generate no edge data or if True use a dictionary - representation of edge data or a list tuples specifying dictionary - key names and types for edge data. - - Returns - ------- - G: NetworkX Graph - The graph corresponding to lines - - Examples - -------- - Edgelist with no data: - - >>> lines = ["1 2", - ... "2 3", - ... "3 4"] - >>> G = nx.parse_edgelist(lines, nodetype = int) - >>> list(G) - [1, 2, 3, 4] - >>> list(G.edges()) - [(1, 2), (2, 3), (3, 4)] - - Edgelist with data in Python dictionary representation: - - >>> lines = ["1 2 {'weight':3}", - ... "2 3 {'weight':27}", - ... "3 4 {'weight':3.0}"] - >>> G = nx.parse_edgelist(lines, nodetype = int) - >>> list(G) - [1, 2, 3, 4] - >>> list(G.edges(data=True)) - [(1, 2, {'weight': 3}), (2, 3, {'weight': 27}), (3, 4, {'weight': 3.0})] - - Edgelist with data in a list: - - >>> lines = ["1 2 3", - ... "2 3 27", - ... "3 4 3.0"] - >>> G = nx.parse_edgelist(lines, nodetype = int, data=(('weight',float),)) - >>> list(G) - [1, 2, 3, 4] - >>> list(G.edges(data=True)) - [(1, 2, {'weight': 3.0}), (2, 3, {'weight': 27.0}), (3, 4, {'weight': 3.0})] - - See Also - -------- - read_weighted_edgelist - """ - from ast import literal_eval - G = nx.empty_graph(0, create_using) - for line in lines: - p = line.find(comments) - if p >= 0: - line = line[:p] - if not len(line): - continue - # split line, should have 2 or more - s = line.strip().split(delimiter) - if len(s) < 2: - continue - u = s.pop(0) - v = s.pop(0) - d = s - if nodetype is not None: - try: - u = nodetype(u) - v = nodetype(v) - except: - raise TypeError("Failed to convert nodes %s,%s to type %s." - % (u, v, nodetype)) - - if len(d) == 0 or data is False: - # no data or data type specified - edgedata = {} - elif data is True: - # no edge types specified - try: # try to evaluate as dictionary - edgedata = dict(literal_eval(' '.join(d))) - except: - raise TypeError( - "Failed to convert edge data (%s) to dictionary." % (d)) - else: - # convert edge data to dictionary with specified keys and type - if len(d) != len(data): - raise IndexError( - "Edge data %s and data_keys %s are not the same length" % - (d, data)) - edgedata = {} - for (edge_key, edge_type), edge_value in zip(data, d): - try: - edge_value = edge_type(edge_value) - except: - raise TypeError( - "Failed to convert %s data %s to type %s." - % (edge_key, edge_value, edge_type)) - edgedata.update({edge_key: edge_value}) - G.add_edge(u, v, **edgedata) - return G - - -@open_file(0, mode='rb') -def read_edgelist(path, comments="#", delimiter=None, create_using=None, - nodetype=None, data=True, edgetype=None, encoding='utf-8'): - """Read a graph from a list of edges. - - Parameters - ---------- - path : file or string - File or filename to read. If a file is provided, it must be - opened in 'rb' mode. - Filenames ending in .gz or .bz2 will be uncompressed. - comments : string, optional - The character used to indicate the start of a comment. - delimiter : string, optional - The string used to separate values. The default is whitespace. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - nodetype : int, float, str, Python type, optional - Convert node data from strings to specified type - data : bool or list of (label,type) tuples - Tuples specifying dictionary key names and types for edge data - edgetype : int, float, str, Python type, optional OBSOLETE - Convert edge data from strings to specified type and use as 'weight' - encoding: string, optional - Specify which encoding to use when reading file. - - Returns - ------- - G : graph - A networkx Graph or other type specified with create_using - - Examples - -------- - >>> nx.write_edgelist(nx.path_graph(4), "test.edgelist") - >>> G=nx.read_edgelist("test.edgelist") - - >>> fh=open("test.edgelist", 'rb') - >>> G=nx.read_edgelist(fh) - >>> fh.close() - - >>> G=nx.read_edgelist("test.edgelist", nodetype=int) - >>> G=nx.read_edgelist("test.edgelist",create_using=nx.DiGraph) - - Edgelist with data in a list: - - >>> textline = '1 2 3' - >>> fh = open('test.edgelist','w') - >>> d = fh.write(textline) - >>> fh.close() - >>> G = nx.read_edgelist('test.edgelist', nodetype=int, data=(('weight',float),)) - >>> list(G) - [1, 2] - >>> list(G.edges(data=True)) - [(1, 2, {'weight': 3.0})] - - See parse_edgelist() for more examples of formatting. - - See Also - -------- - parse_edgelist - write_edgelist - - Notes - ----- - Since nodes must be hashable, the function nodetype must return hashable - types (e.g. int, float, str, frozenset - or tuples of those, etc.) - """ - lines = (line if isinstance(line, str) else line.decode(encoding) for line in path) - return parse_edgelist(lines, comments=comments, delimiter=delimiter, - create_using=create_using, nodetype=nodetype, - data=data) - - -def write_weighted_edgelist(G, path, comments="#", - delimiter=' ', encoding='utf-8'): - """Write graph G as a list of edges with numeric weights. - - Parameters - ---------- - G : graph - A NetworkX graph - path : file or string - File or filename to write. If a file is provided, it must be - opened in 'wb' mode. - Filenames ending in .gz or .bz2 will be compressed. - comments : string, optional - The character used to indicate the start of a comment - delimiter : string, optional - The string used to separate values. The default is whitespace. - encoding: string, optional - Specify which encoding to use when writing file. - - Examples - -------- - >>> G=nx.Graph() - >>> G.add_edge(1,2,weight=7) - >>> nx.write_weighted_edgelist(G, 'test.weighted.edgelist') - - See Also - -------- - read_edgelist - write_edgelist - read_weighted_edgelist - """ - write_edgelist(G, path, comments=comments, delimiter=delimiter, - data=('weight',), encoding=encoding) - - -def read_weighted_edgelist(path, comments="#", delimiter=None, - create_using=None, nodetype=None, encoding='utf-8'): - """Read a graph as list of edges with numeric weights. - - Parameters - ---------- - path : file or string - File or filename to read. If a file is provided, it must be - opened in 'rb' mode. - Filenames ending in .gz or .bz2 will be uncompressed. - comments : string, optional - The character used to indicate the start of a comment. - delimiter : string, optional - The string used to separate values. The default is whitespace. - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - nodetype : int, float, str, Python type, optional - Convert node data from strings to specified type - encoding: string, optional - Specify which encoding to use when reading file. - - Returns - ------- - G : graph - A networkx Graph or other type specified with create_using - - Notes - ----- - Since nodes must be hashable, the function nodetype must return hashable - types (e.g. int, float, str, frozenset - or tuples of those, etc.) - - Example edgelist file format. - - With numeric edge data:: - - # read with - # >>> G=nx.read_weighted_edgelist(fh) - # source target data - a b 1 - a c 3.14159 - d e 42 - - See Also - -------- - write_weighted_edgelist - """ - return read_edgelist(path, - comments=comments, - delimiter=delimiter, - create_using=create_using, - nodetype=nodetype, - data=(('weight', float),), - encoding=encoding - ) - - -# fixture for pytest -def teardown_module(module): - import os - for fname in ['test.edgelist', 'test.edgelist.gz', - 'test.weighted.edgelist']: - if os.path.isfile(fname): - os.unlink(fname) diff --git a/extensions/fablabchemnitz/networkx/readwrite/gexf.py b/extensions/fablabchemnitz/networkx/readwrite/gexf.py deleted file mode 100644 index b8b9dfa2..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/gexf.py +++ /dev/null @@ -1,1052 +0,0 @@ -# Copyright (C) 2013-2019 by -# -# Authors: Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# Based on GraphML NetworkX GraphML reader -"""Read and write graphs in GEXF format. - -GEXF (Graph Exchange XML Format) is a language for describing complex -network structures, their associated data and dynamics. - -This implementation does not support mixed graphs (directed and -undirected edges together). - -Format ------- -GEXF is an XML format. See https://gephi.org/gexf/format/schema.html for the -specification and https://gephi.org/gexf/format/basic.html for examples. -""" -import itertools -import time - -import networkx as nx -from networkx.utils import open_file, make_str -try: - from xml.etree.cElementTree import (Element, ElementTree, SubElement, - tostring) -except ImportError: - try: - from xml.etree.ElementTree import (Element, ElementTree, SubElement, - tostring) - except ImportError: - pass - -__all__ = ['write_gexf', 'read_gexf', 'relabel_gexf_graph', 'generate_gexf'] - - -@open_file(1, mode='wb') -def write_gexf(G, path, encoding='utf-8', prettyprint=True, - version='1.2draft'): - """Write G in GEXF format to path. - - "GEXF (Graph Exchange XML Format) is a language for describing - complex networks structures, their associated data and dynamics" [1]_. - - Node attributes are checked according to the version of the GEXF - schemas used for parameters which are not user defined, - e.g. visualization 'viz' [2]_. See example for usage. - - Parameters - ---------- - G : graph - A NetworkX graph - path : file or string - File or file name to write. - File names ending in .gz or .bz2 will be compressed. - encoding : string (optional, default: 'utf-8') - Encoding for text data. - prettyprint : bool (optional, default: True) - If True use line breaks and indenting in output XML. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_gexf(G, "test.gexf") - - # visualization data - >>> G.nodes[0]['viz'] = {'size': 54} - >>> G.nodes[0]['viz']['position'] = {'x' : 0, 'y' : 1} - >>> G.nodes[0]['viz']['color'] = {'r' : 0, 'g' : 0, 'b' : 256} - - - Notes - ----- - This implementation does not support mixed graphs (directed and undirected - edges together). - - The node id attribute is set to be the string of the node label. - If you want to specify an id use set it as node data, e.g. - node['a']['id']=1 to set the id of node 'a' to 1. - - References - ---------- - .. [1] GEXF File Format, https://gephi.org/gexf/format/ - .. [2] GEXF viz schema 1.1, https://gephi.org/gexf/1.1draft/viz - """ - writer = GEXFWriter(encoding=encoding, prettyprint=prettyprint, - version=version) - writer.add_graph(G) - writer.write(path) - - -def generate_gexf(G, encoding='utf-8', prettyprint=True, version='1.2draft'): - """Generate lines of GEXF format representation of G. - - "GEXF (Graph Exchange XML Format) is a language for describing - complex networks structures, their associated data and dynamics" [1]_. - - Parameters - ---------- - G : graph - A NetworkX graph - encoding : string (optional, default: 'utf-8') - Encoding for text data. - prettyprint : bool (optional, default: True) - If True use line breaks and indenting in output XML. - version : string (default: 1.2draft) - Version of GEFX File Format (see https://gephi.org/gexf/format/schema.html) - Supported values: "1.1draft", "1.2draft" - - - Examples - -------- - >>> G = nx.path_graph(4) - >>> linefeed = chr(10) # linefeed=\n - >>> s = linefeed.join(nx.generate_gexf(G)) # doctest: +SKIP - >>> for line in nx.generate_gexf(G): # doctest: +SKIP - ... print line - - Notes - ----- - This implementation does not support mixed graphs (directed and undirected - edges together). - - The node id attribute is set to be the string of the node label. - If you want to specify an id use set it as node data, e.g. - node['a']['id']=1 to set the id of node 'a' to 1. - - References - ---------- - .. [1] GEXF File Format, https://gephi.org/gexf/format/ - """ - writer = GEXFWriter(encoding=encoding, prettyprint=prettyprint, - version=version) - writer.add_graph(G) - for line in str(writer).splitlines(): - yield line - - -@open_file(0, mode='rb') -def read_gexf(path, node_type=None, relabel=False, version='1.2draft'): - """Read graph in GEXF format from path. - - "GEXF (Graph Exchange XML Format) is a language for describing - complex networks structures, their associated data and dynamics" [1]_. - - Parameters - ---------- - path : file or string - File or file name to write. - File names ending in .gz or .bz2 will be compressed. - node_type: Python type (default: None) - Convert node ids to this type if not None. - relabel : bool (default: False) - If True relabel the nodes to use the GEXF node "label" attribute - instead of the node "id" attribute as the NetworkX node label. - version : string (default: 1.2draft) - Version of GEFX File Format (see https://gephi.org/gexf/format/schema.html) - Supported values: "1.1draft", "1.2draft" - - Returns - ------- - graph: NetworkX graph - If no parallel edges are found a Graph or DiGraph is returned. - Otherwise a MultiGraph or MultiDiGraph is returned. - - Notes - ----- - This implementation does not support mixed graphs (directed and undirected - edges together). - - References - ---------- - .. [1] GEXF File Format, https://gephi.org/gexf/format/ - """ - reader = GEXFReader(node_type=node_type, version=version) - if relabel: - G = relabel_gexf_graph(reader(path)) - else: - G = reader(path) - return G - - -class GEXF(object): - versions = {} - d = {'NS_GEXF': "http://www.gexf.net/1.1draft", - 'NS_VIZ': "http://www.gexf.net/1.1draft/viz", - 'NS_XSI': "http://www.w3.org/2001/XMLSchema-instance", - 'SCHEMALOCATION': ' '.join(['http://www.gexf.net/1.1draft', - 'http://www.gexf.net/1.1draft/gexf.xsd']), - 'VERSION': '1.1'} - versions['1.1draft'] = d - d = {'NS_GEXF': "http://www.gexf.net/1.2draft", - 'NS_VIZ': "http://www.gexf.net/1.2draft/viz", - 'NS_XSI': "http://www.w3.org/2001/XMLSchema-instance", - 'SCHEMALOCATION': ' '.join(['http://www.gexf.net/1.2draft', - 'http://www.gexf.net/1.2draft/gexf.xsd']), - 'VERSION': '1.2'} - versions['1.2draft'] = d - - types = [(int, "integer"), - (float, "float"), - (float, "double"), - (bool, "boolean"), - (list, "string"), - (dict, "string"), - (int, "long"), - (str, "liststring"), - (str, "anyURI"), - (str, "string")] - - # These additions to types allow writing numpy types - try: - import numpy as np - except ImportError: - pass - else: - # prepend so that python types are created upon read (last entry wins) - types = [(np.float64, "float"), (np.float32, "float"), - (np.float16, "float"), (np.float_, "float"), - (np.int, "int"), (np.int8, "int"), - (np.int16, "int"), (np.int32, "int"), - (np.int64, "int"), (np.uint8, "int"), - (np.uint16, "int"), (np.uint32, "int"), - (np.uint64, "int"), (np.int_, "int"), - (np.intc, "int"), (np.intp, "int"), - ] + types - - xml_type = dict(types) - python_type = dict(reversed(a) for a in types) - - # http://www.w3.org/TR/xmlschema-2/#boolean - convert_bool = { - 'true': True, 'false': False, - 'True': True, 'False': False, - '0': False, 0: False, - '1': True, 1: True - } - - def set_version(self, version): - d = self.versions.get(version) - if d is None: - raise nx.NetworkXError('Unknown GEXF version %s.' % version) - self.NS_GEXF = d['NS_GEXF'] - self.NS_VIZ = d['NS_VIZ'] - self.NS_XSI = d['NS_XSI'] - self.SCHEMALOCATION = d['SCHEMALOCATION'] - self.VERSION = d['VERSION'] - self.version = version - - -class GEXFWriter(GEXF): - # class for writing GEXF format files - # use write_gexf() function - def __init__(self, graph=None, encoding='utf-8', prettyprint=True, - version='1.2draft'): - try: - import xml.etree.ElementTree as ET - except ImportError: - raise ImportError('GEXF writer requires ' - 'xml.elementtree.ElementTree') - self.prettyprint = prettyprint - self.encoding = encoding - self.set_version(version) - self.xml = Element('gexf', - {'xmlns': self.NS_GEXF, - 'xmlns:xsi': self.NS_XSI, - 'xsi:schemaLocation': self.SCHEMALOCATION, - 'version': self.VERSION}) - - # Make meta element a non-graph element - # Also add lastmodifieddate as attribute, not tag - meta_element = Element('meta') - subelement_text = 'NetworkX {}'.format(nx.__version__) - SubElement(meta_element, 'creator').text = subelement_text - meta_element.set('lastmodifieddate', time.strftime('%Y-%m-%d')) - self.xml.append(meta_element) - - ET.register_namespace('viz', self.NS_VIZ) - - # counters for edge and attribute identifiers - self.edge_id = itertools.count() - self.attr_id = itertools.count() - self.all_edge_ids = set() - # default attributes are stored in dictionaries - self.attr = {} - self.attr['node'] = {} - self.attr['edge'] = {} - self.attr['node']['dynamic'] = {} - self.attr['node']['static'] = {} - self.attr['edge']['dynamic'] = {} - self.attr['edge']['static'] = {} - - if graph is not None: - self.add_graph(graph) - - def __str__(self): - if self.prettyprint: - self.indent(self.xml) - s = tostring(self.xml).decode(self.encoding) - return s - - def add_graph(self, G): - # first pass through G collecting edge ids - for u, v, dd in G.edges(data=True): - eid = dd.get('id') - if eid is not None: - self.all_edge_ids.add(make_str(eid)) - # set graph attributes - if G.graph.get('mode') == 'dynamic': - mode = 'dynamic' - else: - mode = 'static' - # Add a graph element to the XML - if G.is_directed(): - default = 'directed' - else: - default = 'undirected' - name = G.graph.get('name', '') - graph_element = Element('graph', defaultedgetype=default, mode=mode, - name=name) - self.graph_element = graph_element - self.add_nodes(G, graph_element) - self.add_edges(G, graph_element) - self.xml.append(graph_element) - - def add_nodes(self, G, graph_element): - nodes_element = Element('nodes') - for node, data in G.nodes(data=True): - node_data = data.copy() - node_id = make_str(node_data.pop('id', node)) - kw = {'id': node_id} - label = make_str(node_data.pop('label', node)) - kw['label'] = label - try: - pid = node_data.pop('pid') - kw['pid'] = make_str(pid) - except KeyError: - pass - try: - start = node_data.pop('start') - kw['start'] = make_str(start) - self.alter_graph_mode_timeformat(start) - except KeyError: - pass - try: - end = node_data.pop('end') - kw['end'] = make_str(end) - self.alter_graph_mode_timeformat(end) - except KeyError: - pass - # add node element with attributes - node_element = Element('node', **kw) - # add node element and attr subelements - default = G.graph.get('node_default', {}) - node_data = self.add_parents(node_element, node_data) - if self.version == '1.1': - node_data = self.add_slices(node_element, node_data) - else: - node_data = self.add_spells(node_element, node_data) - node_data = self.add_viz(node_element, node_data) - node_data = self.add_attributes('node', node_element, - node_data, default) - nodes_element.append(node_element) - graph_element.append(nodes_element) - - def add_edges(self, G, graph_element): - def edge_key_data(G): - # helper function to unify multigraph and graph edge iterator - if G.is_multigraph(): - for u, v, key, data in G.edges(data=True, keys=True): - edge_data = data.copy() - edge_data.update(key=key) - edge_id = edge_data.pop('id', None) - if edge_id is None: - edge_id = next(self.edge_id) - while make_str(edge_id) in self.all_edge_ids: - edge_id = next(self.edge_id) - self.all_edge_ids.add(make_str(edge_id)) - yield u, v, edge_id, edge_data - else: - for u, v, data in G.edges(data=True): - edge_data = data.copy() - edge_id = edge_data.pop('id', None) - if edge_id is None: - edge_id = next(self.edge_id) - while make_str(edge_id) in self.all_edge_ids: - edge_id = next(self.edge_id) - self.all_edge_ids.add(make_str(edge_id)) - yield u, v, edge_id, edge_data - edges_element = Element('edges') - for u, v, key, edge_data in edge_key_data(G): - kw = {'id': make_str(key)} - try: - edge_weight = edge_data.pop('weight') - kw['weight'] = make_str(edge_weight) - except KeyError: - pass - try: - edge_type = edge_data.pop('type') - kw['type'] = make_str(edge_type) - except KeyError: - pass - try: - start = edge_data.pop('start') - kw['start'] = make_str(start) - self.alter_graph_mode_timeformat(start) - except KeyError: - pass - try: - end = edge_data.pop('end') - kw['end'] = make_str(end) - self.alter_graph_mode_timeformat(end) - except KeyError: - pass - source_id = make_str(G.nodes[u].get('id', u)) - target_id = make_str(G.nodes[v].get('id', v)) - edge_element = Element('edge', - source=source_id, target=target_id, **kw) - default = G.graph.get('edge_default', {}) - if self.version == '1.1': - edge_data = self.add_slices(edge_element, edge_data) - else: - edge_data = self.add_spells(edge_element, edge_data) - edge_data = self.add_viz(edge_element, edge_data) - edge_data = self.add_attributes('edge', edge_element, - edge_data, default) - edges_element.append(edge_element) - graph_element.append(edges_element) - - def add_attributes(self, node_or_edge, xml_obj, data, default): - # Add attrvalues to node or edge - attvalues = Element('attvalues') - if len(data) == 0: - return data - mode = 'static' - for k, v in data.items(): - # rename generic multigraph key to avoid any name conflict - if k == 'key': - k = 'networkx_key' - val_type = type(v) - if val_type not in self.xml_type: - raise TypeError('attribute value type is not allowed: %s' - % val_type) - if isinstance(v, list): - # dynamic data - for val, start, end in v: - val_type = type(val) - if start is not None or end is not None: - mode = 'dynamic' - self.alter_graph_mode_timeformat(start) - self.alter_graph_mode_timeformat(end) - break - attr_id = self.get_attr_id(make_str(k), - self.xml_type[val_type], - node_or_edge, default, mode) - for val, start, end in v: - e = Element('attvalue') - e.attrib['for'] = attr_id - e.attrib['value'] = make_str(val) - # Handle nan, inf, -inf differently - if val_type == float: - if e.attrib['value'] == 'inf': - e.attrib['value'] = 'INF' - elif e.attrib['value'] == 'nan': - e.attrib['value'] = 'NaN' - elif e.attrib['value'] == '-inf': - e.attrib['value'] = '-INF' - if start is not None: - e.attrib['start'] = make_str(start) - if end is not None: - e.attrib['end'] = make_str(end) - attvalues.append(e) - else: - # static data - mode = 'static' - attr_id = self.get_attr_id(make_str(k), - self.xml_type[val_type], - node_or_edge, default, mode) - e = Element('attvalue') - e.attrib['for'] = attr_id - if isinstance(v, bool): - e.attrib['value'] = make_str(v).lower() - else: - e.attrib['value'] = make_str(v) - # Handle float nan, inf, -inf differently - if val_type == float: - if e.attrib['value'] == 'inf': - e.attrib['value'] = 'INF' - elif e.attrib['value'] == 'nan': - e.attrib['value'] = 'NaN' - elif e.attrib['value'] == '-inf': - e.attrib['value'] = '-INF' - attvalues.append(e) - xml_obj.append(attvalues) - return data - - def get_attr_id(self, title, attr_type, edge_or_node, default, mode): - # find the id of the attribute or generate a new id - try: - return self.attr[edge_or_node][mode][title] - except KeyError: - # generate new id - new_id = str(next(self.attr_id)) - self.attr[edge_or_node][mode][title] = new_id - attr_kwargs = {'id': new_id, 'title': title, 'type': attr_type} - attribute = Element('attribute', **attr_kwargs) - # add subelement for data default value if present - default_title = default.get(title) - if default_title is not None: - default_element = Element('default') - default_element.text = make_str(default_title) - attribute.append(default_element) - # new insert it into the XML - attributes_element = None - for a in self.graph_element.findall('attributes'): - # find existing attributes element by class and mode - a_class = a.get('class') - a_mode = a.get('mode', 'static') - if a_class == edge_or_node and a_mode == mode: - attributes_element = a - if attributes_element is None: - # create new attributes element - attr_kwargs = {'mode': mode, 'class': edge_or_node} - attributes_element = Element('attributes', **attr_kwargs) - self.graph_element.insert(0, attributes_element) - attributes_element.append(attribute) - return new_id - - def add_viz(self, element, node_data): - viz = node_data.pop('viz', False) - if viz: - color = viz.get('color') - if color is not None: - if self.VERSION == '1.1': - e = Element('{%s}color' % self.NS_VIZ, - r=str(color.get('r')), - g=str(color.get('g')), - b=str(color.get('b'))) - else: - e = Element('{%s}color' % self.NS_VIZ, - r=str(color.get('r')), - g=str(color.get('g')), - b=str(color.get('b')), - a=str(color.get('a'))) - element.append(e) - - size = viz.get('size') - if size is not None: - e = Element('{%s}size' % self.NS_VIZ, value=str(size)) - element.append(e) - - thickness = viz.get('thickness') - if thickness is not None: - e = Element('{%s}thickness' % self.NS_VIZ, - value=str(thickness)) - element.append(e) - - shape = viz.get('shape') - if shape is not None: - if shape.startswith('http'): - e = Element('{%s}shape' % self.NS_VIZ, - value='image', uri=str(shape)) - else: - e = Element('{%s}shape' % self.NS_VIZ, value=str(shape)) - element.append(e) - - position = viz.get('position') - if position is not None: - e = Element('{%s}position' % self.NS_VIZ, - x=str(position.get('x')), - y=str(position.get('y')), - z=str(position.get('z'))) - element.append(e) - return node_data - - def add_parents(self, node_element, node_data): - parents = node_data.pop('parents', False) - if parents: - parents_element = Element('parents') - for p in parents: - e = Element('parent') - e.attrib['for'] = str(p) - parents_element.append(e) - node_element.append(parents_element) - return node_data - - def add_slices(self, node_or_edge_element, node_or_edge_data): - slices = node_or_edge_data.pop('slices', False) - if slices: - slices_element = Element('slices') - for start, end in slices: - e = Element('slice', start=str(start), end=str(end)) - slices_element.append(e) - node_or_edge_element.append(slices_element) - return node_or_edge_data - - def add_spells(self, node_or_edge_element, node_or_edge_data): - spells = node_or_edge_data.pop('spells', False) - if spells: - spells_element = Element('spells') - for start, end in spells: - e = Element('spell') - if start is not None: - e.attrib['start'] = make_str(start) - self.alter_graph_mode_timeformat(start) - if end is not None: - e.attrib['end'] = make_str(end) - self.alter_graph_mode_timeformat(end) - spells_element.append(e) - node_or_edge_element.append(spells_element) - return node_or_edge_data - - def alter_graph_mode_timeformat(self, start_or_end): - # If 'start' or 'end' appears, alter Graph mode to dynamic and - # set timeformat - if self.graph_element.get('mode') == 'static': - if start_or_end is not None: - if isinstance(start_or_end, str): - timeformat = 'date' - elif isinstance(start_or_end, float): - timeformat = 'double' - elif isinstance(start_or_end, int): - timeformat = 'long' - else: - raise nx.NetworkXError( - 'timeformat should be of the type int, float or str') - self.graph_element.set('timeformat', timeformat) - self.graph_element.set('mode', 'dynamic') - - def write(self, fh): - # Serialize graph G in GEXF to the open fh - if self.prettyprint: - self.indent(self.xml) - document = ElementTree(self.xml) - document.write(fh, encoding=self.encoding, xml_declaration=True) - - def indent(self, elem, level=0): - # in-place prettyprint formatter - i = "\n" + " " * level - if len(elem): - if not elem.text or not elem.text.strip(): - elem.text = i + " " - if not elem.tail or not elem.tail.strip(): - elem.tail = i - for elem in elem: - self.indent(elem, level + 1) - if not elem.tail or not elem.tail.strip(): - elem.tail = i - else: - if level and (not elem.tail or not elem.tail.strip()): - elem.tail = i - - -class GEXFReader(GEXF): - # Class to read GEXF format files - # use read_gexf() function - def __init__(self, node_type=None, version='1.2draft'): - try: - import xml.etree.ElementTree - except ImportError: - raise ImportError('GEXF reader requires ' - 'xml.elementtree.ElementTree.') - self.node_type = node_type - # assume simple graph and test for multigraph on read - self.simple_graph = True - self.set_version(version) - - def __call__(self, stream): - self.xml = ElementTree(file=stream) - g = self.xml.find('{%s}graph' % self.NS_GEXF) - if g is not None: - return self.make_graph(g) - # try all the versions - for version in self.versions: - self.set_version(version) - g = self.xml.find('{%s}graph' % self.NS_GEXF) - if g is not None: - return self.make_graph(g) - raise nx.NetworkXError('No element in GEXF file.') - - def make_graph(self, graph_xml): - # start with empty DiGraph or MultiDiGraph - edgedefault = graph_xml.get('defaultedgetype', None) - if edgedefault == 'directed': - G = nx.MultiDiGraph() - else: - G = nx.MultiGraph() - - # graph attributes - graph_name = graph_xml.get('name', '') - if graph_name != '': - G.graph['name'] = graph_name - graph_start = graph_xml.get('start') - if graph_start is not None: - G.graph['start'] = graph_start - graph_end = graph_xml.get('end') - if graph_end is not None: - G.graph['end'] = graph_end - graph_mode = graph_xml.get('mode', '') - if graph_mode == 'dynamic': - G.graph['mode'] = 'dynamic' - else: - G.graph['mode'] = 'static' - - # timeformat - self.timeformat = graph_xml.get('timeformat') - if self.timeformat == 'date': - self.timeformat = 'string' - - # node and edge attributes - attributes_elements = graph_xml.findall('{%s}attributes' % - self.NS_GEXF) - # dictionaries to hold attributes and attribute defaults - node_attr = {} - node_default = {} - edge_attr = {} - edge_default = {} - for a in attributes_elements: - attr_class = a.get('class') - if attr_class == 'node': - na, nd = self.find_gexf_attributes(a) - node_attr.update(na) - node_default.update(nd) - G.graph['node_default'] = node_default - elif attr_class == 'edge': - ea, ed = self.find_gexf_attributes(a) - edge_attr.update(ea) - edge_default.update(ed) - G.graph['edge_default'] = edge_default - else: - raise # unknown attribute class - - # Hack to handle Gephi0.7beta bug - # add weight attribute - ea = {'weight': {'type': 'double', 'mode': 'static', - 'title': 'weight'}} - ed = {} - edge_attr.update(ea) - edge_default.update(ed) - G.graph['edge_default'] = edge_default - - # add nodes - nodes_element = graph_xml.find('{%s}nodes' % self.NS_GEXF) - if nodes_element is not None: - for node_xml in nodes_element.findall('{%s}node' % self.NS_GEXF): - self.add_node(G, node_xml, node_attr) - - # add edges - edges_element = graph_xml.find('{%s}edges' % self.NS_GEXF) - if edges_element is not None: - for edge_xml in edges_element.findall('{%s}edge' % self.NS_GEXF): - self.add_edge(G, edge_xml, edge_attr) - - # switch to Graph or DiGraph if no parallel edges were found. - if self.simple_graph: - if G.is_directed(): - G = nx.DiGraph(G) - else: - G = nx.Graph(G) - return G - - def add_node(self, G, node_xml, node_attr, node_pid=None): - # add a single node with attributes to the graph - - # get attributes and subattributues for node - data = self.decode_attr_elements(node_attr, node_xml) - data = self.add_parents(data, node_xml) # add any parents - if self.version == '1.1': - data = self.add_slices(data, node_xml) # add slices - else: - data = self.add_spells(data, node_xml) # add spells - data = self.add_viz(data, node_xml) # add viz - data = self.add_start_end(data, node_xml) # add start/end - - # find the node id and cast it to the appropriate type - node_id = node_xml.get('id') - if self.node_type is not None: - node_id = self.node_type(node_id) - - # every node should have a label - node_label = node_xml.get('label') - data['label'] = node_label - - # parent node id - node_pid = node_xml.get('pid', node_pid) - if node_pid is not None: - data['pid'] = node_pid - - # check for subnodes, recursive - subnodes = node_xml.find('{%s}nodes' % self.NS_GEXF) - if subnodes is not None: - for node_xml in subnodes.findall('{%s}node' % self.NS_GEXF): - self.add_node(G, node_xml, node_attr, node_pid=node_id) - - G.add_node(node_id, **data) - - def add_start_end(self, data, xml): - # start and end times - ttype = self.timeformat - node_start = xml.get('start') - if node_start is not None: - data['start'] = self.python_type[ttype](node_start) - node_end = xml.get('end') - if node_end is not None: - data['end'] = self.python_type[ttype](node_end) - return data - - def add_viz(self, data, node_xml): - # add viz element for node - viz = {} - color = node_xml.find('{%s}color' % self.NS_VIZ) - if color is not None: - if self.VERSION == '1.1': - viz['color'] = {'r': int(color.get('r')), - 'g': int(color.get('g')), - 'b': int(color.get('b'))} - else: - viz['color'] = {'r': int(color.get('r')), - 'g': int(color.get('g')), - 'b': int(color.get('b')), - 'a': float(color.get('a', 1))} - - size = node_xml.find('{%s}size' % self.NS_VIZ) - if size is not None: - viz['size'] = float(size.get('value')) - - thickness = node_xml.find('{%s}thickness' % self.NS_VIZ) - if thickness is not None: - viz['thickness'] = float(thickness.get('value')) - - shape = node_xml.find('{%s}shape' % self.NS_VIZ) - if shape is not None: - viz['shape'] = shape.get('shape') - if viz['shape'] == 'image': - viz['shape'] = shape.get('uri') - - position = node_xml.find('{%s}position' % self.NS_VIZ) - if position is not None: - viz['position'] = {'x': float(position.get('x', 0)), - 'y': float(position.get('y', 0)), - 'z': float(position.get('z', 0))} - - if len(viz) > 0: - data['viz'] = viz - return data - - def add_parents(self, data, node_xml): - parents_element = node_xml.find('{%s}parents' % self.NS_GEXF) - if parents_element is not None: - data['parents'] = [] - for p in parents_element.findall('{%s}parent' % self.NS_GEXF): - parent = p.get('for') - data['parents'].append(parent) - return data - - def add_slices(self, data, node_or_edge_xml): - slices_element = node_or_edge_xml.find('{%s}slices' % self.NS_GEXF) - if slices_element is not None: - data['slices'] = [] - for s in slices_element.findall('{%s}slice' % self.NS_GEXF): - start = s.get('start') - end = s.get('end') - data['slices'].append((start, end)) - return data - - def add_spells(self, data, node_or_edge_xml): - spells_element = node_or_edge_xml.find('{%s}spells' % self.NS_GEXF) - if spells_element is not None: - data['spells'] = [] - ttype = self.timeformat - for s in spells_element.findall('{%s}spell' % self.NS_GEXF): - start = self.python_type[ttype](s.get('start')) - end = self.python_type[ttype](s.get('end')) - data['spells'].append((start, end)) - return data - - def add_edge(self, G, edge_element, edge_attr): - # add an edge to the graph - - # raise error if we find mixed directed and undirected edges - edge_direction = edge_element.get('type') - if G.is_directed() and edge_direction == 'undirected': - raise nx.NetworkXError( - 'Undirected edge found in directed graph.') - if (not G.is_directed()) and edge_direction == 'directed': - raise nx.NetworkXError( - 'Directed edge found in undirected graph.') - - # Get source and target and recast type if required - source = edge_element.get('source') - target = edge_element.get('target') - if self.node_type is not None: - source = self.node_type(source) - target = self.node_type(target) - - data = self.decode_attr_elements(edge_attr, edge_element) - data = self.add_start_end(data, edge_element) - - if self.version == '1.1': - data = self.add_slices(data, edge_element) # add slices - else: - data = self.add_spells(data, edge_element) # add spells - - # GEXF stores edge ids as an attribute - # NetworkX uses them as keys in multigraphs - # if networkx_key is not specified as an attribute - edge_id = edge_element.get('id') - if edge_id is not None: - data['id'] = edge_id - - # check if there is a 'multigraph_key' and use that as edge_id - multigraph_key = data.pop('networkx_key', None) - if multigraph_key is not None: - edge_id = multigraph_key - - weight = edge_element.get('weight') - if weight is not None: - data['weight'] = float(weight) - - edge_label = edge_element.get('label') - if edge_label is not None: - data['label'] = edge_label - - if G.has_edge(source, target): - # seen this edge before - this is a multigraph - self.simple_graph = False - G.add_edge(source, target, key=edge_id, **data) - if edge_direction == 'mutual': - G.add_edge(target, source, key=edge_id, **data) - - def decode_attr_elements(self, gexf_keys, obj_xml): - # Use the key information to decode the attr XML - attr = {} - # look for outer '' element - attr_element = obj_xml.find('{%s}attvalues' % self.NS_GEXF) - if attr_element is not None: - # loop over elements - for a in attr_element.findall('{%s}attvalue' % self.NS_GEXF): - key = a.get('for') # for is required - try: # should be in our gexf_keys dictionary - title = gexf_keys[key]['title'] - except KeyError: - raise nx.NetworkXError('No attribute defined for=%s.' - % key) - atype = gexf_keys[key]['type'] - value = a.get('value') - if atype == 'boolean': - value = self.convert_bool[value] - else: - value = self.python_type[atype](value) - if gexf_keys[key]['mode'] == 'dynamic': - # for dynamic graphs use list of three-tuples - # [(value1,start1,end1), (value2,start2,end2), etc] - ttype = self.timeformat - start = self.python_type[ttype](a.get('start')) - end = self.python_type[ttype](a.get('end')) - if title in attr: - attr[title].append((value, start, end)) - else: - attr[title] = [(value, start, end)] - else: - # for static graphs just assign the value - attr[title] = value - return attr - - def find_gexf_attributes(self, attributes_element): - # Extract all the attributes and defaults - attrs = {} - defaults = {} - mode = attributes_element.get('mode') - for k in attributes_element.findall('{%s}attribute' % self.NS_GEXF): - attr_id = k.get('id') - title = k.get('title') - atype = k.get('type') - attrs[attr_id] = {'title': title, 'type': atype, 'mode': mode} - # check for the 'default' subelement of key element and add - default = k.find('{%s}default' % self.NS_GEXF) - if default is not None: - if atype == 'boolean': - value = self.convert_bool[default.text] - else: - value = self.python_type[atype](default.text) - defaults[title] = value - return attrs, defaults - - -def relabel_gexf_graph(G): - """Relabel graph using "label" node keyword for node label. - - Parameters - ---------- - G : graph - A NetworkX graph read from GEXF data - - Returns - ------- - H : graph - A NetworkX graph with relabed nodes - - Raises - ------ - NetworkXError - If node labels are missing or not unique while relabel=True. - - Notes - ----- - This function relabels the nodes in a NetworkX graph with the - "label" attribute. It also handles relabeling the specific GEXF - node attributes "parents", and "pid". - """ - # build mapping of node labels, do some error checking - try: - mapping = [(u, G.nodes[u]['label']) for u in G] - except KeyError: - raise nx.NetworkXError('Failed to relabel nodes: ' - 'missing node labels found. ' - 'Use relabel=False.') - x, y = zip(*mapping) - if len(set(y)) != len(G): - raise nx.NetworkXError('Failed to relabel nodes: ' - 'duplicate node labels found. ' - 'Use relabel=False.') - mapping = dict(mapping) - H = nx.relabel_nodes(G, mapping) - # relabel attributes - for n in G: - m = mapping[n] - H.nodes[m]['id'] = n - H.nodes[m].pop('label') - if 'pid' in H.nodes[m]: - H.nodes[m]['pid'] = mapping[G.nodes[n]['pid']] - if 'parents' in H.nodes[m]: - H.nodes[m]['parents'] = [mapping[p] for p in G.nodes[n]['parents']] - return H - - -# fixture for pytest -def setup_module(module): - import pytest - xml.etree.cElementTree = pytest.importorskip('xml.etree.cElementTree') - - -# fixture for pytest -def teardown_module(module): - import os - try: - os.unlink('test.gexf') - except Exception as e: - pass diff --git a/extensions/fablabchemnitz/networkx/readwrite/gml.py b/extensions/fablabchemnitz/networkx/readwrite/gml.py deleted file mode 100644 index 8d4e50e8..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/gml.py +++ /dev/null @@ -1,842 +0,0 @@ -# encoding: utf-8 -# Copyright (C) 2008-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Author: Aric Hagberg (hagberg@lanl.gov) -""" -Read graphs in GML format. - -"GML, the Graph Modelling Language, is our proposal for a portable -file format for graphs. GML's key features are portability, simple -syntax, extensibility and flexibility. A GML file consists of a -hierarchical key-value lists. Graphs can be annotated with arbitrary -data structures. The idea for a common file format was born at the -GD'95; this proposal is the outcome of many discussions. GML is the -standard file format in the Graphlet graph editor system. It has been -overtaken and adapted by several other systems for drawing graphs." - -GML files are stored using a 7-bit ASCII encoding with any extended -ASCII characters (iso8859-1) appearing as HTML character entities. -You will need to give some thought into how the exported data should -interact with different languages and even different Python versions. -Re-importing from gml is also a concern. - -Without specifying a `stringizer`/`destringizer`, the code is capable of -handling `int`/`float`/`str`/`dict`/`list` data as required by the GML -specification. For other data types, you need to explicitly supply a -`stringizer`/`destringizer`. - -For better interoperability of data generated by Python 2 and Python 3, -we've provided `literal_stringizer` and `literal_destringizer`. - -For additional documentation on the GML file format, please see the -`GML website `_. - -Several example graphs in GML format may be found on Mark Newman's -`Network data page `_. -""" -try: - try: - from cStringIO import StringIO - except ImportError: - from StringIO import StringIO -except ImportError: - from io import StringIO -from ast import literal_eval -from collections import defaultdict -import networkx as nx -from networkx.exception import NetworkXError -from networkx.utils import open_file - -import re -try: - import htmlentitydefs -except ImportError: - # Python 3.x - import html.entities as htmlentitydefs - -__all__ = ['read_gml', 'parse_gml', 'generate_gml', 'write_gml'] - - -try: - long -except NameError: - long = int -try: - unicode -except NameError: - unicode = str -try: - unichr -except NameError: - unichr = chr -try: - literal_eval(r"u'\u4444'") -except SyntaxError: - # Remove 'u' prefixes in unicode literals in Python 3 - def rtp_fix_unicode(s): return s[1:] -else: - rtp_fix_unicode = None - - -def escape(text): - """Use XML character references to escape characters. - - Use XML character references for unprintable or non-ASCII - characters, double quotes and ampersands in a string - """ - def fixup(m): - ch = m.group(0) - return '&#' + str(ord(ch)) + ';' - - text = re.sub('[^ -~]|[&"]', fixup, text) - return text if isinstance(text, str) else str(text) - - -def unescape(text): - """Replace XML character references with the referenced characters""" - def fixup(m): - text = m.group(0) - if text[1] == '#': - # Character reference - if text[2] == 'x': - code = int(text[3:-1], 16) - else: - code = int(text[2:-1]) - else: - # Named entity - try: - code = htmlentitydefs.name2codepoint[text[1:-1]] - except KeyError: - return text # leave unchanged - try: - return chr(code) if code < 256 else unichr(code) - except (ValueError, OverflowError): - return text # leave unchanged - - return re.sub("&(?:[0-9A-Za-z]+|#(?:[0-9]+|x[0-9A-Fa-f]+));", fixup, text) - - -def literal_destringizer(rep): - """Convert a Python literal to the value it represents. - - Parameters - ---------- - rep : string - A Python literal. - - Returns - ------- - value : object - The value of the Python literal. - - Raises - ------ - ValueError - If `rep` is not a Python literal. - """ - if isinstance(rep, (str, unicode)): - orig_rep = rep - if rtp_fix_unicode is not None: - rep = rtp_fix_unicode(rep) - try: - return literal_eval(rep) - except SyntaxError: - raise ValueError('%r is not a valid Python literal' % (orig_rep,)) - else: - raise ValueError('%r is not a string' % (rep,)) - - -@open_file(0, mode='rb') -def read_gml(path, label='label', destringizer=None): - """Read graph in GML format from `path`. - - Parameters - ---------- - path : filename or filehandle - The filename or filehandle to read from. - - label : string, optional - If not None, the parsed nodes will be renamed according to node - attributes indicated by `label`. Default value: 'label'. - - destringizer : callable, optional - A `destringizer` that recovers values stored as strings in GML. If it - cannot convert a string to a value, a `ValueError` is raised. Default - value : None. - - Returns - ------- - G : NetworkX graph - The parsed graph. - - Raises - ------ - NetworkXError - If the input cannot be parsed. - - See Also - -------- - write_gml, parse_gml, literal_destringizer - - Notes - ----- - GML files are stored using a 7-bit ASCII encoding with any extended - ASCII characters (iso8859-1) appearing as HTML character entities. - Without specifying a `stringizer`/`destringizer`, the code is capable of - handling `int`/`float`/`str`/`dict`/`list` data as required by the GML - specification. For other data types, you need to explicitly supply a - `stringizer`/`destringizer`. - - For additional documentation on the GML file format, please see the - `GML url `_. - - See the module docstring :mod:`networkx.readwrite.gml` for more details. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_gml(G, 'test.gml') - >>> H = nx.read_gml('test.gml') - """ - def filter_lines(lines): - for line in lines: - try: - line = line.decode('ascii') - except UnicodeDecodeError: - raise NetworkXError('input is not ASCII-encoded') - if not isinstance(line, str): - lines = str(lines) - if line and line[-1] == '\n': - line = line[:-1] - yield line - - G = parse_gml_lines(filter_lines(path), label, destringizer) - return G - - -def parse_gml(lines, label='label', destringizer=None): - """Parse GML graph from a string or iterable. - - Parameters - ---------- - lines : string or iterable of strings - Data in GML format. - - label : string, optional - If not None, the parsed nodes will be renamed according to node - attributes indicated by `label`. Default value: 'label'. - - destringizer : callable, optional - A `destringizer` that recovers values stored as strings in GML. If it - cannot convert a string to a value, a `ValueError` is raised. Default - value : None. - - Returns - ------- - G : NetworkX graph - The parsed graph. - - Raises - ------ - NetworkXError - If the input cannot be parsed. - - See Also - -------- - write_gml, read_gml, literal_destringizer - - Notes - ----- - This stores nested GML attributes as dictionaries in the NetworkX graph, - node, and edge attribute structures. - - GML files are stored using a 7-bit ASCII encoding with any extended - ASCII characters (iso8859-1) appearing as HTML character entities. - Without specifying a `stringizer`/`destringizer`, the code is capable of - handling `int`/`float`/`str`/`dict`/`list` data as required by the GML - specification. For other data types, you need to explicitly supply a - `stringizer`/`destringizer`. - - For additional documentation on the GML file format, please see the - `GML url `_. - - See the module docstring :mod:`networkx.readwrite.gml` for more details. - """ - def decode_line(line): - if isinstance(line, bytes): - try: - line.decode('ascii') - except UnicodeDecodeError: - raise NetworkXError('input is not ASCII-encoded') - if not isinstance(line, str): - line = str(line) - return line - - def filter_lines(lines): - if isinstance(lines, (str, unicode)): - lines = decode_line(lines) - lines = lines.splitlines() - for line in lines: - yield line - else: - for line in lines: - line = decode_line(line) - if line and line[-1] == '\n': - line = line[:-1] - if line.find('\n') != -1: - raise NetworkXError('input line contains newline') - yield line - - G = parse_gml_lines(filter_lines(lines), label, destringizer) - return G - - -def parse_gml_lines(lines, label, destringizer): - """Parse GML `lines` into a graph. - """ - def tokenize(): - patterns = [ - r'[A-Za-z][0-9A-Za-z_]*\b', # keys - # reals - r'[+-]?(?:[0-9]*\.[0-9]+|[0-9]+\.[0-9]*)(?:[Ee][+-]?[0-9]+)?', - r'[+-]?[0-9]+', # ints - r'".*?"', # strings - r'\[', # dict start - r'\]', # dict end - r'#.*$|\s+' # comments and whitespaces - ] - tokens = re.compile( - '|'.join('(' + pattern + ')' for pattern in patterns)) - lineno = 0 - for line in lines: - length = len(line) - pos = 0 - while pos < length: - match = tokens.match(line, pos) - if match is not None: - for i in range(len(patterns)): - group = match.group(i + 1) - if group is not None: - if i == 0: # keys - value = group.rstrip() - elif i == 1: # reals - value = float(group) - elif i == 2: # ints - value = int(group) - else: - value = group - if i != 6: # comments and whitespaces - yield (i, value, lineno + 1, pos + 1) - pos += len(group) - break - else: - raise NetworkXError('cannot tokenize %r at (%d, %d)' % - (line[pos:], lineno + 1, pos + 1)) - lineno += 1 - yield (None, None, lineno + 1, 1) # EOF - - def unexpected(curr_token, expected): - category, value, lineno, pos = curr_token - raise NetworkXError( - 'expected %s, found %s at (%d, %d)' % - (expected, repr(value) if value is not None else 'EOF', lineno, - pos)) - - def consume(curr_token, category, expected): - if curr_token[0] == category: - return next(tokens) - unexpected(curr_token, expected) - - def parse_kv(curr_token): - dct = defaultdict(list) - while curr_token[0] == 0: # keys - key = curr_token[1] - curr_token = next(tokens) - category = curr_token[0] - if category == 1 or category == 2: # reals or ints - value = curr_token[1] - curr_token = next(tokens) - elif category == 3: # strings - value = unescape(curr_token[1][1:-1]) - if destringizer: - try: - value = destringizer(value) - except ValueError: - pass - curr_token = next(tokens) - elif category == 4: # dict start - curr_token, value = parse_dict(curr_token) - else: - # Allow for string convertible id and label values - if key in ("id", "label", "source", "target"): - try: - # String convert the token value - value = unescape(str(curr_token[1])) - if destringizer: - try: - value = destringizer(value) - except ValueError: - pass - curr_token = next(tokens) - except Exception: - msg = "an int, float, string, '[' or string" + \ - " convertable ASCII value for node id or label" - unexpected(curr_token, msg) - else: # Otherwise error out - unexpected(curr_token, "an int, float, string or '['") - dct[key].append(value) - dct = {key: (value if not isinstance(value, list) or len(value) != 1 - else value[0]) for key, value in dct.items()} - return curr_token, dct - - def parse_dict(curr_token): - curr_token = consume(curr_token, 4, "'['") # dict start - curr_token, dct = parse_kv(curr_token) - curr_token = consume(curr_token, 5, "']'") # dict end - return curr_token, dct - - def parse_graph(): - curr_token, dct = parse_kv(next(tokens)) - if curr_token[0] is not None: # EOF - unexpected(curr_token, 'EOF') - if 'graph' not in dct: - raise NetworkXError('input contains no graph') - graph = dct['graph'] - if isinstance(graph, list): - raise NetworkXError('input contains more than one graph') - return graph - - tokens = tokenize() - graph = parse_graph() - - directed = graph.pop('directed', False) - multigraph = graph.pop('multigraph', False) - if not multigraph: - G = nx.DiGraph() if directed else nx.Graph() - else: - G = nx.MultiDiGraph() if directed else nx.MultiGraph() - G.graph.update((key, value) for key, value in graph.items() - if key != 'node' and key != 'edge') - - def pop_attr(dct, category, attr, i): - try: - return dct.pop(attr) - except KeyError: - raise NetworkXError( - "%s #%d has no '%s' attribute" % (category, i, attr)) - - nodes = graph.get('node', []) - mapping = {} - node_labels = set() - for i, node in enumerate(nodes if isinstance(nodes, list) else [nodes]): - id = pop_attr(node, 'node', 'id', i) - if id in G: - raise NetworkXError('node id %r is duplicated' % (id,)) - if label is not None and label != 'id': - node_label = pop_attr(node, 'node', label, i) - if node_label in node_labels: - raise NetworkXError('node label %r is duplicated' % - (node_label,)) - node_labels.add(node_label) - mapping[id] = node_label - G.add_node(id, **node) - - edges = graph.get('edge', []) - for i, edge in enumerate(edges if isinstance(edges, list) else [edges]): - source = pop_attr(edge, 'edge', 'source', i) - target = pop_attr(edge, 'edge', 'target', i) - if source not in G: - raise NetworkXError( - 'edge #%d has an undefined source %r' % (i, source)) - if target not in G: - raise NetworkXError( - 'edge #%d has an undefined target %r' % (i, target)) - if not multigraph: - if not G.has_edge(source, target): - G.add_edge(source, target, **edge) - else: - msg = "edge #%d (%r%s%r) is duplicated.\n" - msg2 = 'Hint: If multigraph add "multigraph 1" to file header.' - info = (i, source, '->' if directed else '--', target) - raise nx.NetworkXError((msg % info) + msg2) - else: - key = edge.pop('key', None) - if key is not None and G.has_edge(source, target, key): - raise nx.NetworkXError( - 'edge #%d (%r%s%r, %r) is duplicated' % - (i, source, '->' if directed else '--', target, key)) - G.add_edge(source, target, key, **edge) - - if label is not None and label != 'id': - G = nx.relabel_nodes(G, mapping) - return G - - -def literal_stringizer(value): - """Convert a `value` to a Python literal in GML representation. - - Parameters - ---------- - value : object - The `value` to be converted to GML representation. - - Returns - ------- - rep : string - A double-quoted Python literal representing value. Unprintable - characters are replaced by XML character references. - - Raises - ------ - ValueError - If `value` cannot be converted to GML. - - Notes - ----- - `literal_stringizer` is largely the same as `repr` in terms of - functionality but attempts prefix `unicode` and `bytes` literals with - `u` and `b` to provide better interoperability of data generated by - Python 2 and Python 3. - - The original value can be recovered using the - :func:`networkx.readwrite.gml.literal_destringizer` function. - """ - def stringize(value): - if isinstance(value, (int, long, bool)) or value is None: - if value is True: # GML uses 1/0 for boolean values. - buf.write(str(1)) - elif value is False: - buf.write(str(0)) - else: - buf.write(str(value)) - elif isinstance(value, unicode): - text = repr(value) - if text[0] != 'u': - try: - value.encode('latin1') - except UnicodeEncodeError: - text = 'u' + text - buf.write(text) - elif isinstance(value, (float, complex, str, bytes)): - buf.write(repr(value)) - elif isinstance(value, list): - buf.write('[') - first = True - for item in value: - if not first: - buf.write(',') - else: - first = False - stringize(item) - buf.write(']') - elif isinstance(value, tuple): - if len(value) > 1: - buf.write('(') - first = True - for item in value: - if not first: - buf.write(',') - else: - first = False - stringize(item) - buf.write(')') - elif value: - buf.write('(') - stringize(value[0]) - buf.write(',)') - else: - buf.write('()') - elif isinstance(value, dict): - buf.write('{') - first = True - for key, value in value.items(): - if not first: - buf.write(',') - else: - first = False - stringize(key) - buf.write(':') - stringize(value) - buf.write('}') - elif isinstance(value, set): - buf.write('{') - first = True - for item in value: - if not first: - buf.write(',') - else: - first = False - stringize(item) - buf.write('}') - else: - raise ValueError( - '%r cannot be converted into a Python literal' % (value,)) - - buf = StringIO() - stringize(value) - return buf.getvalue() - - -def generate_gml(G, stringizer=None): - r"""Generate a single entry of the graph `G` in GML format. - - Parameters - ---------- - G : NetworkX graph - The graph to be converted to GML. - - stringizer : callable, optional - A `stringizer` which converts non-int/non-float/non-dict values into - strings. If it cannot convert a value into a string, it should raise a - `ValueError` to indicate that. Default value: None. - - Returns - ------- - lines: generator of strings - Lines of GML data. Newlines are not appended. - - Raises - ------ - NetworkXError - If `stringizer` cannot convert a value into a string, or the value to - convert is not a string while `stringizer` is None. - - See Also - -------- - literal_stringizer - - Notes - ----- - Graph attributes named 'directed', 'multigraph', 'node' or - 'edge', node attributes named 'id' or 'label', edge attributes - named 'source' or 'target' (or 'key' if `G` is a multigraph) - are ignored because these attribute names are used to encode the graph - structure. - - GML files are stored using a 7-bit ASCII encoding with any extended - ASCII characters (iso8859-1) appearing as HTML character entities. - Without specifying a `stringizer`/`destringizer`, the code is capable of - handling `int`/`float`/`str`/`dict`/`list` data as required by the GML - specification. For other data types, you need to explicitly supply a - `stringizer`/`destringizer`. - - For additional documentation on the GML file format, please see the - `GML url `_. - - See the module docstring :mod:`networkx.readwrite.gml` for more details. - - Examples - -------- - >>> G = nx.Graph() - >>> G.add_node("1") - >>> print("\n".join(nx.generate_gml(G))) - graph [ - node [ - id 0 - label "1" - ] - ] - >>> G = nx.OrderedMultiGraph([("a", "b"), ("a", "b")]) - >>> print("\n".join(nx.generate_gml(G))) - graph [ - multigraph 1 - node [ - id 0 - label "a" - ] - node [ - id 1 - label "b" - ] - edge [ - source 0 - target 1 - key 0 - ] - edge [ - source 0 - target 1 - key 1 - ] - ] - """ - valid_keys = re.compile('^[A-Za-z][0-9A-Za-z]*$') - - def stringize(key, value, ignored_keys, indent, in_list=False): - if not isinstance(key, (str, unicode)): - raise NetworkXError('%r is not a string' % (key,)) - if not valid_keys.match(key): - raise NetworkXError('%r is not a valid key' % (key,)) - if not isinstance(key, str): - key = str(key) - if key not in ignored_keys: - if isinstance(value, (int, long, bool)): - if key == 'label': - yield indent + key + ' "' + str(value) + '"' - elif value is True: - # python bool is an instance of int - yield indent + key + ' 1' - elif value is False: - yield indent + key + ' 0' - # GML only supports signed 32-bit integers - elif value < -2**31 or value >= 2**31: - yield indent + key + ' "' + str(value) + '"' - else: - yield indent + key + ' ' + str(value) - elif isinstance(value, float): - text = repr(value).upper() - # GML requires that a real literal contain a decimal point, but - # repr may not output a decimal point when the mantissa is - # integral and hence needs fixing. - epos = text.rfind('E') - if epos != -1 and text.find('.', 0, epos) == -1: - text = text[:epos] + '.' + text[epos:] - if key == 'label': - yield indent + key + ' "' + text + '"' - else: - yield indent + key + ' ' + text - elif isinstance(value, dict): - yield indent + key + ' [' - next_indent = indent + ' ' - for key, value in value.items(): - for line in stringize(key, value, (), next_indent): - yield line - yield indent + ']' - elif isinstance(value, (list, tuple)) and key != 'label' \ - and value and not in_list: - next_indent = indent + ' ' - for val in value: - for line in stringize(key, val, (), next_indent, True): - yield line - else: - if stringizer: - try: - value = stringizer(value) - except ValueError: - raise NetworkXError( - '%r cannot be converted into a string' % (value,)) - if not isinstance(value, (str, unicode)): - raise NetworkXError('%r is not a string' % (value,)) - yield indent + key + ' "' + escape(value) + '"' - - multigraph = G.is_multigraph() - yield 'graph [' - - # Output graph attributes - if G.is_directed(): - yield ' directed 1' - if multigraph: - yield ' multigraph 1' - ignored_keys = {'directed', 'multigraph', 'node', 'edge'} - for attr, value in G.graph.items(): - for line in stringize(attr, value, ignored_keys, ' '): - yield line - - # Output node data - node_id = dict(zip(G, range(len(G)))) - ignored_keys = {'id', 'label'} - for node, attrs in G.nodes.items(): - yield ' node [' - yield ' id ' + str(node_id[node]) - for line in stringize('label', node, (), ' '): - yield line - for attr, value in attrs.items(): - for line in stringize(attr, value, ignored_keys, ' '): - yield line - yield ' ]' - - # Output edge data - ignored_keys = {'source', 'target'} - kwargs = {'data': True} - if multigraph: - ignored_keys.add('key') - kwargs['keys'] = True - for e in G.edges(**kwargs): - yield ' edge [' - yield ' source ' + str(node_id[e[0]]) - yield ' target ' + str(node_id[e[1]]) - if multigraph: - for line in stringize('key', e[2], (), ' '): - yield line - for attr, value in e[-1].items(): - for line in stringize(attr, value, ignored_keys, ' '): - yield line - yield ' ]' - yield ']' - - -@open_file(1, mode='wb') -def write_gml(G, path, stringizer=None): - """Write a graph `G` in GML format to the file or file handle `path`. - - Parameters - ---------- - G : NetworkX graph - The graph to be converted to GML. - - path : filename or filehandle - The filename or filehandle to write. Files whose names end with .gz or - .bz2 will be compressed. - - stringizer : callable, optional - A `stringizer` which converts non-int/non-float/non-dict values into - strings. If it cannot convert a value into a string, it should raise a - `ValueError` to indicate that. Default value: None. - - Raises - ------ - NetworkXError - If `stringizer` cannot convert a value into a string, or the value to - convert is not a string while `stringizer` is None. - - See Also - -------- - read_gml, generate_gml, literal_stringizer - - Notes - ----- - Graph attributes named 'directed', 'multigraph', 'node' or - 'edge', node attributes named 'id' or 'label', edge attributes - named 'source' or 'target' (or 'key' if `G` is a multigraph) - are ignored because these attribute names are used to encode the graph - structure. - - GML files are stored using a 7-bit ASCII encoding with any extended - ASCII characters (iso8859-1) appearing as HTML character entities. - Without specifying a `stringizer`/`destringizer`, the code is capable of - handling `int`/`float`/`str`/`dict`/`list` data as required by the GML - specification. For other data types, you need to explicitly supply a - `stringizer`/`destringizer`. - - Note that while we allow non-standard GML to be read from a file, we make - sure to write GML format. In particular, underscores are not allowed in - attribute names. - For additional documentation on the GML file format, please see the - `GML url `_. - - See the module docstring :mod:`networkx.readwrite.gml` for more details. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_gml(G, "test.gml") - - Filenames ending in .gz or .bz2 will be compressed. - - >>> nx.write_gml(G, "test.gml.gz") - """ - for line in generate_gml(G, stringizer): - path.write((line + '\n').encode('ascii')) - - -# fixture for pytest -def teardown_module(module): - import os - for fname in ['test.gml', 'test.gml.gz']: - if os.path.isfile(fname): - os.unlink(fname) diff --git a/extensions/fablabchemnitz/networkx/readwrite/gpickle.py b/extensions/fablabchemnitz/networkx/readwrite/gpickle.py deleted file mode 100644 index f7519ca5..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/gpickle.py +++ /dev/null @@ -1,107 +0,0 @@ -""" -************** -Pickled Graphs -************** -Read and write NetworkX graphs as Python pickles. - -"The pickle module implements a fundamental, but powerful algorithm -for serializing and de-serializing a Python object -structure. "Pickling" is the process whereby a Python object hierarchy -is converted into a byte stream, and "unpickling" is the inverse -operation, whereby a byte stream is converted back into an object -hierarchy." - -Note that NetworkX graphs can contain any hashable Python object as -node (not just integers and strings). For arbitrary data types it may -be difficult to represent the data as text. In that case using Python -pickles to store the graph data can be used. - -Format ------- -See https://docs.python.org/2/library/pickle.html -""" -__author__ = """Aric Hagberg (hagberg@lanl.gov)\nDan Schult (dschult@colgate.edu)""" -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. - -__all__ = ['read_gpickle', 'write_gpickle'] - -import networkx as nx -from networkx.utils import open_file - -try: - import cPickle as pickle -except ImportError: - import pickle - - -@open_file(1, mode='wb') -def write_gpickle(G, path, protocol=pickle.HIGHEST_PROTOCOL): - """Write graph in Python pickle format. - - Pickles are a serialized byte stream of a Python object [1]_. - This format will preserve Python objects used as nodes or edges. - - Parameters - ---------- - G : graph - A NetworkX graph - - path : file or string - File or filename to write. - Filenames ending in .gz or .bz2 will be compressed. - - protocol : integer - Pickling protocol to use. Default value: ``pickle.HIGHEST_PROTOCOL``. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_gpickle(G, "test.gpickle") - - References - ---------- - .. [1] https://docs.python.org/2/library/pickle.html - """ - pickle.dump(G, path, protocol) - - -@open_file(0, mode='rb') -def read_gpickle(path): - """Read graph object in Python pickle format. - - Pickles are a serialized byte stream of a Python object [1]_. - This format will preserve Python objects used as nodes or edges. - - Parameters - ---------- - path : file or string - File or filename to write. - Filenames ending in .gz or .bz2 will be uncompressed. - - Returns - ------- - G : graph - A NetworkX graph - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_gpickle(G, "test.gpickle") - >>> G = nx.read_gpickle("test.gpickle") - - References - ---------- - .. [1] https://docs.python.org/2/library/pickle.html - """ - return pickle.load(path) - - -# fixture for pytest -def teardown_module(module): - import os - os.unlink('test.gpickle') diff --git a/extensions/fablabchemnitz/networkx/readwrite/graph6.py b/extensions/fablabchemnitz/networkx/readwrite/graph6.py deleted file mode 100644 index 82e5ca1d..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/graph6.py +++ /dev/null @@ -1,410 +0,0 @@ -# Original author: D. Eppstein, UC Irvine, August 12, 2003. -# The original code at http://www.ics.uci.edu/~eppstein/PADS/ is public domain. -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# Tomas Gavenciak -# All rights reserved. -# BSD license. -# -# Authors: Tomas Gavenciak -# Aric Hagberg -"""Functions for reading and writing graphs in the *graph6* format. - -The *graph6* file format is suitable for small graphs or large dense -graphs. For large sparse graphs, use the *sparse6* format. - -For more information, see the `graph6`_ homepage. - -.. _graph6: http://users.cecs.anu.edu.au/~bdm/data/formats.html - -""" -from itertools import islice -import sys - -import networkx as nx -from networkx.exception import NetworkXError -from networkx.utils import open_file, not_implemented_for - -__all__ = ['from_graph6_bytes', 'read_graph6', 'to_graph6_bytes', - 'write_graph6'] - - -def _generate_graph6_bytes(G, nodes, header): - """Yield bytes in the graph6 encoding of a graph. - - `G` is an undirected simple graph. `nodes` is the list of nodes for - which the node-induced subgraph will be encoded; if `nodes` is the - list of all nodes in the graph, the entire graph will be - encoded. `header` is a Boolean that specifies whether to generate - the header ``b'>>graph6<<'`` before the remaining data. - - This function generates `bytes` objects in the following order: - - 1. the header (if requested), - 2. the encoding of the number of nodes, - 3. each character, one-at-a-time, in the encoding of the requested - node-induced subgraph, - 4. a newline character. - - This function raises :exc:`ValueError` if the graph is too large for - the graph6 format (that is, greater than ``2 ** 36`` nodes). - - """ - n = len(G) - if n >= 2 ** 36: - raise ValueError('graph6 is only defined if number of nodes is less ' - 'than 2 ** 36') - if header: - yield b'>>graph6<<' - for d in n_to_data(n): - yield str.encode(chr(d + 63)) - # This generates the same as `(v in G[u] for u, v in combinations(G, 2))`, - # but in "column-major" order instead of "row-major" order. - bits = (nodes[j] in G[nodes[i]] for j in range(1, n) for i in range(j)) - chunk = list(islice(bits, 6)) - while chunk: - d = sum(b << 5 - i for i, b in enumerate(chunk)) - yield str.encode(chr(d + 63)) - chunk = list(islice(bits, 6)) - yield b'\n' - - -def from_graph6_bytes(string): - """Read a simple undirected graph in graph6 format from string. - - Parameters - ---------- - string : string - Data in graph6 format, without a trailing newline. - - Returns - ------- - G : Graph - - Raises - ------ - NetworkXError - If the string is unable to be parsed in graph6 format - - ValueError - If any character ``c`` in the input string does not satisfy - ``63 <= ord(c) < 127``. - - Examples - -------- - >>> G = nx.from_graph6_bytes(b'A_') - >>> sorted(G.edges()) - [(0, 1)] - - See Also - -------- - read_graph6, write_graph6 - - References - ---------- - .. [1] Graph6 specification - - - """ - def bits(): - """Returns sequence of individual bits from 6-bit-per-value - list of data values.""" - for d in data: - for i in [5, 4, 3, 2, 1, 0]: - yield (d >> i) & 1 - - if string.startswith(b'>>graph6<<'): - string = string[10:] - - if sys.version_info < (3, ): - data = [ord(c) - 63 for c in string] - else: - data = [c - 63 for c in string] - if any(c > 63 for c in data): - raise ValueError('each input character must be in range(63, 127)') - - n, data = data_to_n(data) - nd = (n * (n - 1) // 2 + 5) // 6 - if len(data) != nd: - raise NetworkXError( - 'Expected %d bits but got %d in graph6' % (n * (n - 1) // 2, len(data) * 6)) - - G = nx.Graph() - G.add_nodes_from(range(n)) - for (i, j), b in zip([(i, j) for j in range(1, n) for i in range(j)], bits()): - if b: - G.add_edge(i, j) - - return G - - -def to_graph6_bytes(G, nodes=None, header=True): - """Convert a simple undirected graph to bytes in graph6 format. - - Parameters - ---------- - G : Graph (undirected) - - nodes: list or iterable - Nodes are labeled 0...n-1 in the order provided. If None the ordering - given by ``G.nodes()`` is used. - - header: bool - If True add '>>graph6<<' bytes to head of data. - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or is a multigraph. - - ValueError - If the graph has at least ``2 ** 36`` nodes; the graph6 format - is only defined for graphs of order less than ``2 ** 36``. - - Examples - -------- - >>> nx.to_graph6_bytes(nx.path_graph(2)) # doctest: +SKIP - b'>>graph6< - - """ - if nodes is not None: - G = G.subgraph(nodes) - H = nx.convert_node_labels_to_integers(G) - nodes = sorted(H.nodes()) - return b''.join(_generate_graph6_bytes(H, nodes, header)) - - -@open_file(0, mode='rb') -def read_graph6(path): - """Read simple undirected graphs in graph6 format from path. - - Parameters - ---------- - path : file or string - File or filename to write. - - Returns - ------- - G : Graph or list of Graphs - If the file contains multiple lines then a list of graphs is returned - - Raises - ------ - NetworkXError - If the string is unable to be parsed in graph6 format - - Examples - -------- - You can read a graph6 file by giving the path to the file:: - - >>> import tempfile - >>> with tempfile.NamedTemporaryFile() as f: - ... _ = f.write(b'>>graph6<>> list(G.edges()) - [(0, 1)] - - You can also read a graph6 file by giving an open file-like object:: - - >>> import tempfile - >>> with tempfile.NamedTemporaryFile() as f: - ... _ = f.write(b'>>graph6<>> list(G.edges()) - [(0, 1)] - - See Also - -------- - from_graph6_bytes, write_graph6 - - References - ---------- - .. [1] Graph6 specification - - - """ - glist = [] - for line in path: - line = line.strip() - if not len(line): - continue - glist.append(from_graph6_bytes(line)) - if len(glist) == 1: - return glist[0] - else: - return glist - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -@open_file(1, mode='wb') -def write_graph6(G, path, nodes=None, header=True): - """Write a simple undirected graph to a path in graph6 format. - - Parameters - ---------- - G : Graph (undirected) - - path : str - The path naming the file to which to write the graph. - - nodes: list or iterable - Nodes are labeled 0...n-1 in the order provided. If None the ordering - given by ``G.nodes()`` is used. - - header: bool - If True add '>>graph6<<' string to head of data - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or is a multigraph. - - ValueError - If the graph has at least ``2 ** 36`` nodes; the graph6 format - is only defined for graphs of order less than ``2 ** 36``. - - Examples - -------- - You can write a graph6 file by giving the path to a file:: - - >>> import tempfile - >>> with tempfile.NamedTemporaryFile() as f: - ... nx.write_graph6(nx.path_graph(2), f.name) - ... _ = f.seek(0) - ... print(f.read()) # doctest: +SKIP - b'>>graph6< - - """ - return write_graph6_file(G, path, nodes=nodes, header=header) - - -@not_implemented_for('directed') -@not_implemented_for('multigraph') -def write_graph6_file(G, f, nodes=None, header=True): - """Write a simple undirected graph to a file-like object in graph6 format. - - Parameters - ---------- - G : Graph (undirected) - - f : file-like object - The file to write. - - nodes: list or iterable - Nodes are labeled 0...n-1 in the order provided. If None the ordering - given by ``G.nodes()`` is used. - - header: bool - If True add '>>graph6<<' string to head of data - - Raises - ------ - NetworkXNotImplemented - If the graph is directed or is a multigraph. - - ValueError - If the graph has at least ``2 ** 36`` nodes; the graph6 format - is only defined for graphs of order less than ``2 ** 36``. - - Examples - -------- - You can write a graph6 file by giving an open file-like object:: - - >>> import tempfile - >>> with tempfile.NamedTemporaryFile() as f: - ... nx.write_graph6(nx.path_graph(2), f) - ... _ = f.seek(0) - ... print(f.read()) # doctest: +SKIP - b'>>graph6< - - """ - if nodes is not None: - G = G.subgraph(nodes) - H = nx.convert_node_labels_to_integers(G) - nodes = sorted(H.nodes()) - for b in _generate_graph6_bytes(H, nodes, header): - f.write(b) - - -def data_to_n(data): - """Read initial one-, four- or eight-unit value from graph6 - integer sequence. - - Return (value, rest of seq.)""" - if data[0] <= 62: - return data[0], data[1:] - if data[1] <= 62: - return (data[1] << 12) + (data[2] << 6) + data[3], data[4:] - return ((data[2] << 30) + (data[3] << 24) + (data[4] << 18) + - (data[5] << 12) + (data[6] << 6) + data[7], data[8:]) - - -def n_to_data(n): - """Convert an integer to one-, four- or eight-unit graph6 sequence. - - This function is undefined if `n` is not in ``range(2 ** 36)``. - - """ - if n <= 62: - return [n] - elif n <= 258047: - return [63, (n >> 12) & 0x3f, (n >> 6) & 0x3f, n & 0x3f] - else: # if n <= 68719476735: - return [63, 63, - (n >> 30) & 0x3f, (n >> 24) & 0x3f, (n >> 18) & 0x3f, - (n >> 12) & 0x3f, (n >> 6) & 0x3f, n & 0x3f] diff --git a/extensions/fablabchemnitz/networkx/readwrite/graphml.py b/extensions/fablabchemnitz/networkx/readwrite/graphml.py deleted file mode 100644 index 03403641..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/graphml.py +++ /dev/null @@ -1,918 +0,0 @@ -# Copyright (C) 2008-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Salim Fadhley -# Aric Hagberg (hagberg@lanl.gov) -""" -******* -GraphML -******* -Read and write graphs in GraphML format. - -This implementation does not support mixed graphs (directed and unidirected -edges together), hyperedges, nested graphs, or ports. - -"GraphML is a comprehensive and easy-to-use file format for graphs. It -consists of a language core to describe the structural properties of a -graph and a flexible extension mechanism to add application-specific -data. Its main features include support of - - * directed, undirected, and mixed graphs, - * hypergraphs, - * hierarchical graphs, - * graphical representations, - * references to external data, - * application-specific attribute data, and - * light-weight parsers. - -Unlike many other file formats for graphs, GraphML does not use a -custom syntax. Instead, it is based on XML and hence ideally suited as -a common denominator for all kinds of services generating, archiving, -or processing graphs." - -http://graphml.graphdrawing.org/ - -Format ------- -GraphML is an XML format. See -http://graphml.graphdrawing.org/specification.html for the specification and -http://graphml.graphdrawing.org/primer/graphml-primer.html -for examples. -""" -import warnings -from collections import defaultdict - -try: - from xml.etree.cElementTree import Element, ElementTree - from xml.etree.cElementTree import tostring, fromstring -except ImportError: - try: - from xml.etree.ElementTree import Element, ElementTree - from xml.etree.ElementTree import tostring, fromstring - except ImportError: - pass - -try: - import lxml.etree as lxmletree -except ImportError: - lxmletree = None - -import networkx as nx -from networkx.utils import open_file, make_str - -__all__ = ['write_graphml', 'read_graphml', 'generate_graphml', - 'write_graphml_xml', 'write_graphml_lxml', - 'parse_graphml', 'GraphMLWriter', 'GraphMLReader'] - - -@open_file(1, mode='wb') -def write_graphml_xml(G, path, encoding='utf-8', prettyprint=True, - infer_numeric_types=False): - """Write G in GraphML XML format to path - - Parameters - ---------- - G : graph - A networkx graph - path : file or string - File or filename to write. - Filenames ending in .gz or .bz2 will be compressed. - encoding : string (optional) - Encoding for text data. - prettyprint : bool (optional) - If True use line breaks and indenting in output XML. - infer_numeric_types : boolean - Determine if numeric types should be generalized. - For example, if edges have both int and float 'weight' attributes, - we infer in GraphML that both are floats. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_graphml(G, "test.graphml") - - Notes - ----- - It may be a good idea in Python2 to convert strings to unicode - before giving the graph to write_gml. At least the strings with - either many characters to escape. - - This implementation does not support mixed graphs (directed - and unidirected edges together) hyperedges, nested graphs, or ports. - """ - writer = GraphMLWriter(encoding=encoding, prettyprint=prettyprint, - infer_numeric_types=infer_numeric_types) - writer.add_graph_element(G) - writer.dump(path) - - -@open_file(1, mode='wb') -def write_graphml_lxml(G, path, encoding='utf-8', prettyprint=True, - infer_numeric_types=False): - """Write G in GraphML XML format to path - - This function uses the LXML framework and should be faster than - the version using the xml library. - - Parameters - ---------- - G : graph - A networkx graph - path : file or string - File or filename to write. - Filenames ending in .gz or .bz2 will be compressed. - encoding : string (optional) - Encoding for text data. - prettyprint : bool (optional) - If True use line breaks and indenting in output XML. - infer_numeric_types : boolean - Determine if numeric types should be generalized. - For example, if edges have both int and float 'weight' attributes, - we infer in GraphML that both are floats. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> nx.write_graphml_lxml(G, "fourpath.graphml") # doctest: +SKIP - - Notes - ----- - This implementation does not support mixed graphs (directed - and unidirected edges together) hyperedges, nested graphs, or ports. - """ - writer = GraphMLWriterLxml(path, graph=G, encoding=encoding, - prettyprint=prettyprint, - infer_numeric_types=infer_numeric_types) - writer.dump() - - -def generate_graphml(G, encoding='utf-8', prettyprint=True): - """Generate GraphML lines for G - - Parameters - ---------- - G : graph - A networkx graph - encoding : string (optional) - Encoding for text data. - prettyprint : bool (optional) - If True use line breaks and indenting in output XML. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> linefeed = chr(10) # linefeed = \n - >>> s = linefeed.join(nx.generate_graphml(G)) # doctest: +SKIP - >>> for line in nx.generate_graphml(G): # doctest: +SKIP - ... print(line) - - Notes - ----- - This implementation does not support mixed graphs (directed and unidirected - edges together) hyperedges, nested graphs, or ports. - """ - writer = GraphMLWriter(encoding=encoding, prettyprint=prettyprint) - writer.add_graph_element(G) - for line in str(writer).splitlines(): - yield line - - -@open_file(0, mode='rb') -def read_graphml(path, node_type=str, edge_key_type=int): - """Read graph in GraphML format from path. - - Parameters - ---------- - path : file or string - File or filename to write. - Filenames ending in .gz or .bz2 will be compressed. - - node_type: Python type (default: str) - Convert node ids to this type - - edge_key_type: Python type (default: int) - Convert graphml edge ids to this type as key of multi-edges - - - Returns - ------- - graph: NetworkX graph - If no parallel edges are found a Graph or DiGraph is returned. - Otherwise a MultiGraph or MultiDiGraph is returned. - - Notes - ----- - Default node and edge attributes are not propagated to each node and edge. - They can be obtained from `G.graph` and applied to node and edge attributes - if desired using something like this: - - >>> default_color = G.graph['node_default']['color'] # doctest: +SKIP - >>> for node, data in G.nodes(data=True): # doctest: +SKIP - ... if 'color' not in data: - ... data['color']=default_color - >>> default_color = G.graph['edge_default']['color'] # doctest: +SKIP - >>> for u, v, data in G.edges(data=True): # doctest: +SKIP - ... if 'color' not in data: - ... data['color']=default_color - - This implementation does not support mixed graphs (directed and unidirected - edges together), hypergraphs, nested graphs, or ports. - - For multigraphs the GraphML edge "id" will be used as the edge - key. If not specified then they "key" attribute will be used. If - there is no "key" attribute a default NetworkX multigraph edge key - will be provided. - - Files with the yEd "yfiles" extension will can be read but the graphics - information is discarded. - - yEd compressed files ("file.graphmlz" extension) can be read by renaming - the file to "file.graphml.gz". - - """ - reader = GraphMLReader(node_type=node_type, edge_key_type=edge_key_type) - # need to check for multiple graphs - glist = list(reader(path=path)) - if len(glist) == 0: - # If no graph comes back, try looking for an incomplete header - header = b'' - path.seek(0) - old_bytes = path.read() - new_bytes = old_bytes.replace(b'', header) - glist = list(reader(string=new_bytes)) - if len(glist) == 0: - raise nx.NetworkXError('file not successfully read as graphml') - return glist[0] - - -def parse_graphml(graphml_string, node_type=str): - """Read graph in GraphML format from string. - - Parameters - ---------- - graphml_string : string - String containing graphml information - (e.g., contents of a graphml file). - - node_type: Python type (default: str) - Convert node ids to this type - - Returns - ------- - graph: NetworkX graph - If no parallel edges are found a Graph or DiGraph is returned. - Otherwise a MultiGraph or MultiDiGraph is returned. - - Examples - -------- - >>> G = nx.path_graph(4) - >>> linefeed = chr(10) # linefeed = \n - >>> s = linefeed.join(nx.generate_graphml(G)) - >>> H = nx.parse_graphml(s) - - Notes - ----- - Default node and edge attributes are not propagated to each node and edge. - They can be obtained from `G.graph` and applied to node and edge attributes - if desired using something like this: - - >>> default_color = G.graph['node_default']['color'] # doctest: +SKIP - >>> for node, data in G.nodes(data=True): # doctest: +SKIP - ... if 'color' not in data: - ... data['color']=default_color - >>> default_color = G.graph['edge_default']['color'] # doctest: +SKIP - >>> for u, v, data in G.edges(data=True): # doctest: +SKIP - ... if 'color' not in data: - ... data['color']=default_color - - This implementation does not support mixed graphs (directed and unidirected - edges together), hypergraphs, nested graphs, or ports. - - For multigraphs the GraphML edge "id" will be used as the edge - key. If not specified then they "key" attribute will be used. If - there is no "key" attribute a default NetworkX multigraph edge key - will be provided. - - """ - reader = GraphMLReader(node_type=node_type) - # need to check for multiple graphs - glist = list(reader(string=graphml_string)) - if len(glist) == 0: - # If no graph comes back, try looking for an incomplete header - header = '' - new_string = graphml_string.replace('', header) - glist = list(reader(string=new_string)) - if len(glist) == 0: - raise nx.NetworkXError('file not successfully read as graphml') - return glist[0] - - -class GraphML(object): - NS_GRAPHML = "http://graphml.graphdrawing.org/xmlns" - NS_XSI = "http://www.w3.org/2001/XMLSchema-instance" - # xmlns:y="http://www.yworks.com/xml/graphml" - NS_Y = "http://www.yworks.com/xml/graphml" - SCHEMALOCATION = \ - ' '.join(['http://graphml.graphdrawing.org/xmlns', - 'http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd']) - - try: - chr(12345) # Fails on Py!=3. - unicode = str # Py3k's str is our unicode type - long = int # Py3K's int is our long type - except ValueError: - # Python 2.x - pass - - types = [(int, "integer"), # for Gephi GraphML bug - (str, "yfiles"), (str, "string"), (unicode, "string"), - (int, "int"), (long, "long"), - (float, "float"), (float, "double"), - (bool, "boolean")] - - # These additions to types allow writing numpy types - try: - import numpy as np - except: - pass - else: - # prepend so that python types are created upon read (last entry wins) - types = [(np.float64, "float"), (np.float32, "float"), - (np.float16, "float"), (np.float_, "float"), - (np.int, "int"), (np.int8, "int"), - (np.int16, "int"), (np.int32, "int"), - (np.int64, "int"), (np.uint8, "int"), - (np.uint16, "int"), (np.uint32, "int"), - (np.uint64, "int"), (np.int_, "int"), - (np.intc, "int"), (np.intp, "int"), - ] + types - - xml_type = dict(types) - python_type = dict(reversed(a) for a in types) - - # This page says that data types in GraphML follow Java(TM). - # http://graphml.graphdrawing.org/primer/graphml-primer.html#AttributesDefinition - # true and false are the only boolean literals: - # http://en.wikibooks.org/wiki/Java_Programming/Literals#Boolean_Literals - convert_bool = { - # We use data.lower() in actual use. - 'true': True, 'false': False, - # Include integer strings for convenience. - '0': False, 0: False, - '1': True, 1: True - } - - -class GraphMLWriter(GraphML): - def __init__(self, graph=None, encoding="utf-8", prettyprint=True, - infer_numeric_types=False): - try: - import xml.etree.ElementTree - except ImportError: - msg = 'GraphML writer requires xml.elementtree.ElementTree' - raise ImportError(msg) - self.myElement = Element - - self.infer_numeric_types = infer_numeric_types - self.prettyprint = prettyprint - self.encoding = encoding - self.xml = self.myElement("graphml", - {'xmlns': self.NS_GRAPHML, - 'xmlns:xsi': self.NS_XSI, - 'xsi:schemaLocation': self.SCHEMALOCATION}) - self.keys = {} - self.attributes = defaultdict(list) - self.attribute_types = defaultdict(set) - - if graph is not None: - self.add_graph_element(graph) - - def __str__(self): - if self.prettyprint: - self.indent(self.xml) - s = tostring(self.xml).decode(self.encoding) - return s - - def attr_type(self, name, scope, value): - """Infer the attribute type of data named name. Currently this only - supports inference of numeric types. - - If self.infer_numeric_types is false, type is used. Otherwise, pick the - most general of types found across all values with name and scope. This - means edges with data named 'weight' are treated separately from nodes - with data named 'weight'. - """ - if self.infer_numeric_types: - types = self.attribute_types[(name, scope)] - - try: - chr(12345) # Fails on Py<3. - local_long = int # Py3's int is Py2's long type - local_unicode = str # Py3's str is Py2's unicode type - except ValueError: - # Python 2.x - local_long = long - local_unicode = unicode - - if len(types) > 1: - if str in types: - return str - elif local_unicode in types: - return local_unicode - elif float in types: - return float - elif local_long in types: - return local_long - else: - return int - else: - return list(types)[0] - else: - return type(value) - - def get_key(self, name, attr_type, scope, default): - keys_key = (name, attr_type, scope) - try: - return self.keys[keys_key] - except KeyError: - new_id = "d%i" % len(list(self.keys)) - self.keys[keys_key] = new_id - key_kwargs = {"id": new_id, - "for": scope, - "attr.name": name, - "attr.type": attr_type} - key_element = self.myElement("key", **key_kwargs) - # add subelement for data default value if present - if default is not None: - default_element = self.myElement("default") - default_element.text = make_str(default) - key_element.append(default_element) - self.xml.insert(0, key_element) - return new_id - - def add_data(self, name, element_type, value, - scope="all", - default=None): - """ - Make a data element for an edge or a node. Keep a log of the - type in the keys table. - """ - if element_type not in self.xml_type: - msg = 'GraphML writer does not support %s as data values.' - raise nx.NetworkXError(msg % element_type) - keyid = self.get_key(name, self.xml_type[element_type], scope, default) - data_element = self.myElement("data", key=keyid) - data_element.text = make_str(value) - return data_element - - def add_attributes(self, scope, xml_obj, data, default): - """Appends attribute data to edges or nodes, and stores type information - to be added later. See add_graph_element. - """ - for k, v in data.items(): - self.attribute_types[(make_str(k), scope)].add(type(v)) - self.attributes[xml_obj].append([k, v, scope, default.get(k)]) - - def add_nodes(self, G, graph_element): - default = G.graph.get('node_default', {}) - for node, data in G.nodes(data=True): - node_element = self.myElement("node", id=make_str(node)) - self.add_attributes("node", node_element, data, default) - graph_element.append(node_element) - - def add_edges(self, G, graph_element): - if G.is_multigraph(): - for u, v, key, data in G.edges(data=True, keys=True): - edge_element = self.myElement("edge", source=make_str(u), - target=make_str(v), - id=make_str(key)) - default = G.graph.get('edge_default', {}) - self.add_attributes("edge", edge_element, data, default) - graph_element.append(edge_element) - else: - for u, v, data in G.edges(data=True): - edge_element = self.myElement("edge", source=make_str(u), - target=make_str(v)) - default = G.graph.get('edge_default', {}) - self.add_attributes("edge", edge_element, data, default) - graph_element.append(edge_element) - - def add_graph_element(self, G): - """ - Serialize graph G in GraphML to the stream. - """ - if G.is_directed(): - default_edge_type = 'directed' - else: - default_edge_type = 'undirected' - - graphid = G.graph.pop('id', None) - if graphid is None: - graph_element = self.myElement("graph", - edgedefault=default_edge_type) - else: - graph_element = self.myElement("graph", - edgedefault=default_edge_type, - id=graphid) - default = {} - data = {k: v for (k, v) in G.graph.items() - if k not in ['node_default', 'edge_default']} - self.add_attributes("graph", graph_element, data, default) - self.add_nodes(G, graph_element) - self.add_edges(G, graph_element) - - # self.attributes contains a mapping from XML Objects to a list of - # data that needs to be added to them. - # We postpone processing in order to do type inference/generalization. - # See self.attr_type - for (xml_obj, data) in self.attributes.items(): - for (k, v, scope, default) in data: - xml_obj.append(self.add_data(make_str(k), - self.attr_type(k, scope, v), - make_str(v), scope, default)) - self.xml.append(graph_element) - - def add_graphs(self, graph_list): - """ Add many graphs to this GraphML document. """ - for G in graph_list: - self.add_graph_element(G) - - def dump(self, stream): - if self.prettyprint: - self.indent(self.xml) - document = ElementTree(self.xml) - document.write(stream, encoding=self.encoding, xml_declaration=True) - - def indent(self, elem, level=0): - # in-place prettyprint formatter - i = "\n" + level * " " - if len(elem): - if not elem.text or not elem.text.strip(): - elem.text = i + " " - if not elem.tail or not elem.tail.strip(): - elem.tail = i - for elem in elem: - self.indent(elem, level + 1) - if not elem.tail or not elem.tail.strip(): - elem.tail = i - else: - if level and (not elem.tail or not elem.tail.strip()): - elem.tail = i - - -class IncrementalElement(object): - """Wrapper for _IncrementalWriter providing an Element like interface. - - This wrapper does not intend to be a complete implementation but rather to - deal with those calls used in GraphMLWriter. - """ - - def __init__(self, xml, prettyprint): - self.xml = xml - self.prettyprint = prettyprint - - def append(self, element): - self.xml.write(element, pretty_print=self.prettyprint) - - -class GraphMLWriterLxml(GraphMLWriter): - def __init__(self, path, graph=None, encoding='utf-8', prettyprint=True, - infer_numeric_types=False): - self.myElement = lxmletree.Element - - self._encoding = encoding - self._prettyprint = prettyprint - self.infer_numeric_types = infer_numeric_types - - self._xml_base = lxmletree.xmlfile(path, encoding=encoding) - self._xml = self._xml_base.__enter__() - self._xml.write_declaration() - - # We need to have a xml variable that support insertion. This call is - # used for adding the keys to the document. - # We will store those keys in a plain list, and then after the graph - # element is closed we will add them to the main graphml element. - self.xml = [] - self._keys = self.xml - self._graphml = self._xml.element( - 'graphml', - { - 'xmlns': self.NS_GRAPHML, - 'xmlns:xsi': self.NS_XSI, - 'xsi:schemaLocation': self.SCHEMALOCATION - }) - self._graphml.__enter__() - self.keys = {} - self.attribute_types = defaultdict(set) - - if graph is not None: - self.add_graph_element(graph) - - def add_graph_element(self, G): - """ - Serialize graph G in GraphML to the stream. - """ - if G.is_directed(): - default_edge_type = 'directed' - else: - default_edge_type = 'undirected' - - graphid = G.graph.pop('id', None) - if graphid is None: - graph_element = self._xml.element('graph', - edgedefault=default_edge_type) - else: - graph_element = self._xml.element('graph', - edgedefault=default_edge_type, - id=graphid) - - # gather attributes types for the whole graph - # to find the most general numeric format needed. - # Then pass through attributes to create key_id for each. - graphdata = {k: v for k, v in G.graph.items() - if k not in ('node_default', 'edge_default')} - node_default = G.graph.get('node_default', {}) - edge_default = G.graph.get('edge_default', {}) - # Graph attributes - for k, v in graphdata.items(): - self.attribute_types[(make_str(k), "graph")].add(type(v)) - for k, v in graphdata.items(): - element_type = self.xml_type[self.attr_type(k, "graph", v)] - self.get_key(make_str(k), element_type, "graph", None) - # Nodes and data - for node, d in G.nodes(data=True): - for k, v in d.items(): - self.attribute_types[(make_str(k), "node")].add(type(v)) - for node, d in G.nodes(data=True): - for k, v in d.items(): - T = self.xml_type[self.attr_type(k, "node", v)] - self.get_key(make_str(k), T, "node", node_default.get(k)) - # Edges and data - if G.is_multigraph(): - for u, v, ekey, d in G.edges(keys=True, data=True): - for k, v in d.items(): - self.attribute_types[(make_str(k), "edge")].add(type(v)) - for u, v, ekey, d in G.edges(keys=True, data=True): - for k, v in d.items(): - T = self.xml_type[self.attr_type(k, "edge", v)] - self.get_key(make_str(k), T, "edge", edge_default.get(k)) - else: - for u, v, d in G.edges(data=True): - for k, v in d.items(): - self.attribute_types[(make_str(k), "edge")].add(type(v)) - for u, v, d in G.edges(data=True): - for k, v in d.items(): - T = self.xml_type[self.attr_type(k, "edge", v)] - self.get_key(make_str(k), T, "edge", edge_default.get(k)) - - # Now add attribute keys to the xml file - for key in self.xml: - self._xml.write(key, pretty_print=self._prettyprint) - - # The incremental_writer writes each node/edge as it is created - incremental_writer = IncrementalElement(self._xml, self._prettyprint) - with graph_element: - self.add_attributes('graph', incremental_writer, graphdata, {}) - self.add_nodes(G, incremental_writer) # adds attributes too - self.add_edges(G, incremental_writer) # adds attributes too - - def add_attributes(self, scope, xml_obj, data, default): - """Appends attribute data.""" - for k, v in data.items(): - data_element = self.add_data(make_str(k), - self.attr_type(make_str(k), scope, v), - make_str(v), scope, default.get(k)) - xml_obj.append(data_element) - - def __str__(self): - return object.__str__(self) - - def dump(self): - self._graphml.__exit__(None, None, None) - self._xml_base.__exit__(None, None, None) - - -# Choose a writer function for default -if lxmletree is None: - write_graphml = write_graphml_xml -else: - write_graphml = write_graphml_lxml - - -class GraphMLReader(GraphML): - """Read a GraphML document. Produces NetworkX graph objects.""" - - def __init__(self, node_type=str, edge_key_type=int): - try: - import xml.etree.ElementTree - except ImportError: - msg = 'GraphML reader requires xml.elementtree.ElementTree' - raise ImportError(msg) - self.node_type = node_type - self.edge_key_type = edge_key_type - self.multigraph = False # assume multigraph and test for multiedges - self.edge_ids = {} # dict mapping (u,v) tuples to id edge attributes - - def __call__(self, path=None, string=None): - if path is not None: - self.xml = ElementTree(file=path) - elif string is not None: - self.xml = fromstring(string) - else: - raise ValueError("Must specify either 'path' or 'string' as kwarg") - (keys, defaults) = self.find_graphml_keys(self.xml) - for g in self.xml.findall("{%s}graph" % self.NS_GRAPHML): - yield self.make_graph(g, keys, defaults) - - def make_graph(self, graph_xml, graphml_keys, defaults, G=None): - # set default graph type - edgedefault = graph_xml.get("edgedefault", None) - if G is None: - if edgedefault == 'directed': - G = nx.MultiDiGraph() - else: - G = nx.MultiGraph() - # set defaults for graph attributes - G.graph['node_default'] = {} - G.graph['edge_default'] = {} - for key_id, value in defaults.items(): - key_for = graphml_keys[key_id]['for'] - name = graphml_keys[key_id]['name'] - python_type = graphml_keys[key_id]['type'] - if key_for == 'node': - G.graph['node_default'].update({name: python_type(value)}) - if key_for == 'edge': - G.graph['edge_default'].update({name: python_type(value)}) - # hyperedges are not supported - hyperedge = graph_xml.find("{%s}hyperedge" % self.NS_GRAPHML) - if hyperedge is not None: - raise nx.NetworkXError("GraphML reader doesn't support hyperedges") - # add nodes - for node_xml in graph_xml.findall("{%s}node" % self.NS_GRAPHML): - self.add_node(G, node_xml, graphml_keys, defaults) - # add edges - for edge_xml in graph_xml.findall("{%s}edge" % self.NS_GRAPHML): - self.add_edge(G, edge_xml, graphml_keys) - # add graph data - data = self.decode_data_elements(graphml_keys, graph_xml) - G.graph.update(data) - - # switch to Graph or DiGraph if no parallel edges were found. - if not self.multigraph: - if G.is_directed(): - G = nx.DiGraph(G) - else: - G = nx.Graph(G) - nx.set_edge_attributes(G, values=self.edge_ids, name='id') - - return G - - def add_node(self, G, node_xml, graphml_keys, defaults): - """Add a node to the graph. - """ - # warn on finding unsupported ports tag - ports = node_xml.find("{%s}port" % self.NS_GRAPHML) - if ports is not None: - warnings.warn("GraphML port tag not supported.") - # find the node by id and cast it to the appropriate type - node_id = self.node_type(node_xml.get("id")) - # get data/attributes for node - data = self.decode_data_elements(graphml_keys, node_xml) - G.add_node(node_id, **data) - # get child nodes - if node_xml.attrib.get('yfiles.foldertype') == 'group': - graph_xml = node_xml.find("{%s}graph" % self.NS_GRAPHML) - self.make_graph(graph_xml, graphml_keys, defaults, G) - - def add_edge(self, G, edge_element, graphml_keys): - """Add an edge to the graph. - """ - # warn on finding unsupported ports tag - ports = edge_element.find("{%s}port" % self.NS_GRAPHML) - if ports is not None: - warnings.warn("GraphML port tag not supported.") - - # raise error if we find mixed directed and undirected edges - directed = edge_element.get("directed") - if G.is_directed() and directed == 'false': - msg = "directed=false edge found in directed graph." - raise nx.NetworkXError(msg) - if (not G.is_directed()) and directed == 'true': - msg = "directed=true edge found in undirected graph." - raise nx.NetworkXError(msg) - - source = self.node_type(edge_element.get("source")) - target = self.node_type(edge_element.get("target")) - data = self.decode_data_elements(graphml_keys, edge_element) - # GraphML stores edge ids as an attribute - # NetworkX uses them as keys in multigraphs too if no key - # attribute is specified - edge_id = edge_element.get("id") - if edge_id: - # self.edge_ids is used by `make_graph` method for non-multigraphs - self.edge_ids[source, target] = edge_id - try: - edge_id = self.edge_key_type(edge_id) - except ValueError: # Could not convert. - pass - else: - edge_id = data.get('key') - - if G.has_edge(source, target): - # mark this as a multigraph - self.multigraph = True - - # Use add_edges_from to avoid error with add_edge when `'key' in data` - G.add_edges_from([(source, target, edge_id, data)]) - - def decode_data_elements(self, graphml_keys, obj_xml): - """Use the key information to decode the data XML if present.""" - data = {} - for data_element in obj_xml.findall("{%s}data" % self.NS_GRAPHML): - key = data_element.get("key") - try: - data_name = graphml_keys[key]['name'] - data_type = graphml_keys[key]['type'] - except KeyError: - raise nx.NetworkXError("Bad GraphML data: no key %s" % key) - text = data_element.text - # assume anything with subelements is a yfiles extension - if text is not None and len(list(data_element)) == 0: - if data_type == bool: - # Ignore cases. - # http://docs.oracle.com/javase/6/docs/api/java/lang/ - # Boolean.html#parseBoolean%28java.lang.String%29 - data[data_name] = self.convert_bool[text.lower()] - else: - data[data_name] = data_type(text) - elif len(list(data_element)) > 0: - # Assume yfiles as subelements, try to extract node_label - node_label = None - for node_type in ['ShapeNode', 'SVGNode', 'ImageNode']: - pref = "{%s}%s/{%s}" % (self.NS_Y, node_type, self.NS_Y) - geometry = data_element.find("%sGeometry" % pref) - if geometry is not None: - data['x'] = geometry.get('x') - data['y'] = geometry.get('y') - if node_label is None: - node_label = data_element.find("%sNodeLabel" % pref) - if node_label is not None: - data['label'] = node_label.text - - # check all the different types of edges avaivable in yEd. - for e in ['PolyLineEdge', 'SplineEdge', 'QuadCurveEdge', - 'BezierEdge', 'ArcEdge']: - pref = "{%s}%s/{%s}" % (self.NS_Y, e, self.NS_Y) - edge_label = data_element.find("%sEdgeLabel" % pref) - if edge_label is not None: - break - - if edge_label is not None: - data['label'] = edge_label.text - return data - - def find_graphml_keys(self, graph_element): - """Extracts all the keys and key defaults from the xml. - """ - graphml_keys = {} - graphml_key_defaults = {} - for k in graph_element.findall("{%s}key" % self.NS_GRAPHML): - attr_id = k.get("id") - attr_type = k.get('attr.type') - attr_name = k.get("attr.name") - yfiles_type = k.get("yfiles.type") - if yfiles_type is not None: - attr_name = yfiles_type - attr_type = 'yfiles' - if attr_type is None: - attr_type = "string" - warnings.warn("No key type for id %s. Using string" % attr_id) - if attr_name is None: - raise nx.NetworkXError("Unknown key for id %s." % attr_id) - graphml_keys[attr_id] = {"name": attr_name, - "type": self.python_type[attr_type], - "for": k.get("for")} - # check for "default" subelement of key element - default = k.find("{%s}default" % self.NS_GRAPHML) - if default is not None: - graphml_key_defaults[attr_id] = default.text - return graphml_keys, graphml_key_defaults - - -# fixture for pytest -def setup_module(module): - import pytest - xml.etree.ElementTree = pytest.importorskip('xml.etree.ElementTree') - - -# fixture for pytest -def teardown_module(module): - import os - try: - os.unlink('test.graphml') - except: - pass diff --git a/extensions/fablabchemnitz/networkx/readwrite/json_graph/__init__.py b/extensions/fablabchemnitz/networkx/readwrite/json_graph/__init__.py deleted file mode 100644 index 7715fbba..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/json_graph/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -""" -********* -JSON data -********* -Generate and parse JSON serializable data for NetworkX graphs. - -These formats are suitable for use with the d3.js examples https://d3js.org/ - -The three formats that you can generate with NetworkX are: - - - node-link like in the d3.js example https://bl.ocks.org/mbostock/4062045 - - tree like in the d3.js example https://bl.ocks.org/mbostock/4063550 - - adjacency like in the d3.js example https://bost.ocks.org/mike/miserables/ -""" -from networkx.readwrite.json_graph.node_link import * -from networkx.readwrite.json_graph.adjacency import * -from networkx.readwrite.json_graph.tree import * -from networkx.readwrite.json_graph.jit import * -from networkx.readwrite.json_graph.cytoscape import * diff --git a/extensions/fablabchemnitz/networkx/readwrite/json_graph/adjacency.py b/extensions/fablabchemnitz/networkx/readwrite/json_graph/adjacency.py deleted file mode 100644 index 1f2d9dcd..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/json_graph/adjacency.py +++ /dev/null @@ -1,162 +0,0 @@ -# Copyright (C) 2011-2013 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -from itertools import chain -import networkx as nx -__author__ = """Aric Hagberg """ -__all__ = ['adjacency_data', 'adjacency_graph'] - -_attrs = dict(id='id', key='key') - - -def adjacency_data(G, attrs=_attrs): - """Returns data in adjacency format that is suitable for JSON serialization - and use in Javascript documents. - - Parameters - ---------- - G : NetworkX graph - - attrs : dict - A dictionary that contains two keys 'id' and 'key'. The corresponding - values provide the attribute names for storing NetworkX-internal graph - data. The values should be unique. Default value: - :samp:`dict(id='id', key='key')`. - - If some user-defined graph data use these attribute names as data keys, - they may be silently dropped. - - Returns - ------- - data : dict - A dictionary with adjacency formatted data. - - Raises - ------ - NetworkXError - If values in attrs are not unique. - - Examples - -------- - >>> from networkx.readwrite import json_graph - >>> G = nx.Graph([(1,2)]) - >>> data = json_graph.adjacency_data(G) - - To serialize with json - - >>> import json - >>> s = json.dumps(data) - - Notes - ----- - Graph, node, and link attributes will be written when using this format - but attribute keys must be strings if you want to serialize the resulting - data with JSON. - - The default value of attrs will be changed in a future release of NetworkX. - - See Also - -------- - adjacency_graph, node_link_data, tree_data - """ - multigraph = G.is_multigraph() - id_ = attrs['id'] - # Allow 'key' to be omitted from attrs if the graph is not a multigraph. - key = None if not multigraph else attrs['key'] - if id_ == key: - raise nx.NetworkXError('Attribute names are not unique.') - data = {} - data['directed'] = G.is_directed() - data['multigraph'] = multigraph - data['graph'] = list(G.graph.items()) - data['nodes'] = [] - data['adjacency'] = [] - for n, nbrdict in G.adjacency(): - data['nodes'].append(dict(chain(G.nodes[n].items(), [(id_, n)]))) - adj = [] - if multigraph: - for nbr, keys in nbrdict.items(): - for k, d in keys.items(): - adj.append(dict(chain(d.items(), [(id_, nbr), (key, k)]))) - else: - for nbr, d in nbrdict.items(): - adj.append(dict(chain(d.items(), [(id_, nbr)]))) - data['adjacency'].append(adj) - return data - - -def adjacency_graph(data, directed=False, multigraph=True, attrs=_attrs): - """Returns graph from adjacency data format. - - Parameters - ---------- - data : dict - Adjacency list formatted graph data - - Returns - ------- - G : NetworkX graph - A NetworkX graph object - - directed : bool - If True, and direction not specified in data, return a directed graph. - - multigraph : bool - If True, and multigraph not specified in data, return a multigraph. - - attrs : dict - A dictionary that contains two keys 'id' and 'key'. The corresponding - values provide the attribute names for storing NetworkX-internal graph - data. The values should be unique. Default value: - :samp:`dict(id='id', key='key')`. - - Examples - -------- - >>> from networkx.readwrite import json_graph - >>> G = nx.Graph([(1,2)]) - >>> data = json_graph.adjacency_data(G) - >>> H = json_graph.adjacency_graph(data) - - Notes - ----- - The default value of attrs will be changed in a future release of NetworkX. - - See Also - -------- - adjacency_graph, node_link_data, tree_data - """ - multigraph = data.get('multigraph', multigraph) - directed = data.get('directed', directed) - if multigraph: - graph = nx.MultiGraph() - else: - graph = nx.Graph() - if directed: - graph = graph.to_directed() - id_ = attrs['id'] - # Allow 'key' to be omitted from attrs if the graph is not a multigraph. - key = None if not multigraph else attrs['key'] - graph.graph = dict(data.get('graph', [])) - mapping = [] - for d in data['nodes']: - node_data = d.copy() - node = node_data.pop(id_) - mapping.append(node) - graph.add_node(node) - graph.nodes[node].update(node_data) - for i, d in enumerate(data['adjacency']): - source = mapping[i] - for tdata in d: - target_data = tdata.copy() - target = target_data.pop(id_) - if not multigraph: - graph.add_edge(source, target) - graph[source][target].update(tdata) - else: - ky = target_data.pop(key, None) - graph.add_edge(source, target, key=ky) - graph[source][target][ky].update(tdata) - return graph diff --git a/extensions/fablabchemnitz/networkx/readwrite/json_graph/cytoscape.py b/extensions/fablabchemnitz/networkx/readwrite/json_graph/cytoscape.py deleted file mode 100644 index 45a87eb5..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/json_graph/cytoscape.py +++ /dev/null @@ -1,112 +0,0 @@ -# BSD license. - -import networkx as nx - -__all__ = ['cytoscape_data', 'cytoscape_graph'] - -_attrs = dict(name='name', ident='id') - - -def cytoscape_data(G, attrs=None): - """Returns data in Cytoscape JSON format (cyjs). - - Parameters - ---------- - G : NetworkX Graph - - - Returns - ------- - data: dict - A dictionary with cyjs formatted data. - Raises - ------ - NetworkXError - If values in attrs are not unique. - """ - if not attrs: - attrs = _attrs - else: - attrs.update({k: v for (k, v) in _attrs.items() if k not in attrs}) - - name = attrs["name"] - ident = attrs["ident"] - - if len(set([name, ident])) < 2: - raise nx.NetworkXError('Attribute names are not unique.') - - jsondata = {"data": list(G.graph.items())} - jsondata['directed'] = G.is_directed() - jsondata['multigraph'] = G.is_multigraph() - jsondata["elements"] = {"nodes": [], "edges": []} - nodes = jsondata["elements"]["nodes"] - edges = jsondata["elements"]["edges"] - - for i, j in G.nodes.items(): - n = {"data": j.copy()} - n["data"]["id"] = j.get(ident) or str(i) - n["data"]["value"] = i - n["data"]["name"] = j.get(name) or str(i) - nodes.append(n) - - if G.is_multigraph(): - for e in G.edges(keys=True): - n = {"data": G.adj[e[0]][e[1]][e[2]].copy()} - n["data"]["source"] = e[0] - n["data"]["target"] = e[1] - n["data"]["key"] = e[2] - edges.append(n) - else: - for e in G.edges(): - n = {"data": G.adj[e[0]][e[1]].copy()} - n["data"]["source"] = e[0] - n["data"]["target"] = e[1] - edges.append(n) - return jsondata - - -def cytoscape_graph(data, attrs=None): - if not attrs: - attrs = _attrs - else: - attrs.update({k: v for (k, v) in _attrs.items() if k not in attrs}) - - name = attrs["name"] - ident = attrs["ident"] - - if len(set([ident, name])) < 2: - raise nx.NetworkXError('Attribute names are not unique.') - - multigraph = data.get('multigraph') - directed = data.get('directed') - if multigraph: - graph = nx.MultiGraph() - else: - graph = nx.Graph() - if directed: - graph = graph.to_directed() - graph.graph = dict(data.get('data')) - for d in data["elements"]["nodes"]: - node_data = d["data"].copy() - node = d["data"]["value"] - - if d["data"].get(name): - node_data[name] = d["data"].get(name) - if d["data"].get(ident): - node_data[ident] = d["data"].get(ident) - - graph.add_node(node) - graph.nodes[node].update(node_data) - - for d in data["elements"]["edges"]: - edge_data = d["data"].copy() - sour = d["data"].pop("source") - targ = d["data"].pop("target") - if multigraph: - key = d["data"].get("key", 0) - graph.add_edge(sour, targ, key=key) - graph.edges[sour, targ, key].update(edge_data) - else: - graph.add_edge(sour, targ) - graph.edges[sour, targ].update(edge_data) - return graph diff --git a/extensions/fablabchemnitz/networkx/readwrite/json_graph/jit.py b/extensions/fablabchemnitz/networkx/readwrite/json_graph/jit.py deleted file mode 100644 index 3e956551..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/json_graph/jit.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright (C) 2011-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. - -""" -Read and write NetworkX graphs as JavaScript InfoVis Toolkit (JIT) format JSON. - -See the `JIT documentation`_ for more examples. - -Format ------- -var json = [ - { - "id": "aUniqueIdentifier", - "name": "usually a nodes name", - "data": { - "some key": "some value", - "some other key": "some other value" - }, - "adjacencies": [ - { - nodeTo:"aNodeId", - data: {} //put whatever you want here - }, - 'other adjacencies go here...' - }, - - 'other nodes go here...' -]; -.. _JIT documentation: http://thejit.org -""" - -import json -import networkx as nx -from networkx.utils.decorators import not_implemented_for - -__all__ = ['jit_graph', 'jit_data'] - - -def jit_graph(data, create_using=None): - """Read a graph from JIT JSON. - - Parameters - ---------- - data : JSON Graph Object - - create_using : Networkx Graph, optional (default: Graph()) - Return graph of this type. The provided instance will be cleared. - - Returns - ------- - G : NetworkX Graph built from create_using if provided. - """ - if create_using is None: - G = nx.Graph() - else: - G = create_using - G.clear() - - if nx.utils.is_string_like(data): - data = json.loads(data) - - for node in data: - G.add_node(node['id'], **node['data']) - if node.get('adjacencies') is not None: - for adj in node['adjacencies']: - G.add_edge(node['id'], adj['nodeTo'], **adj['data']) - return G - - -@not_implemented_for('multigraph') -def jit_data(G, indent=None): - """Returns data in JIT JSON format. - - Parameters - ---------- - G : NetworkX Graph - - indent: optional, default=None - If indent is a non-negative integer, then JSON array elements and - object members will be pretty-printed with that indent level. - An indent level of 0, or negative, will only insert newlines. - None (the default) selects the most compact representation. - - Returns - ------- - data: JIT JSON string - """ - json_graph = [] - for node in G.nodes(): - json_node = { - "id": node, - "name": node - } - # node data - json_node["data"] = G.nodes[node] - # adjacencies - if G[node]: - json_node["adjacencies"] = [] - for neighbour in G[node]: - adjacency = { - "nodeTo": neighbour, - } - # adjacency data - adjacency["data"] = G.edges[node, neighbour] - json_node["adjacencies"].append(adjacency) - json_graph.append(json_node) - return json.dumps(json_graph, indent=indent) diff --git a/extensions/fablabchemnitz/networkx/readwrite/json_graph/node_link.py b/extensions/fablabchemnitz/networkx/readwrite/json_graph/node_link.py deleted file mode 100644 index 38576bbc..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/json_graph/node_link.py +++ /dev/null @@ -1,183 +0,0 @@ -# Copyright (C) 2011-2019 by -# -# Aric Hagberg -# Dan Schult -# Pieter Swart -# Michael E. Rose -# -# All rights reserved. -# BSD license. -from itertools import chain, count -import networkx as nx -from networkx.utils import make_str, to_tuple -__all__ = ['node_link_data', 'node_link_graph'] - - -_attrs = dict(source='source', target='target', name='id', - key='key', link='links') - - -def node_link_data(G, attrs=None): - """Returns data in node-link format that is suitable for JSON serialization - and use in Javascript documents. - - Parameters - ---------- - G : NetworkX graph - - attrs : dict - A dictionary that contains five keys 'source', 'target', 'name', - 'key' and 'link'. The corresponding values provide the attribute - names for storing NetworkX-internal graph data. The values should - be unique. Default value:: - - dict(source='source', target='target', name='id', - key='key', link='links') - - If some user-defined graph data use these attribute names as data keys, - they may be silently dropped. - - Returns - ------- - data : dict - A dictionary with node-link formatted data. - - Raises - ------ - NetworkXError - If values in attrs are not unique. - - Examples - -------- - >>> from networkx.readwrite import json_graph - >>> G = nx.Graph([('A', 'B')]) - >>> data1 = json_graph.node_link_data(G) - >>> H = nx.gn_graph(2) - >>> data2 = json_graph.node_link_data(H, {'link': 'edges', 'source': 'from', 'target': 'to'}) - - To serialize with json - - >>> import json - >>> s1 = json.dumps(data1) - >>> s2 = json.dumps(data2, default={'link': 'edges', 'source': 'from', 'target': 'to'}) - - Notes - ----- - Graph, node, and link attributes are stored in this format. Note that - attribute keys will be converted to strings in order to comply with JSON. - - Attribute 'key' is only used for multigraphs. - - See Also - -------- - node_link_graph, adjacency_data, tree_data - """ - multigraph = G.is_multigraph() - # Allow 'attrs' to keep default values. - if attrs is None: - attrs = _attrs - else: - attrs.update({k: v for (k, v) in _attrs.items() if k not in attrs}) - name = attrs['name'] - source = attrs['source'] - target = attrs['target'] - links = attrs['link'] - # Allow 'key' to be omitted from attrs if the graph is not a multigraph. - key = None if not multigraph else attrs['key'] - if len({source, target, key}) < 3: - raise nx.NetworkXError('Attribute names are not unique.') - data = {'directed': G.is_directed(), 'multigraph': multigraph, 'graph': G.graph, - 'nodes': [dict(chain(G.nodes[n].items(), [(name, n)])) for n in G]} - if multigraph: - data[links] = [ - dict(chain(d.items(), - [(source, u), (target, v), (key, k)])) - for u, v, k, d in G.edges(keys=True, data=True)] - else: - data[links] = [ - dict(chain(d.items(), - [(source, u), (target, v)])) - for u, v, d in G.edges(data=True)] - return data - - -def node_link_graph(data, directed=False, multigraph=True, attrs=None): - """Returns graph from node-link data format. - - Parameters - ---------- - data : dict - node-link formatted graph data - - directed : bool - If True, and direction not specified in data, return a directed graph. - - multigraph : bool - If True, and multigraph not specified in data, return a multigraph. - - attrs : dict - A dictionary that contains five keys 'source', 'target', 'name', - 'key' and 'link'. The corresponding values provide the attribute - names for storing NetworkX-internal graph data. Default value: - - dict(source='source', target='target', name='id', - key='key', link='links') - - Returns - ------- - G : NetworkX graph - A NetworkX graph object - - Examples - -------- - >>> from networkx.readwrite import json_graph - >>> G = nx.Graph([('A', 'B')]) - >>> data = json_graph.node_link_data(G) - >>> H = json_graph.node_link_graph(data) - - Notes - ----- - Attribute 'key' is only used for multigraphs. - - See Also - -------- - node_link_data, adjacency_data, tree_data - """ - # Allow 'attrs' to keep default values. - if attrs is None: - attrs = _attrs - else: - attrs.update({k: v for k, v in _attrs.items() if k not in attrs}) - multigraph = data.get('multigraph', multigraph) - directed = data.get('directed', directed) - if multigraph: - graph = nx.MultiGraph() - else: - graph = nx.Graph() - if directed: - graph = graph.to_directed() - name = attrs['name'] - source = attrs['source'] - target = attrs['target'] - links = attrs['link'] - # Allow 'key' to be omitted from attrs if the graph is not a multigraph. - key = None if not multigraph else attrs['key'] - graph.graph = data.get('graph', {}) - c = count() - for d in data['nodes']: - node = to_tuple(d.get(name, next(c))) - nodedata = dict((make_str(k), v) for k, v in d.items() if k != name) - graph.add_node(node, **nodedata) - for d in data[links]: - src = tuple(d[source]) if isinstance(d[source], list) else d[source] - tgt = tuple(d[target]) if isinstance(d[target], list) else d[target] - if not multigraph: - edgedata = dict((make_str(k), v) for k, v in d.items() - if k != source and k != target) - graph.add_edge(src, tgt, **edgedata) - else: - ky = d.get(key, None) - edgedata = dict((make_str(k), v) for k, v in d.items() - if k != source and k != target and k != key) - graph.add_edge(src, tgt, ky, **edgedata) - return graph diff --git a/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/__init__.py b/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/test_adjacency.py b/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/test_adjacency.py deleted file mode 100644 index d1e3cdb0..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/test_adjacency.py +++ /dev/null @@ -1,59 +0,0 @@ -import json -import pytest -import networkx as nx -from networkx.readwrite.json_graph import * - - -class TestAdjacency: - - def test_graph(self): - G = nx.path_graph(4) - H = adjacency_graph(adjacency_data(G)) - nx.is_isomorphic(G, H) - - def test_graph_attributes(self): - G = nx.path_graph(4) - G.add_node(1, color='red') - G.add_edge(1, 2, width=7) - G.graph['foo'] = 'bar' - G.graph[1] = 'one' - - H = adjacency_graph(adjacency_data(G)) - assert H.graph['foo'] == 'bar' - assert H.nodes[1]['color'] == 'red' - assert H[1][2]['width'] == 7 - - d = json.dumps(adjacency_data(G)) - H = adjacency_graph(json.loads(d)) - assert H.graph['foo'] == 'bar' - assert H.graph[1] == 'one' - assert H.nodes[1]['color'] == 'red' - assert H[1][2]['width'] == 7 - - def test_digraph(self): - G = nx.DiGraph() - nx.add_path(G, [1, 2, 3]) - H = adjacency_graph(adjacency_data(G)) - assert H.is_directed() - nx.is_isomorphic(G, H) - - def test_multidigraph(self): - G = nx.MultiDiGraph() - nx.add_path(G, [1, 2, 3]) - H = adjacency_graph(adjacency_data(G)) - assert H.is_directed() - assert H.is_multigraph() - - def test_multigraph(self): - G = nx.MultiGraph() - G.add_edge(1, 2, key='first') - G.add_edge(1, 2, key='second', color='blue') - H = adjacency_graph(adjacency_data(G)) - nx.is_isomorphic(G, H) - assert H[1][2]['second']['color'] == 'blue' - - def test_exception(self): - with pytest.raises(nx.NetworkXError): - G = nx.MultiDiGraph() - attrs = dict(id='node', key='node') - adjacency_data(G, attrs) diff --git a/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/test_cytoscape.py b/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/test_cytoscape.py deleted file mode 100644 index 8e61c4d7..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/test_cytoscape.py +++ /dev/null @@ -1,64 +0,0 @@ -import json -import pytest -import networkx as nx -from networkx.readwrite.json_graph import * - - -class TestCytoscape: - - def test_graph(self): - G = nx.path_graph(4) - H = cytoscape_graph(cytoscape_data(G)) - nx.is_isomorphic(G, H) - - def test_graph_attributes(self): - G = nx.path_graph(4) - G.add_node(1, color='red') - G.add_edge(1, 2, width=7) - G.graph['foo'] = 'bar' - G.graph[1] = 'one' - G.add_node(3, name="node", id="123") - - H = cytoscape_graph(cytoscape_data(G)) - assert H.graph['foo'] == 'bar' - assert H.nodes[1]['color'] == 'red' - assert H[1][2]['width'] == 7 - assert H.nodes[3]['name'] == 'node' - assert H.nodes[3]['id'] == '123' - - d = json.dumps(cytoscape_data(G)) - H = cytoscape_graph(json.loads(d)) - assert H.graph['foo'] == 'bar' - assert H.graph[1] == 'one' - assert H.nodes[1]['color'] == 'red' - assert H[1][2]['width'] == 7 - assert H.nodes[3]['name'] == 'node' - assert H.nodes[3]['id'] == '123' - - def test_digraph(self): - G = nx.DiGraph() - nx.add_path(G, [1, 2, 3]) - H = cytoscape_graph(cytoscape_data(G)) - assert H.is_directed() - nx.is_isomorphic(G, H) - - def test_multidigraph(self): - G = nx.MultiDiGraph() - nx.add_path(G, [1, 2, 3]) - H = cytoscape_graph(cytoscape_data(G)) - assert H.is_directed() - assert H.is_multigraph() - - def test_multigraph(self): - G = nx.MultiGraph() - G.add_edge(1, 2, key='first') - G.add_edge(1, 2, key='second', color='blue') - H = cytoscape_graph(cytoscape_data(G)) - assert nx.is_isomorphic(G, H) - assert H[1][2]['second']['color'] == 'blue' - - def test_exception(self): - with pytest.raises(nx.NetworkXError): - G = nx.MultiDiGraph() - attrs = dict(name='node', ident='node') - cytoscape_data(G, attrs) diff --git a/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/test_jit.py b/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/test_jit.py deleted file mode 100644 index b0e89ecb..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/test_jit.py +++ /dev/null @@ -1,64 +0,0 @@ -import json -import pytest -import networkx as nx -from networkx.readwrite.json_graph import jit_data, jit_graph - - -class TestJIT(object): - def test_jit(self): - G = nx.Graph() - G.add_node('Node1', node_data='foobar') - G.add_node('Node3', node_data='bar') - G.add_node('Node4') - G.add_edge('Node1', 'Node2', weight=9, something='isSomething') - G.add_edge('Node2', 'Node3', weight=4, something='isNotSomething') - G.add_edge('Node1', 'Node2') - d = jit_data(G) - K = jit_graph(json.loads(d)) - assert nx.is_isomorphic(G, K) - - def test_jit_2(self): - G = nx.Graph() - G.add_node(1, node_data=3) - G.add_node(3, node_data=0) - G.add_edge(1, 2, weight=9, something=0) - G.add_edge(2, 3, weight=4, something=3) - G.add_edge(1, 2) - d = jit_data(G) - K = jit_graph(json.loads(d)) - assert nx.is_isomorphic(G, K) - - def test_jit_directed(self): - G = nx.DiGraph() - G.add_node(1, node_data=3) - G.add_node(3, node_data=0) - G.add_edge(1, 2, weight=9, something=0) - G.add_edge(2, 3, weight=4, something=3) - G.add_edge(1, 2) - d = jit_data(G) - K = jit_graph(json.loads(d), create_using=nx.DiGraph()) - assert nx.is_isomorphic(G, K) - - def test_jit_multi_directed(self): - G = nx.MultiDiGraph() - G.add_node(1, node_data=3) - G.add_node(3, node_data=0) - G.add_edge(1, 2, weight=9, something=0) - G.add_edge(2, 3, weight=4, something=3) - G.add_edge(1, 2) - pytest.raises(nx.NetworkXNotImplemented, jit_data, G) - - H = nx.DiGraph(G) - d = jit_data(H) - K = jit_graph(json.loads(d), create_using=nx.MultiDiGraph()) - assert nx.is_isomorphic(H, K) - K.add_edge(1, 2) - assert not nx.is_isomorphic(H, K) - assert nx.is_isomorphic(G, K) - - def test_jit_round_trip(self): - G = nx.Graph() - d = nx.jit_data(G) - H = jit_graph(json.loads(d)) - K = jit_graph(d) - assert nx.is_isomorphic(H, K) diff --git a/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/test_node_link.py b/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/test_node_link.py deleted file mode 100644 index 4a1a40c6..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/test_node_link.py +++ /dev/null @@ -1,105 +0,0 @@ -# -*- coding: utf-8 -*- -import json -import pytest -import networkx as nx -from networkx.readwrite.json_graph import * - - -class TestNodeLink: - - def test_graph(self): - G = nx.path_graph(4) - H = node_link_graph(node_link_data(G)) - assert nx.is_isomorphic(G, H) - - def test_graph_attributes(self): - G = nx.path_graph(4) - G.add_node(1, color='red') - G.add_edge(1, 2, width=7) - G.graph[1] = 'one' - G.graph['foo'] = 'bar' - - H = node_link_graph(node_link_data(G)) - assert H.graph['foo'] == 'bar' - assert H.nodes[1]['color'] == 'red' - assert H[1][2]['width'] == 7 - - d = json.dumps(node_link_data(G)) - H = node_link_graph(json.loads(d)) - assert H.graph['foo'] == 'bar' - assert H.graph['1'] == 'one' - assert H.nodes[1]['color'] == 'red' - assert H[1][2]['width'] == 7 - - def test_digraph(self): - G = nx.DiGraph() - H = node_link_graph(node_link_data(G)) - assert H.is_directed() - - def test_multigraph(self): - G = nx.MultiGraph() - G.add_edge(1, 2, key='first') - G.add_edge(1, 2, key='second', color='blue') - H = node_link_graph(node_link_data(G)) - nx.is_isomorphic(G, H) - assert H[1][2]['second']['color'] == 'blue' - - def test_graph_with_tuple_nodes(self): - G = nx.Graph() - G.add_edge((0, 0), (1, 0), color=[255, 255, 0]) - d = node_link_data(G) - dumped_d = json.dumps(d) - dd = json.loads(dumped_d) - H = node_link_graph(dd) - assert H.nodes[(0, 0)] == G.nodes[(0, 0)] - assert H[(0, 0)][(1, 0)]['color'] == [255, 255, 0] - - def test_unicode_keys(self): - try: - q = unicode("qualité", 'utf-8') - except NameError: - q = "qualité" - G = nx.Graph() - G.add_node(1, **{q: q}) - s = node_link_data(G) - output = json.dumps(s, ensure_ascii=False) - data = json.loads(output) - H = node_link_graph(data) - assert H.nodes[1][q] == q - - def test_exception(self): - with pytest.raises(nx.NetworkXError): - G = nx.MultiDiGraph() - attrs = dict(name='node', source='node', target='node', key='node') - node_link_data(G, attrs) - - def test_string_ids(self): - try: - q = unicode("qualité", 'utf-8') - except NameError: - q = "qualité" - - G = nx.DiGraph() - G.add_node('A') - G.add_node(q) - G.add_edge('A', q) - data = node_link_data(G) - assert data['links'][0]['source'] == 'A' - assert data['links'][0]['target'] == q - H = node_link_graph(data) - assert nx.is_isomorphic(G, H) - - def test_custom_attrs(self): - G = nx.path_graph(4) - G.add_node(1, color='red') - G.add_edge(1, 2, width=7) - G.graph[1] = 'one' - G.graph['foo'] = 'bar' - - attrs = dict(source='c_source', target='c_target', name='c_id', key='c_key', link='c_links') - - H = node_link_graph(node_link_data(G, attrs=attrs), multigraph=False, attrs=attrs) - assert nx.is_isomorphic(G, H) - assert H.graph['foo'] == 'bar' - assert H.nodes[1]['color'] == 'red' - assert H[1][2]['width'] == 7 diff --git a/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/test_tree.py b/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/test_tree.py deleted file mode 100644 index 19e36fad..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/json_graph/tests/test_tree.py +++ /dev/null @@ -1,36 +0,0 @@ -import json -import pytest -import networkx as nx -from networkx.readwrite.json_graph import * - - -class TestTree: - - def test_graph(self): - G = nx.DiGraph() - G.add_nodes_from([1, 2, 3], color='red') - G.add_edge(1, 2, foo=7) - G.add_edge(1, 3, foo=10) - G.add_edge(3, 4, foo=10) - H = tree_graph(tree_data(G, 1)) - nx.is_isomorphic(G, H) - - def test_graph_attributes(self): - G = nx.DiGraph() - G.add_nodes_from([1, 2, 3], color='red') - G.add_edge(1, 2, foo=7) - G.add_edge(1, 3, foo=10) - G.add_edge(3, 4, foo=10) - H = tree_graph(tree_data(G, 1)) - assert H.nodes[1]['color'] == 'red' - - d = json.dumps(tree_data(G, 1)) - H = tree_graph(json.loads(d)) - assert H.nodes[1]['color'] == 'red' - - def test_exception(self): - with pytest.raises(nx.NetworkXError): - G = nx.MultiDiGraph() - G.add_node(0) - attrs = dict(id='node', children='node') - tree_data(G, 0, attrs) diff --git a/extensions/fablabchemnitz/networkx/readwrite/json_graph/tree.py b/extensions/fablabchemnitz/networkx/readwrite/json_graph/tree.py deleted file mode 100644 index 69c508c6..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/json_graph/tree.py +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright (C) 2011 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -from itertools import chain -import networkx as nx -from networkx.utils import make_str -__author__ = """Aric Hagberg (hagberg@lanl.gov))""" -__all__ = ['tree_data', 'tree_graph'] - -_attrs = dict(id='id', children='children') - - -def tree_data(G, root, attrs=_attrs): - """Returns data in tree format that is suitable for JSON serialization - and use in Javascript documents. - - Parameters - ---------- - G : NetworkX graph - G must be an oriented tree - - root : node - The root of the tree - - attrs : dict - A dictionary that contains two keys 'id' and 'children'. The - corresponding values provide the attribute names for storing - NetworkX-internal graph data. The values should be unique. Default - value: :samp:`dict(id='id', children='children')`. - - If some user-defined graph data use these attribute names as data keys, - they may be silently dropped. - - Returns - ------- - data : dict - A dictionary with node-link formatted data. - - Raises - ------ - NetworkXError - If values in attrs are not unique. - - Examples - -------- - >>> from networkx.readwrite import json_graph - >>> G = nx.DiGraph([(1,2)]) - >>> data = json_graph.tree_data(G,root=1) - - To serialize with json - - >>> import json - >>> s = json.dumps(data) - - Notes - ----- - Node attributes are stored in this format but keys - for attributes must be strings if you want to serialize with JSON. - - Graph and edge attributes are not stored. - - The default value of attrs will be changed in a future release of NetworkX. - - See Also - -------- - tree_graph, node_link_data, node_link_data - """ - if G.number_of_nodes() != G.number_of_edges() + 1: - raise TypeError("G is not a tree.") - if not G.is_directed(): - raise TypeError("G is not directed.") - - id_ = attrs['id'] - children = attrs['children'] - if id_ == children: - raise nx.NetworkXError('Attribute names are not unique.') - - def add_children(n, G): - nbrs = G[n] - if len(nbrs) == 0: - return [] - children_ = [] - for child in nbrs: - d = dict(chain(G.nodes[child].items(), [(id_, child)])) - c = add_children(child, G) - if c: - d[children] = c - children_.append(d) - return children_ - - data = dict(chain(G.nodes[root].items(), [(id_, root)])) - data[children] = add_children(root, G) - return data - - -def tree_graph(data, attrs=_attrs): - """Returns graph from tree data format. - - Parameters - ---------- - data : dict - Tree formatted graph data - - Returns - ------- - G : NetworkX DiGraph - - attrs : dict - A dictionary that contains two keys 'id' and 'children'. The - corresponding values provide the attribute names for storing - NetworkX-internal graph data. The values should be unique. Default - value: :samp:`dict(id='id', children='children')`. - - Examples - -------- - >>> from networkx.readwrite import json_graph - >>> G = nx.DiGraph([(1,2)]) - >>> data = json_graph.tree_data(G,root=1) - >>> H = json_graph.tree_graph(data) - - Notes - ----- - The default value of attrs will be changed in a future release of NetworkX. - - See Also - -------- - tree_graph, node_link_data, adjacency_data - """ - graph = nx.DiGraph() - id_ = attrs['id'] - children = attrs['children'] - - def add_children(parent, children_): - for data in children_: - child = data[id_] - graph.add_edge(parent, child) - grandchildren = data.get(children, []) - if grandchildren: - add_children(child, grandchildren) - nodedata = dict((make_str(k), v) for k, v in data.items() - if k != id_ and k != children) - graph.add_node(child, **nodedata) - - root = data[id_] - children_ = data.get(children, []) - nodedata = dict((make_str(k), v) for k, v in data.items() - if k != id_ and k != children) - graph.add_node(root, **nodedata) - add_children(root, children_) - return graph diff --git a/extensions/fablabchemnitz/networkx/readwrite/leda.py b/extensions/fablabchemnitz/networkx/readwrite/leda.py deleted file mode 100644 index 996e8e01..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/leda.py +++ /dev/null @@ -1,108 +0,0 @@ -""" -Read graphs in LEDA format. - -LEDA is a C++ class library for efficient data types and algorithms. - -Format ------- -See http://www.algorithmic-solutions.info/leda_guide/graphs/leda_native_graph_fileformat.html - -""" -# Original author: D. Eppstein, UC Irvine, August 12, 2003. -# The original code at http://www.ics.uci.edu/~eppstein/PADS/ is public domain. -__author__ = """Aric Hagberg (hagberg@lanl.gov)""" -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. - -__all__ = ['read_leda', 'parse_leda'] - -import networkx as nx -from networkx.exception import NetworkXError -from networkx.utils import open_file, is_string_like - - -@open_file(0, mode='rb') -def read_leda(path, encoding='UTF-8'): - """Read graph in LEDA format from path. - - Parameters - ---------- - path : file or string - File or filename to read. Filenames ending in .gz or .bz2 will be - uncompressed. - - Returns - ------- - G : NetworkX graph - - Examples - -------- - G=nx.read_leda('file.leda') - - References - ---------- - .. [1] http://www.algorithmic-solutions.info/leda_guide/graphs/leda_native_graph_fileformat.html - """ - lines = (line.decode(encoding) for line in path) - G = parse_leda(lines) - return G - - -def parse_leda(lines): - """Read graph in LEDA format from string or iterable. - - Parameters - ---------- - lines : string or iterable - Data in LEDA format. - - Returns - ------- - G : NetworkX graph - - Examples - -------- - G=nx.parse_leda(string) - - References - ---------- - .. [1] http://www.algorithmic-solutions.info/leda_guide/graphs/leda_native_graph_fileformat.html - """ - if is_string_like(lines): - lines = iter(lines.split('\n')) - lines = iter([line.rstrip('\n') for line in lines - if not (line.startswith('#') or line.startswith('\n') or line == '')]) - for i in range(3): - next(lines) - # Graph - du = int(next(lines)) # -1=directed, -2=undirected - if du == -1: - G = nx.DiGraph() - else: - G = nx.Graph() - - # Nodes - n = int(next(lines)) # number of nodes - node = {} - for i in range(1, n + 1): # LEDA counts from 1 to n - symbol = next(lines).rstrip().strip('|{}| ') - if symbol == "": - symbol = str(i) # use int if no label - could be trouble - node[i] = symbol - - G.add_nodes_from([s for i, s in node.items()]) - - # Edges - m = int(next(lines)) # number of edges - for i in range(m): - try: - s, t, reversal, label = next(lines).split() - except: - raise NetworkXError('Too few fields in LEDA.GRAPH edge %d' % (i + 1)) - # BEWARE: no handling of reversal edges - G.add_edge(node[int(s)], node[int(t)], label=label[2:-2]) - return G diff --git a/extensions/fablabchemnitz/networkx/readwrite/multiline_adjlist.py b/extensions/fablabchemnitz/networkx/readwrite/multiline_adjlist.py deleted file mode 100644 index 34c5d78b..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/multiline_adjlist.py +++ /dev/null @@ -1,382 +0,0 @@ -# -*- coding: utf-8 -*- -""" -************************* -Multi-line Adjacency List -************************* -Read and write NetworkX graphs as multi-line adjacency lists. - -The multi-line adjacency list format is useful for graphs with -nodes that can be meaningfully represented as strings. With this format -simple edge data can be stored but node or graph data is not. - -Format ------- -The first label in a line is the source node label followed by the node degree -d. The next d lines are target node labels and optional edge data. -That pattern repeats for all nodes in the graph. - -The graph with edges a-b, a-c, d-e can be represented as the following -adjacency list (anything following the # in a line is a comment):: - - # example.multiline-adjlist - a 2 - b - c - d 1 - e -""" -__author__ = '\n'.join(['Aric Hagberg ', - 'Dan Schult ', - 'Loïc Séguin-C. ']) -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. - -__all__ = ['generate_multiline_adjlist', - 'write_multiline_adjlist', - 'parse_multiline_adjlist', - 'read_multiline_adjlist'] - -from networkx.utils import make_str, open_file -import networkx as nx - - -def generate_multiline_adjlist(G, delimiter=' '): - """Generate a single line of the graph G in multiline adjacency list format. - - Parameters - ---------- - G : NetworkX graph - - delimiter : string, optional - Separator for node labels - - Returns - ------- - lines : string - Lines of data in multiline adjlist format. - - Examples - -------- - >>> G = nx.lollipop_graph(4, 3) - >>> for line in nx.generate_multiline_adjlist(G): - ... print(line) - 0 3 - 1 {} - 2 {} - 3 {} - 1 2 - 2 {} - 3 {} - 2 1 - 3 {} - 3 1 - 4 {} - 4 1 - 5 {} - 5 1 - 6 {} - 6 0 - - See Also - -------- - write_multiline_adjlist, read_multiline_adjlist - """ - if G.is_directed(): - if G.is_multigraph(): - for s, nbrs in G.adjacency(): - nbr_edges = [(u, data) - for u, datadict in nbrs.items() - for key, data in datadict.items()] - deg = len(nbr_edges) - yield make_str(s) + delimiter + str(deg) - for u, d in nbr_edges: - if d is None: - yield make_str(u) - else: - yield make_str(u) + delimiter + make_str(d) - else: # directed single edges - for s, nbrs in G.adjacency(): - deg = len(nbrs) - yield make_str(s) + delimiter + str(deg) - for u, d in nbrs.items(): - if d is None: - yield make_str(u) - else: - yield make_str(u) + delimiter + make_str(d) - else: # undirected - if G.is_multigraph(): - seen = set() # helper dict used to avoid duplicate edges - for s, nbrs in G.adjacency(): - nbr_edges = [(u, data) - for u, datadict in nbrs.items() - if u not in seen - for key, data in datadict.items()] - deg = len(nbr_edges) - yield make_str(s) + delimiter + str(deg) - for u, d in nbr_edges: - if d is None: - yield make_str(u) - else: - yield make_str(u) + delimiter + make_str(d) - seen.add(s) - else: # undirected single edges - seen = set() # helper dict used to avoid duplicate edges - for s, nbrs in G.adjacency(): - nbr_edges = [(u, d) for u, d in nbrs.items() if u not in seen] - deg = len(nbr_edges) - yield make_str(s) + delimiter + str(deg) - for u, d in nbr_edges: - if d is None: - yield make_str(u) - else: - yield make_str(u) + delimiter + make_str(d) - seen.add(s) - - -@open_file(1, mode='wb') -def write_multiline_adjlist(G, path, delimiter=' ', - comments='#', encoding='utf-8'): - """ Write the graph G in multiline adjacency list format to path - - Parameters - ---------- - G : NetworkX graph - - comments : string, optional - Marker for comment lines - - delimiter : string, optional - Separator for node labels - - encoding : string, optional - Text encoding. - - Examples - -------- - >>> G=nx.path_graph(4) - >>> nx.write_multiline_adjlist(G,"test.adjlist") - - The path can be a file handle or a string with the name of the file. If a - file handle is provided, it has to be opened in 'wb' mode. - - >>> fh=open("test.adjlist",'wb') - >>> nx.write_multiline_adjlist(G,fh) - - Filenames ending in .gz or .bz2 will be compressed. - - >>> nx.write_multiline_adjlist(G,"test.adjlist.gz") - - See Also - -------- - read_multiline_adjlist - """ - import sys - import time - - pargs = comments + " ".join(sys.argv) - header = ("{}\n".format(pargs) - + comments + " GMT {}\n".format(time.asctime(time.gmtime())) - + comments + " {}\n".format(G.name)) - path.write(header.encode(encoding)) - - for multiline in generate_multiline_adjlist(G, delimiter): - multiline += '\n' - path.write(multiline.encode(encoding)) - - -def parse_multiline_adjlist(lines, comments='#', delimiter=None, - create_using=None, nodetype=None, - edgetype=None): - """Parse lines of a multiline adjacency list representation of a graph. - - Parameters - ---------- - lines : list or iterator of strings - Input data in multiline adjlist format - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - nodetype : Python type, optional - Convert nodes to this type. - - comments : string, optional - Marker for comment lines - - delimiter : string, optional - Separator for node labels. The default is whitespace. - - Returns - ------- - G: NetworkX graph - The graph corresponding to the lines in multiline adjacency list format. - - Examples - -------- - >>> lines = ['1 2', - ... "2 {'weight':3, 'name': 'Frodo'}", - ... "3 {}", - ... "2 1", - ... "5 {'weight':6, 'name': 'Saruman'}"] - >>> G = nx.parse_multiline_adjlist(iter(lines), nodetype=int) - >>> list(G) - [1, 2, 3, 5] - - """ - from ast import literal_eval - G = nx.empty_graph(0, create_using) - for line in lines: - p = line.find(comments) - if p >= 0: - line = line[:p] - if not line: - continue - try: - (u, deg) = line.strip().split(delimiter) - deg = int(deg) - except: - raise TypeError("Failed to read node and degree on line ({})".format(line)) - if nodetype is not None: - try: - u = nodetype(u) - except: - raise TypeError("Failed to convert node ({}) to type {}" - .format(u, nodetype)) - G.add_node(u) - for i in range(deg): - while True: - try: - line = next(lines) - except StopIteration: - msg = "Failed to find neighbor for node ({})".format(u) - raise TypeError(msg) - p = line.find(comments) - if p >= 0: - line = line[:p] - if line: - break - vlist = line.strip().split(delimiter) - numb = len(vlist) - if numb < 1: - continue # isolated node - v = vlist.pop(0) - data = ''.join(vlist) - if nodetype is not None: - try: - v = nodetype(v) - except: - raise TypeError( - "Failed to convert node ({}) to type {}" - .format(v, nodetype)) - if edgetype is not None: - try: - edgedata = {'weight': edgetype(data)} - except: - raise TypeError( - "Failed to convert edge data ({}) to type {}" - .format(data, edgetype)) - else: - try: # try to evaluate - edgedata = literal_eval(data) - except: - edgedata = {} - G.add_edge(u, v, **edgedata) - - return G - - -@open_file(0, mode='rb') -def read_multiline_adjlist(path, comments="#", delimiter=None, - create_using=None, - nodetype=None, edgetype=None, - encoding='utf-8'): - """Read graph in multi-line adjacency list format from path. - - Parameters - ---------- - path : string or file - Filename or file handle to read. - Filenames ending in .gz or .bz2 will be uncompressed. - - create_using : NetworkX graph constructor, optional (default=nx.Graph) - Graph type to create. If graph instance, then cleared before populated. - - nodetype : Python type, optional - Convert nodes to this type. - - edgetype : Python type, optional - Convert edge data to this type. - - comments : string, optional - Marker for comment lines - - delimiter : string, optional - Separator for node labels. The default is whitespace. - - Returns - ------- - G: NetworkX graph - - Examples - -------- - >>> G=nx.path_graph(4) - >>> nx.write_multiline_adjlist(G,"test.adjlist") - >>> G=nx.read_multiline_adjlist("test.adjlist") - - The path can be a file or a string with the name of the file. If a - file s provided, it has to be opened in 'rb' mode. - - >>> fh=open("test.adjlist", 'rb') - >>> G=nx.read_multiline_adjlist(fh) - - Filenames ending in .gz or .bz2 will be compressed. - - >>> nx.write_multiline_adjlist(G,"test.adjlist.gz") - >>> G=nx.read_multiline_adjlist("test.adjlist.gz") - - The optional nodetype is a function to convert node strings to nodetype. - - For example - - >>> G=nx.read_multiline_adjlist("test.adjlist", nodetype=int) - - will attempt to convert all nodes to integer type. - - The optional edgetype is a function to convert edge data strings to - edgetype. - - >>> G=nx.read_multiline_adjlist("test.adjlist") - - The optional create_using parameter is a NetworkX graph container. - The default is Graph(), an undirected graph. To read the data as - a directed graph use - - >>> G=nx.read_multiline_adjlist("test.adjlist", create_using=nx.DiGraph) - - Notes - ----- - This format does not store graph, node, or edge data. - - See Also - -------- - write_multiline_adjlist - """ - lines = (line.decode(encoding) for line in path) - return parse_multiline_adjlist(lines, - comments=comments, - delimiter=delimiter, - create_using=create_using, - nodetype=nodetype, - edgetype=edgetype) - - -# fixture for pytest -def teardown_module(module): - import os - for fname in ['test.adjlist', 'test.adjlist.gz']: - if os.path.isfile(fname): - os.unlink(fname) diff --git a/extensions/fablabchemnitz/networkx/readwrite/nx_shp.py b/extensions/fablabchemnitz/networkx/readwrite/nx_shp.py deleted file mode 100644 index 906c07af..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/nx_shp.py +++ /dev/null @@ -1,331 +0,0 @@ -""" -********* -Shapefile -********* - -Generates a networkx.DiGraph from point and line shapefiles. - -"The Esri Shapefile or simply a shapefile is a popular geospatial vector -data format for geographic information systems software. It is developed -and regulated by Esri as a (mostly) open specification for data -interoperability among Esri and other software products." -See https://en.wikipedia.org/wiki/Shapefile for additional information. -""" -# Copyright (C) 2004-2019 by -# Ben Reilly -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -import networkx as nx -__author__ = """Ben Reilly (benwreilly@gmail.com)""" -__all__ = ['read_shp', 'write_shp'] - - -def read_shp(path, simplify=True, geom_attrs=True, strict=True): - """Generates a networkx.DiGraph from shapefiles. Point geometries are - translated into nodes, lines into edges. Coordinate tuples are used as - keys. Attributes are preserved, line geometries are simplified into start - and end coordinates. Accepts a single shapefile or directory of many - shapefiles. - - "The Esri Shapefile or simply a shapefile is a popular geospatial vector - data format for geographic information systems software [1]_." - - Parameters - ---------- - path : file or string - File, directory, or filename to read. - - simplify: bool - If True, simplify line geometries to start and end coordinates. - If False, and line feature geometry has multiple segments, the - non-geometric attributes for that feature will be repeated for each - edge comprising that feature. - - geom_attrs: bool - If True, include the Wkb, Wkt and Json geometry attributes with - each edge. - - NOTE: if these attributes are available, write_shp will use them - to write the geometry. If nodes store the underlying coordinates for - the edge geometry as well (as they do when they are read via - this method) and they change, your geomety will be out of sync. - - strict: bool - If True, raise NetworkXError when feature geometry is missing or - GeometryType is not supported. - If False, silently ignore missing or unsupported geometry in features. - - Returns - ------- - G : NetworkX graph - - Raises - ------ - ImportError - If ogr module is not available. - - RuntimeError - If file cannot be open or read. - - NetworkXError - If strict=True and feature is missing geometry or GeometryType is - not supported. - - Examples - -------- - >>> G=nx.read_shp('test.shp') # doctest: +SKIP - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Shapefile - """ - try: - from osgeo import ogr - except ImportError: - raise ImportError("read_shp requires OGR: http://www.gdal.org/") - - if not isinstance(path, str): - return - - net = nx.DiGraph() - shp = ogr.Open(path) - if shp is None: - raise RuntimeError("Unable to open {}".format(path)) - for lyr in shp: - fields = [x.GetName() for x in lyr.schema] - for f in lyr: - g = f.geometry() - if g is None: - if strict: - raise nx.NetworkXError("Bad data: feature missing geometry") - else: - continue - flddata = [f.GetField(f.GetFieldIndex(x)) for x in fields] - attributes = dict(zip(fields, flddata)) - attributes["ShpName"] = lyr.GetName() - # Note: Using layer level geometry type - if g.GetGeometryType() == ogr.wkbPoint: - net.add_node((g.GetPoint_2D(0)), **attributes) - elif g.GetGeometryType() in (ogr.wkbLineString, - ogr.wkbMultiLineString): - for edge in edges_from_line(g, attributes, simplify, - geom_attrs): - e1, e2, attr = edge - net.add_edge(e1, e2) - net[e1][e2].update(attr) - else: - if strict: - raise nx.NetworkXError("GeometryType {} not supported". - format(g.GetGeometryType())) - - return net - - -def edges_from_line(geom, attrs, simplify=True, geom_attrs=True): - """ - Generate edges for each line in geom - Written as a helper for read_shp - - Parameters - ---------- - - geom: ogr line geometry - To be converted into an edge or edges - - attrs: dict - Attributes to be associated with all geoms - - simplify: bool - If True, simplify the line as in read_shp - - geom_attrs: bool - If True, add geom attributes to edge as in read_shp - - - Returns - ------- - edges: generator of edges - each edge is a tuple of form - (node1_coord, node2_coord, attribute_dict) - suitable for expanding into a networkx Graph add_edge call - """ - try: - from osgeo import ogr - except ImportError: - raise ImportError("edges_from_line requires OGR: http://www.gdal.org/") - - if geom.GetGeometryType() == ogr.wkbLineString: - if simplify: - edge_attrs = attrs.copy() - last = geom.GetPointCount() - 1 - if geom_attrs: - edge_attrs["Wkb"] = geom.ExportToWkb() - edge_attrs["Wkt"] = geom.ExportToWkt() - edge_attrs["Json"] = geom.ExportToJson() - yield (geom.GetPoint_2D(0), geom.GetPoint_2D(last), edge_attrs) - else: - for i in range(0, geom.GetPointCount() - 1): - pt1 = geom.GetPoint_2D(i) - pt2 = geom.GetPoint_2D(i + 1) - edge_attrs = attrs.copy() - if geom_attrs: - segment = ogr.Geometry(ogr.wkbLineString) - segment.AddPoint_2D(pt1[0], pt1[1]) - segment.AddPoint_2D(pt2[0], pt2[1]) - edge_attrs["Wkb"] = segment.ExportToWkb() - edge_attrs["Wkt"] = segment.ExportToWkt() - edge_attrs["Json"] = segment.ExportToJson() - del segment - yield (pt1, pt2, edge_attrs) - - elif geom.GetGeometryType() == ogr.wkbMultiLineString: - for i in range(geom.GetGeometryCount()): - geom_i = geom.GetGeometryRef(i) - for edge in edges_from_line(geom_i, attrs, simplify, geom_attrs): - yield edge - - -def write_shp(G, outdir): - """Writes a networkx.DiGraph to two shapefiles, edges and nodes. - Nodes and edges are expected to have a Well Known Binary (Wkb) or - Well Known Text (Wkt) key in order to generate geometries. Also - acceptable are nodes with a numeric tuple key (x,y). - - "The Esri Shapefile or simply a shapefile is a popular geospatial vector - data format for geographic information systems software [1]_." - - Parameters - ---------- - outdir : directory path - Output directory for the two shapefiles. - - Returns - ------- - None - - Examples - -------- - nx.write_shp(digraph, '/shapefiles') # doctest +SKIP - - References - ---------- - .. [1] https://en.wikipedia.org/wiki/Shapefile - """ - try: - from osgeo import ogr - except ImportError: - raise ImportError("write_shp requires OGR: http://www.gdal.org/") - # easier to debug in python if ogr throws exceptions - ogr.UseExceptions() - - def netgeometry(key, data): - if 'Wkb' in data: - geom = ogr.CreateGeometryFromWkb(data['Wkb']) - elif 'Wkt' in data: - geom = ogr.CreateGeometryFromWkt(data['Wkt']) - elif type(key[0]).__name__ == 'tuple': # edge keys are packed tuples - geom = ogr.Geometry(ogr.wkbLineString) - _from, _to = key[0], key[1] - try: - geom.SetPoint(0, *_from) - geom.SetPoint(1, *_to) - except TypeError: - # assume user used tuple of int and choked ogr - _ffrom = [float(x) for x in _from] - _fto = [float(x) for x in _to] - geom.SetPoint(0, *_ffrom) - geom.SetPoint(1, *_fto) - else: - geom = ogr.Geometry(ogr.wkbPoint) - try: - geom.SetPoint(0, *key) - except TypeError: - # assume user used tuple of int and choked ogr - fkey = [float(x) for x in key] - geom.SetPoint(0, *fkey) - - return geom - - # Create_feature with new optional attributes arg (should be dict type) - def create_feature(geometry, lyr, attributes=None): - feature = ogr.Feature(lyr.GetLayerDefn()) - feature.SetGeometry(g) - if attributes is not None: - # Loop through attributes, assigning data to each field - for field, data in attributes.items(): - feature.SetField(field, data) - lyr.CreateFeature(feature) - feature.Destroy() - - # Conversion dict between python and ogr types - OGRTypes = {int: ogr.OFTInteger, str: ogr.OFTString, float: ogr.OFTReal} - - # Check/add fields from attribute data to Shapefile layers - def add_fields_to_layer(key, value, fields, layer): - # Field not in previous edges so add to dict - if type(value) in OGRTypes: - fields[key] = OGRTypes[type(value)] - else: - # Data type not supported, default to string (char 80) - fields[key] = ogr.OFTString - # Create the new field - newfield = ogr.FieldDefn(key, fields[key]) - layer.CreateField(newfield) - - - drv = ogr.GetDriverByName("ESRI Shapefile") - shpdir = drv.CreateDataSource(outdir) - # delete pre-existing output first otherwise ogr chokes - try: - shpdir.DeleteLayer("nodes") - except: - pass - nodes = shpdir.CreateLayer("nodes", None, ogr.wkbPoint) - - # Storage for node field names and their data types - node_fields = {} - - def create_attributes(data, fields, layer): - attributes = {} # storage for attribute data (indexed by field names) - for key, value in data.items(): - # Reject spatial data not required for attribute table - if (key != 'Json' and key != 'Wkt' and key != 'Wkb' - and key != 'ShpName'): - # Check/add field and data type to fields dict - if key not in fields: - add_fields_to_layer(key, value, fields, layer) - # Store the data from new field to dict for CreateLayer() - attributes[key] = value - return attributes, layer - - for n in G: - data = G.nodes[n] - g = netgeometry(n, data) - attributes, nodes = create_attributes(data, node_fields, nodes) - create_feature(g, nodes, attributes) - - try: - shpdir.DeleteLayer("edges") - except: - pass - edges = shpdir.CreateLayer("edges", None, ogr.wkbLineString) - - # New edge attribute write support merged into edge loop - edge_fields = {} # storage for field names and their data types - - for e in G.edges(data=True): - data = G.get_edge_data(*e) - g = netgeometry(e, data) - attributes, edges = create_attributes(e[2], edge_fields, edges) - create_feature(g, edges, attributes) - - nodes, edges = None, None - - -# fixture for pytest -def setup_module(module): - import pytest - ogr = pytest.importorskip('ogr') diff --git a/extensions/fablabchemnitz/networkx/readwrite/nx_yaml.py b/extensions/fablabchemnitz/networkx/readwrite/nx_yaml.py deleted file mode 100644 index 8e60a084..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/nx_yaml.py +++ /dev/null @@ -1,114 +0,0 @@ -""" -**** -YAML -**** -Read and write NetworkX graphs in YAML format. - -"YAML is a data serialization format designed for human readability -and interaction with scripting languages." -See http://www.yaml.org for documentation. - -Format ------- -http://pyyaml.org/wiki/PyYAML - -""" -__author__ = """Aric Hagberg (hagberg@lanl.gov)""" -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. - -__all__ = ['read_yaml', 'write_yaml'] - -import networkx as nx -from networkx.utils import open_file - - -@open_file(1, mode='w') -def write_yaml(G_to_be_yaml, path_for_yaml_output, **kwds): - """Write graph G in YAML format to path. - - YAML is a data serialization format designed for human readability - and interaction with scripting languages [1]_. - - Parameters - ---------- - G : graph - A NetworkX graph - path : file or string - File or filename to write. - Filenames ending in .gz or .bz2 will be compressed. - - Notes - ----- - To use encoding on the output file include e.g. `encoding='utf-8'` - in the keyword arguments. - - Examples - -------- - >>> G=nx.path_graph(4) - >>> nx.write_yaml(G,'test.yaml') - - References - ---------- - .. [1] http://www.yaml.org - """ - try: - import yaml - except ImportError: - raise ImportError("write_yaml() requires PyYAML: http://pyyaml.org/") - yaml.dump(G_to_be_yaml, path_for_yaml_output, **kwds) - - -@open_file(0, mode='r') -def read_yaml(path): - """Read graph in YAML format from path. - - YAML is a data serialization format designed for human readability - and interaction with scripting languages [1]_. - - Parameters - ---------- - path : file or string - File or filename to read. Filenames ending in .gz or .bz2 - will be uncompressed. - - Returns - ------- - G : NetworkX graph - - Examples - -------- - >>> G=nx.path_graph(4) - >>> nx.write_yaml(G,'test.yaml') - >>> G=nx.read_yaml('test.yaml') - - References - ---------- - .. [1] http://www.yaml.org - - """ - try: - import yaml - except ImportError: - raise ImportError("read_yaml() requires PyYAML: http://pyyaml.org/") - - G = yaml.load(path, Loader=yaml.FullLoader) - return G - - -# fixture for pytest -def setup_module(module): - try: - import yaml - except: - from pytest import skip - skip("PyYAML not available", allow_module_level=True) - -# fixture for pytest -def teardown_module(module): - import os - os.unlink('test.yaml') diff --git a/extensions/fablabchemnitz/networkx/readwrite/p2g.py b/extensions/fablabchemnitz/networkx/readwrite/p2g.py deleted file mode 100644 index 934c4564..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/p2g.py +++ /dev/null @@ -1,110 +0,0 @@ -""" -This module provides the following: read and write of p2g format -used in metabolic pathway studies. - -See https://web.archive.org/web/20080626113807/http://www.cs.purdue.edu/homes/koyuturk/pathway/ for a description. - -The summary is included here: - -A file that describes a uniquely labeled graph (with extension ".gr") -format looks like the following: - - -name -3 4 -a -1 2 -b - -c -0 2 - -"name" is simply a description of what the graph corresponds to. The -second line displays the number of nodes and number of edges, -respectively. This sample graph contains three nodes labeled "a", "b", -and "c". The rest of the graph contains two lines for each node. The -first line for a node contains the node label. After the declaration -of the node label, the out-edges of that node in the graph are -provided. For instance, "a" is linked to nodes 1 and 2, which are -labeled "b" and "c", while the node labeled "b" has no outgoing -edges. Observe that node labeled "c" has an outgoing edge to -itself. Indeed, self-loops are allowed. Node index starts from 0. - -""" -# Copyright (C) 2008-2012 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -import networkx -from networkx.utils import is_string_like, open_file -__author__ = '\n'.join(['Willem Ligtenberg (w.p.a.ligtenberg@tue.nl)', - 'Aric Hagberg (aric.hagberg@gmail.com)']) - - -@open_file(1, mode='w') -def write_p2g(G, path, encoding='utf-8'): - """Write NetworkX graph in p2g format. - - Notes - ----- - This format is meant to be used with directed graphs with - possible self loops. - """ - path.write(("%s\n" % G.name).encode(encoding)) - path.write(("%s %s\n" % (G.order(), G.size())).encode(encoding)) - nodes = list(G) - # make dictionary mapping nodes to integers - nodenumber = dict(zip(nodes, range(len(nodes)))) - for n in nodes: - path.write(("%s\n" % n).encode(encoding)) - for nbr in G.neighbors(n): - path.write(("%s " % nodenumber[nbr]).encode(encoding)) - path.write("\n".encode(encoding)) - - -@open_file(0, mode='r') -def read_p2g(path, encoding='utf-8'): - """Read graph in p2g format from path. - - Returns - ------- - MultiDiGraph - - Notes - ----- - If you want a DiGraph (with no self loops allowed and no edge data) - use D=networkx.DiGraph(read_p2g(path)) - """ - lines = (line.decode(encoding) for line in path) - G = parse_p2g(lines) - return G - - -def parse_p2g(lines): - """Parse p2g format graph from string or iterable. - - Returns - ------- - MultiDiGraph - """ - description = next(lines).strip() - # are multiedges (parallel edges) allowed? - G = networkx.MultiDiGraph(name=description, selfloops=True) - nnodes, nedges = map(int, next(lines).split()) - nodelabel = {} - nbrs = {} - # loop over the nodes keeping track of node labels and out neighbors - # defer adding edges until all node labels are known - for i in range(nnodes): - n = next(lines).strip() - nodelabel[i] = n - G.add_node(n) - nbrs[n] = map(int, next(lines).split()) - # now we know all of the node labels so we can add the edges - # with the correct labels - for n in G: - for nbr in nbrs[n]: - G.add_edge(n, nodelabel[nbr]) - return G diff --git a/extensions/fablabchemnitz/networkx/readwrite/pajek.py b/extensions/fablabchemnitz/networkx/readwrite/pajek.py deleted file mode 100644 index c9774d01..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/pajek.py +++ /dev/null @@ -1,286 +0,0 @@ -# Copyright (C) 2008-2014 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg (hagberg@lanl.gov) -""" -***** -Pajek -***** -Read graphs in Pajek format. - -This implementation handles directed and undirected graphs including -those with self loops and parallel edges. - -Format ------- -See http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/draweps.htm -for format information. - -""" - -import warnings - -import networkx as nx -from networkx.utils import is_string_like, open_file, make_str - -__all__ = ['read_pajek', 'parse_pajek', 'generate_pajek', 'write_pajek'] - - -def generate_pajek(G): - """Generate lines in Pajek graph format. - - Parameters - ---------- - G : graph - A Networkx graph - - References - ---------- - See http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/draweps.htm - for format information. - """ - if G.name == '': - name = 'NetworkX' - else: - name = G.name - # Apparently many Pajek format readers can't process this line - # So we'll leave it out for now. - # yield '*network %s'%name - - # write nodes with attributes - yield '*vertices %s' % (G.order()) - nodes = list(G) - # make dictionary mapping nodes to integers - nodenumber = dict(zip(nodes, range(1, len(nodes) + 1))) - for n in nodes: - # copy node attributes and pop mandatory attributes - # to avoid duplication. - na = G.nodes.get(n, {}).copy() - x = na.pop('x', 0.0) - y = na.pop('y', 0.0) - id = int(na.pop('id', nodenumber[n])) - nodenumber[n] = id - shape = na.pop('shape', 'ellipse') - s = ' '.join(map(make_qstr, (id, n, x, y, shape))) - # only optional attributes are left in na. - for k, v in na.items(): - if is_string_like(v) and v.strip() != '': - s += ' %s %s' % (make_qstr(k), make_qstr(v)) - else: - warnings.warn('Node attribute %s is not processed. %s.' % - (k, - 'Empty attribute' if is_string_like(v) else - 'Non-string attribute')) - yield s - - # write edges with attributes - if G.is_directed(): - yield '*arcs' - else: - yield '*edges' - for u, v, edgedata in G.edges(data=True): - d = edgedata.copy() - value = d.pop('weight', 1.0) # use 1 as default edge value - s = ' '.join(map(make_qstr, (nodenumber[u], nodenumber[v], value))) - for k, v in d.items(): - if is_string_like(v) and v.strip() != '': - s += ' %s %s' % (make_qstr(k), make_qstr(v)) - else: - warnings.warn('Edge attribute %s is not processed. %s.' % - (k, - 'Empty attribute' if is_string_like(v) else - 'Non-string attribute')) - yield s - - -@open_file(1, mode='wb') -def write_pajek(G, path, encoding='UTF-8'): - """Write graph in Pajek format to path. - - Parameters - ---------- - G : graph - A Networkx graph - path : file or string - File or filename to write. - Filenames ending in .gz or .bz2 will be compressed. - - Examples - -------- - >>> G=nx.path_graph(4) - >>> nx.write_pajek(G, "test.net") - - Warnings - -------- - Optional node attributes and edge attributes must be non-empty strings. - Otherwise it will not be written into the file. You will need to - convert those attributes to strings if you want to keep them. - - References - ---------- - See http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/draweps.htm - for format information. - """ - for line in generate_pajek(G): - line += '\n' - path.write(line.encode(encoding)) - - -@open_file(0, mode='rb') -def read_pajek(path, encoding='UTF-8'): - """Read graph in Pajek format from path. - - Parameters - ---------- - path : file or string - File or filename to write. - Filenames ending in .gz or .bz2 will be uncompressed. - - Returns - ------- - G : NetworkX MultiGraph or MultiDiGraph. - - Examples - -------- - >>> G=nx.path_graph(4) - >>> nx.write_pajek(G, "test.net") - >>> G=nx.read_pajek("test.net") - - To create a Graph instead of a MultiGraph use - - >>> G1=nx.Graph(G) - - References - ---------- - See http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/draweps.htm - for format information. - """ - lines = (line.decode(encoding) for line in path) - return parse_pajek(lines) - - -def parse_pajek(lines): - """Parse Pajek format graph from string or iterable. - - Parameters - ---------- - lines : string or iterable - Data in Pajek format. - - Returns - ------- - G : NetworkX graph - - See Also - -------- - read_pajek() - - """ - import shlex - # multigraph=False - if is_string_like(lines): - lines = iter(lines.split('\n')) - lines = iter([line.rstrip('\n') for line in lines]) - G = nx.MultiDiGraph() # are multiedges allowed in Pajek? assume yes - labels = [] # in the order of the file, needed for matrix - while lines: - try: - l = next(lines) - except: # EOF - break - if l.lower().startswith("*network"): - try: - label, name = l.split(None, 1) - except ValueError: - # Line was not of the form: *network NAME - pass - else: - G.graph['name'] = name - elif l.lower().startswith("*vertices"): - nodelabels = {} - l, nnodes = l.split() - for i in range(int(nnodes)): - l = next(lines) - try: - splitline = [x.decode('utf-8') for x in - shlex.split(make_str(l).encode('utf-8'))] - except AttributeError: - splitline = shlex.split(str(l)) - id, label = splitline[0:2] - labels.append(label) - G.add_node(label) - nodelabels[id] = label - G.nodes[label]['id'] = id - try: - x, y, shape = splitline[2:5] - G.nodes[label].update({'x': float(x), - 'y': float(y), - 'shape': shape}) - except: - pass - extra_attr = zip(splitline[5::2], splitline[6::2]) - G.nodes[label].update(extra_attr) - elif l.lower().startswith("*edges") or l.lower().startswith("*arcs"): - if l.lower().startswith("*edge"): - # switch from multidigraph to multigraph - G = nx.MultiGraph(G) - if l.lower().startswith("*arcs"): - # switch to directed with multiple arcs for each existing edge - G = G.to_directed() - for l in lines: - try: - splitline = [x.decode('utf-8') for x in - shlex.split(make_str(l).encode('utf-8'))] - except AttributeError: - splitline = shlex.split(str(l)) - - if len(splitline) < 2: - continue - ui, vi = splitline[0:2] - u = nodelabels.get(ui, ui) - v = nodelabels.get(vi, vi) - # parse the data attached to this edge and put in a dictionary - edge_data = {} - try: - # there should always be a single value on the edge? - w = splitline[2:3] - edge_data.update({'weight': float(w[0])}) - except: - pass - # if there isn't, just assign a 1 -# edge_data.update({'value':1}) - extra_attr = zip(splitline[3::2], splitline[4::2]) - edge_data.update(extra_attr) - # if G.has_edge(u,v): - # multigraph=True - G.add_edge(u, v, **edge_data) - elif l.lower().startswith("*matrix"): - G = nx.DiGraph(G) - adj_list = ((labels[row], labels[col], {'weight': int(data)}) - for (row, line) in enumerate(lines) - for (col, data) in enumerate(line.split()) - if int(data) != 0) - G.add_edges_from(adj_list) - - return G - - -def make_qstr(t): - """Returns the string representation of t. - Add outer double-quotes if the string has a space. - """ - if not is_string_like(t): - t = str(t) - if " " in t: - t = r'"%s"' % t - return t - - -# fixture for pytest -def teardown_module(module): - import os - os.unlink('test.net') diff --git a/extensions/fablabchemnitz/networkx/readwrite/sparse6.py b/extensions/fablabchemnitz/networkx/readwrite/sparse6.py deleted file mode 100644 index 9b7b9088..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/sparse6.py +++ /dev/null @@ -1,384 +0,0 @@ -# Original author: D. Eppstein, UC Irvine, August 12, 2003. -# The original code at http://www.ics.uci.edu/~eppstein/PADS/ is public domain. -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# Tomas Gavenciak -# All rights reserved. -# BSD license. -# -# Authors: Tomas Gavenciak -# Aric Hagberg -"""Functions for reading and writing graphs in the *sparse6* format. - -The *sparse6* file format is a space-efficient format for large sparse -graphs. For small graphs or large dense graphs, use the *graph6* file -format. - -For more information, see the `sparse6`_ homepage. - -.. _sparse6: http://users.cecs.anu.edu.au/~bdm/data/formats.html - -""" -from itertools import chain -import math -import sys - -import networkx as nx -from networkx.exception import NetworkXError -from networkx.utils import open_file, not_implemented_for -from networkx.readwrite.graph6 import data_to_n, n_to_data - -__all__ = ['from_sparse6_bytes', 'read_sparse6', 'to_sparse6_bytes', - 'write_sparse6'] - - -def _generate_sparse6_bytes(G, nodes, header): - """Yield bytes in the sparse6 encoding of a graph. - - `G` is an undirected simple graph. `nodes` is the list of nodes for - which the node-induced subgraph will be encoded; if `nodes` is the - list of all nodes in the graph, the entire graph will be - encoded. `header` is a Boolean that specifies whether to generate - the header ``b'>>sparse6<<'`` before the remaining data. - - This function generates `bytes` objects in the following order: - - 1. the header (if requested), - 2. the encoding of the number of nodes, - 3. each character, one-at-a-time, in the encoding of the requested - node-induced subgraph, - 4. a newline character. - - This function raises :exc:`ValueError` if the graph is too large for - the graph6 format (that is, greater than ``2 ** 36`` nodes). - - """ - n = len(G) - if n >= 2 ** 36: - raise ValueError('sparse6 is only defined if number of nodes is less ' - 'than 2 ** 36') - if header: - yield b'>>sparse6<<' - yield b':' - for d in n_to_data(n): - yield str.encode(chr(d + 63)) - - k = 1 - while 1 << k < n: - k += 1 - - def enc(x): - """Big endian k-bit encoding of x""" - return [1 if (x & 1 << (k - 1 - i)) else 0 for i in range(k)] - - edges = sorted((max(u, v), min(u, v)) for u, v in G.edges()) - bits = [] - curv = 0 - for (v, u) in edges: - if v == curv: # current vertex edge - bits.append(0) - bits.extend(enc(u)) - elif v == curv + 1: # next vertex edge - curv += 1 - bits.append(1) - bits.extend(enc(u)) - else: # skip to vertex v and then add edge to u - curv = v - bits.append(1) - bits.extend(enc(v)) - bits.append(0) - bits.extend(enc(u)) - if k < 6 and n == (1 << k) and ((-len(bits)) % 6) >= k and curv < (n - 1): - # Padding special case: small k, n=2^k, - # more than k bits of padding needed, - # current vertex is not (n-1) -- - # appending 1111... would add a loop on (n-1) - bits.append(0) - bits.extend([1] * ((-len(bits)) % 6)) - else: - bits.extend([1] * ((-len(bits)) % 6)) - - data = [(bits[i + 0] << 5) + (bits[i + 1] << 4) + (bits[i + 2] << 3) + (bits[i + 3] << 2) + - (bits[i + 4] << 1) + (bits[i + 5] << 0) for i in range(0, len(bits), 6)] - - for d in data: - yield str.encode(chr(d + 63)) - yield b'\n' - - -def from_sparse6_bytes(string): - """Read an undirected graph in sparse6 format from string. - - Parameters - ---------- - string : string - Data in sparse6 format - - Returns - ------- - G : Graph - - Raises - ------ - NetworkXError - If the string is unable to be parsed in sparse6 format - - Examples - -------- - >>> G = nx.from_sparse6_bytes(b':A_') - >>> sorted(G.edges()) - [(0, 1), (0, 1), (0, 1)] - - See Also - -------- - read_sparse6, write_sparse6 - - References - ---------- - .. [1] Sparse6 specification - - - """ - if string.startswith(b'>>sparse6<<'): - string = string[11:] - if not string.startswith(b':'): - raise NetworkXError('Expected leading colon in sparse6') - - if sys.version_info < (3, ): - chars = [ord(c) - 63 for c in string[1:]] - else: - chars = [c - 63 for c in string[1:]] - n, data = data_to_n(chars) - k = 1 - while 1 << k < n: - k += 1 - - def parseData(): - """Returns stream of pairs b[i], x[i] for sparse6 format.""" - chunks = iter(data) - d = None # partial data word - dLen = 0 # how many unparsed bits are left in d - - while 1: - if dLen < 1: - try: - d = next(chunks) - except StopIteration: - return - dLen = 6 - dLen -= 1 - b = (d >> dLen) & 1 # grab top remaining bit - - x = d & ((1 << dLen) - 1) # partially built up value of x - xLen = dLen # how many bits included so far in x - while xLen < k: # now grab full chunks until we have enough - try: - d = next(chunks) - except StopIteration: - return - dLen = 6 - x = (x << 6) + d - xLen += 6 - x = (x >> (xLen - k)) # shift back the extra bits - dLen = xLen - k - yield b, x - - v = 0 - - G = nx.MultiGraph() - G.add_nodes_from(range(n)) - - multigraph = False - for b, x in parseData(): - if b == 1: - v += 1 - # padding with ones can cause overlarge number here - if x >= n or v >= n: - break - elif x > v: - v = x - else: - if G.has_edge(x, v): - multigraph = True - G.add_edge(x, v) - if not multigraph: - G = nx.Graph(G) - return G - - -def to_sparse6_bytes(G, nodes=None, header=True): - """Convert an undirected graph to bytes in sparse6 format. - - Parameters - ---------- - G : Graph (undirected) - - nodes: list or iterable - Nodes are labeled 0...n-1 in the order provided. If None the ordering - given by ``G.nodes()`` is used. - - header: bool - If True add '>>sparse6<<' bytes to head of data. - - Raises - ------ - NetworkXNotImplemented - If the graph is directed. - - ValueError - If the graph has at least ``2 ** 36`` nodes; the sparse6 format - is only defined for graphs of order less than ``2 ** 36``. - - Examples - -------- - >>> nx.to_sparse6_bytes(nx.path_graph(2)) # doctest: +SKIP - b'>>sparse6<<:An\\n' - - See Also - -------- - to_sparse6_bytes, read_sparse6, write_sparse6_bytes - - Notes - ----- - The returned bytes end with a newline character. - - The format does not support edge or node labels. - - References - ---------- - .. [1] Graph6 specification - - - """ - if nodes is not None: - G = G.subgraph(nodes) - G = nx.convert_node_labels_to_integers(G, ordering='sorted') - return b''.join(_generate_sparse6_bytes(G, nodes, header)) - - -@open_file(0, mode='rb') -def read_sparse6(path): - """Read an undirected graph in sparse6 format from path. - - Parameters - ---------- - path : file or string - File or filename to write. - - Returns - ------- - G : Graph/Multigraph or list of Graphs/MultiGraphs - If the file contains multiple lines then a list of graphs is returned - - Raises - ------ - NetworkXError - If the string is unable to be parsed in sparse6 format - - Examples - -------- - You can read a sparse6 file by giving the path to the file:: - - >>> import tempfile - >>> with tempfile.NamedTemporaryFile() as f: - ... _ = f.write(b'>>sparse6<<:An\\n') - ... _ = f.seek(0) - ... G = nx.read_sparse6(f.name) - >>> list(G.edges()) - [(0, 1)] - - You can also read a sparse6 file by giving an open file-like object:: - - >>> import tempfile - >>> with tempfile.NamedTemporaryFile() as f: - ... _ = f.write(b'>>sparse6<<:An\\n') - ... _ = f.seek(0) - ... G = nx.read_sparse6(f) - >>> list(G.edges()) - [(0, 1)] - - See Also - -------- - read_sparse6, from_sparse6_bytes - - References - ---------- - .. [1] Sparse6 specification - - - """ - glist = [] - for line in path: - line = line.strip() - if not len(line): - continue - glist.append(from_sparse6_bytes(line)) - if len(glist) == 1: - return glist[0] - else: - return glist - - -@not_implemented_for('directed') -@open_file(1, mode='wb') -def write_sparse6(G, path, nodes=None, header=True): - """Write graph G to given path in sparse6 format. - - Parameters - ---------- - G : Graph (undirected) - - path : file or string - File or filename to write - - nodes: list or iterable - Nodes are labeled 0...n-1 in the order provided. If None the ordering - given by G.nodes() is used. - - header: bool - If True add '>>sparse6<<' string to head of data - - Raises - ------ - NetworkXError - If the graph is directed - - Examples - -------- - You can write a sparse6 file by giving the path to the file:: - - >>> import tempfile - >>> with tempfile.NamedTemporaryFile() as f: - ... nx.write_sparse6(nx.path_graph(2), f.name) - ... print(f.read()) # doctest: +SKIP - b'>>sparse6<<:An\\n' - - You can also write a sparse6 file by giving an open file-like object:: - - >>> with tempfile.NamedTemporaryFile() as f: - ... nx.write_sparse6(nx.path_graph(2), f) - ... _ = f.seek(0) - ... print(f.read()) # doctest: +SKIP - b'>>sparse6<<:An\\n' - - See Also - -------- - read_sparse6, from_sparse6_bytes - - Notes - ----- - The format does not support edge or node labels. - - References - ---------- - .. [1] Sparse6 specification - - - """ - if nodes is not None: - G = G.subgraph(nodes) - G = nx.convert_node_labels_to_integers(G, ordering='sorted') - for b in _generate_sparse6_bytes(G, nodes, header): - path.write(b) diff --git a/extensions/fablabchemnitz/networkx/readwrite/tests/__init__.py b/extensions/fablabchemnitz/networkx/readwrite/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/readwrite/tests/test_adjlist.py b/extensions/fablabchemnitz/networkx/readwrite/tests/test_adjlist.py deleted file mode 100644 index 634442e3..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/tests/test_adjlist.py +++ /dev/null @@ -1,247 +0,0 @@ -# -*- coding: utf-8 -*- -""" - Unit tests for adjlist. -""" -import io -import pytest -import os -import tempfile -import networkx as nx -from networkx.testing import (assert_nodes_equal, assert_edges_equal, - assert_graphs_equal) - - -class TestAdjlist(): - - @classmethod - def setup_class(cls): - cls.G = nx.Graph(name="test") - e = [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'e'), ('e', 'f'), ('a', 'f')] - cls.G.add_edges_from(e) - cls.G.add_node('g') - cls.DG = nx.DiGraph(cls.G) - cls.XG = nx.MultiGraph() - cls.XG.add_weighted_edges_from([(1, 2, 5), (1, 2, 5), (1, 2, 1), (3, 3, 42)]) - cls.XDG = nx.MultiDiGraph(cls.XG) - - def test_read_multiline_adjlist_1(self): - # Unit test for https://networkx.lanl.gov/trac/ticket/252 - s = b"""# comment line -1 2 -# comment line -2 -3 -""" - bytesIO = io.BytesIO(s) - G = nx.read_multiline_adjlist(bytesIO) - adj = {'1': {'3': {}, '2': {}}, '3': {'1': {}}, '2': {'1': {}}} - assert_graphs_equal(G, nx.Graph(adj)) - - def test_unicode(self): - G = nx.Graph() - try: # Python 3.x - name1 = chr(2344) + chr(123) + chr(6543) - name2 = chr(5543) + chr(1543) + chr(324) - except ValueError: # Python 2.6+ - name1 = unichr(2344) + unichr(123) + unichr(6543) - name2 = unichr(5543) + unichr(1543) + unichr(324) - G.add_edge(name1, 'Radiohead', **{name2: 3}) - fd, fname = tempfile.mkstemp() - nx.write_multiline_adjlist(G, fname) - H = nx.read_multiline_adjlist(fname) - assert_graphs_equal(G, H) - os.close(fd) - os.unlink(fname) - - def test_latin1_err(self): - G = nx.Graph() - try: # Python 3.x - name1 = chr(2344) + chr(123) + chr(6543) - name2 = chr(5543) + chr(1543) + chr(324) - except ValueError: # Python 2.6+ - name1 = unichr(2344) + unichr(123) + unichr(6543) - name2 = unichr(5543) + unichr(1543) + unichr(324) - G.add_edge(name1, 'Radiohead', **{name2: 3}) - fd, fname = tempfile.mkstemp() - pytest.raises(UnicodeEncodeError, - nx.write_multiline_adjlist, - G, fname, encoding='latin-1') - os.close(fd) - os.unlink(fname) - - def test_latin1(self): - G = nx.Graph() - try: # Python 3.x - blurb = chr(1245) # just to trigger the exception - name1 = 'Bj' + chr(246) + 'rk' - name2 = chr(220) + 'ber' - except ValueError: # Python 2.6+ - name1 = 'Bj' + unichr(246) + 'rk' - name2 = unichr(220) + 'ber' - G.add_edge(name1, 'Radiohead', **{name2: 3}) - fd, fname = tempfile.mkstemp() - nx.write_multiline_adjlist(G, fname, encoding='latin-1') - H = nx.read_multiline_adjlist(fname, encoding='latin-1') - assert_graphs_equal(G, H) - os.close(fd) - os.unlink(fname) - - def test_adjlist_graph(self): - G = self.G - (fd, fname) = tempfile.mkstemp() - nx.write_adjlist(G, fname) - H = nx.read_adjlist(fname) - H2 = nx.read_adjlist(fname) - assert H != H2 # they should be different graphs - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_adjlist_digraph(self): - G = self.DG - (fd, fname) = tempfile.mkstemp() - nx.write_adjlist(G, fname) - H = nx.read_adjlist(fname, create_using=nx.DiGraph()) - H2 = nx.read_adjlist(fname, create_using=nx.DiGraph()) - assert H != H2 # they should be different graphs - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_adjlist_integers(self): - (fd, fname) = tempfile.mkstemp() - G = nx.convert_node_labels_to_integers(self.G) - nx.write_adjlist(G, fname) - H = nx.read_adjlist(fname, nodetype=int) - H2 = nx.read_adjlist(fname, nodetype=int) - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_adjlist_multigraph(self): - G = self.XG - (fd, fname) = tempfile.mkstemp() - nx.write_adjlist(G, fname) - H = nx.read_adjlist(fname, nodetype=int, - create_using=nx.MultiGraph()) - H2 = nx.read_adjlist(fname, nodetype=int, - create_using=nx.MultiGraph()) - assert H != H2 # they should be different graphs - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_adjlist_multidigraph(self): - G = self.XDG - (fd, fname) = tempfile.mkstemp() - nx.write_adjlist(G, fname) - H = nx.read_adjlist(fname, nodetype=int, - create_using=nx.MultiDiGraph()) - H2 = nx.read_adjlist(fname, nodetype=int, - create_using=nx.MultiDiGraph()) - assert H != H2 # they should be different graphs - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_adjlist_delimiter(self): - fh = io.BytesIO() - G = nx.path_graph(3) - nx.write_adjlist(G, fh, delimiter=':') - fh.seek(0) - H = nx.read_adjlist(fh, nodetype=int, delimiter=':') - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - - -class TestMultilineAdjlist(): - - @classmethod - def setup_class(cls): - cls.G = nx.Graph(name="test") - e = [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'e'), ('e', 'f'), ('a', 'f')] - cls.G.add_edges_from(e) - cls.G.add_node('g') - cls.DG = nx.DiGraph(cls.G) - cls.DG.remove_edge('b', 'a') - cls.DG.remove_edge('b', 'c') - cls.XG = nx.MultiGraph() - cls.XG.add_weighted_edges_from([(1, 2, 5), (1, 2, 5), (1, 2, 1), (3, 3, 42)]) - cls.XDG = nx.MultiDiGraph(cls.XG) - - def test_multiline_adjlist_graph(self): - G = self.G - (fd, fname) = tempfile.mkstemp() - nx.write_multiline_adjlist(G, fname) - H = nx.read_multiline_adjlist(fname) - H2 = nx.read_multiline_adjlist(fname) - assert H != H2 # they should be different graphs - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_multiline_adjlist_digraph(self): - G = self.DG - (fd, fname) = tempfile.mkstemp() - nx.write_multiline_adjlist(G, fname) - H = nx.read_multiline_adjlist(fname, create_using=nx.DiGraph()) - H2 = nx.read_multiline_adjlist(fname, create_using=nx.DiGraph()) - assert H != H2 # they should be different graphs - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_multiline_adjlist_integers(self): - (fd, fname) = tempfile.mkstemp() - G = nx.convert_node_labels_to_integers(self.G) - nx.write_multiline_adjlist(G, fname) - H = nx.read_multiline_adjlist(fname, nodetype=int) - H2 = nx.read_multiline_adjlist(fname, nodetype=int) - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_multiline_adjlist_multigraph(self): - G = self.XG - (fd, fname) = tempfile.mkstemp() - nx.write_multiline_adjlist(G, fname) - H = nx.read_multiline_adjlist(fname, nodetype=int, - create_using=nx.MultiGraph()) - H2 = nx.read_multiline_adjlist(fname, nodetype=int, - create_using=nx.MultiGraph()) - assert H != H2 # they should be different graphs - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_multiline_adjlist_multidigraph(self): - G = self.XDG - (fd, fname) = tempfile.mkstemp() - nx.write_multiline_adjlist(G, fname) - H = nx.read_multiline_adjlist(fname, nodetype=int, - create_using=nx.MultiDiGraph()) - H2 = nx.read_multiline_adjlist(fname, nodetype=int, - create_using=nx.MultiDiGraph()) - assert H != H2 # they should be different graphs - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_multiline_adjlist_delimiter(self): - fh = io.BytesIO() - G = nx.path_graph(3) - nx.write_multiline_adjlist(G, fh, delimiter=':') - fh.seek(0) - H = nx.read_multiline_adjlist(fh, nodetype=int, delimiter=':') - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) diff --git a/extensions/fablabchemnitz/networkx/readwrite/tests/test_edgelist.py b/extensions/fablabchemnitz/networkx/readwrite/tests/test_edgelist.py deleted file mode 100644 index 814db8c4..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/tests/test_edgelist.py +++ /dev/null @@ -1,245 +0,0 @@ -""" - Unit tests for edgelists. -""" -import pytest -import io -import tempfile -import os - -import networkx as nx -from networkx.testing import (assert_edges_equal, assert_nodes_equal, - assert_graphs_equal) - - -class TestEdgelist: - - @classmethod - def setup_class(cls): - cls.G = nx.Graph(name="test") - e = [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'e'), ('e', 'f'), ('a', 'f')] - cls.G.add_edges_from(e) - cls.G.add_node('g') - cls.DG = nx.DiGraph(cls.G) - cls.XG = nx.MultiGraph() - cls.XG.add_weighted_edges_from([(1, 2, 5), (1, 2, 5), (1, 2, 1), (3, 3, 42)]) - cls.XDG = nx.MultiDiGraph(cls.XG) - - def test_read_edgelist_1(self): - s = b"""\ -# comment line -1 2 -# comment line -2 3 -""" - bytesIO = io.BytesIO(s) - G = nx.read_edgelist(bytesIO, nodetype=int) - assert_edges_equal(G.edges(), [(1, 2), (2, 3)]) - - def test_read_edgelist_2(self): - s = b"""\ -# comment line -1 2 2.0 -# comment line -2 3 3.0 -""" - bytesIO = io.BytesIO(s) - G = nx.read_edgelist(bytesIO, nodetype=int, data=False) - assert_edges_equal(G.edges(), [(1, 2), (2, 3)]) - - bytesIO = io.BytesIO(s) - G = nx.read_weighted_edgelist(bytesIO, nodetype=int) - assert_edges_equal(G.edges(data=True), - [(1, 2, {'weight': 2.0}), (2, 3, {'weight': 3.0})]) - - def test_read_edgelist_3(self): - s = b"""\ -# comment line -1 2 {'weight':2.0} -# comment line -2 3 {'weight':3.0} -""" - bytesIO = io.BytesIO(s) - G = nx.read_edgelist(bytesIO, nodetype=int, data=False) - assert_edges_equal(G.edges(), [(1, 2), (2, 3)]) - - bytesIO = io.BytesIO(s) - G = nx.read_edgelist(bytesIO, nodetype=int, data=True) - assert_edges_equal(G.edges(data=True), - [(1, 2, {'weight': 2.0}), (2, 3, {'weight': 3.0})]) - - def test_read_edgelist_4(self): - s = b"""\ -# comment line -1 2 {'weight':2.0} -# comment line -2 3 {'weight':3.0} -""" - bytesIO = io.BytesIO(s) - G = nx.read_edgelist(bytesIO, nodetype=int, data=False) - assert_edges_equal(G.edges(), [(1, 2), (2, 3)]) - - bytesIO = io.BytesIO(s) - G = nx.read_edgelist(bytesIO, nodetype=int, data=True) - assert_edges_equal(G.edges(data=True), - [(1, 2, {'weight': 2.0}), (2, 3, {'weight': 3.0})]) - - - s = """\ -# comment line -1 2 {'weight':2.0} -# comment line -2 3 {'weight':3.0} -""" - StringIO = io.StringIO(s) - G = nx.read_edgelist(StringIO, nodetype=int, data=False) - assert_edges_equal(G.edges(), [(1, 2), (2, 3)]) - - StringIO = io.StringIO(s) - G = nx.read_edgelist(StringIO, nodetype=int, data=True) - assert_edges_equal(G.edges(data=True), - [(1, 2, {'weight': 2.0}), (2, 3, {'weight': 3.0})]) - - def test_write_edgelist_1(self): - fh = io.BytesIO() - G = nx.OrderedGraph() - G.add_edges_from([(1, 2), (2, 3)]) - nx.write_edgelist(G, fh, data=False) - fh.seek(0) - assert fh.read() == b"1 2\n2 3\n" - - def test_write_edgelist_2(self): - fh = io.BytesIO() - G = nx.OrderedGraph() - G.add_edges_from([(1, 2), (2, 3)]) - nx.write_edgelist(G, fh, data=True) - fh.seek(0) - assert fh.read() == b"1 2 {}\n2 3 {}\n" - - def test_write_edgelist_3(self): - fh = io.BytesIO() - G = nx.OrderedGraph() - G.add_edge(1, 2, weight=2.0) - G.add_edge(2, 3, weight=3.0) - nx.write_edgelist(G, fh, data=True) - fh.seek(0) - assert fh.read() == b"1 2 {'weight': 2.0}\n2 3 {'weight': 3.0}\n" - - def test_write_edgelist_4(self): - fh = io.BytesIO() - G = nx.OrderedGraph() - G.add_edge(1, 2, weight=2.0) - G.add_edge(2, 3, weight=3.0) - nx.write_edgelist(G, fh, data=[('weight')]) - fh.seek(0) - assert fh.read() == b"1 2 2.0\n2 3 3.0\n" - - def test_unicode(self): - G = nx.Graph() - try: # Python 3.x - name1 = chr(2344) + chr(123) + chr(6543) - name2 = chr(5543) + chr(1543) + chr(324) - except ValueError: # Python 2.6+ - name1 = unichr(2344) + unichr(123) + unichr(6543) - name2 = unichr(5543) + unichr(1543) + unichr(324) - G.add_edge(name1, 'Radiohead', **{name2: 3}) - fd, fname = tempfile.mkstemp() - nx.write_edgelist(G, fname) - H = nx.read_edgelist(fname) - assert_graphs_equal(G, H) - os.close(fd) - os.unlink(fname) - - def test_latin1_issue(self): - G = nx.Graph() - try: # Python 3.x - name1 = chr(2344) + chr(123) + chr(6543) - name2 = chr(5543) + chr(1543) + chr(324) - except ValueError: # Python 2.6+ - name1 = unichr(2344) + unichr(123) + unichr(6543) - name2 = unichr(5543) + unichr(1543) + unichr(324) - G.add_edge(name1, 'Radiohead', **{name2: 3}) - fd, fname = tempfile.mkstemp() - pytest.raises(UnicodeEncodeError, - nx.write_edgelist, - G, fname, encoding='latin-1') - os.close(fd) - os.unlink(fname) - - def test_latin1(self): - G = nx.Graph() - try: # Python 3.x - blurb = chr(1245) # just to trigger the exception - name1 = 'Bj' + chr(246) + 'rk' - name2 = chr(220) + 'ber' - except ValueError: # Python 2.6+ - name1 = 'Bj' + unichr(246) + 'rk' - name2 = unichr(220) + 'ber' - G.add_edge(name1, 'Radiohead', **{name2: 3}) - fd, fname = tempfile.mkstemp() - nx.write_edgelist(G, fname, encoding='latin-1') - H = nx.read_edgelist(fname, encoding='latin-1') - assert_graphs_equal(G, H) - os.close(fd) - os.unlink(fname) - - def test_edgelist_graph(self): - G = self.G - (fd, fname) = tempfile.mkstemp() - nx.write_edgelist(G, fname) - H = nx.read_edgelist(fname) - H2 = nx.read_edgelist(fname) - assert H != H2 # they should be different graphs - G.remove_node('g') # isolated nodes are not written in edgelist - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_edgelist_digraph(self): - G = self.DG - (fd, fname) = tempfile.mkstemp() - nx.write_edgelist(G, fname) - H = nx.read_edgelist(fname, create_using=nx.DiGraph()) - H2 = nx.read_edgelist(fname, create_using=nx.DiGraph()) - assert H != H2 # they should be different graphs - G.remove_node('g') # isolated nodes are not written in edgelist - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_edgelist_integers(self): - G = nx.convert_node_labels_to_integers(self.G) - (fd, fname) = tempfile.mkstemp() - nx.write_edgelist(G, fname) - H = nx.read_edgelist(fname, nodetype=int) - # isolated nodes are not written in edgelist - G.remove_nodes_from(list(nx.isolates(G))) - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_edgelist_multigraph(self): - G = self.XG - (fd, fname) = tempfile.mkstemp() - nx.write_edgelist(G, fname) - H = nx.read_edgelist(fname, nodetype=int, create_using=nx.MultiGraph()) - H2 = nx.read_edgelist(fname, nodetype=int, create_using=nx.MultiGraph()) - assert H != H2 # they should be different graphs - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) - - def test_edgelist_multidigraph(self): - G = self.XDG - (fd, fname) = tempfile.mkstemp() - nx.write_edgelist(G, fname) - H = nx.read_edgelist(fname, nodetype=int, create_using=nx.MultiDiGraph()) - H2 = nx.read_edgelist(fname, nodetype=int, create_using=nx.MultiDiGraph()) - assert H != H2 # they should be different graphs - assert_nodes_equal(list(H), list(G)) - assert_edges_equal(list(H.edges()), list(G.edges())) - os.close(fd) - os.unlink(fname) diff --git a/extensions/fablabchemnitz/networkx/readwrite/tests/test_gexf.py b/extensions/fablabchemnitz/networkx/readwrite/tests/test_gexf.py deleted file mode 100644 index 0c5ee620..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/tests/test_gexf.py +++ /dev/null @@ -1,500 +0,0 @@ -#!/usr/bin/env python -import io -import sys -import time -import pytest - -import networkx as nx - - -class TestGEXF(object): - @classmethod - def setup_class(cls): - _ = pytest.importorskip("xml.etree.ElementTree") - - cls.simple_directed_data = """ - - - - - - - - - - - -""" - cls.simple_directed_graph = nx.DiGraph() - cls.simple_directed_graph.add_node('0', label='Hello') - cls.simple_directed_graph.add_node('1', label='World') - cls.simple_directed_graph.add_edge('0', '1', id='0') - - cls.simple_directed_fh = \ - io.BytesIO(cls.simple_directed_data.encode('UTF-8')) - - cls.attribute_data = """\ - - - Gephi.org - A Web network - - - - - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -""" - cls.attribute_graph = nx.DiGraph() - cls.attribute_graph.graph['node_default'] = {'frog': True} - cls.attribute_graph.add_node('0', - label='Gephi', - url='https://gephi.org', - indegree=1, frog=False) - cls.attribute_graph.add_node('1', - label='Webatlas', - url='http://webatlas.fr', - indegree=2, frog=False) - cls.attribute_graph.add_node('2', - label='RTGI', - url='http://rtgi.fr', - indegree=1, frog=True) - cls.attribute_graph.add_node('3', - label='BarabasiLab', - url='http://barabasilab.com', - indegree=1, frog=True) - cls.attribute_graph.add_edge('0', '1', id='0') - cls.attribute_graph.add_edge('0', '2', id='1') - cls.attribute_graph.add_edge('1', '0', id='2') - cls.attribute_graph.add_edge('2', '1', id='3') - cls.attribute_graph.add_edge('0', '3', id='4') - cls.attribute_fh = io.BytesIO(cls.attribute_data.encode('UTF-8')) - - cls.simple_undirected_data = """ - - - - - - - - - - - -""" - cls.simple_undirected_graph = nx.Graph() - cls.simple_undirected_graph.add_node('0', label='Hello') - cls.simple_undirected_graph.add_node('1', label='World') - cls.simple_undirected_graph.add_edge('0', '1', id='0') - - cls.simple_undirected_fh = io.BytesIO(cls.simple_undirected_data - .encode('UTF-8')) - - def test_read_simple_directed_graphml(self): - G = self.simple_directed_graph - H = nx.read_gexf(self.simple_directed_fh) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(G.edges()) == sorted(H.edges()) - assert (sorted(G.edges(data=True)) == - sorted(H.edges(data=True))) - self.simple_directed_fh.seek(0) - - def test_write_read_simple_directed_graphml(self): - G = self.simple_directed_graph - fh = io.BytesIO() - nx.write_gexf(G, fh) - fh.seek(0) - H = nx.read_gexf(fh) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(G.edges()) == sorted(H.edges()) - assert (sorted(G.edges(data=True)) == - sorted(H.edges(data=True))) - self.simple_directed_fh.seek(0) - - def test_read_simple_undirected_graphml(self): - G = self.simple_undirected_graph - H = nx.read_gexf(self.simple_undirected_fh) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert ( - sorted(sorted(e) for e in G.edges()) == - sorted(sorted(e) for e in H.edges())) - self.simple_undirected_fh.seek(0) - - def test_read_attribute_graphml(self): - G = self.attribute_graph - H = nx.read_gexf(self.attribute_fh) - assert sorted(G.nodes(True)) == sorted(H.nodes(data=True)) - ge = sorted(G.edges(data=True)) - he = sorted(H.edges(data=True)) - for a, b in zip(ge, he): - assert a == b - self.attribute_fh.seek(0) - - def test_directed_edge_in_undirected(self): - s = """ - - - - - - - - - - - -""" - fh = io.BytesIO(s.encode('UTF-8')) - pytest.raises(nx.NetworkXError, nx.read_gexf, fh) - - def test_undirected_edge_in_directed(self): - s = """ - - - - - - - - - - - -""" - fh = io.BytesIO(s.encode('UTF-8')) - pytest.raises(nx.NetworkXError, nx.read_gexf, fh) - - def test_key_raises(self): - s = """ - - - - - - - - - - - - - - - -""" - fh = io.BytesIO(s.encode('UTF-8')) - pytest.raises(nx.NetworkXError, nx.read_gexf, fh) - - def test_relabel(self): - s = """ - - - - - - - - - - - -""" - fh = io.BytesIO(s.encode('UTF-8')) - G = nx.read_gexf(fh, relabel=True) - assert sorted(G.nodes()) == ["Hello", "Word"] - - def test_default_attribute(self): - G = nx.Graph() - G.add_node(1, label='1', color='green') - nx.add_path(G, [0, 1, 2, 3]) - G.add_edge(1, 2, foo=3) - G.graph['node_default'] = {'color': 'yellow'} - G.graph['edge_default'] = {'foo': 7} - fh = io.BytesIO() - nx.write_gexf(G, fh) - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert ( - sorted(sorted(e) for e in G.edges()) == - sorted(sorted(e) for e in H.edges())) - # Reading a gexf graph always sets mode attribute to either - # 'static' or 'dynamic'. Remove the mode attribute from the - # read graph for the sake of comparing remaining attributes. - del H.graph['mode'] - assert G.graph == H.graph - - def test_serialize_ints_to_strings(self): - G = nx.Graph() - G.add_node(1, id=7, label=77) - fh = io.BytesIO() - nx.write_gexf(G, fh) - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - assert list(H) == [7] - assert H.nodes[7]['label'] == '77' - -# FIXME: We should test xml without caring about their order This is causing a -# problem b/c of a change in Python 3.8 -# -# "Prior to Python 3.8, the serialisation order of the XML attributes of -# elements was artificially made predictable by sorting the attributes by their -# name. Based on the now guaranteed ordering of dicts, this arbitrary -# reordering was removed in Python 3.8 to preserve the order in which -# attributes were originally parsed or created by user code." -# -# https://docs.python.org/3.8/library/xml.etree.elementtree.html -# https://bugs.python.org/issue34160 - - def test_write_with_node_attributes(self): - # Addresses #673. - G = nx.OrderedGraph() - G.add_edges_from([(0, 1), (1, 2), (2, 3)]) - for i in range(4): - G.nodes[i]['id'] = i - G.nodes[i]['label'] = i - G.nodes[i]['pid'] = i - G.nodes[i]['start'] = i - G.nodes[i]['end'] = i + 1 - - if sys.version_info < (3, 8): - expected = """ - - NetworkX {} - - - - - - - - - - - - - - -""".format(time.strftime('%Y-%m-%d'), nx.__version__) - else: - expected = """ - - NetworkX {} - - - - - - - - - - - - - - -""".format(time.strftime('%Y-%m-%d'), nx.__version__) - obtained = '\n'.join(nx.generate_gexf(G)) - assert expected == obtained - - def test_edge_id_construct(self): - G = nx.Graph() - G.add_edges_from([(0, 1, {'id': 0}), (1, 2, {'id': 2}), (2, 3)]) - - if sys.version_info < (3, 8): - expected = """ - - NetworkX {} - - - - - - - - - - - - - - -""".format(time.strftime('%Y-%m-%d'), nx.__version__) - else: - expected = """ - - NetworkX {} - - - - - - - - - - - - - - -""".format(time.strftime('%Y-%m-%d'), nx.__version__) - - obtained = '\n'.join(nx.generate_gexf(G)) - assert expected == obtained - - def test_numpy_type(self): - G = nx.path_graph(4) - try: - import numpy - except ImportError: - return - nx.set_node_attributes(G, {n: n for n in numpy.arange(4)}, 'number') - G[0][1]['edge-number'] = numpy.float64(1.1) - - expected = """ - - NetworkX {} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -""".format(time.strftime('%Y-%m-%d'), nx.__version__) - obtained = '\n'.join(nx.generate_gexf(G)) - assert expected == obtained - - def test_bool(self): - G = nx.Graph() - G.add_node(1, testattr=True) - fh = io.BytesIO() - nx.write_gexf(G, fh) - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - assert H.nodes[1]['testattr'] == True - - # Test for NaN, INF and -INF - def test_specials(self): - from math import isnan - inf, nan = float('inf'), float('nan') - G = nx.Graph() - G.add_node(1, testattr=inf, strdata='inf', key='a') - G.add_node(2, testattr=nan, strdata='nan', key='b') - G.add_node(3, testattr=-inf, strdata='-inf', key='c') - - fh = io.BytesIO() - nx.write_gexf(G, fh) - fh.seek(0) - filetext = fh.read() - fh.seek(0) - H = nx.read_gexf(fh, node_type=int) - - assert b'INF' in filetext - assert b'NaN' in filetext - assert b'-INF' in filetext - - assert H.nodes[1]['testattr'] == inf - assert isnan(H.nodes[2]['testattr']) - assert H.nodes[3]['testattr'] == -inf - - assert H.nodes[1]['strdata'] == 'inf' - assert H.nodes[2]['strdata'] == 'nan' - assert H.nodes[3]['strdata'] == '-inf' - - assert H.nodes[1]['networkx_key'] == 'a' - assert H.nodes[2]['networkx_key'] == 'b' - assert H.nodes[3]['networkx_key'] == 'c' diff --git a/extensions/fablabchemnitz/networkx/readwrite/tests/test_gml.py b/extensions/fablabchemnitz/networkx/readwrite/tests/test_gml.py deleted file mode 100644 index fc3d94d7..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/tests/test_gml.py +++ /dev/null @@ -1,514 +0,0 @@ -#!/usr/bin/env python -# encoding: utf-8 - -from ast import literal_eval -import codecs -import io -import pytest -import networkx as nx -from networkx.readwrite.gml import literal_stringizer, literal_destringizer -import os -import tempfile - -try: - unicode -except NameError: - unicode = str -try: - unichr -except NameError: - unichr = chr - - -class TestGraph(object): - - @classmethod - def setup_class(cls): - cls.simple_data = """Creator "me" -Version "xx" -graph [ - comment "This is a sample graph" - directed 1 - IsPlanar 1 - pos [ x 0 y 1 ] - node [ - id 1 - label "Node 1" - pos [ x 1 y 1 ] - ] - node [ - id 2 - pos [ x 1 y 2 ] - label "Node 2" - ] - node [ - id 3 - label "Node 3" - pos [ x 1 y 3 ] - ] - edge [ - source 1 - target 2 - label "Edge from node 1 to node 2" - color [line "blue" thickness 3] - - ] - edge [ - source 2 - target 3 - label "Edge from node 2 to node 3" - ] - edge [ - source 3 - target 1 - label "Edge from node 3 to node 1" - ] -] -""" - - def test_parse_gml_cytoscape_bug(self): - # example from issue #321, originally #324 in trac - cytoscape_example = """ -Creator "Cytoscape" -Version 1.0 -graph [ - node [ - root_index -3 - id -3 - graphics [ - x -96.0 - y -67.0 - w 40.0 - h 40.0 - fill "#ff9999" - type "ellipse" - outline "#666666" - outline_width 1.5 - ] - label "node2" - ] - node [ - root_index -2 - id -2 - graphics [ - x 63.0 - y 37.0 - w 40.0 - h 40.0 - fill "#ff9999" - type "ellipse" - outline "#666666" - outline_width 1.5 - ] - label "node1" - ] - node [ - root_index -1 - id -1 - graphics [ - x -31.0 - y -17.0 - w 40.0 - h 40.0 - fill "#ff9999" - type "ellipse" - outline "#666666" - outline_width 1.5 - ] - label "node0" - ] - edge [ - root_index -2 - target -2 - source -1 - graphics [ - width 1.5 - fill "#0000ff" - type "line" - Line [ - ] - source_arrow 0 - target_arrow 3 - ] - label "DirectedEdge" - ] - edge [ - root_index -1 - target -1 - source -3 - graphics [ - width 1.5 - fill "#0000ff" - type "line" - Line [ - ] - source_arrow 0 - target_arrow 3 - ] - label "DirectedEdge" - ] -] -""" - nx.parse_gml(cytoscape_example) - - def test_parse_gml(self): - G = nx.parse_gml(self.simple_data, label='label') - assert (sorted(G.nodes()) == - ['Node 1', 'Node 2', 'Node 3']) - assert ([e for e in sorted(G.edges())] == - [('Node 1', 'Node 2'), - ('Node 2', 'Node 3'), - ('Node 3', 'Node 1')]) - - assert ([e for e in sorted(G.edges(data=True))] == - [('Node 1', 'Node 2', - {'color': {'line': 'blue', 'thickness': 3}, - 'label': 'Edge from node 1 to node 2'}), - ('Node 2', 'Node 3', - {'label': 'Edge from node 2 to node 3'}), - ('Node 3', 'Node 1', - {'label': 'Edge from node 3 to node 1'})]) - - def test_read_gml(self): - (fd, fname) = tempfile.mkstemp() - fh = open(fname, 'w') - fh.write(self.simple_data) - fh.close() - Gin = nx.read_gml(fname, label='label') - G = nx.parse_gml(self.simple_data, label='label') - assert sorted(G.nodes(data=True)) == sorted(Gin.nodes(data=True)) - assert sorted(G.edges(data=True)) == sorted(Gin.edges(data=True)) - os.close(fd) - os.unlink(fname) - - def test_labels_are_strings(self): - # GML requires labels to be strings (i.e., in quotes) - answer = """graph [ - node [ - id 0 - label "1203" - ] -]""" - G = nx.Graph() - G.add_node(1203) - data = '\n'.join(nx.generate_gml(G, stringizer=literal_stringizer)) - assert data == answer - - def test_relabel_duplicate(self): - data = """ -graph -[ - label "" - directed 1 - node - [ - id 0 - label "same" - ] - node - [ - id 1 - label "same" - ] -] -""" - fh = io.BytesIO(data.encode('UTF-8')) - fh.seek(0) - pytest.raises( - nx.NetworkXError, nx.read_gml, fh, label='label') - - def test_tuplelabels(self): - # https://github.com/networkx/networkx/pull/1048 - # Writing tuple labels to GML failed. - G = nx.OrderedGraph() - G.add_edge((0, 1), (1, 0)) - data = '\n'.join(nx.generate_gml(G, stringizer=literal_stringizer)) - answer = """graph [ - node [ - id 0 - label "(0,1)" - ] - node [ - id 1 - label "(1,0)" - ] - edge [ - source 0 - target 1 - ] -]""" - assert data == answer - - def test_quotes(self): - # https://github.com/networkx/networkx/issues/1061 - # Encoding quotes as HTML entities. - G = nx.path_graph(1) - G.name = "path_graph(1)" - attr = 'This is "quoted" and this is a copyright: ' + unichr(169) - G.nodes[0]['demo'] = attr - fobj = tempfile.NamedTemporaryFile() - nx.write_gml(G, fobj) - fobj.seek(0) - # Should be bytes in 2.x and 3.x - data = fobj.read().strip().decode('ascii') - answer = """graph [ - name "path_graph(1)" - node [ - id 0 - label "0" - demo "This is "quoted" and this is a copyright: ©" - ] -]""" - assert data == answer - - def test_unicode_node(self): - node = 'node' + unichr(169) - G = nx.Graph() - G.add_node(node) - fobj = tempfile.NamedTemporaryFile() - nx.write_gml(G, fobj) - fobj.seek(0) - # Should be bytes in 2.x and 3.x - data = fobj.read().strip().decode('ascii') - answer = """graph [ - node [ - id 0 - label "node©" - ] -]""" - assert data == answer - - def test_float_label(self): - node = 1.0 - G = nx.Graph() - G.add_node(node) - fobj = tempfile.NamedTemporaryFile() - nx.write_gml(G, fobj) - fobj.seek(0) - # Should be bytes in 2.x and 3.x - data = fobj.read().strip().decode('ascii') - answer = """graph [ - node [ - id 0 - label "1.0" - ] -]""" - assert data == answer - - def test_name(self): - G = nx.parse_gml('graph [ name "x" node [ id 0 label "x" ] ]') - assert 'x' == G.graph['name'] - G = nx.parse_gml('graph [ node [ id 0 label "x" ] ]') - assert '' == G.name - assert 'name' not in G.graph - - def test_graph_types(self): - for directed in [None, False, True]: - for multigraph in [None, False, True]: - gml = 'graph [' - if directed is not None: - gml += ' directed ' + str(int(directed)) - if multigraph is not None: - gml += ' multigraph ' + str(int(multigraph)) - gml += ' node [ id 0 label "0" ]' - gml += ' edge [ source 0 target 0 ]' - gml += ' ]' - G = nx.parse_gml(gml) - assert bool(directed) == G.is_directed() - assert bool(multigraph) == G.is_multigraph() - gml = 'graph [\n' - if directed is True: - gml += ' directed 1\n' - if multigraph is True: - gml += ' multigraph 1\n' - gml += """ node [ - id 0 - label "0" - ] - edge [ - source 0 - target 0 -""" - if multigraph: - gml += ' key 0\n' - gml += ' ]\n]' - assert gml == '\n'.join(nx.generate_gml(G)) - - def test_data_types(self): - data = [True, False, 10 ** 20, -2e33, "'", '"&&&""', - [{(b'\xfd',): '\x7f', unichr(0x4444): (1, 2)}, (2, "3")]] - try: # fails under IronPython - data.append(unichr(0x14444)) - except ValueError: - data.append(unichr(0x1444)) - try: # fails under Python 2.7 - data.append(literal_eval('{2.3j, 1 - 2.3j, ()}')) - except ValueError: - data.append([2.3j, 1 - 2.3j, ()]) - G = nx.Graph() - G.name = data - G.graph['data'] = data - G.add_node(0, int=-1, data=dict(data=data)) - G.add_edge(0, 0, float=-2.5, data=data) - gml = '\n'.join(nx.generate_gml(G, stringizer=literal_stringizer)) - G = nx.parse_gml(gml, destringizer=literal_destringizer) - assert data == G.name - assert {'name': data, unicode('data'): data} == G.graph - assert (list(G.nodes(data=True)) == - [(0, dict(int=-1, data=dict(data=data)))]) - assert (list(G.edges(data=True)) == - [(0, 0, dict(float=-2.5, data=data))]) - G = nx.Graph() - G.graph['data'] = 'frozenset([1, 2, 3])' - G = nx.parse_gml(nx.generate_gml(G), destringizer=literal_eval) - assert G.graph['data'] == 'frozenset([1, 2, 3])' - - def test_escape_unescape(self): - gml = """graph [ - name "&"䑄��&unknown;" -]""" - G = nx.parse_gml(gml) - assert ( - '&"\x0f' + unichr(0x4444) + - '��&unknown;' == - G.name) - gml = '\n'.join(nx.generate_gml(G)) - alnu = "#1234567890;&#x1234567890abcdef" - answer = """graph [ - name "&"䑄&""" + alnu + """;&unknown;" -]""" - assert answer == gml - - def test_exceptions(self): - pytest.raises(ValueError, literal_destringizer, '(') - pytest.raises(ValueError, literal_destringizer, 'frozenset([1, 2, 3])') - pytest.raises(ValueError, literal_destringizer, literal_destringizer) - pytest.raises(ValueError, literal_stringizer, frozenset([1, 2, 3])) - pytest.raises(ValueError, literal_stringizer, literal_stringizer) - with tempfile.TemporaryFile() as f: - f.write(codecs.BOM_UTF8 + 'graph[]'.encode('ascii')) - f.seek(0) - pytest.raises(nx.NetworkXError, nx.read_gml, f) - - def assert_parse_error(gml): - pytest.raises(nx.NetworkXError, nx.parse_gml, gml) - - assert_parse_error(['graph [\n\n', unicode(']')]) - assert_parse_error('') - assert_parse_error('Creator ""') - assert_parse_error('0') - assert_parse_error('graph ]') - assert_parse_error('graph [ 1 ]') - assert_parse_error('graph [ 1.E+2 ]') - assert_parse_error('graph [ "A" ]') - assert_parse_error('graph [ ] graph ]') - assert_parse_error('graph [ ] graph [ ]') - assert_parse_error('graph [ data [1, 2, 3] ]') - assert_parse_error('graph [ node [ ] ]') - assert_parse_error('graph [ node [ id 0 ] ]') - nx.parse_gml('graph [ node [ id "a" ] ]', label='id') - assert_parse_error( - 'graph [ node [ id 0 label 0 ] node [ id 0 label 1 ] ]') - assert_parse_error( - 'graph [ node [ id 0 label 0 ] node [ id 1 label 0 ] ]') - assert_parse_error('graph [ node [ id 0 label 0 ] edge [ ] ]') - assert_parse_error('graph [ node [ id 0 label 0 ] edge [ source 0 ] ]') - nx.parse_gml( - 'graph [edge [ source 0 target 0 ] node [ id 0 label 0 ] ]') - assert_parse_error( - 'graph [ node [ id 0 label 0 ] edge [ source 1 target 0 ] ]') - assert_parse_error( - 'graph [ node [ id 0 label 0 ] edge [ source 0 target 1 ] ]') - assert_parse_error( - 'graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] ' - 'edge [ source 0 target 1 ] edge [ source 1 target 0 ] ]') - nx.parse_gml( - 'graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] ' - 'edge [ source 0 target 1 ] edge [ source 1 target 0 ] ' - 'directed 1 ]') - nx.parse_gml( - 'graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] ' - 'edge [ source 0 target 1 ] edge [ source 0 target 1 ]' - 'multigraph 1 ]') - nx.parse_gml( - 'graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] ' - 'edge [ source 0 target 1 key 0 ] edge [ source 0 target 1 ]' - 'multigraph 1 ]') - assert_parse_error( - 'graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] ' - 'edge [ source 0 target 1 key 0 ] edge [ source 0 target 1 key 0 ]' - 'multigraph 1 ]') - nx.parse_gml( - 'graph [ node [ id 0 label 0 ] node [ id 1 label 1 ] ' - 'edge [ source 0 target 1 key 0 ] edge [ source 1 target 0 key 0 ]' - 'directed 1 multigraph 1 ]') - - # Tests for string convertable alphanumeric id and label values - nx.parse_gml( - 'graph [edge [ source a target a ] node [ id a label b ] ]') - nx.parse_gml( - 'graph [ node [ id n42 label 0 ] node [ id x43 label 1 ]' - 'edge [ source n42 target x43 key 0 ]' - 'edge [ source x43 target n42 key 0 ]' - 'directed 1 multigraph 1 ]') - assert_parse_error( - "graph [edge [ source u'u\4200' target u'u\4200' ] " + - "node [ id u'u\4200' label b ] ]") - - def assert_generate_error(*args, **kwargs): - pytest.raises(nx.NetworkXError, - lambda: list(nx.generate_gml(*args, **kwargs))) - - G = nx.Graph() - G.graph[3] = 3 - assert_generate_error(G) - G = nx.Graph() - G.graph['3'] = 3 - assert_generate_error(G) - G = nx.Graph() - G.graph['data'] = frozenset([1, 2, 3]) - assert_generate_error(G, stringizer=literal_stringizer) - G = nx.Graph() - G.graph['data'] = [] - assert_generate_error(G) - assert_generate_error(G, stringizer=len) - - def test_label_kwarg(self): - G = nx.parse_gml(self.simple_data, label='id') - assert sorted(G.nodes) == [1, 2, 3] - labels = [G.nodes[n]['label'] for n in sorted(G.nodes)] - assert labels == ['Node 1', 'Node 2', 'Node 3'] - - G = nx.parse_gml(self.simple_data, label=None) - assert sorted(G.nodes) == [1, 2, 3] - labels = [G.nodes[n]['label'] for n in sorted(G.nodes)] - assert labels == ['Node 1', 'Node 2', 'Node 3'] - - def test_outofrange_integers(self): - # GML restricts integers to 32 signed bits. - # Check that we honor this restriction on export - G = nx.Graph() - # Test export for numbers that barely fit or don't fit into 32 bits, - # and 3 numbers in the middle - numbers = {'toosmall': (-2**31)-1, - 'small': -2**31, - 'med1': -4, - 'med2': 0, - 'med3': 17, - 'big': (2**31)-1, - 'toobig': 2**31} - G.add_node('Node', **numbers) - - fd, fname = tempfile.mkstemp() - try: - nx.write_gml(G, fname) - # Check that the export wrote the nonfitting numbers as strings - G2 = nx.read_gml(fname) - for attr, value in G2.nodes['Node'].items(): - if attr == 'toosmall' or attr == 'toobig': - assert type(value) == str - else: - assert type(value) == int - finally: - os.close(fd) - os.unlink(fname) diff --git a/extensions/fablabchemnitz/networkx/readwrite/tests/test_gpickle.py b/extensions/fablabchemnitz/networkx/readwrite/tests/test_gpickle.py deleted file mode 100644 index 72c8f14d..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/tests/test_gpickle.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python -import os -import tempfile - -import networkx as nx -from networkx.testing.utils import * - - -class TestGpickle(object): - @classmethod - def setup_class(cls): - G = nx.Graph(name="test") - e = [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'e'), ('e', 'f'), ('a', 'f')] - G.add_edges_from(e, width=10) - G.add_node('g', color='green') - G.graph['number'] = 1 - DG = nx.DiGraph(G) - MG = nx.MultiGraph(G) - MG.add_edge('a', 'a') - MDG = nx.MultiDiGraph(G) - MDG.add_edge('a', 'a') - fG = G.copy() - fDG = DG.copy() - fMG = MG.copy() - fMDG = MDG.copy() - nx.freeze(fG) - nx.freeze(fDG) - nx.freeze(fMG) - nx.freeze(fMDG) - cls.G = G - cls.DG = DG - cls.MG = MG - cls.MDG = MDG - cls.fG = fG - cls.fDG = fDG - cls.fMG = fMG - cls.fMDG = fMDG - - def test_gpickle(self): - for G in [self.G, self.DG, self.MG, self.MDG, - self.fG, self.fDG, self.fMG, self.fMDG]: - (fd, fname) = tempfile.mkstemp() - nx.write_gpickle(G, fname) - Gin = nx.read_gpickle(fname) - assert_nodes_equal(list(G.nodes(data=True)), - list(Gin.nodes(data=True))) - assert_edges_equal(list(G.edges(data=True)), - list(Gin.edges(data=True))) - assert_graphs_equal(G, Gin) - os.close(fd) - os.unlink(fname) - - def test_protocol(self): - for G in [self.G, self.DG, self.MG, self.MDG, - self.fG, self.fDG, self.fMG, self.fMDG]: - with tempfile.TemporaryFile() as f: - nx.write_gpickle(G, f, 0) - f.seek(0) - Gin = nx.read_gpickle(f) - assert_nodes_equal(list(G.nodes(data=True)), - list(Gin.nodes(data=True))) - assert_edges_equal(list(G.edges(data=True)), - list(Gin.edges(data=True))) - assert_graphs_equal(G, Gin) diff --git a/extensions/fablabchemnitz/networkx/readwrite/tests/test_graph6.py b/extensions/fablabchemnitz/networkx/readwrite/tests/test_graph6.py deleted file mode 100644 index 48c6976f..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/tests/test_graph6.py +++ /dev/null @@ -1,124 +0,0 @@ - -from io import BytesIO -import tempfile -from unittest import TestCase - - -import networkx as nx -import networkx.readwrite.graph6 as g6 -from networkx.testing.utils import assert_edges_equal -from networkx.testing.utils import assert_nodes_equal - - -class TestGraph6Utils(object): - - def test_n_data_n_conversion(self): - for i in [0, 1, 42, 62, 63, 64, 258047, 258048, 7744773, 68719476735]: - assert g6.data_to_n(g6.n_to_data(i))[0] == i - assert g6.data_to_n(g6.n_to_data(i))[1] == [] - assert (g6.data_to_n(g6.n_to_data(i) + [42, 43])[1] == - [42, 43]) - - -class TestFromGraph6Bytes(TestCase): - - def test_from_graph6_bytes(self): - data = b'DF{' - G = nx.from_graph6_bytes(data) - assert_nodes_equal(G.nodes(), [0, 1, 2, 3, 4]) - assert_edges_equal(G.edges(), - [(0, 3), (0, 4), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]) - - def test_read_equals_from_bytes(self): - data = b'DF{' - G = nx.from_graph6_bytes(data) - fh = BytesIO(data) - Gin = nx.read_graph6(fh) - assert_nodes_equal(G.nodes(), Gin.nodes()) - assert_edges_equal(G.edges(), Gin.edges()) - - -class TestReadGraph6(TestCase): - - def test_read_many_graph6(self): - """Test for reading many graphs from a file into a list.""" - data = b'DF{\nD`{\nDqK\nD~{\n' - fh = BytesIO(data) - glist = nx.read_graph6(fh) - assert len(glist) == 4 - for G in glist: - assert sorted(G) == list(range(5)) - - -class TestWriteGraph6(TestCase): - """Unit tests for writing a graph to a file in graph6 format.""" - - def test_null_graph(self): - result = BytesIO() - nx.write_graph6(nx.null_graph(), result) - self.assertEqual(result.getvalue(), b'>>graph6<>graph6<<@\n') - - def test_complete_graph(self): - result = BytesIO() - nx.write_graph6(nx.complete_graph(4), result) - self.assertEqual(result.getvalue(), b'>>graph6<>graph6<>graph6<>graph6<>graph6< - - - - - - - - - - - - - - - - - - - - - - - - - - -""" - cls.simple_directed_graph = nx.DiGraph() - cls.simple_directed_graph.add_node('n10') - cls.simple_directed_graph.add_edge('n0', 'n2', id='foo') - cls.simple_directed_graph.add_edges_from([('n1', 'n2'), - ('n2', 'n3'), - ('n3', 'n5'), - ('n3', 'n4'), - ('n4', 'n6'), - ('n6', 'n5'), - ('n5', 'n7'), - ('n6', 'n8'), - ('n8', 'n7'), - ('n8', 'n9'), - ]) - cls.simple_directed_fh = \ - io.BytesIO(cls.simple_directed_data.encode('UTF-8')) - - cls.attribute_data = """ - - - yellow - - - - - green - - - - blue - - - red - - - - turquoise - - - 1.0 - - - 1.0 - - - 2.0 - - - - - - 1.1 - - - -""" - cls.attribute_graph = nx.DiGraph(id='G') - cls.attribute_graph.graph['node_default'] = {'color': 'yellow'} - cls.attribute_graph.add_node('n0', color='green') - cls.attribute_graph.add_node('n2', color='blue') - cls.attribute_graph.add_node('n3', color='red') - cls.attribute_graph.add_node('n4') - cls.attribute_graph.add_node('n5', color='turquoise') - cls.attribute_graph.add_edge('n0', 'n2', id='e0', weight=1.0) - cls.attribute_graph.add_edge('n0', 'n1', id='e1', weight=1.0) - cls.attribute_graph.add_edge('n1', 'n3', id='e2', weight=2.0) - cls.attribute_graph.add_edge('n3', 'n2', id='e3') - cls.attribute_graph.add_edge('n2', 'n4', id='e4') - cls.attribute_graph.add_edge('n3', 'n5', id='e5') - cls.attribute_graph.add_edge('n5', 'n4', id='e6', weight=1.1) - cls.attribute_fh = io.BytesIO(cls.attribute_data.encode('UTF-8')) - - cls.attribute_numeric_type_data = """ - - - - - - 1 - - - 2.0 - - - 1 - - - k - - - 1.0 - - - -""" - cls.attribute_numeric_type_graph = nx.DiGraph() - cls.attribute_numeric_type_graph.add_node('n0', weight=1) - cls.attribute_numeric_type_graph.add_node('n1', weight=2.0) - cls.attribute_numeric_type_graph.add_edge('n0', 'n1', weight=1) - cls.attribute_numeric_type_graph.add_edge('n1', 'n1', weight=1.0) - fh = io.BytesIO(cls.attribute_numeric_type_data.encode('UTF-8')) - cls.attribute_numeric_type_fh = fh - - cls.simple_undirected_data = """ - - - - - - - - - - -""" -# - cls.simple_undirected_graph = nx.Graph() - cls.simple_undirected_graph.add_node('n10') - cls.simple_undirected_graph.add_edge('n0', 'n2', id='foo') - cls.simple_undirected_graph.add_edges_from([('n1', 'n2'), - ('n2', 'n3'), - ]) - fh = io.BytesIO(cls.simple_undirected_data.encode('UTF-8')) - cls.simple_undirected_fh = fh - - -class TestReadGraphML(BaseGraphML): - def test_read_simple_directed_graphml(self): - G = self.simple_directed_graph - H = nx.read_graphml(self.simple_directed_fh) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(G.edges()) == sorted(H.edges()) - assert (sorted(G.edges(data=True)) == - sorted(H.edges(data=True))) - self.simple_directed_fh.seek(0) - - I = nx.parse_graphml(self.simple_directed_data) - assert sorted(G.nodes()) == sorted(I.nodes()) - assert sorted(G.edges()) == sorted(I.edges()) - assert (sorted(G.edges(data=True)) == - sorted(I.edges(data=True))) - - def test_read_simple_undirected_graphml(self): - G = self.simple_undirected_graph - H = nx.read_graphml(self.simple_undirected_fh) - assert_nodes_equal(G.nodes(), H.nodes()) - assert_edges_equal(G.edges(), H.edges()) - self.simple_undirected_fh.seek(0) - - I = nx.parse_graphml(self.simple_undirected_data) - assert_nodes_equal(G.nodes(), I.nodes()) - assert_edges_equal(G.edges(), I.edges()) - - def test_read_attribute_graphml(self): - G = self.attribute_graph - H = nx.read_graphml(self.attribute_fh) - assert_nodes_equal(G.nodes(True), sorted(H.nodes(data=True))) - ge = sorted(G.edges(data=True)) - he = sorted(H.edges(data=True)) - for a, b in zip(ge, he): - assert a == b - self.attribute_fh.seek(0) - - I = nx.parse_graphml(self.attribute_data) - assert sorted(G.nodes(True)) == sorted(I.nodes(data=True)) - ge = sorted(G.edges(data=True)) - he = sorted(I.edges(data=True)) - for a, b in zip(ge, he): - assert a == b - - def test_directed_edge_in_undirected(self): - s = """ - - - - - - - - -""" - fh = io.BytesIO(s.encode('UTF-8')) - pytest.raises(nx.NetworkXError, nx.read_graphml, fh) - pytest.raises(nx.NetworkXError, nx.parse_graphml, s) - - def test_undirected_edge_in_directed(self): - s = """ - - - - - - - - -""" - fh = io.BytesIO(s.encode('UTF-8')) - pytest.raises(nx.NetworkXError, nx.read_graphml, fh) - pytest.raises(nx.NetworkXError, nx.parse_graphml, s) - - def test_key_raise(self): - s = """ - - - yellow - - - - - green - - - - blue - - - 1.0 - - - -""" - fh = io.BytesIO(s.encode('UTF-8')) - pytest.raises(nx.NetworkXError, nx.read_graphml, fh) - pytest.raises(nx.NetworkXError, nx.parse_graphml, s) - - def test_hyperedge_raise(self): - s = """ - - - yellow - - - - - green - - - - blue - - - - - - - - -""" - fh = io.BytesIO(s.encode('UTF-8')) - pytest.raises(nx.NetworkXError, nx.read_graphml, fh) - pytest.raises(nx.NetworkXError, nx.parse_graphml, s) - - def test_multigraph_keys(self): - # Test that reading multigraphs uses edge id attributes as keys - s = """ - - - - - - - - -""" - fh = io.BytesIO(s.encode('UTF-8')) - G = nx.read_graphml(fh) - expected = [("n0", "n1", "e0"), ("n0", "n1", "e1")] - assert sorted(G.edges(keys=True)) == expected - fh.seek(0) - H = nx.parse_graphml(s) - assert sorted(H.edges(keys=True)) == expected - - def test_preserve_multi_edge_data(self): - """ - Test that data and keys of edges are preserved on consequent - write and reads - """ - G = nx.MultiGraph() - G.add_node(1) - G.add_node(2) - G.add_edges_from([ - # edges with no data, no keys: - (1, 2), - # edges with only data: - (1, 2, dict(key='data_key1')), - (1, 2, dict(id='data_id2')), - (1, 2, dict(key='data_key3', id='data_id3')), - # edges with both data and keys: - (1, 2, 103, dict(key='data_key4')), - (1, 2, 104, dict(id='data_id5')), - (1, 2, 105, dict(key='data_key6', id='data_id7')), - ]) - fh = io.BytesIO() - nx.write_graphml(G, fh) - fh.seek(0) - H = nx.read_graphml(fh, node_type=int) - assert_edges_equal( - G.edges(data=True, keys=True), H.edges(data=True, keys=True) - ) - assert G._adj == H._adj - - def test_yfiles_extension(self): - data = """ - - - - - - - - - - - - - - - - - - - - 1 - - - - - - - - - - - 2 - - - - - - - - - - - - - - - - - - - -""" - fh = io.BytesIO(data.encode('UTF-8')) - G = nx.read_graphml(fh) - assert list(G.edges()) == [('n0', 'n1')] - assert G['n0']['n1']['id'] == 'e0' - assert G.nodes['n0']['label'] == '1' - assert G.nodes['n1']['label'] == '2' - - H = nx.parse_graphml(data) - assert list(H.edges()) == [('n0', 'n1')] - assert H['n0']['n1']['id'] == 'e0' - assert H.nodes['n0']['label'] == '1' - assert H.nodes['n1']['label'] == '2' - - def test_bool(self): - s = """ - - - false - - - - true - - - - false - - - FaLsE - - - True - - - 0 - - - 1 - - - -""" - fh = io.BytesIO(s.encode('UTF-8')) - G = nx.read_graphml(fh) - H = nx.parse_graphml(s) - for graph in [G, H]: - assert graph.nodes['n0']['test'] == True - assert graph.nodes['n2']['test'] == False - assert graph.nodes['n3']['test'] == False - assert graph.nodes['n4']['test'] == True - assert graph.nodes['n5']['test'] == False - assert graph.nodes['n6']['test'] == True - - def test_graphml_header_line(self): - good = """ - - - false - - - - true - - - -""" - bad = """ - - - false - - - - true - - - -""" - ugly = """ - - - false - - - - true - - - -""" - for s in (good, bad): - fh = io.BytesIO(s.encode('UTF-8')) - G = nx.read_graphml(fh) - H = nx.parse_graphml(s) - for graph in [G, H]: - assert graph.nodes['n0']['test'] == True - - fh = io.BytesIO(ugly.encode('UTF-8')) - pytest.raises(nx.NetworkXError, nx.read_graphml, fh) - pytest.raises(nx.NetworkXError, nx.parse_graphml, ugly) - - def test_read_attributes_with_groups(self): - data = """\ - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 - - - - - - - - - - - - - - - - - - - - - - Group 3 - - - - - - - - - - Folder 3 - - - - - - - - - - - - - - - - - - - - - Group 1 - - - - - - - - - - Folder 1 - - - - - - - - - - - - - - - - - - 1 - - - - - - - - - - - - - - - - - - - 3 - - - - - - - - - - - - - - - - - - - - - - - - Group 2 - - - - - - - - - - Folder 2 - - - - - - - - - - - - - - - - - - 5 - - - - - - - - - - - - - - - - - - - 6 - - - - - - - - - - - - - - - - - - - - - - - 9 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -""" - # verify that nodes / attributes are correctly read when part of a group - fh = io.BytesIO(data.encode('UTF-8')) - G = nx.read_graphml(fh) - data = [x for _, x in G.nodes(data=True)] - assert len(data) == 9 - for node_data in data: - assert node_data['CustomProperty'] != '' - - -class TestWriteGraphML(BaseGraphML): - writer = staticmethod(nx.write_graphml_lxml) - - @classmethod - def setup_class(cls): - BaseGraphML.setup_class() - _ = pytest.importorskip("lxml.etree") - - def test_write_interface(self): - try: - import lxml.etree - assert nx.write_graphml == nx.write_graphml_lxml - except ImportError: - assert nx.write_graphml == nx.write_graphml_xml - - def test_write_read_simple_directed_graphml(self): - G = self.simple_directed_graph - G.graph['hi'] = 'there' - fh = io.BytesIO() - self.writer(G, fh) - fh.seek(0) - H = nx.read_graphml(fh) - assert sorted(G.nodes()) == sorted(H.nodes()) - assert sorted(G.edges()) == sorted(H.edges()) - assert sorted(G.edges(data=True)) == sorted(H.edges(data=True)) - self.simple_directed_fh.seek(0) - - def test_write_read_attribute_numeric_type_graphml(self): - from xml.etree.ElementTree import parse - - G = self.attribute_numeric_type_graph - fh = io.BytesIO() - self.writer(G, fh, infer_numeric_types=True) - fh.seek(0) - H = nx.read_graphml(fh) - fh.seek(0) - - assert_nodes_equal(G.nodes(), H.nodes()) - assert_edges_equal(G.edges(), H.edges()) - assert_edges_equal(G.edges(data=True), H.edges(data=True)) - self.attribute_numeric_type_fh.seek(0) - - xml = parse(fh) - # Children are the key elements, and the graph element - children = xml.getroot().getchildren() - assert len(children) == 3 - - keys = [child.items() for child in children[:2]] - - assert len(keys) == 2 - assert ('attr.type', 'double') in keys[0] - assert ('attr.type', 'double') in keys[1] - - def test_more_multigraph_keys(self): - """Writing keys as edge id attributes means keys become strings. - The original keys are stored as data, so read them back in - if `make_str(key) == edge_id` - This allows the adjacency to remain the same. - """ - G = nx.MultiGraph() - G.add_edges_from([('a', 'b', 2), ('a', 'b', 3)]) - fd, fname = tempfile.mkstemp() - self.writer(G, fname) - H = nx.read_graphml(fname) - assert H.is_multigraph() - assert_edges_equal(G.edges(keys=True), H.edges(keys=True)) - assert G._adj == H._adj - os.close(fd) - os.unlink(fname) - - def test_default_attribute(self): - G = nx.Graph(name="Fred") - G.add_node(1, label=1, color='green') - nx.add_path(G, [0, 1, 2, 3]) - G.add_edge(1, 2, weight=3) - G.graph['node_default'] = {'color': 'yellow'} - G.graph['edge_default'] = {'weight': 7} - fh = io.BytesIO() - self.writer(G, fh) - fh.seek(0) - H = nx.read_graphml(fh, node_type=int) - assert_nodes_equal(G.nodes(), H.nodes()) - assert_edges_equal(G.edges(), H.edges()) - assert G.graph == H.graph - - def test_mixed_type_attributes(self): - G = nx.MultiGraph() - G.add_node('n0', special=False) - G.add_node('n1', special=0) - G.add_edge('n0', 'n1', special=False) - G.add_edge('n0', 'n1', special=0) - fh = io.BytesIO() - self.writer(G, fh) - fh.seek(0) - H = nx.read_graphml(fh) - assert H.nodes['n0']['special'] is False - assert H.nodes['n1']['special'] is 0 - assert H.edges['n0','n1',0]['special'] is False - assert H.edges['n0','n1',1]['special'] is 0 - - def test_multigraph_to_graph(self): - # test converting multigraph to graph if no parallel edges found - G = nx.MultiGraph() - G.add_edges_from([('a', 'b', 2), ('b', 'c', 3)]) # no multiedges - fd, fname = tempfile.mkstemp() - self.writer(G, fname) - H = nx.read_graphml(fname) - assert not H.is_multigraph() - os.close(fd) - os.unlink(fname) - - def test_numpy_float(self): - try: - import numpy as np - except: - return - wt = np.float(3.4) - G = nx.Graph([(1, 2, {'weight': wt})]) - fd, fname = tempfile.mkstemp() - self.writer(G, fname) - H = nx.read_graphml(fname, node_type=int) - assert G._adj == H._adj - os.close(fd) - os.unlink(fname) - - def test_numpy_float64(self): - try: - import numpy as np - except: - return - wt = np.float64(3.4) - G = nx.Graph([(1, 2, {'weight': wt})]) - fd, fname = tempfile.mkstemp() - self.writer(G, fname) - H = nx.read_graphml(fname, node_type=int) - assert G.edges == H.edges - wtG = G[1][2]['weight'] - wtH = H[1][2]['weight'] - assert almost_equal(wtG, wtH, places=6) - assert type(wtG) == np.float64 - assert type(wtH) == float - os.close(fd) - os.unlink(fname) - - def test_numpy_float32(self): - try: - import numpy as np - except: - return - wt = np.float32(3.4) - G = nx.Graph([(1, 2, {'weight': wt})]) - fd, fname = tempfile.mkstemp() - self.writer(G, fname) - H = nx.read_graphml(fname, node_type=int) - assert G.edges == H.edges - wtG = G[1][2]['weight'] - wtH = H[1][2]['weight'] - assert almost_equal(wtG, wtH, places=6) - assert type(wtG) == np.float32 - assert type(wtH) == float - os.close(fd) - os.unlink(fname) - - def test_unicode_attributes(self): - G = nx.Graph() - try: # Python 3.x - name1 = chr(2344) + chr(123) + chr(6543) - name2 = chr(5543) + chr(1543) + chr(324) - node_type = str - except ValueError: # Python 2.6+ - name1 = unichr(2344) + unichr(123) + unichr(6543) - name2 = unichr(5543) + unichr(1543) + unichr(324) - node_type = unicode - G.add_edge(name1, 'Radiohead', foo=name2) - fd, fname = tempfile.mkstemp() - self.writer(G, fname) - H = nx.read_graphml(fname, node_type=node_type) - assert G._adj == H._adj - os.close(fd) - os.unlink(fname) - - def test_unicode_escape(self): - # test for handling json escaped stings in python 2 Issue #1880 - import json - a = dict(a='{"a": "123"}') # an object with many chars to escape - try: # Python 3.x - chr(2344) - sa = json.dumps(a) - except ValueError: # Python 2.6+ - sa = unicode(json.dumps(a)) - G = nx.Graph() - G.graph['test'] = sa - fh = io.BytesIO() - self.writer(G, fh) - fh.seek(0) - H = nx.read_graphml(fh) - assert G.graph['test'] == H.graph['test'] - - -class TestXMLGraphML(TestWriteGraphML): - writer = staticmethod(nx.write_graphml_xml) - - @classmethod - def setup_class(cls): - TestWriteGraphML.setup_class() - _ = pytest.importorskip("xml.etree.ElementTree") diff --git a/extensions/fablabchemnitz/networkx/readwrite/tests/test_leda.py b/extensions/fablabchemnitz/networkx/readwrite/tests/test_leda.py deleted file mode 100644 index edf9318d..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/tests/test_leda.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -import networkx as nx -import io - - -class TestLEDA(object): - - def test_parse_leda(self): - data = """#header section \nLEDA.GRAPH \nstring\nint\n-1\n#nodes section\n5 \n|{v1}| \n|{v2}| \n|{v3}| \n|{v4}| \n|{v5}| \n\n#edges section\n7 \n1 2 0 |{4}| \n1 3 0 |{3}| \n2 3 0 |{2}| \n3 4 0 |{3}| \n3 5 0 |{7}| \n4 5 0 |{6}| \n5 1 0 |{foo}|""" - G = nx.parse_leda(data) - G = nx.parse_leda(data.split('\n')) - assert (sorted(G.nodes()) == - ['v1', 'v2', 'v3', 'v4', 'v5']) - assert (sorted(G.edges(data=True)) == - [('v1', 'v2', {'label': '4'}), - ('v1', 'v3', {'label': '3'}), - ('v2', 'v3', {'label': '2'}), - ('v3', 'v4', {'label': '3'}), - ('v3', 'v5', {'label': '7'}), - ('v4', 'v5', {'label': '6'}), - ('v5', 'v1', {'label': 'foo'})]) - - def test_read_LEDA(self): - fh = io.BytesIO() - data = """#header section \nLEDA.GRAPH \nstring\nint\n-1\n#nodes section\n5 \n|{v1}| \n|{v2}| \n|{v3}| \n|{v4}| \n|{v5}| \n\n#edges section\n7 \n1 2 0 |{4}| \n1 3 0 |{3}| \n2 3 0 |{2}| \n3 4 0 |{3}| \n3 5 0 |{7}| \n4 5 0 |{6}| \n5 1 0 |{foo}|""" - G = nx.parse_leda(data) - fh.write(data.encode('UTF-8')) - fh.seek(0) - Gin = nx.read_leda(fh) - assert sorted(G.nodes()) == sorted(Gin.nodes()) - assert sorted(G.edges()) == sorted(Gin.edges()) diff --git a/extensions/fablabchemnitz/networkx/readwrite/tests/test_p2g.py b/extensions/fablabchemnitz/networkx/readwrite/tests/test_p2g.py deleted file mode 100644 index bd7f37c1..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/tests/test_p2g.py +++ /dev/null @@ -1,62 +0,0 @@ -import networkx as nx -import io -from networkx.readwrite.p2g import * -from networkx.testing import * - - -class TestP2G: - - @classmethod - def setup_class(cls): - cls.G = nx.Graph(name="test") - e = [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'e'), ('e', 'f'), ('a', 'f')] - cls.G.add_edges_from(e) - cls.G.add_node('g') - cls.DG = nx.DiGraph(cls.G) - - def test_read_p2g(self): - s = b"""\ -name -3 4 -a -1 2 -b - -c -0 2 -""" - bytesIO = io.BytesIO(s) - G = read_p2g(bytesIO) - assert G.name == 'name' - assert sorted(G) == ['a', 'b', 'c'] - edges = [(str(u), str(v)) for u, v in G.edges()] - assert_edges_equal(G.edges(), [('a', 'c'), ('a', 'b'), ('c', 'a'), ('c', 'c')]) - - def test_write_p2g(self): - s = b"""foo -3 2 -1 -1 -2 -2 -3 - -""" - fh = io.BytesIO() - G = nx.OrderedDiGraph() - G.name = 'foo' - G.add_edges_from([(1, 2), (2, 3)]) - write_p2g(G, fh) - fh.seek(0) - r = fh.read() - assert r == s - - def test_write_read_p2g(self): - fh = io.BytesIO() - G = nx.DiGraph() - G.name = 'foo' - G.add_edges_from([('a', 'b'), ('b', 'c')]) - write_p2g(G, fh) - fh.seek(0) - H = read_p2g(fh) - assert_edges_equal(G.edges(), H.edges()) diff --git a/extensions/fablabchemnitz/networkx/readwrite/tests/test_pajek.py b/extensions/fablabchemnitz/networkx/readwrite/tests/test_pajek.py deleted file mode 100644 index f034347a..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/tests/test_pajek.py +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env python -""" -Pajek tests -""" -import networkx as nx -import os -import tempfile -from networkx.testing import assert_edges_equal, assert_nodes_equal - - -class TestPajek(object): - @classmethod - def setup_class(cls): - cls.data = """*network Tralala\n*vertices 4\n 1 "A1" 0.0938 0.0896 ellipse x_fact 1 y_fact 1\n 2 "Bb" 0.8188 0.2458 ellipse x_fact 1 y_fact 1\n 3 "C" 0.3688 0.7792 ellipse x_fact 1\n 4 "D2" 0.9583 0.8563 ellipse x_fact 1\n*arcs\n1 1 1 h2 0 w 3 c Blue s 3 a1 -130 k1 0.6 a2 -130 k2 0.6 ap 0.5 l "Bezier loop" lc BlueViolet fos 20 lr 58 lp 0.3 la 360\n2 1 1 h2 0 a1 120 k1 1.3 a2 -120 k2 0.3 ap 25 l "Bezier arc" lphi 270 la 180 lr 19 lp 0.5\n1 2 1 h2 0 a1 40 k1 2.8 a2 30 k2 0.8 ap 25 l "Bezier arc" lphi 90 la 0 lp 0.65\n4 2 -1 h2 0 w 1 k1 -2 k2 250 ap 25 l "Circular arc" c Red lc OrangeRed\n3 4 1 p Dashed h2 0 w 2 c OliveGreen ap 25 l "Straight arc" lc PineGreen\n1 3 1 p Dashed h2 0 w 5 k1 -1 k2 -20 ap 25 l "Oval arc" c Brown lc Black\n3 3 -1 h1 6 w 1 h2 12 k1 -2 k2 -15 ap 0.5 l "Circular loop" c Red lc OrangeRed lphi 270 la 180""" - cls.G = nx.MultiDiGraph() - cls.G.add_nodes_from(['A1', 'Bb', 'C', 'D2']) - cls.G.add_edges_from([('A1', 'A1'), ('A1', 'Bb'), ('A1', 'C'), - ('Bb', 'A1'), ('C', 'C'), ('C', 'D2'), - ('D2', 'Bb')]) - - cls.G.graph['name'] = 'Tralala' - (fd, cls.fname) = tempfile.mkstemp() - with os.fdopen(fd, 'wb') as fh: - fh.write(cls.data.encode('UTF-8')) - - @classmethod - def teardown_class(cls): - os.unlink(cls.fname) - - def test_parse_pajek_simple(self): - # Example without node positions or shape - data = """*Vertices 2\n1 "1"\n2 "2"\n*Edges\n1 2\n2 1""" - G = nx.parse_pajek(data) - assert sorted(G.nodes()) == ['1', '2'] - assert_edges_equal(G.edges(), [('1', '2'), ('1', '2')]) - - def test_parse_pajek(self): - G = nx.parse_pajek(self.data) - assert sorted(G.nodes()) == ['A1', 'Bb', 'C', 'D2'] - assert_edges_equal(G.edges(), [('A1', 'A1'), ('A1', 'Bb'), - ('A1', 'C'), ('Bb', 'A1'), - ('C', 'C'), ('C', 'D2'), ('D2', 'Bb')]) - - def test_parse_pajet_mat(self): - data = """*Vertices 3\n1 "one"\n2 "two"\n3 "three"\n*Matrix\n1 1 0\n0 1 0\n0 1 0\n""" - G = nx.parse_pajek(data) - assert set(G.nodes()) == {'one', 'two', 'three'} - assert G.nodes['two'] == {'id': '2'} - assert_edges_equal(set(G.edges()), {('one', 'one'), ('two', 'one'), ('two', 'two'), ('two', 'three')}) - - def test_read_pajek(self): - G = nx.parse_pajek(self.data) - Gin = nx.read_pajek(self.fname) - assert sorted(G.nodes()) == sorted(Gin.nodes()) - assert_edges_equal(G.edges(), Gin.edges()) - assert self.G.graph == Gin.graph - for n in G: - assert G.nodes[n] == Gin.nodes[n] - - def test_write_pajek(self): - import io - G = nx.parse_pajek(self.data) - fh = io.BytesIO() - nx.write_pajek(G,fh) - fh.seek(0) - H = nx.read_pajek(fh) - assert_nodes_equal(list(G), list(H)) - assert_edges_equal(list(G.edges()), list(H.edges())) - # Graph name is left out for now, therefore it is not tested. - # assert_equal(G.graph, H.graph) - - def test_ignored_attribute(self): - import io - G = nx.Graph() - fh = io.BytesIO() - G.add_node(1, int_attr=1) - G.add_node(2, empty_attr=' ') - G.add_edge(1, 2, int_attr=2) - G.add_edge(2, 3, empty_attr=' ') - - import warnings - with warnings.catch_warnings(record=True) as w: - nx.write_pajek(G,fh) - assert len(w) == 4 - - def test_noname(self): - # Make sure we can parse a line such as: *network - # Issue #952 - line = "*network\n" - other_lines = self.data.split('\n')[1:] - data = line + '\n'.join(other_lines) - G = nx.parse_pajek(data) - - def test_unicode(self): - import io - G = nx.Graph() - try: # Python 3.x - name1 = chr(2344) + chr(123) + chr(6543) - name2 = chr(5543) + chr(1543) + chr(324) - except ValueError: # Python 2.6+ - name1 = unichr(2344) + unichr(123) + unichr(6543) - name2 = unichr(5543) + unichr(1543) + unichr(324) - G.add_edge(name1, 'Radiohead', foo=name2) - fh = io.BytesIO() - nx.write_pajek(G, fh) - fh.seek(0) - H = nx.read_pajek(fh) - assert_nodes_equal(list(G), list(H)) - assert_edges_equal(list(G.edges()), list(H.edges())) - assert G.graph == H.graph diff --git a/extensions/fablabchemnitz/networkx/readwrite/tests/test_shp.py b/extensions/fablabchemnitz/networkx/readwrite/tests/test_shp.py deleted file mode 100644 index 1725bd04..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/tests/test_shp.py +++ /dev/null @@ -1,290 +0,0 @@ -"""Unit tests for shp. -""" - -import os -import tempfile -import pytest -ogr = pytest.importorskip('osgeo.ogr') - -import networkx as nx - - -class TestShp(object): - def setup_method(self): - - def createlayer(driver, layerType=ogr.wkbLineString): - lyr = driver.CreateLayer("edges", None, layerType) - namedef = ogr.FieldDefn("Name", ogr.OFTString) - namedef.SetWidth(32) - lyr.CreateField(namedef) - return lyr - - drv = ogr.GetDriverByName("ESRI Shapefile") - - testdir = os.path.join(tempfile.gettempdir(), 'shpdir') - shppath = os.path.join(tempfile.gettempdir(), 'tmpshp.shp') - multi_shppath = os.path.join(tempfile.gettempdir(), 'tmp_mshp.shp') - - self.deletetmp(drv, testdir, shppath, multi_shppath) - os.mkdir(testdir) - - self.names = ['a', 'b', 'c', 'c'] # edgenames - self.paths = ([(1.0, 1.0), (2.0, 2.0)], - [(2.0, 2.0), (3.0, 3.0)], - [(0.9, 0.9), (4.0, 0.9), (4.0, 2.0)]) - - self.simplified_names = ['a', 'b', 'c'] # edgenames - self.simplified_paths = ([(1.0, 1.0), (2.0, 2.0)], - [(2.0, 2.0), (3.0, 3.0)], - [(0.9, 0.9), (4.0, 2.0)]) - - self.multi_names = ['a', 'a', 'a', 'a'] # edgenames - - shp = drv.CreateDataSource(shppath) - lyr = createlayer(shp) - - for path, name in zip(self.paths, self.names): - feat = ogr.Feature(lyr.GetLayerDefn()) - g = ogr.Geometry(ogr.wkbLineString) - for p in path: - g.AddPoint_2D(*p) - feat.SetGeometry(g) - feat.SetField("Name", name) - lyr.CreateFeature(feat) - - # create single record multiline shapefile for testing - multi_shp = drv.CreateDataSource(multi_shppath) - multi_lyr = createlayer(multi_shp, ogr.wkbMultiLineString) - - multi_g = ogr.Geometry(ogr.wkbMultiLineString) - for path in self.paths: - - g = ogr.Geometry(ogr.wkbLineString) - for p in path: - g.AddPoint_2D(*p) - - multi_g.AddGeometry(g) - - multi_feat = ogr.Feature(multi_lyr.GetLayerDefn()) - multi_feat.SetGeometry(multi_g) - multi_feat.SetField("Name", 'a') - multi_lyr.CreateFeature(multi_feat) - - self.shppath = shppath - self.multi_shppath = multi_shppath - self.testdir = testdir - self.drv = drv - - def deletetmp(self, drv, *paths): - for p in paths: - if os.path.exists(p): - drv.DeleteDataSource(p) - - def testload(self): - - def compare_graph_paths_names(g, paths, names): - expected = nx.DiGraph() - for p in paths: - nx.add_path(expected, p) - assert sorted(expected.nodes) == sorted(g.nodes) - assert sorted(expected.edges()) == sorted(g.edges()) - g_names = [g.get_edge_data(s, e)['Name'] for s, e in g.edges()] - assert names == sorted(g_names) - - # simplified - G = nx.read_shp(self.shppath) - compare_graph_paths_names(G, self.simplified_paths, - self.simplified_names) - - # unsimplified - G = nx.read_shp(self.shppath, simplify=False) - compare_graph_paths_names(G, self.paths, self.names) - - # multiline unsimplified - G = nx.read_shp(self.multi_shppath, simplify=False) - compare_graph_paths_names(G, self.paths, self.multi_names) - - def checkgeom(self, lyr, expected): - feature = lyr.GetNextFeature() - actualwkt = [] - while feature: - actualwkt.append(feature.GetGeometryRef().ExportToWkt()) - feature = lyr.GetNextFeature() - assert sorted(expected) == sorted(actualwkt) - - def test_geometryexport(self): - expectedpoints_simple = ( - "POINT (1 1)", - "POINT (2 2)", - "POINT (3 3)", - "POINT (0.9 0.9)", - "POINT (4 2)" - ) - expectedlines_simple = ( - "LINESTRING (1 1,2 2)", - "LINESTRING (2 2,3 3)", - "LINESTRING (0.9 0.9,4.0 0.9,4 2)" - ) - expectedpoints = ( - "POINT (1 1)", - "POINT (2 2)", - "POINT (3 3)", - "POINT (0.9 0.9)", - "POINT (4.0 0.9)", - "POINT (4 2)" - ) - expectedlines = ( - "LINESTRING (1 1,2 2)", - "LINESTRING (2 2,3 3)", - "LINESTRING (0.9 0.9,4.0 0.9)", - "LINESTRING (4.0 0.9,4 2)" - ) - - tpath = os.path.join(tempfile.gettempdir(), 'shpdir') - G = nx.read_shp(self.shppath) - nx.write_shp(G, tpath) - shpdir = ogr.Open(tpath) - self.checkgeom(shpdir.GetLayerByName("nodes"), expectedpoints_simple) - self.checkgeom(shpdir.GetLayerByName("edges"), expectedlines_simple) - - # Test unsimplified - # Nodes should have additional point, - # edges should be 'flattened' - G = nx.read_shp(self.shppath, simplify=False) - nx.write_shp(G, tpath) - shpdir = ogr.Open(tpath) - self.checkgeom(shpdir.GetLayerByName("nodes"), expectedpoints) - self.checkgeom(shpdir.GetLayerByName("edges"), expectedlines) - - def test_attributeexport(self): - def testattributes(lyr, graph): - feature = lyr.GetNextFeature() - while feature: - coords = [] - ref = feature.GetGeometryRef() - last = ref.GetPointCount() - 1 - edge_nodes = (ref.GetPoint_2D(0), ref.GetPoint_2D(last)) - name = feature.GetFieldAsString('Name') - assert graph.get_edge_data(*edge_nodes)['Name'] == name - feature = lyr.GetNextFeature() - - tpath = os.path.join(tempfile.gettempdir(), 'shpdir') - - G = nx.read_shp(self.shppath) - nx.write_shp(G, tpath) - shpdir = ogr.Open(tpath) - edges = shpdir.GetLayerByName("edges") - testattributes(edges, G) - - # Test export of node attributes in nx.write_shp (#2778) - def test_nodeattributeexport(self): - tpath = os.path.join(tempfile.gettempdir(), 'shpdir') - - G = nx.DiGraph() - A = (0, 0) - B = (1, 1) - C = (2, 2) - G.add_edge(A, B) - G.add_edge(A, C) - label = 'node_label' - for n, d in G.nodes(data=True): - d['label'] = label - nx.write_shp(G, tpath) - - H = nx.read_shp(tpath) - for n, d in H.nodes(data=True): - assert d['label'] == label - - def test_wkt_export(self): - G = nx.DiGraph() - tpath = os.path.join(tempfile.gettempdir(), 'shpdir') - points = ( - "POINT (0.9 0.9)", - "POINT (4 2)" - ) - line = ( - "LINESTRING (0.9 0.9,4 2)", - ) - G.add_node(1, Wkt=points[0]) - G.add_node(2, Wkt=points[1]) - G.add_edge(1, 2, Wkt=line[0]) - try: - nx.write_shp(G, tpath) - except Exception as e: - assert False, e - shpdir = ogr.Open(tpath) - self.checkgeom(shpdir.GetLayerByName("nodes"), points) - self.checkgeom(shpdir.GetLayerByName("edges"), line) - - def teardown_method(self): - self.deletetmp(self.drv, self.testdir, self.shppath) - - -def test_read_shp_nofile(): - with pytest.raises(RuntimeError): - G = nx.read_shp("hopefully_this_file_will_not_be_available") - - -class TestMissingGeometry(object): - def setup_method(self): - self.setup_path() - self.delete_shapedir() - self.create_shapedir() - - def teardown_method(self): - self.delete_shapedir() - - def setup_path(self): - self.path = os.path.join(tempfile.gettempdir(), 'missing_geometry') - - def create_shapedir(self): - drv = ogr.GetDriverByName("ESRI Shapefile") - shp = drv.CreateDataSource(self.path) - lyr = shp.CreateLayer("nodes", None, ogr.wkbPoint) - feature = ogr.Feature(lyr.GetLayerDefn()) - feature.SetGeometry(None) - lyr.CreateFeature(feature) - feature.Destroy() - - def delete_shapedir(self): - drv = ogr.GetDriverByName("ESRI Shapefile") - if os.path.exists(self.path): - drv.DeleteDataSource(self.path) - - def test_missing_geometry(self): - with pytest.raises(nx.NetworkXError): - G = nx.read_shp(self.path) - - -class TestMissingAttrWrite(object): - def setup_method(self): - self.setup_path() - self.delete_shapedir() - - def teardown_method(self): - self.delete_shapedir() - - def setup_path(self): - self.path = os.path.join(tempfile.gettempdir(), 'missing_attributes') - - def delete_shapedir(self): - drv = ogr.GetDriverByName("ESRI Shapefile") - if os.path.exists(self.path): - drv.DeleteDataSource(self.path) - - def test_missing_attributes(self): - G = nx.DiGraph() - A = (0, 0) - B = (1, 1) - C = (2, 2) - G.add_edge(A, B, foo=100) - G.add_edge(A, C) - - nx.write_shp(G, self.path) - H = nx.read_shp(self.path) - - for u, v, d in H.edges(data=True): - if u == A and v == B: - assert d['foo'] == 100 - if u == A and v == C: - assert d['foo'] == None diff --git a/extensions/fablabchemnitz/networkx/readwrite/tests/test_sparse6.py b/extensions/fablabchemnitz/networkx/readwrite/tests/test_sparse6.py deleted file mode 100644 index a35b2d4e..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/tests/test_sparse6.py +++ /dev/null @@ -1,147 +0,0 @@ -from io import BytesIO -import tempfile -from unittest import TestCase - - -import networkx as nx -from networkx.testing.utils import assert_edges_equal -from networkx.testing.utils import assert_nodes_equal - - -class TestSparseGraph6(object): - - def test_from_sparse6_bytes(self): - data = b':Q___eDcdFcDeFcE`GaJ`IaHbKNbLM' - G = nx.from_sparse6_bytes(data) - assert_nodes_equal(sorted(G.nodes()), - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17]) - assert_edges_equal(G.edges(), - [(0, 1), (0, 2), (0, 3), (1, 12), (1, 14), (2, 13), - (2, 15), (3, 16), (3, 17), (4, 7), (4, 9), (4, 11), - (5, 6), (5, 8), (5, 9), (6, 10), (6, 11), (7, 8), - (7, 10), (8, 12), (9, 15), (10, 14), (11, 13), - (12, 16), (13, 17), (14, 17), (15, 16)]) - - def test_from_bytes_multigraph_graph(self): - graph_data = b':An' - G = nx.from_sparse6_bytes(graph_data) - assert type(G), nx.Graph - multigraph_data = b':Ab' - M = nx.from_sparse6_bytes(multigraph_data) - assert type(M), nx.MultiGraph - - def test_read_sparse6(self): - data = b':Q___eDcdFcDeFcE`GaJ`IaHbKNbLM' - G = nx.from_sparse6_bytes(data) - fh = BytesIO(data) - Gin = nx.read_sparse6(fh) - assert_nodes_equal(G.nodes(), Gin.nodes()) - assert_edges_equal(G.edges(), Gin.edges()) - - def test_read_many_graph6(self): - # Read many graphs into list - data = (b':Q___eDcdFcDeFcE`GaJ`IaHbKNbLM\n' - b':Q___dCfDEdcEgcbEGbFIaJ`JaHN`IM') - fh = BytesIO(data) - glist = nx.read_sparse6(fh) - assert len(glist) == 2 - for G in glist: - assert_nodes_equal(G.nodes(), - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17]) - - -class TestWriteSparse6(TestCase): - """Unit tests for writing graphs in the sparse6 format. - - Most of the test cases were checked against the sparse6 encoder in Sage. - - """ - - def test_null_graph(self): - G = nx.null_graph() - result = BytesIO() - nx.write_sparse6(G, result) - self.assertEqual(result.getvalue(), b'>>sparse6<<:?\n') - - def test_trivial_graph(self): - G = nx.trivial_graph() - result = BytesIO() - nx.write_sparse6(G, result) - self.assertEqual(result.getvalue(), b'>>sparse6<<:@\n') - - def test_empty_graph(self): - G = nx.empty_graph(5) - result = BytesIO() - nx.write_sparse6(G, result) - self.assertEqual(result.getvalue(), b'>>sparse6<<:D\n') - - def test_large_empty_graph(self): - G = nx.empty_graph(68) - result = BytesIO() - nx.write_sparse6(G, result) - self.assertEqual(result.getvalue(), b'>>sparse6<<:~?@C\n') - - def test_very_large_empty_graph(self): - G = nx.empty_graph(258049) - result = BytesIO() - nx.write_sparse6(G, result) - self.assertEqual(result.getvalue(), b'>>sparse6<<:~~???~?@\n') - - def test_complete_graph(self): - G = nx.complete_graph(4) - result = BytesIO() - nx.write_sparse6(G, result) - self.assertEqual(result.getvalue(), b'>>sparse6<<:CcKI\n') - - def test_no_header(self): - G = nx.complete_graph(4) - result = BytesIO() - nx.write_sparse6(G, result, header=False) - self.assertEqual(result.getvalue(), b':CcKI\n') - - def test_padding(self): - codes = (b':Cdv', b':DaYn', b':EaYnN', b':FaYnL', b':GaYnLz') - for n, code in enumerate(codes, start=4): - G = nx.path_graph(n) - result = BytesIO() - nx.write_sparse6(G, result, header=False) - self.assertEqual(result.getvalue(), code + b'\n') - - def test_complete_bipartite(self): - G = nx.complete_bipartite_graph(6, 9) - result = BytesIO() - nx.write_sparse6(G, result) - # Compared with sage - expected = b'>>sparse6<<:Nk' + b'?G`cJ' * 9 + b'\n' - assert result.getvalue() == expected - - def test_read_write_inverse(self): - for i in list(range(13)) + [31, 47, 62, 63, 64, 72]: - m = min(2 * i, i * i // 2) - g = nx.random_graphs.gnm_random_graph(i, m, seed=i) - gstr = BytesIO() - nx.write_sparse6(g, gstr, header=False) - # Strip the trailing newline. - gstr = gstr.getvalue().rstrip() - g2 = nx.from_sparse6_bytes(gstr) - assert g2.order() == g.order() - assert_edges_equal(g2.edges(), g.edges()) - - def no_directed_graphs(self): - with self.assertRaises(nx.NetworkXNotImplemented): - nx.write_sparse6(nx.DiGraph(), BytesIO()) - - def test_write_path(self): - # On Windows, we can't reopen a file that is open - # So, for test we get a valid name from tempfile but close it. - with tempfile.NamedTemporaryFile() as f: - fullfilename = f.name - # file should be closed now, so write_sparse6 can open it - nx.write_sparse6(nx.null_graph(), fullfilename) - fh = open(fullfilename, mode='rb') - self.assertEqual(fh.read(), b'>>sparse6<<:?\n') - fh.close() - import os - os.remove(fullfilename) diff --git a/extensions/fablabchemnitz/networkx/readwrite/tests/test_yaml.py b/extensions/fablabchemnitz/networkx/readwrite/tests/test_yaml.py deleted file mode 100644 index db7b6b2e..00000000 --- a/extensions/fablabchemnitz/networkx/readwrite/tests/test_yaml.py +++ /dev/null @@ -1,54 +0,0 @@ -""" - Unit tests for yaml. -""" - -import os -import tempfile -import pytest - -import networkx as nx -from networkx.testing import assert_edges_equal, assert_nodes_equal - - -class TestYaml(object): - @classmethod - def setup_class(cls): - cls.build_graphs() - - @classmethod - def build_graphs(cls): - cls.G = nx.Graph(name="test") - e = [('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'e'), ('e', 'f'), ('a', 'f')] - cls.G.add_edges_from(e) - cls.G.add_node('g') - - cls.DG = nx.DiGraph(cls.G) - - cls.MG = nx.MultiGraph() - cls.MG.add_weighted_edges_from([(1, 2, 5), (1, 2, 5), (1, 2, 1), (3, 3, 42)]) - - def assert_equal(self, G, data=False): - (fd, fname) = tempfile.mkstemp() - nx.write_yaml(G, fname) - Gin = nx.read_yaml(fname) - - assert_nodes_equal(list(G), list(Gin)) - assert_edges_equal(G.edges(data=data), Gin.edges(data=data)) - - os.close(fd) - os.unlink(fname) - - def testUndirected(self): - self.assert_equal(self.G, data=False) - - def testDirected(self): - self.assert_equal(self.DG, data=False) - - def testMultiGraph(self): - self.assert_equal(self.MG, data=True) - - -# fixture for pytest tests -def setup_module(module): - import pytest - yaml = pytest.importorskip("yaml") diff --git a/extensions/fablabchemnitz/networkx/relabel.py b/extensions/fablabchemnitz/networkx/relabel.py deleted file mode 100644 index 50ed7714..00000000 --- a/extensions/fablabchemnitz/networkx/relabel.py +++ /dev/null @@ -1,225 +0,0 @@ -# Copyright (C) 2006-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -import networkx as nx - -__all__ = ['convert_node_labels_to_integers', 'relabel_nodes'] - - -def relabel_nodes(G, mapping, copy=True): - """Relabel the nodes of the graph G. - - Parameters - ---------- - G : graph - A NetworkX graph - - mapping : dictionary - A dictionary with the old labels as keys and new labels as values. - A partial mapping is allowed. - - copy : bool (optional, default=True) - If True return a copy, or if False relabel the nodes in place. - - Examples - -------- - To create a new graph with nodes relabeled according to a given - dictionary: - - >>> G = nx.path_graph(3) - >>> sorted(G) - [0, 1, 2] - >>> mapping = {0: 'a', 1: 'b', 2: 'c'} - >>> H = nx.relabel_nodes(G, mapping) - >>> sorted(H) - ['a', 'b', 'c'] - - Nodes can be relabeled with any hashable object, including numbers - and strings: - - >>> import string - >>> G = nx.path_graph(26) # nodes are integers 0 through 25 - >>> sorted(G)[:3] - [0, 1, 2] - >>> mapping = dict(zip(G, string.ascii_lowercase)) - >>> G = nx.relabel_nodes(G, mapping) # nodes are characters a through z - >>> sorted(G)[:3] - ['a', 'b', 'c'] - >>> mapping = dict(zip(G, range(1, 27))) - >>> G = nx.relabel_nodes(G, mapping) # nodes are integers 1 through 26 - >>> sorted(G)[:3] - [1, 2, 3] - - To perform a partial in-place relabeling, provide a dictionary - mapping only a subset of the nodes, and set the `copy` keyword - argument to False: - - >>> G = nx.path_graph(3) # nodes 0-1-2 - >>> mapping = {0: 'a', 1: 'b'} # 0->'a' and 1->'b' - >>> G = nx.relabel_nodes(G, mapping, copy=False) - >>> sorted(G, key=str) - [2, 'a', 'b'] - - A mapping can also be given as a function: - - >>> G = nx.path_graph(3) - >>> H = nx.relabel_nodes(G, lambda x: x ** 2) - >>> list(H) - [0, 1, 4] - - Notes - ----- - Only the nodes specified in the mapping will be relabeled. - - The keyword setting copy=False modifies the graph in place. - Relabel_nodes avoids naming collisions by building a - directed graph from ``mapping`` which specifies the order of - relabelings. Naming collisions, such as a->b, b->c, are ordered - such that "b" gets renamed to "c" before "a" gets renamed "b". - In cases of circular mappings (e.g. a->b, b->a), modifying the - graph is not possible in-place and an exception is raised. - In that case, use copy=True. - - See Also - -------- - convert_node_labels_to_integers - """ - # you can pass a function f(old_label)->new_label - # but we'll just make a dictionary here regardless - if not hasattr(mapping, "__getitem__"): - m = {n: mapping(n) for n in G} - else: - m = mapping - if copy: - return _relabel_copy(G, m) - else: - return _relabel_inplace(G, m) - - -def _relabel_inplace(G, mapping): - old_labels = set(mapping.keys()) - new_labels = set(mapping.values()) - if len(old_labels & new_labels) > 0: - # labels sets overlap - # can we topological sort and still do the relabeling? - D = nx.DiGraph(list(mapping.items())) - D.remove_edges_from(nx.selfloop_edges(D)) - try: - nodes = reversed(list(nx.topological_sort(D))) - except nx.NetworkXUnfeasible: - raise nx.NetworkXUnfeasible('The node label sets are overlapping ' - 'and no ordering can resolve the ' - 'mapping. Use copy=True.') - else: - # non-overlapping label sets - nodes = old_labels - - multigraph = G.is_multigraph() - directed = G.is_directed() - - for old in nodes: - try: - new = mapping[old] - except KeyError: - continue - if new == old: - continue - try: - G.add_node(new, **G.nodes[old]) - except KeyError: - raise KeyError("Node %s is not in the graph" % old) - if multigraph: - new_edges = [(new, new if old == target else target, key, data) - for (_, target, key, data) - in G.edges(old, data=True, keys=True)] - if directed: - new_edges += [(new if old == source else source, new, key, data) - for (source, _, key, data) - in G.in_edges(old, data=True, keys=True)] - else: - new_edges = [(new, new if old == target else target, data) - for (_, target, data) in G.edges(old, data=True)] - if directed: - new_edges += [(new if old == source else source, new, data) - for (source, _, data) in G.in_edges(old, data=True)] - G.remove_node(old) - G.add_edges_from(new_edges) - return G - - -def _relabel_copy(G, mapping): - H = G.__class__() - H.add_nodes_from(mapping.get(n, n) for n in G) - H._node.update((mapping.get(n, n), d.copy()) for n, d in G.nodes.items()) - if G.is_multigraph(): - H.add_edges_from((mapping.get(n1, n1), mapping.get(n2, n2), k, d.copy()) - for (n1, n2, k, d) in G.edges(keys=True, data=True)) - else: - H.add_edges_from((mapping.get(n1, n1), mapping.get(n2, n2), d.copy()) - for (n1, n2, d) in G.edges(data=True)) - H.graph.update(G.graph) - return H - - -def convert_node_labels_to_integers(G, first_label=0, ordering="default", - label_attribute=None): - """Returns a copy of the graph G with the nodes relabeled using - consecutive integers. - - Parameters - ---------- - G : graph - A NetworkX graph - - first_label : int, optional (default=0) - An integer specifying the starting offset in numbering nodes. - The new integer labels are numbered first_label, ..., n-1+first_label. - - ordering : string - "default" : inherit node ordering from G.nodes() - "sorted" : inherit node ordering from sorted(G.nodes()) - "increasing degree" : nodes are sorted by increasing degree - "decreasing degree" : nodes are sorted by decreasing degree - - label_attribute : string, optional (default=None) - Name of node attribute to store old label. If None no attribute - is created. - - Notes - ----- - Node and edge attribute data are copied to the new (relabeled) graph. - - There is no guarantee that the relabeling of nodes to integers will - give the same two integers for two (even identical graphs). - Use the `ordering` argument to try to preserve the order. - - See Also - -------- - relabel_nodes - """ - N = G.number_of_nodes() + first_label - if ordering == "default": - mapping = dict(zip(G.nodes(), range(first_label, N))) - elif ordering == "sorted": - nlist = sorted(G.nodes()) - mapping = dict(zip(nlist, range(first_label, N))) - elif ordering == "increasing degree": - dv_pairs = [(d, n) for (n, d) in G.degree()] - dv_pairs.sort() # in-place sort from lowest to highest degree - mapping = dict(zip([n for d, n in dv_pairs], range(first_label, N))) - elif ordering == "decreasing degree": - dv_pairs = [(d, n) for (n, d) in G.degree()] - dv_pairs.sort() # in-place sort from lowest to highest degree - dv_pairs.reverse() - mapping = dict(zip([n for d, n in dv_pairs], range(first_label, N))) - else: - raise nx.NetworkXError('Unknown node ordering: %s' % ordering) - H = relabel_nodes(G, mapping) - # create node attribute with the old label - if label_attribute is not None: - nx.set_node_attributes(H, {v: k for k, v in mapping.items()}, - label_attribute) - return H diff --git a/extensions/fablabchemnitz/networkx/release.py b/extensions/fablabchemnitz/networkx/release.py deleted file mode 100644 index 4f7bbbdf..00000000 --- a/extensions/fablabchemnitz/networkx/release.py +++ /dev/null @@ -1,224 +0,0 @@ -"""Release data for NetworkX. - -When NetworkX is imported a number of steps are followed to determine -the version information. - - 1) If the release is not a development release (dev=False), then version - information is read from version.py, a file containing statically - defined version information. This file should exist on every - downloadable release of NetworkX since setup.py creates it during - packaging/installation. However, version.py might not exist if one - is running NetworkX from the mercurial repository. In the event that - version.py does not exist, then no vcs information will be available. - - 2) If the release is a development release, then version information - is read dynamically, when possible. If no dynamic information can be - read, then an attempt is made to read the information from version.py. - If version.py does not exist, then no vcs information will be available. - -Clarification: - version.py is created only by setup.py - -When setup.py creates version.py, it does so before packaging/installation. -So the created file is included in the source distribution. When a user -downloads a tar.gz file and extracts the files, the files will not be in a -live version control repository. So when the user runs setup.py to install -NetworkX, we must make sure write_versionfile() does not overwrite the -revision information contained in the version.py that was included in the -tar.gz file. This is why write_versionfile() includes an early escape. - -""" - -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. - -import os -import sys -import time -import datetime - -basedir = os.path.abspath(os.path.split(__file__)[0]) - - -def write_versionfile(): - """Creates a static file containing version information.""" - versionfile = os.path.join(basedir, 'version.py') - - text = '''""" -Version information for NetworkX, created during installation. - -Do not add this file to the repository. - -""" - -import datetime - -version = %(version)r -date = %(date)r - -# Was NetworkX built from a development version? If so, remember that the major -# and minor versions reference the "target" (rather than "current") release. -dev = %(dev)r - -# Format: (name, major, min, revision) -version_info = %(version_info)r - -# Format: a 'datetime.datetime' instance -date_info = %(date_info)r - -# Format: (vcs, vcs_tuple) -vcs_info = %(vcs_info)r - -''' - - # Try to update all information - date, date_info, version, version_info, vcs_info = get_info(dynamic=True) - - def writefile(): - fh = open(versionfile, 'w') - subs = { - 'dev': dev, - 'version': version, - 'version_info': version_info, - 'date': date, - 'date_info': date_info, - 'vcs_info': vcs_info - } - fh.write(text % subs) - fh.close() - - if vcs_info[0] == 'mercurial': - # Then, we want to update version.py. - writefile() - else: - if os.path.isfile(versionfile): - # This is *good*, and the most likely place users will be when - # running setup.py. We do not want to overwrite version.py. - # Grab the version so that setup can use it. - # sys.path.insert(0, basedir) - from version import version - # del sys.path[0] - else: - # This is *bad*. It means the user might have a tarball that - # does not include version.py. Let this error raise so we can - # fix the tarball. - # raise Exception('version.py not found!') - - # We no longer require that prepared tarballs include a version.py - # So we use the possibly trunctated value from get_info() - # Then we write a new file. - writefile() - - return version - - -def get_revision(): - """Returns revision and vcs information, dynamically obtained.""" - vcs, revision, tag = None, None, None - - gitdir = os.path.join(basedir, '..', '.git') - - if os.path.isdir(gitdir): - vcs = 'git' - # For now, we are not bothering with revision and tag. - - vcs_info = (vcs, (revision, tag)) - - return revision, vcs_info - - -def get_info(dynamic=True): - # Date information - date_info = datetime.datetime.utcfromtimestamp(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))) - date = time.asctime(date_info.timetuple()) - - revision, version, version_info, vcs_info = None, None, None, None - - import_failed = False - dynamic_failed = False - - if dynamic: - revision, vcs_info = get_revision() - if revision is None: - dynamic_failed = True - - if dynamic_failed or not dynamic: - # This is where most final releases of NetworkX will be. - # All info should come from version.py. If it does not exist, then - # no vcs information will be provided. - # sys.path.insert(0, basedir) - try: - from version import date, date_info, version, version_info, vcs_info - except ImportError: - import_failed = True - vcs_info = (None, (None, None)) - else: - revision = vcs_info[1][0] - #del sys.path[0] - - if import_failed or (dynamic and not dynamic_failed): - # We are here if: - # we failed to determine static versioning info, or - # we successfully obtained dynamic revision info - version = ''.join([str(major), '.', str(minor)]) - if dev: - version += '.dev_' + date_info.strftime("%Y%m%d%H%M%S") - version_info = (name, major, minor, revision) - - return date, date_info, version, version_info, vcs_info - - -# Version information -name = 'networkx' -major = "2" -minor = "4" - - -# Declare current release as a development release. -# Change to False before tagging a release; then change back. -dev = False - - -description = "Python package for creating and manipulating graphs and networks" -license = 'BSD' -authors = {'Hagberg': ('Aric Hagberg', 'hagberg@lanl.gov'), - 'Schult': ('Dan Schult', 'dschult@colgate.edu'), - 'Swart': ('Pieter Swart', 'swart@lanl.gov')} -maintainer = "NetworkX Developers" -maintainer_email = "networkx-discuss@googlegroups.com" -url = 'http://networkx.github.io/' -project_urls = { - "Bug Tracker": "https://github.com/networkx/networkx/issues", - "Documentation": "https://networkx.github.io/documentation/stable/", - "Source Code": "https://github.com/networkx/networkx", -} -platforms = ['Linux', 'Mac OSX', 'Windows', 'Unix'] -keywords = ['Networks', 'Graph Theory', 'Mathematics', - 'network', 'graph', 'discrete mathematics', 'math'] -classifiers = [ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3 :: Only', - 'Topic :: Software Development :: Libraries :: Python Modules', - 'Topic :: Scientific/Engineering :: Bio-Informatics', - 'Topic :: Scientific/Engineering :: Information Analysis', - 'Topic :: Scientific/Engineering :: Mathematics', - 'Topic :: Scientific/Engineering :: Physics'] - -date, date_info, version, version_info, vcs_info = get_info() - -if __name__ == '__main__': - # Write versionfile for nightly snapshots. - write_versionfile() diff --git a/extensions/fablabchemnitz/networkx/testing/__init__.py b/extensions/fablabchemnitz/networkx/testing/__init__.py deleted file mode 100644 index 884ac83d..00000000 --- a/extensions/fablabchemnitz/networkx/testing/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from networkx.testing.utils import * -from networkx.testing.test import run diff --git a/extensions/fablabchemnitz/networkx/testing/test.py b/extensions/fablabchemnitz/networkx/testing/test.py deleted file mode 100644 index 580024b1..00000000 --- a/extensions/fablabchemnitz/networkx/testing/test.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python - - -def run(verbosity=1, doctest=False): - """Run NetworkX tests. - - Parameters - ---------- - verbosity: integer, optional - Level of detail in test reports. Higher numbers provide more detail. - - doctest: bool, optional - True to run doctests in code modules - """ - - import pytest - - pytest_args = ['-l'] - - if verbosity and int(verbosity) > 1: - pytest_args += ["-" + "v"*(int(verbosity)-1)] - - if doctest: - pytest_args += ["--doctest-modules"] - - pytest_args += ["--pyargs", "networkx"] - - try: - code = pytest.main(pytest_args) - except SystemExit as exc: - code = exc.code - - return (code == 0) - - -if __name__ == "__main__": - run() diff --git a/extensions/fablabchemnitz/networkx/testing/tests/__init__.py b/extensions/fablabchemnitz/networkx/testing/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/testing/tests/test_utils.py b/extensions/fablabchemnitz/networkx/testing/tests/test_utils.py deleted file mode 100644 index ba8d3fc6..00000000 --- a/extensions/fablabchemnitz/networkx/testing/tests/test_utils.py +++ /dev/null @@ -1,161 +0,0 @@ -import networkx as nx -from networkx.testing import * - -# thanks to numpy for this GenericTest class (numpy/testing/test_utils.py) - - -class _GenericTest(object): - @classmethod - def _test_equal(cls, a, b): - cls._assert_func(a, b) - - @classmethod - def _test_not_equal(cls, a, b): - try: - cls._assert_func(a, b) - passed = True - except AssertionError: - pass - else: - raise AssertionError("a and b are found equal but are not") - - -class TestNodesEqual(_GenericTest): - _assert_func = assert_nodes_equal - - def test_nodes_equal(self): - a = [1, 2, 5, 4] - b = [4, 5, 1, 2] - self._test_equal(a, b) - - def test_nodes_not_equal(self): - a = [1, 2, 5, 4] - b = [4, 5, 1, 3] - self._test_not_equal(a, b) - - def test_nodes_with_data_equal(self): - G = nx.Graph() - G.add_nodes_from([1, 2, 3], color='red') - H = nx.Graph() - H.add_nodes_from([1, 2, 3], color='red') - self._test_equal(G.nodes(data=True), H.nodes(data=True)) - - def test_edges_with_data_not_equal(self): - G = nx.Graph() - G.add_nodes_from([1, 2, 3], color='red') - H = nx.Graph() - H.add_nodes_from([1, 2, 3], color='blue') - self._test_not_equal(G.nodes(data=True), H.nodes(data=True)) - - -class TestEdgesEqual(_GenericTest): - _assert_func = assert_edges_equal - - def test_edges_equal(self): - a = [(1, 2), (5, 4)] - b = [(4, 5), (1, 2)] - self._test_equal(a, b) - - def test_edges_not_equal(self): - a = [(1, 2), (5, 4)] - b = [(4, 5), (1, 3)] - self._test_not_equal(a, b) - - def test_edges_with_data_equal(self): - G = nx.MultiGraph() - nx.add_path(G, [0, 1, 2], weight=1) - H = nx.MultiGraph() - nx.add_path(H, [0, 1, 2], weight=1) - self._test_equal(G.edges(data=True, keys=True), - H.edges(data=True, keys=True)) - - def test_edges_with_data_not_equal(self): - G = nx.MultiGraph() - nx.add_path(G, [0, 1, 2], weight=1) - H = nx.MultiGraph() - nx.add_path(H, [0, 1, 2], weight=2) - self._test_not_equal(G.edges(data=True, keys=True), - H.edges(data=True, keys=True)) - - def test_no_edges(self): - G = nx.MultiGraph() - H = nx.MultiGraph() - self._test_equal(G.edges(data=True, keys=True), - H.edges(data=True, keys=True)) - - def test_duplicate_edges(self): - a = [(1, 2), (5, 4), (1, 2)] - b = [(4, 5), (1, 2)] - self._test_not_equal(a, b) - - def test_duplicate_edges_with_data(self): - a = [(1, 2, {'weight': 10}), (5, 4), (1, 2, {'weight': 1})] - b = [(4, 5), (1, 2), (1, 2, {'weight': 1})] - self._test_not_equal(a, b) - - def test_order_of_edges_with_data(self): - a = [(1, 2, {'weight': 10}), (1, 2, {'weight': 1})] - b = [(1, 2, {'weight': 1}), (1, 2, {'weight': 10})] - self._test_equal(a, b) - - def test_order_of_multiedges(self): - wt1 = {'weight': 1} - wt2 = {'weight': 2} - a = [(1, 2, wt1), (1, 2, wt1), (1, 2, wt2)] - b = [(1, 2, wt1), (1, 2, wt2), (1, 2, wt2)] - self._test_not_equal(a, b) - - def test_order_of_edges_with_keys(self): - a = [(1, 2, 0, {'weight': 10}), (1, 2, 1, {'weight': 1}), (1, 2, 2)] - b = [(1, 2, 1, {'weight': 1}), (1, 2, 2), (1, 2, 0, {'weight': 10})] - self._test_equal(a, b) - a = [(1, 2, 1, {'weight': 10}), (1, 2, 0, {'weight': 1}), (1, 2, 2)] - b = [(1, 2, 1, {'weight': 1}), (1, 2, 2), (1, 2, 0, {'weight': 10})] - self._test_not_equal(a, b) - - -class TestGraphsEqual(_GenericTest): - _assert_func = assert_graphs_equal - - def test_graphs_equal(self): - G = nx.path_graph(4) - H = nx.Graph() - nx.add_path(H, range(4)) - self._test_equal(G, H) - - def test_digraphs_equal(self): - G = nx.path_graph(4, create_using=nx.DiGraph()) - H = nx.DiGraph() - nx.add_path(H, range(4)) - self._test_equal(G, H) - - def test_multigraphs_equal(self): - G = nx.path_graph(4, create_using=nx.MultiGraph()) - H = nx.MultiGraph() - nx.add_path(H, range(4)) - self._test_equal(G, H) - - def test_multidigraphs_equal(self): - G = nx.path_graph(4, create_using=nx.MultiDiGraph()) - H = nx.MultiDiGraph() - nx.add_path(H, range(4)) - self._test_equal(G, H) - - def test_graphs_not_equal(self): - G = nx.path_graph(4) - H = nx.Graph() - nx.add_cycle(H, range(4)) - self._test_not_equal(G, H) - - def test_graphs_not_equal2(self): - G = nx.path_graph(4) - H = nx.Graph() - nx.add_path(H, range(3)) - self._test_not_equal(G, H) - - def test_graphs_not_equal3(self): - G = nx.path_graph(4) - H = nx.Graph() - nx.add_path(H, range(4)) - H.name = 'path_graph(4)' - self._test_not_equal(G, H) diff --git a/extensions/fablabchemnitz/networkx/testing/utils.py b/extensions/fablabchemnitz/networkx/testing/utils.py deleted file mode 100644 index 1d767917..00000000 --- a/extensions/fablabchemnitz/networkx/testing/utils.py +++ /dev/null @@ -1,60 +0,0 @@ -__all__ = ['assert_nodes_equal', 'assert_edges_equal', 'assert_graphs_equal', - 'almost_equal'] - - -def almost_equal(x, y, places=7): - return round(abs(x - y), places) == 0 - - -def assert_nodes_equal(nodes1, nodes2): - # Assumes iterables of nodes, or (node,datadict) tuples - nlist1 = list(nodes1) - nlist2 = list(nodes2) - try: - d1 = dict(nlist1) - d2 = dict(nlist2) - except (ValueError, TypeError): - d1 = dict.fromkeys(nlist1) - d2 = dict.fromkeys(nlist2) - assert d1 == d2 - - -def assert_edges_equal(edges1, edges2): - # Assumes iterables with u,v nodes as - # edge tuples (u,v), or - # edge tuples with data dicts (u,v,d), or - # edge tuples with keys and data dicts (u,v,k, d) - from collections import defaultdict - d1 = defaultdict(dict) - d2 = defaultdict(dict) - c1 = 0 - for c1, e in enumerate(edges1): - u, v = e[0], e[1] - data = [e[2:]] - if v in d1[u]: - data = d1[u][v] + data - d1[u][v] = data - d1[v][u] = data - c2 = 0 - for c2, e in enumerate(edges2): - u, v = e[0], e[1] - data = [e[2:]] - if v in d2[u]: - data = d2[u][v] + data - d2[u][v] = data - d2[v][u] = data - assert c1 == c2 - # can check one direction because lengths are the same. - for n, nbrdict in d1.items(): - for nbr, datalist in nbrdict.items(): - assert n in d2 - assert nbr in d2[n] - d2datalist = d2[n][nbr] - for data in datalist: - assert datalist.count(data) == d2datalist.count(data) - - -def assert_graphs_equal(graph1, graph2): - assert graph1.adj == graph2.adj - assert graph1.nodes == graph2.nodes - assert graph1.graph == graph2.graph diff --git a/extensions/fablabchemnitz/networkx/tests/__init__.py b/extensions/fablabchemnitz/networkx/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/tests/test_all_random_functions.py b/extensions/fablabchemnitz/networkx/tests/test_all_random_functions.py deleted file mode 100644 index ec92d965..00000000 --- a/extensions/fablabchemnitz/networkx/tests/test_all_random_functions.py +++ /dev/null @@ -1,209 +0,0 @@ -try: - import numpy as np -except ImportError: - from pytest import skip - skip('Numpy not available', allow_module_level=True) -import random - -import networkx as nx -from networkx.algorithms import approximation as approx -from networkx.algorithms import threshold - -progress = 0 - -# store the random numbers after setting a global seed -np.random.seed(42) -np_rv = np.random.rand() -random.seed(42) -py_rv = random.random() - - -def t(f, *args, **kwds): - """call one function and check if global RNG changed""" - global progress - progress += 1 - print(progress, ",", end="") - - f(*args, **kwds) - - after_np_rv = np.random.rand() - # if np_rv != after_np_rv: - # print(np_rv, after_np_rv, "don't match np!") - assert np_rv == after_np_rv - np.random.seed(42) - - after_py_rv = random.random() - # if py_rv != after_py_rv: - # print(py_rv, after_py_rv, "don't match py!") - assert py_rv == after_py_rv - random.seed(42) - - -def run_all_random_functions(seed): - n = 20 - m = 10 - k = l = 2 - s = v = 10 - p = q = p1 = p2 = p_in = p_out = 0.4 - alpha = radius = theta = 0.75 - sizes = (20, 20, 10) - colors = [1, 2, 3] - G = nx.barbell_graph(12, 20) - deg_sequence = in_degree_sequence = w = sequence = aseq = bseq = \ - [3, 2, 1, 3, 2, 1, 3, 2, 1, 2, 1, 2, 1] - - # print("starting...") - t(nx.maximal_independent_set, G, seed=seed) - t(nx.rich_club_coefficient, G, seed=seed, normalized=False) - t(nx.random_reference, G, seed=seed) - t(nx.lattice_reference, G, seed=seed) - t(nx.sigma, G, 1, 2, seed=seed) - t(nx.omega, G, 1, 2, seed=seed) - # print("out of smallworld.py") - t(nx.double_edge_swap, G, seed=seed) - # print("starting connected_double_edge_swap") - t(nx.connected_double_edge_swap, nx.complete_graph(9), seed=seed) - # print("ending connected_double_edge_swap") - t(nx.random_layout, G, seed=seed) - t(nx.fruchterman_reingold_layout, G, seed=seed) - t(nx.algebraic_connectivity, G, seed=seed) - t(nx.fiedler_vector, G, seed=seed) - t(nx.spectral_ordering, G, seed=seed) - # print('starting average_clustering') - t(approx.average_clustering, G, seed=seed) - t(nx.betweenness_centrality, G, seed=seed) - t(nx.edge_betweenness_centrality, G, seed=seed) - t(nx.edge_betweenness, G, seed=seed) - t(nx.approximate_current_flow_betweenness_centrality, G, seed=seed) - # print("kernighan") - t(nx.algorithms.community.kernighan_lin_bisection, G, seed=seed) - # nx.algorithms.community.asyn_lpa_communities(G, seed=seed) - t(nx.algorithms.tree.greedy_branching, G, seed=seed) - t(nx.algorithms.tree.Edmonds, G, seed=seed) - # print('done with graph argument functions') - - t(nx.spectral_graph_forge, G, alpha, seed=seed) - t(nx.algorithms.community.asyn_fluidc, G, k, max_iter=1, seed=seed) - t(nx.algorithms.connectivity.edge_augmentation.greedy_k_edge_augmentation, - G, k, seed=seed) - t(nx.algorithms.coloring.strategy_random_sequential, G, colors, seed=seed) - - cs = ['d', 'i', 'i', 'd', 'd', 'i'] - t(threshold.swap_d, cs, seed=seed) - t(nx.configuration_model, deg_sequence, seed=seed) - t(nx.directed_configuration_model, - in_degree_sequence, in_degree_sequence, seed=seed) - t(nx.expected_degree_graph, w, seed=seed) - t(nx.random_degree_sequence_graph, sequence, seed=seed) - joint_degrees = {1: {4: 1}, - 2: {2: 2, 3: 2, 4: 2}, - 3: {2: 2, 4: 1}, - 4: {1: 1, 2: 2, 3: 1}} - t(nx.joint_degree_graph, joint_degrees, seed=seed) - joint_degree_sequence = [(1, 0), (1, 0), (1, 0), (2, 0), (1, 0), (2, 1), - (0, 1), (0, 1)] - t(nx.random_clustered_graph, joint_degree_sequence, seed=seed) - constructor = [(3, 3, .5), (10, 10, .7)] - t(nx.random_shell_graph, constructor, seed=seed) - mapping = {1: 0.4, 2: 0.3, 3: 0.3} - t(nx.utils.random_weighted_sample, mapping, k, seed=seed) - t(nx.utils.weighted_choice, mapping, seed=seed) - t(nx.algorithms.bipartite.configuration_model, aseq, bseq, seed=seed) - t(nx.algorithms.bipartite.preferential_attachment_graph, - aseq, p, seed=seed) - - def kernel_integral(u, w, z): - return (z - w) - - t(nx.random_kernel_graph, n, kernel_integral, seed=seed) - - sizes = [75, 75, 300] - probs = [[0.25, 0.05, 0.02], - [0.05, 0.35, 0.07], - [0.02, 0.07, 0.40]] - t(nx.stochastic_block_model, sizes, probs, seed=seed) - t(nx.random_partition_graph, sizes, p_in, p_out, seed=seed) - - # print("starting generator functions") - t(threshold.random_threshold_sequence, n, p, seed=seed) - t(nx.tournament.random_tournament, n, seed=seed) - t(nx.relaxed_caveman_graph, l, k, p, seed=seed) - t(nx.planted_partition_graph, l, k, p_in, p_out, seed=seed) - t(nx.gaussian_random_partition_graph, n, s, v, p_in, p_out, seed=seed) - t(nx.gn_graph, n, seed=seed) - t(nx.gnr_graph, n, p, seed=seed) - t(nx.gnc_graph, n, seed=seed) - t(nx.scale_free_graph, n, seed=seed) - t(nx.directed.random_uniform_k_out_graph, n, k, seed=seed) - t(nx.random_k_out_graph, n, k, alpha, seed=seed) - N = 1000 - t(nx.partial_duplication_graph, N, n, p, q, seed=seed) - t(nx.duplication_divergence_graph, n, p, seed=seed) - t(nx.random_geometric_graph, n, radius, seed=seed) - t(nx.soft_random_geometric_graph, n, radius, seed=seed) - t(nx.geographical_threshold_graph, n, theta, seed=seed) - t(nx.waxman_graph, n, seed=seed) - t(nx.navigable_small_world_graph, n, seed=seed) - t(nx.thresholded_random_geometric_graph, n, radius, theta, seed=seed) - t(nx.uniform_random_intersection_graph, n, m, p, seed=seed) - t(nx.k_random_intersection_graph, n, m, k, seed=seed) - - t(nx.general_random_intersection_graph, n, 2, [0.1, 0.5], seed=seed) - t(nx.fast_gnp_random_graph, n, p, seed=seed) - t(nx.gnp_random_graph, n, p, seed=seed) - t(nx.dense_gnm_random_graph, n, m, seed=seed) - t(nx.gnm_random_graph, n, m, seed=seed) - t(nx.newman_watts_strogatz_graph, n, k, p, seed=seed) - t(nx.watts_strogatz_graph, n, k, p, seed=seed) - t(nx.connected_watts_strogatz_graph, n, k, p, seed=seed) - t(nx.random_regular_graph, 3, n, seed=seed) - t(nx.barabasi_albert_graph, n, m, seed=seed) - t(nx.extended_barabasi_albert_graph, n, m, p, q, seed=seed) - t(nx.powerlaw_cluster_graph, n, m, p, seed=seed) - t(nx.random_lobster, n, p1, p2, seed=seed) - t(nx.random_powerlaw_tree, n, seed=seed, tries=5000) - t(nx.random_powerlaw_tree_sequence, 10, seed=seed, tries=5000) - t(nx.random_tree, n, seed=seed) - t(nx.utils.powerlaw_sequence, n, seed=seed) - t(nx.utils.zipf_rv, 2.3, seed=seed) - cdist = [.2, .4, .5, .7, .9, 1.0] - t(nx.utils.discrete_sequence, n, cdistribution=cdist, seed=seed) - t(nx.algorithms.bipartite.random_graph, n, m, p, seed=seed) - t(nx.algorithms.bipartite.gnmk_random_graph, n, m, k, seed=seed) - LFR = nx.generators.LFR_benchmark_graph - t(LFR, 25, 3, 1.5, 0.1, average_degree=3, min_community=10, - seed=seed, max_community=20) - t(nx.random_internet_as_graph, n, seed=seed) - # print("done") - - -# choose to test an integer seed, or whether a single RNG can be everywhere -# np_rng = np.random.RandomState(14) -# seed = np_rng -# seed = 14 - - -# print("NetworkX Version:", nx.__version__) -def test_rng_interface(): - global progress - - # try different kinds of seeds - for seed in [14, np.random.RandomState(14)]: - np.random.seed(42) - random.seed(42) - run_all_random_functions(seed) - progress = 0 - - # check that both global RNGs are unaffected - after_np_rv = np.random.rand() -# if np_rv != after_np_rv: -# print(np_rv, after_np_rv, "don't match np!") - assert np_rv == after_np_rv - after_py_rv = random.random() -# if py_rv != after_py_rv: -# print(py_rv, after_py_rv, "don't match py!") - assert py_rv == after_py_rv - -# print("\nDone testing seed:", seed) - -# test_rng_interface() diff --git a/extensions/fablabchemnitz/networkx/tests/test_convert.py b/extensions/fablabchemnitz/networkx/tests/test_convert.py deleted file mode 100644 index d79abfa6..00000000 --- a/extensions/fablabchemnitz/networkx/tests/test_convert.py +++ /dev/null @@ -1,276 +0,0 @@ -#!/usr/bin/env python -import pytest - -import networkx as nx -from networkx.testing import assert_nodes_equal, assert_edges_equal, assert_graphs_equal -from networkx.convert import (to_networkx_graph, - to_dict_of_dicts, - from_dict_of_dicts, - to_dict_of_lists, - from_dict_of_lists) -from networkx.generators.classic import barbell_graph, cycle_graph - - -class TestConvert(): - def edgelists_equal(self, e1, e2): - return sorted(sorted(e) for e in e1) == sorted(sorted(e) for e in e2) - - def test_simple_graphs(self): - for dest, source in [(to_dict_of_dicts, from_dict_of_dicts), - (to_dict_of_lists, from_dict_of_lists)]: - G = barbell_graph(10, 3) - G.graph = {} - dod = dest(G) - - # Dict of [dicts, lists] - GG = source(dod) - assert_graphs_equal(G, GG) - GW = to_networkx_graph(dod) - assert_graphs_equal(G, GW) - GI = nx.Graph(dod) - assert_graphs_equal(G, GI) - - # With nodelist keyword - P4 = nx.path_graph(4) - P3 = nx.path_graph(3) - P4.graph = {} - P3.graph = {} - dod = dest(P4, nodelist=[0, 1, 2]) - Gdod = nx.Graph(dod) - assert_graphs_equal(Gdod, P3) - - def test_exceptions(self): - # NX graph - class G(object): - adj = None - - pytest.raises(nx.NetworkXError, to_networkx_graph, G) - - # pygraphviz agraph - class G(object): - is_strict = None - - pytest.raises(nx.NetworkXError, to_networkx_graph, G) - - # Dict of [dicts, lists] - G = {"a": 0} - pytest.raises(TypeError, to_networkx_graph, G) - - # list or generator of edges - class G(object): - next = None - - pytest.raises(nx.NetworkXError, to_networkx_graph, G) - - # no match - pytest.raises(nx.NetworkXError, to_networkx_graph, "a") - - def test_digraphs(self): - for dest, source in [(to_dict_of_dicts, from_dict_of_dicts), - (to_dict_of_lists, from_dict_of_lists)]: - G = cycle_graph(10) - - # Dict of [dicts, lists] - dod = dest(G) - GG = source(dod) - assert_nodes_equal(sorted(G.nodes()), sorted(GG.nodes())) - assert_edges_equal(sorted(G.edges()), sorted(GG.edges())) - GW = to_networkx_graph(dod) - assert_nodes_equal(sorted(G.nodes()), sorted(GW.nodes())) - assert_edges_equal(sorted(G.edges()), sorted(GW.edges())) - GI = nx.Graph(dod) - assert_nodes_equal(sorted(G.nodes()), sorted(GI.nodes())) - assert_edges_equal(sorted(G.edges()), sorted(GI.edges())) - - G = cycle_graph(10, create_using=nx.DiGraph) - dod = dest(G) - GG = source(dod, create_using=nx.DiGraph) - assert sorted(G.nodes()) == sorted(GG.nodes()) - assert sorted(G.edges()) == sorted(GG.edges()) - GW = to_networkx_graph(dod, create_using=nx.DiGraph) - assert sorted(G.nodes()) == sorted(GW.nodes()) - assert sorted(G.edges()) == sorted(GW.edges()) - GI = nx.DiGraph(dod) - assert sorted(G.nodes()) == sorted(GI.nodes()) - assert sorted(G.edges()) == sorted(GI.edges()) - - def test_graph(self): - g = nx.cycle_graph(10) - G = nx.Graph() - G.add_nodes_from(g) - G.add_weighted_edges_from((u, v, u) for u, v in g.edges()) - - # Dict of dicts - dod = to_dict_of_dicts(G) - GG = from_dict_of_dicts(dod, create_using=nx.Graph) - assert_nodes_equal(sorted(G.nodes()), sorted(GG.nodes())) - assert_edges_equal(sorted(G.edges()), sorted(GG.edges())) - GW = to_networkx_graph(dod, create_using=nx.Graph) - assert_nodes_equal(sorted(G.nodes()), sorted(GW.nodes())) - assert_edges_equal(sorted(G.edges()), sorted(GW.edges())) - GI = nx.Graph(dod) - assert sorted(G.nodes()) == sorted(GI.nodes()) - assert sorted(G.edges()) == sorted(GI.edges()) - - # Dict of lists - dol = to_dict_of_lists(G) - GG = from_dict_of_lists(dol, create_using=nx.Graph) - # dict of lists throws away edge data so set it to none - enone = [(u, v, {}) for (u, v, d) in G.edges(data=True)] - assert_nodes_equal(sorted(G.nodes()), sorted(GG.nodes())) - assert_edges_equal(enone, sorted(GG.edges(data=True))) - GW = to_networkx_graph(dol, create_using=nx.Graph) - assert_nodes_equal(sorted(G.nodes()), sorted(GW.nodes())) - assert_edges_equal(enone, sorted(GW.edges(data=True))) - GI = nx.Graph(dol) - assert_nodes_equal(sorted(G.nodes()), sorted(GI.nodes())) - assert_edges_equal(enone, sorted(GI.edges(data=True))) - - def test_with_multiedges_self_loops(self): - G = cycle_graph(10) - XG = nx.Graph() - XG.add_nodes_from(G) - XG.add_weighted_edges_from((u, v, u) for u, v in G.edges()) - XGM = nx.MultiGraph() - XGM.add_nodes_from(G) - XGM.add_weighted_edges_from((u, v, u) for u, v in G.edges()) - XGM.add_edge(0, 1, weight=2) # multiedge - XGS = nx.Graph() - XGS.add_nodes_from(G) - XGS.add_weighted_edges_from((u, v, u) for u, v in G.edges()) - XGS.add_edge(0, 0, weight=100) # self loop - - # Dict of dicts - # with self loops, OK - dod = to_dict_of_dicts(XGS) - GG = from_dict_of_dicts(dod, create_using=nx.Graph) - assert_nodes_equal(XGS.nodes(), GG.nodes()) - assert_edges_equal(XGS.edges(), GG.edges()) - GW = to_networkx_graph(dod, create_using=nx.Graph) - assert_nodes_equal(XGS.nodes(), GW.nodes()) - assert_edges_equal(XGS.edges(), GW.edges()) - GI = nx.Graph(dod) - assert_nodes_equal(XGS.nodes(), GI.nodes()) - assert_edges_equal(XGS.edges(), GI.edges()) - - # Dict of lists - # with self loops, OK - dol = to_dict_of_lists(XGS) - GG = from_dict_of_lists(dol, create_using=nx.Graph) - # dict of lists throws away edge data so set it to none - enone = [(u, v, {}) for (u, v, d) in XGS.edges(data=True)] - assert_nodes_equal(sorted(XGS.nodes()), sorted(GG.nodes())) - assert_edges_equal(enone, sorted(GG.edges(data=True))) - GW = to_networkx_graph(dol, create_using=nx.Graph) - assert_nodes_equal(sorted(XGS.nodes()), sorted(GW.nodes())) - assert_edges_equal(enone, sorted(GW.edges(data=True))) - GI = nx.Graph(dol) - assert_nodes_equal(sorted(XGS.nodes()), sorted(GI.nodes())) - assert_edges_equal(enone, sorted(GI.edges(data=True))) - - # Dict of dicts - # with multiedges, OK - dod = to_dict_of_dicts(XGM) - GG = from_dict_of_dicts(dod, create_using=nx.MultiGraph, - multigraph_input=True) - assert_nodes_equal(sorted(XGM.nodes()), sorted(GG.nodes())) - assert_edges_equal(sorted(XGM.edges()), sorted(GG.edges())) - GW = to_networkx_graph(dod, create_using=nx.MultiGraph, multigraph_input=True) - assert_nodes_equal(sorted(XGM.nodes()), sorted(GW.nodes())) - assert_edges_equal(sorted(XGM.edges()), sorted(GW.edges())) - GI = nx.MultiGraph(dod) # convert can't tell whether to duplicate edges! - assert_nodes_equal(sorted(XGM.nodes()), sorted(GI.nodes())) - #assert_not_equal(sorted(XGM.edges()), sorted(GI.edges())) - assert not sorted(XGM.edges()) == sorted(GI.edges()) - GE = from_dict_of_dicts(dod, create_using=nx.MultiGraph, - multigraph_input=False) - assert_nodes_equal(sorted(XGM.nodes()), sorted(GE.nodes())) - assert sorted(XGM.edges()) != sorted(GE.edges()) - GI = nx.MultiGraph(XGM) - assert_nodes_equal(sorted(XGM.nodes()), sorted(GI.nodes())) - assert_edges_equal(sorted(XGM.edges()), sorted(GI.edges())) - GM = nx.MultiGraph(G) - assert_nodes_equal(sorted(GM.nodes()), sorted(G.nodes())) - assert_edges_equal(sorted(GM.edges()), sorted(G.edges())) - - # Dict of lists - # with multiedges, OK, but better write as DiGraph else you'll - # get double edges - dol = to_dict_of_lists(G) - GG = from_dict_of_lists(dol, create_using=nx.MultiGraph) - assert_nodes_equal(sorted(G.nodes()), sorted(GG.nodes())) - assert_edges_equal(sorted(G.edges()), sorted(GG.edges())) - GW = to_networkx_graph(dol, create_using=nx.MultiGraph) - assert_nodes_equal(sorted(G.nodes()), sorted(GW.nodes())) - assert_edges_equal(sorted(G.edges()), sorted(GW.edges())) - GI = nx.MultiGraph(dol) - assert_nodes_equal(sorted(G.nodes()), sorted(GI.nodes())) - assert_edges_equal(sorted(G.edges()), sorted(GI.edges())) - - def test_edgelists(self): - P = nx.path_graph(4) - e = [(0, 1), (1, 2), (2, 3)] - G = nx.Graph(e) - assert_nodes_equal(sorted(G.nodes()), sorted(P.nodes())) - assert_edges_equal(sorted(G.edges()), sorted(P.edges())) - assert_edges_equal(sorted(G.edges(data=True)), sorted(P.edges(data=True))) - - e = [(0, 1, {}), (1, 2, {}), (2, 3, {})] - G = nx.Graph(e) - assert_nodes_equal(sorted(G.nodes()), sorted(P.nodes())) - assert_edges_equal(sorted(G.edges()), sorted(P.edges())) - assert_edges_equal(sorted(G.edges(data=True)), sorted(P.edges(data=True))) - - e = ((n, n + 1) for n in range(3)) - G = nx.Graph(e) - assert_nodes_equal(sorted(G.nodes()), sorted(P.nodes())) - assert_edges_equal(sorted(G.edges()), sorted(P.edges())) - assert_edges_equal(sorted(G.edges(data=True)), sorted(P.edges(data=True))) - - def test_directed_to_undirected(self): - edges1 = [(0, 1), (1, 2), (2, 0)] - edges2 = [(0, 1), (1, 2), (0, 2)] - assert self.edgelists_equal(nx.Graph(nx.DiGraph(edges1)).edges(), edges1) - assert self.edgelists_equal(nx.Graph(nx.DiGraph(edges2)).edges(), edges1) - assert self.edgelists_equal(nx.MultiGraph(nx.DiGraph(edges1)).edges(), edges1) - assert self.edgelists_equal(nx.MultiGraph(nx.DiGraph(edges2)).edges(), edges1) - - assert self.edgelists_equal(nx.MultiGraph(nx.MultiDiGraph(edges1)).edges(), - edges1) - assert self.edgelists_equal(nx.MultiGraph(nx.MultiDiGraph(edges2)).edges(), - edges1) - - assert self.edgelists_equal(nx.Graph(nx.MultiDiGraph(edges1)).edges(), edges1) - assert self.edgelists_equal(nx.Graph(nx.MultiDiGraph(edges2)).edges(), edges1) - - def test_attribute_dict_integrity(self): - # we must not replace dict-like graph data structures with dicts - G = nx.OrderedGraph() - G.add_nodes_from("abc") - H = to_networkx_graph(G, create_using=nx.OrderedGraph) - assert list(H.nodes) == list(G.nodes) - H = nx.OrderedDiGraph(G) - assert list(H.nodes) == list(G.nodes) - - def test_to_edgelist(self): - G = nx.Graph([(1, 1)]) - elist = nx.to_edgelist(G, nodelist=list(G)) - assert_edges_equal(G.edges(data=True), elist) - - def test_custom_node_attr_dict_safekeeping(self): - class custom_dict(dict): - pass - - class Custom(nx.Graph): - node_attr_dict_factory = custom_dict - - g = nx.Graph() - g.add_node(1, weight=1) - - h = Custom(g) - assert isinstance(g._node[1], dict) - assert isinstance(h._node[1], custom_dict) - - # this raise exception - # h._node.update((n, dd.copy()) for n, dd in g.nodes.items()) - # assert isinstance(h._node[1], custom_dict) diff --git a/extensions/fablabchemnitz/networkx/tests/test_convert_numpy.py b/extensions/fablabchemnitz/networkx/tests/test_convert_numpy.py deleted file mode 100644 index 49f92d69..00000000 --- a/extensions/fablabchemnitz/networkx/tests/test_convert_numpy.py +++ /dev/null @@ -1,450 +0,0 @@ -import pytest - -import networkx as nx -from networkx.generators.classic import barbell_graph, cycle_graph, path_graph -from networkx.testing.utils import assert_graphs_equal - -#numpy = pytest.importorskip("numpy") - -class TestConvertNumpy(object): - @classmethod - def setup_class(cls): - global np - global np_assert_equal - try: - import numpy as np - np_assert_equal = np.testing.assert_equal - except ImportError: - pytest.skip('Numpy not available', allow_module_level=True) - - def setup_method(self): - self.G1 = barbell_graph(10, 3) - self.G2 = cycle_graph(10, create_using=nx.DiGraph) - - self.G3 = self.create_weighted(nx.Graph()) - self.G4 = self.create_weighted(nx.DiGraph()) - - def test_exceptions(self): - G = np.array("a") - pytest.raises(nx.NetworkXError, nx.to_networkx_graph, G) - - def create_weighted(self, G): - g = cycle_graph(4) - G.add_nodes_from(g) - G.add_weighted_edges_from((u, v, 10 + u) for u, v in g.edges()) - return G - - def assert_equal(self, G1, G2): - assert sorted(G1.nodes()) == sorted(G2.nodes()) - assert sorted(G1.edges()) == sorted(G2.edges()) - - def identity_conversion(self, G, A, create_using): - assert(A.sum() > 0) - GG = nx.from_numpy_matrix(A, create_using=create_using) - self.assert_equal(G, GG) - GW = nx.to_networkx_graph(A, create_using=create_using) - self.assert_equal(G, GW) - GI = nx.empty_graph(0, create_using).__class__(A) - self.assert_equal(G, GI) - - def test_shape(self): - "Conversion from non-square array." - A = np.array([[1, 2, 3], [4, 5, 6]]) - pytest.raises(nx.NetworkXError, nx.from_numpy_matrix, A) - - def test_identity_graph_matrix(self): - "Conversion from graph to matrix to graph." - A = nx.to_numpy_matrix(self.G1) - self.identity_conversion(self.G1, A, nx.Graph()) - - def test_identity_graph_array(self): - "Conversion from graph to array to graph." - A = nx.to_numpy_matrix(self.G1) - A = np.asarray(A) - self.identity_conversion(self.G1, A, nx.Graph()) - - def test_identity_digraph_matrix(self): - """Conversion from digraph to matrix to digraph.""" - A = nx.to_numpy_matrix(self.G2) - self.identity_conversion(self.G2, A, nx.DiGraph()) - - def test_identity_digraph_array(self): - """Conversion from digraph to array to digraph.""" - A = nx.to_numpy_matrix(self.G2) - A = np.asarray(A) - self.identity_conversion(self.G2, A, nx.DiGraph()) - - def test_identity_weighted_graph_matrix(self): - """Conversion from weighted graph to matrix to weighted graph.""" - A = nx.to_numpy_matrix(self.G3) - self.identity_conversion(self.G3, A, nx.Graph()) - - def test_identity_weighted_graph_array(self): - """Conversion from weighted graph to array to weighted graph.""" - A = nx.to_numpy_matrix(self.G3) - A = np.asarray(A) - self.identity_conversion(self.G3, A, nx.Graph()) - - def test_identity_weighted_digraph_matrix(self): - """Conversion from weighted digraph to matrix to weighted digraph.""" - A = nx.to_numpy_matrix(self.G4) - self.identity_conversion(self.G4, A, nx.DiGraph()) - - def test_identity_weighted_digraph_array(self): - """Conversion from weighted digraph to array to weighted digraph.""" - A = nx.to_numpy_matrix(self.G4) - A = np.asarray(A) - self.identity_conversion(self.G4, A, nx.DiGraph()) - - def test_nodelist(self): - """Conversion from graph to matrix to graph with nodelist.""" - P4 = path_graph(4) - P3 = path_graph(3) - nodelist = list(P3) - A = nx.to_numpy_matrix(P4, nodelist=nodelist) - GA = nx.Graph(A) - self.assert_equal(GA, P3) - - # Make nodelist ambiguous by containing duplicates. - nodelist += [nodelist[0]] - pytest.raises(nx.NetworkXError, nx.to_numpy_matrix, P3, nodelist=nodelist) - - def test_weight_keyword(self): - WP4 = nx.Graph() - WP4.add_edges_from((n, n + 1, dict(weight=0.5, other=0.3)) for n in range(3)) - P4 = path_graph(4) - A = nx.to_numpy_matrix(P4) - np_assert_equal(A, nx.to_numpy_matrix(WP4, weight=None)) - np_assert_equal(0.5 * A, nx.to_numpy_matrix(WP4)) - np_assert_equal(0.3 * A, nx.to_numpy_matrix(WP4, weight='other')) - - def test_from_numpy_matrix_type(self): - A = np.matrix([[1]]) - G = nx.from_numpy_matrix(A) - assert type(G[0][0]['weight']) == int - - A = np.matrix([[1]]).astype(np.float) - G = nx.from_numpy_matrix(A) - assert type(G[0][0]['weight']) == float - - A = np.matrix([[1]]).astype(np.str) - G = nx.from_numpy_matrix(A) - assert type(G[0][0]['weight']) == str - - A = np.matrix([[1]]).astype(np.bool) - G = nx.from_numpy_matrix(A) - assert type(G[0][0]['weight']) == bool - - A = np.matrix([[1]]).astype(np.complex) - G = nx.from_numpy_matrix(A) - assert type(G[0][0]['weight']) == complex - - A = np.matrix([[1]]).astype(np.object) - pytest.raises(TypeError, nx.from_numpy_matrix, A) - - G = nx.cycle_graph(3) - A = nx.adj_matrix(G).todense() - H = nx.from_numpy_matrix(A) - assert all(type(m) == int and type(n) == int for m, n in H.edges()) - H = nx.from_numpy_array(A) - assert all(type(m) == int and type(n) == int for m, n in H.edges()) - - def test_from_numpy_matrix_dtype(self): - dt = [('weight', float), ('cost', int)] - A = np.matrix([[(1.0, 2)]], dtype=dt) - G = nx.from_numpy_matrix(A) - assert type(G[0][0]['weight']) == float - assert type(G[0][0]['cost']) == int - assert G[0][0]['cost'] == 2 - assert G[0][0]['weight'] == 1.0 - - def test_to_numpy_recarray(self): - G = nx.Graph() - G.add_edge(1, 2, weight=7.0, cost=5) - A = nx.to_numpy_recarray(G, dtype=[('weight', float), ('cost', int)]) - assert sorted(A.dtype.names) == ['cost', 'weight'] - assert A.weight[0, 1] == 7.0 - assert A.weight[0, 0] == 0.0 - assert A.cost[0, 1] == 5 - assert A.cost[0, 0] == 0 - - def test_numpy_multigraph(self): - G = nx.MultiGraph() - G.add_edge(1, 2, weight=7) - G.add_edge(1, 2, weight=70) - A = nx.to_numpy_matrix(G) - assert A[1, 0] == 77 - A = nx.to_numpy_matrix(G, multigraph_weight=min) - assert A[1, 0] == 7 - A = nx.to_numpy_matrix(G, multigraph_weight=max) - assert A[1, 0] == 70 - - def test_from_numpy_matrix_parallel_edges(self): - """Tests that the :func:`networkx.from_numpy_matrix` function - interprets integer weights as the number of parallel edges when - creating a multigraph. - - """ - A = np.matrix([[1, 1], [1, 2]]) - # First, with a simple graph, each integer entry in the adjacency - # matrix is interpreted as the weight of a single edge in the graph. - expected = nx.DiGraph() - edges = [(0, 0), (0, 1), (1, 0)] - expected.add_weighted_edges_from([(u, v, 1) for (u, v) in edges]) - expected.add_edge(1, 1, weight=2) - actual = nx.from_numpy_matrix(A, parallel_edges=True, - create_using=nx.DiGraph) - assert_graphs_equal(actual, expected) - actual = nx.from_numpy_matrix(A, parallel_edges=False, - create_using=nx.DiGraph) - assert_graphs_equal(actual, expected) - # Now each integer entry in the adjacency matrix is interpreted as the - # number of parallel edges in the graph if the appropriate keyword - # argument is specified. - edges = [(0, 0), (0, 1), (1, 0), (1, 1), (1, 1)] - expected = nx.MultiDiGraph() - expected.add_weighted_edges_from([(u, v, 1) for (u, v) in edges]) - actual = nx.from_numpy_matrix(A, parallel_edges=True, - create_using=nx.MultiDiGraph) - assert_graphs_equal(actual, expected) - expected = nx.MultiDiGraph() - expected.add_edges_from(set(edges), weight=1) - # The sole self-loop (edge 0) on vertex 1 should have weight 2. - expected[1][1][0]['weight'] = 2 - actual = nx.from_numpy_matrix(A, parallel_edges=False, - create_using=nx.MultiDiGraph) - assert_graphs_equal(actual, expected) - - def test_symmetric(self): - """Tests that a symmetric matrix has edges added only once to an - undirected multigraph when using :func:`networkx.from_numpy_matrix`. - - """ - A = np.matrix([[0, 1], [1, 0]]) - G = nx.from_numpy_matrix(A, create_using=nx.MultiGraph) - expected = nx.MultiGraph() - expected.add_edge(0, 1, weight=1) - assert_graphs_equal(G, expected) - - def test_dtype_int_graph(self): - """Test that setting dtype int actually gives an integer matrix. - - For more information, see GitHub pull request #1363. - - """ - G = nx.complete_graph(3) - A = nx.to_numpy_matrix(G, dtype=int) - assert A.dtype == int - - def test_dtype_int_multigraph(self): - """Test that setting dtype int actually gives an integer matrix. - - For more information, see GitHub pull request #1363. - - """ - G = nx.MultiGraph(nx.complete_graph(3)) - A = nx.to_numpy_matrix(G, dtype=int) - assert A.dtype == int - - -class TestConvertNumpyArray(object): - - @classmethod - def setup_class(cls): - global np - global np_assert_equal - np = pytest.importorskip('numpy') - np_assert_equal = np.testing.assert_equal - - def setup_method(self): - self.G1 = barbell_graph(10, 3) - self.G2 = cycle_graph(10, create_using=nx.DiGraph) - self.G3 = self.create_weighted(nx.Graph()) - self.G4 = self.create_weighted(nx.DiGraph()) - - def create_weighted(self, G): - g = cycle_graph(4) - G.add_nodes_from(g) - G.add_weighted_edges_from((u, v, 10 + u) for u, v in g.edges()) - return G - - def assert_equal(self, G1, G2): - assert sorted(G1.nodes()) == sorted(G2.nodes()) - assert sorted(G1.edges()) == sorted(G2.edges()) - - def identity_conversion(self, G, A, create_using): - assert(A.sum() > 0) - GG = nx.from_numpy_array(A, create_using=create_using) - self.assert_equal(G, GG) - GW = nx.to_networkx_graph(A, create_using=create_using) - self.assert_equal(G, GW) - GI = nx.empty_graph(0, create_using).__class__(A) - self.assert_equal(G, GI) - - def test_shape(self): - "Conversion from non-square array." - A = np.array([[1, 2, 3], [4, 5, 6]]) - pytest.raises(nx.NetworkXError, nx.from_numpy_array, A) - - def test_identity_graph_array(self): - "Conversion from graph to array to graph." - A = nx.to_numpy_array(self.G1) - self.identity_conversion(self.G1, A, nx.Graph()) - - def test_identity_digraph_array(self): - """Conversion from digraph to array to digraph.""" - A = nx.to_numpy_array(self.G2) - self.identity_conversion(self.G2, A, nx.DiGraph()) - - def test_identity_weighted_graph_array(self): - """Conversion from weighted graph to array to weighted graph.""" - A = nx.to_numpy_array(self.G3) - self.identity_conversion(self.G3, A, nx.Graph()) - - def test_identity_weighted_digraph_array(self): - """Conversion from weighted digraph to array to weighted digraph.""" - A = nx.to_numpy_array(self.G4) - self.identity_conversion(self.G4, A, nx.DiGraph()) - - def test_nodelist(self): - """Conversion from graph to array to graph with nodelist.""" - P4 = path_graph(4) - P3 = path_graph(3) - nodelist = list(P3) - A = nx.to_numpy_array(P4, nodelist=nodelist) - GA = nx.Graph(A) - self.assert_equal(GA, P3) - - # Make nodelist ambiguous by containing duplicates. - nodelist += [nodelist[0]] - pytest.raises(nx.NetworkXError, nx.to_numpy_array, P3, nodelist=nodelist) - - def test_weight_keyword(self): - WP4 = nx.Graph() - WP4.add_edges_from((n, n + 1, dict(weight=0.5, other=0.3)) for n in range(3)) - P4 = path_graph(4) - A = nx.to_numpy_array(P4) - np_assert_equal(A, nx.to_numpy_array(WP4, weight=None)) - np_assert_equal(0.5 * A, nx.to_numpy_array(WP4)) - np_assert_equal(0.3 * A, nx.to_numpy_array(WP4, weight='other')) - - def test_from_numpy_array_type(self): - A = np.array([[1]]) - G = nx.from_numpy_array(A) - assert type(G[0][0]['weight']) == int - - A = np.array([[1]]).astype(np.float) - G = nx.from_numpy_array(A) - assert type(G[0][0]['weight']) == float - - A = np.array([[1]]).astype(np.str) - G = nx.from_numpy_array(A) - assert type(G[0][0]['weight']) == str - - A = np.array([[1]]).astype(np.bool) - G = nx.from_numpy_array(A) - assert type(G[0][0]['weight']) == bool - - A = np.array([[1]]).astype(np.complex) - G = nx.from_numpy_array(A) - assert type(G[0][0]['weight']) == complex - - A = np.array([[1]]).astype(np.object) - pytest.raises(TypeError, nx.from_numpy_array, A) - - def test_from_numpy_array_dtype(self): - dt = [('weight', float), ('cost', int)] - A = np.array([[(1.0, 2)]], dtype=dt) - G = nx.from_numpy_array(A) - assert type(G[0][0]['weight']) == float - assert type(G[0][0]['cost']) == int - assert G[0][0]['cost'] == 2 - assert G[0][0]['weight'] == 1.0 - - def test_to_numpy_recarray(self): - G = nx.Graph() - G.add_edge(1, 2, weight=7.0, cost=5) - A = nx.to_numpy_recarray(G, dtype=[('weight', float), ('cost', int)]) - assert sorted(A.dtype.names) == ['cost', 'weight'] - assert A.weight[0, 1] == 7.0 - assert A.weight[0, 0] == 0.0 - assert A.cost[0, 1] == 5 - assert A.cost[0, 0] == 0 - - def test_numpy_multigraph(self): - G = nx.MultiGraph() - G.add_edge(1, 2, weight=7) - G.add_edge(1, 2, weight=70) - A = nx.to_numpy_array(G) - assert A[1, 0] == 77 - A = nx.to_numpy_array(G, multigraph_weight=min) - assert A[1, 0] == 7 - A = nx.to_numpy_array(G, multigraph_weight=max) - assert A[1, 0] == 70 - - def test_from_numpy_array_parallel_edges(self): - """Tests that the :func:`networkx.from_numpy_array` function - interprets integer weights as the number of parallel edges when - creating a multigraph. - - """ - A = np.array([[1, 1], [1, 2]]) - # First, with a simple graph, each integer entry in the adjacency - # matrix is interpreted as the weight of a single edge in the graph. - expected = nx.DiGraph() - edges = [(0, 0), (0, 1), (1, 0)] - expected.add_weighted_edges_from([(u, v, 1) for (u, v) in edges]) - expected.add_edge(1, 1, weight=2) - actual = nx.from_numpy_array(A, parallel_edges=True, - create_using=nx.DiGraph) - assert_graphs_equal(actual, expected) - actual = nx.from_numpy_array(A, parallel_edges=False, - create_using=nx.DiGraph) - assert_graphs_equal(actual, expected) - # Now each integer entry in the adjacency matrix is interpreted as the - # number of parallel edges in the graph if the appropriate keyword - # argument is specified. - edges = [(0, 0), (0, 1), (1, 0), (1, 1), (1, 1)] - expected = nx.MultiDiGraph() - expected.add_weighted_edges_from([(u, v, 1) for (u, v) in edges]) - actual = nx.from_numpy_array(A, parallel_edges=True, - create_using=nx.MultiDiGraph) - assert_graphs_equal(actual, expected) - expected = nx.MultiDiGraph() - expected.add_edges_from(set(edges), weight=1) - # The sole self-loop (edge 0) on vertex 1 should have weight 2. - expected[1][1][0]['weight'] = 2 - actual = nx.from_numpy_array(A, parallel_edges=False, - create_using=nx.MultiDiGraph) - assert_graphs_equal(actual, expected) - - def test_symmetric(self): - """Tests that a symmetric array has edges added only once to an - undirected multigraph when using :func:`networkx.from_numpy_array`. - - """ - A = np.array([[0, 1], [1, 0]]) - G = nx.from_numpy_array(A, create_using=nx.MultiGraph) - expected = nx.MultiGraph() - expected.add_edge(0, 1, weight=1) - assert_graphs_equal(G, expected) - - def test_dtype_int_graph(self): - """Test that setting dtype int actually gives an integer array. - - For more information, see GitHub pull request #1363. - - """ - G = nx.complete_graph(3) - A = nx.to_numpy_array(G, dtype=int) - assert A.dtype == int - - def test_dtype_int_multigraph(self): - """Test that setting dtype int actually gives an integer array. - - For more information, see GitHub pull request #1363. - - """ - G = nx.MultiGraph(nx.complete_graph(3)) - A = nx.to_numpy_array(G, dtype=int) - assert A.dtype == int diff --git a/extensions/fablabchemnitz/networkx/tests/test_convert_pandas.py b/extensions/fablabchemnitz/networkx/tests/test_convert_pandas.py deleted file mode 100644 index 0744b100..00000000 --- a/extensions/fablabchemnitz/networkx/tests/test_convert_pandas.py +++ /dev/null @@ -1,173 +0,0 @@ -import pytest -pd = pytest.importorskip("pandas") - -import networkx as nx -from networkx.testing import assert_nodes_equal, assert_edges_equal, \ - assert_graphs_equal - - -class TestConvertPandas(object): - def setup_method(self): - self.rng = pd.np.random.RandomState(seed=5) - ints = self.rng.randint(1, 11, size=(3, 2)) - a = ['A', 'B', 'C'] - b = ['D', 'A', 'E'] - df = pd.DataFrame(ints, columns=['weight', 'cost']) - df[0] = a # Column label 0 (int) - df['b'] = b # Column label 'b' (str) - self.df = df - - mdf = pd.DataFrame([[4, 16, 'A', 'D']], - columns=['weight', 'cost', 0, 'b']) - self.mdf = df.append(mdf) - - def test_exceptions(self): - G = pd.DataFrame(["a"]) # adj - pytest.raises(nx.NetworkXError, nx.to_networkx_graph, G) - G = pd.DataFrame(["a", 0.0]) # elist - pytest.raises(nx.NetworkXError, nx.to_networkx_graph, G) - df = pd.DataFrame([[1, 1], [1, 0]], dtype=int, - index=[1, 2], columns=["a", "b"]) - pytest.raises(nx.NetworkXError, nx.from_pandas_adjacency, df) - - def test_from_edgelist_all_attr(self): - Gtrue = nx.Graph([('E', 'C', {'cost': 9, 'weight': 10}), - ('B', 'A', {'cost': 1, 'weight': 7}), - ('A', 'D', {'cost': 7, 'weight': 4})]) - G = nx.from_pandas_edgelist(self.df, 0, 'b', True) - assert_graphs_equal(G, Gtrue) - # MultiGraph - MGtrue = nx.MultiGraph(Gtrue) - MGtrue.add_edge('A', 'D', cost=16, weight=4) - MG = nx.from_pandas_edgelist(self.mdf, 0, 'b', True, nx.MultiGraph()) - assert_graphs_equal(MG, MGtrue) - - def test_from_edgelist_multi_attr(self): - Gtrue = nx.Graph([('E', 'C', {'cost': 9, 'weight': 10}), - ('B', 'A', {'cost': 1, 'weight': 7}), - ('A', 'D', {'cost': 7, 'weight': 4})]) - G = nx.from_pandas_edgelist(self.df, 0, 'b', ['weight', 'cost']) - assert_graphs_equal(G, Gtrue) - - def test_from_edgelist_multi_attr_incl_target(self): - Gtrue = nx.Graph([('E', 'C', {0: 'C', 'b': 'E', 'weight': 10}), - ('B', 'A', {0: 'B', 'b': 'A', 'weight': 7}), - ('A', 'D', {0: 'A', 'b': 'D', 'weight': 4})]) - G = nx.from_pandas_edgelist(self.df, 0, 'b', [0, 'b', 'weight']) - assert_graphs_equal(G, Gtrue) - - def test_from_edgelist_multidigraph_and_edge_attr(self): - # example from issue #2374 - edges = [('X1', 'X4', {'Co': 'zA', 'Mi': 0, 'St': 'X1'}), - ('X1', 'X4', {'Co': 'zB', 'Mi': 54, 'St': 'X2'}), - ('X1', 'X4', {'Co': 'zB', 'Mi': 49, 'St': 'X3'}), - ('X1', 'X4', {'Co': 'zB', 'Mi': 44, 'St': 'X4'}), - ('Y1', 'Y3', {'Co': 'zC', 'Mi': 0, 'St': 'Y1'}), - ('Y1', 'Y3', {'Co': 'zC', 'Mi': 34, 'St': 'Y2'}), - ('Y1', 'Y3', {'Co': 'zC', 'Mi': 29, 'St': 'X2'}), - ('Y1', 'Y3', {'Co': 'zC', 'Mi': 24, 'St': 'Y3'}), - ('Z1', 'Z3', {'Co': 'zD', 'Mi': 0, 'St': 'Z1'}), - ('Z1', 'Z3', {'Co': 'zD', 'Mi': 14, 'St': 'X3'})] - Gtrue = nx.MultiDiGraph(edges) - df = pd.DataFrame.from_dict({ - 'O': ['X1', 'X1', 'X1', 'X1', 'Y1', 'Y1', 'Y1', 'Y1', 'Z1', 'Z1'], - 'D': ['X4', 'X4', 'X4', 'X4', 'Y3', 'Y3', 'Y3', 'Y3', 'Z3', 'Z3'], - 'St': ['X1', 'X2', 'X3', 'X4', 'Y1', 'Y2', 'X2', 'Y3', 'Z1', 'X3'], - 'Co': ['zA', 'zB', 'zB', 'zB', 'zC', 'zC', 'zC', 'zC', 'zD', 'zD'], - 'Mi': [0, 54, 49, 44, 0, 34, 29, 24, 0, 14]}) - G1 = nx.from_pandas_edgelist(df, source='O', target='D', - edge_attr=True, - create_using=nx.MultiDiGraph) - G2 = nx.from_pandas_edgelist(df, source='O', target='D', - edge_attr=['St', 'Co', 'Mi'], - create_using=nx.MultiDiGraph) - assert_graphs_equal(G1, Gtrue) - assert_graphs_equal(G2, Gtrue) - - def test_from_edgelist_one_attr(self): - Gtrue = nx.Graph([('E', 'C', {'weight': 10}), - ('B', 'A', {'weight': 7}), - ('A', 'D', {'weight': 4})]) - G = nx.from_pandas_edgelist(self.df, 0, 'b', 'weight') - assert_graphs_equal(G, Gtrue) - - def test_from_edgelist_int_attr_name(self): - # note: this also tests that edge_attr can be `source` - Gtrue = nx.Graph([('E', 'C', {0: 'C'}), - ('B', 'A', {0: 'B'}), - ('A', 'D', {0: 'A'})]) - G = nx.from_pandas_edgelist(self.df, 0, 'b', 0) - assert_graphs_equal(G, Gtrue) - - def test_from_edgelist_invalid_attr(self): - pytest.raises(nx.NetworkXError, nx.from_pandas_edgelist, - self.df, 0, 'b', 'misspell') - pytest.raises(nx.NetworkXError, nx.from_pandas_edgelist, - self.df, 0, 'b', 1) - # see Issue #3562 - edgeframe = pd.DataFrame([[0, 1], [1, 2], [2, 0]], columns=['s', 't']) - pytest.raises(nx.NetworkXError, nx.from_pandas_edgelist, - edgeframe, 's', 't', True) - pytest.raises(nx.NetworkXError, nx.from_pandas_edgelist, - edgeframe, 's', 't', 'weight') - pytest.raises(nx.NetworkXError, nx.from_pandas_edgelist, - edgeframe, 's', 't', ['weight', 'size']) - - def test_from_edgelist_no_attr(self): - Gtrue = nx.Graph([('E', 'C', {}), - ('B', 'A', {}), - ('A', 'D', {})]) - G = nx.from_pandas_edgelist(self.df, 0, 'b',) - assert_graphs_equal(G, Gtrue) - - def test_from_edgelist(self): - # Pandas DataFrame - g = nx.cycle_graph(10) - G = nx.Graph() - G.add_nodes_from(g) - G.add_weighted_edges_from((u, v, u) for u, v in g.edges()) - edgelist = nx.to_edgelist(G) - source = [s for s, t, d in edgelist] - target = [t for s, t, d in edgelist] - weight = [d['weight'] for s, t, d in edgelist] - edges = pd.DataFrame({'source': source, - 'target': target, - 'weight': weight}) - GG = nx.from_pandas_edgelist(edges, edge_attr='weight') - assert_nodes_equal(G.nodes(), GG.nodes()) - assert_edges_equal(G.edges(), GG.edges()) - GW = nx.to_networkx_graph(edges, create_using=nx.Graph) - assert_nodes_equal(G.nodes(), GW.nodes()) - assert_edges_equal(G.edges(), GW.edges()) - - def test_from_adjacency(self): - nodelist = [1, 2] - dftrue = pd.DataFrame([[1, 1], [1, 0]], dtype=int, - index=nodelist, columns=nodelist) - G = nx.Graph([(1, 1), (1, 2)]) - df = nx.to_pandas_adjacency(G, dtype=int) - pd.testing.assert_frame_equal(df, dftrue) - - def test_roundtrip(self): - # edgelist - Gtrue = nx.Graph([(1, 1), (1, 2)]) - df = nx.to_pandas_edgelist(Gtrue) - G = nx.from_pandas_edgelist(df) - assert_graphs_equal(Gtrue, G) - # adjacency - adj = {1: {1: {'weight': 1}, 2: {'weight': 1}}, 2: {1: {'weight': 1}}} - Gtrue = nx.Graph(adj) - df = nx.to_pandas_adjacency(Gtrue, dtype=int) - G = nx.from_pandas_adjacency(df) - assert_graphs_equal(Gtrue, G) - - def test_from_adjacency_named(self): - # example from issue #3105 - data = {"A": {"A": 0, "B": 0, "C": 0}, - "B": {"A": 1, "B": 0, "C": 0}, - "C": {"A": 0, "B": 1, "C": 0}} - dftrue = pd.DataFrame(data) - df = dftrue[["A", "C", "B"]] - G = nx.from_pandas_adjacency(df, create_using=nx.DiGraph()) - df = nx.to_pandas_adjacency(G, dtype=int) - pd.testing.assert_frame_equal(df, dftrue) diff --git a/extensions/fablabchemnitz/networkx/tests/test_convert_scipy.py b/extensions/fablabchemnitz/networkx/tests/test_convert_scipy.py deleted file mode 100644 index 90dc7c47..00000000 --- a/extensions/fablabchemnitz/networkx/tests/test_convert_scipy.py +++ /dev/null @@ -1,240 +0,0 @@ -import pytest - -import networkx as nx -from networkx.testing import assert_graphs_equal -from networkx.generators.classic import barbell_graph, cycle_graph, path_graph - - -class TestConvertNumpy(object): - @classmethod - def setup_class(cls): - global np, sp, sparse, np_assert_equal - np = pytest.importorskip('numpy') - sp = pytest.importorskip('scipy') - sparse = sp.sparse - np_assert_equal = np.testing.assert_equal - - def setup_method(self): - self.G1 = barbell_graph(10, 3) - self.G2 = cycle_graph(10, create_using=nx.DiGraph) - - self.G3 = self.create_weighted(nx.Graph()) - self.G4 = self.create_weighted(nx.DiGraph()) - - def test_exceptions(self): - class G(object): - format = None - - pytest.raises(nx.NetworkXError, nx.to_networkx_graph, G) - - def create_weighted(self, G): - g = cycle_graph(4) - e = list(g.edges()) - source = [u for u, v in e] - dest = [v for u, v in e] - weight = [s + 10 for s in source] - ex = zip(source, dest, weight) - G.add_weighted_edges_from(ex) - return G - - def assert_isomorphic(self, G1, G2): - assert nx.is_isomorphic(G1, G2) - - def identity_conversion(self, G, A, create_using): - GG = nx.from_scipy_sparse_matrix(A, create_using=create_using) - self.assert_isomorphic(G, GG) - - GW = nx.to_networkx_graph(A, create_using=create_using) - self.assert_isomorphic(G, GW) - - GI = nx.empty_graph(0, create_using).__class__(A) - self.assert_isomorphic(G, GI) - - ACSR = A.tocsr() - GI = nx.empty_graph(0, create_using).__class__(ACSR) - self.assert_isomorphic(G, GI) - - ACOO = A.tocoo() - GI = nx.empty_graph(0, create_using).__class__(ACOO) - self.assert_isomorphic(G, GI) - - ACSC = A.tocsc() - GI = nx.empty_graph(0, create_using).__class__(ACSC) - self.assert_isomorphic(G, GI) - - AD = A.todense() - GI = nx.empty_graph(0, create_using).__class__(AD) - self.assert_isomorphic(G, GI) - - AA = A.toarray() - GI = nx.empty_graph(0, create_using).__class__(AA) - self.assert_isomorphic(G, GI) - - def test_shape(self): - "Conversion from non-square sparse array." - A = sp.sparse.lil_matrix([[1, 2, 3], [4, 5, 6]]) - pytest.raises(nx.NetworkXError, nx.from_scipy_sparse_matrix, A) - - def test_identity_graph_matrix(self): - "Conversion from graph to sparse matrix to graph." - A = nx.to_scipy_sparse_matrix(self.G1) - self.identity_conversion(self.G1, A, nx.Graph()) - - def test_identity_digraph_matrix(self): - "Conversion from digraph to sparse matrix to digraph." - A = nx.to_scipy_sparse_matrix(self.G2) - self.identity_conversion(self.G2, A, nx.DiGraph()) - - def test_identity_weighted_graph_matrix(self): - """Conversion from weighted graph to sparse matrix to weighted graph.""" - A = nx.to_scipy_sparse_matrix(self.G3) - self.identity_conversion(self.G3, A, nx.Graph()) - - def test_identity_weighted_digraph_matrix(self): - """Conversion from weighted digraph to sparse matrix to weighted digraph.""" - A = nx.to_scipy_sparse_matrix(self.G4) - self.identity_conversion(self.G4, A, nx.DiGraph()) - - def test_nodelist(self): - """Conversion from graph to sparse matrix to graph with nodelist.""" - P4 = path_graph(4) - P3 = path_graph(3) - nodelist = list(P3.nodes()) - A = nx.to_scipy_sparse_matrix(P4, nodelist=nodelist) - GA = nx.Graph(A) - self.assert_isomorphic(GA, P3) - - # Make nodelist ambiguous by containing duplicates. - nodelist += [nodelist[0]] - pytest.raises(nx.NetworkXError, nx.to_numpy_matrix, P3, - nodelist=nodelist) - - def test_weight_keyword(self): - WP4 = nx.Graph() - WP4.add_edges_from((n, n + 1, dict(weight=0.5, other=0.3)) - for n in range(3)) - P4 = path_graph(4) - A = nx.to_scipy_sparse_matrix(P4) - np_assert_equal(A.todense(), - nx.to_scipy_sparse_matrix(WP4, weight=None).todense()) - np_assert_equal(0.5 * A.todense(), - nx.to_scipy_sparse_matrix(WP4).todense()) - np_assert_equal(0.3 * A.todense(), - nx.to_scipy_sparse_matrix(WP4, weight='other').todense()) - - def test_format_keyword(self): - WP4 = nx.Graph() - WP4.add_edges_from((n, n + 1, dict(weight=0.5, other=0.3)) - for n in range(3)) - P4 = path_graph(4) - A = nx.to_scipy_sparse_matrix(P4, format='csr') - np_assert_equal(A.todense(), - nx.to_scipy_sparse_matrix(WP4, weight=None).todense()) - - A = nx.to_scipy_sparse_matrix(P4, format='csc') - np_assert_equal(A.todense(), - nx.to_scipy_sparse_matrix(WP4, weight=None).todense()) - - A = nx.to_scipy_sparse_matrix(P4, format='coo') - np_assert_equal(A.todense(), - nx.to_scipy_sparse_matrix(WP4, weight=None).todense()) - - A = nx.to_scipy_sparse_matrix(P4, format='bsr') - np_assert_equal(A.todense(), - nx.to_scipy_sparse_matrix(WP4, weight=None).todense()) - - A = nx.to_scipy_sparse_matrix(P4, format='lil') - np_assert_equal(A.todense(), - nx.to_scipy_sparse_matrix(WP4, weight=None).todense()) - - A = nx.to_scipy_sparse_matrix(P4, format='dia') - np_assert_equal(A.todense(), - nx.to_scipy_sparse_matrix(WP4, weight=None).todense()) - - A = nx.to_scipy_sparse_matrix(P4, format='dok') - np_assert_equal(A.todense(), - nx.to_scipy_sparse_matrix(WP4, weight=None).todense()) - - def test_format_keyword_raise(self): - with pytest.raises(nx.NetworkXError): - WP4 = nx.Graph() - WP4.add_edges_from((n, n + 1, dict(weight=0.5, other=0.3)) - for n in range(3)) - P4 = path_graph(4) - nx.to_scipy_sparse_matrix(P4, format='any_other') - - def test_null_raise(self): - with pytest.raises(nx.NetworkXError): - nx.to_scipy_sparse_matrix(nx.Graph()) - - def test_empty(self): - G = nx.Graph() - G.add_node(1) - M = nx.to_scipy_sparse_matrix(G) - np_assert_equal(M.todense(), np.matrix([[0]])) - - def test_ordering(self): - G = nx.DiGraph() - G.add_edge(1, 2) - G.add_edge(2, 3) - G.add_edge(3, 1) - M = nx.to_scipy_sparse_matrix(G, nodelist=[3, 2, 1]) - np_assert_equal(M.todense(), np.matrix([[0, 0, 1], [1, 0, 0], [0, 1, 0]])) - - def test_selfloop_graph(self): - G = nx.Graph([(1, 1)]) - M = nx.to_scipy_sparse_matrix(G) - np_assert_equal(M.todense(), np.matrix([[1]])) - - def test_selfloop_digraph(self): - G = nx.DiGraph([(1, 1)]) - M = nx.to_scipy_sparse_matrix(G) - np_assert_equal(M.todense(), np.matrix([[1]])) - - def test_from_scipy_sparse_matrix_parallel_edges(self): - """Tests that the :func:`networkx.from_scipy_sparse_matrix` function - interprets integer weights as the number of parallel edges when - creating a multigraph. - - """ - A = sparse.csr_matrix([[1, 1], [1, 2]]) - # First, with a simple graph, each integer entry in the adjacency - # matrix is interpreted as the weight of a single edge in the graph. - expected = nx.DiGraph() - edges = [(0, 0), (0, 1), (1, 0)] - expected.add_weighted_edges_from([(u, v, 1) for (u, v) in edges]) - expected.add_edge(1, 1, weight=2) - actual = nx.from_scipy_sparse_matrix(A, parallel_edges=True, - create_using=nx.DiGraph) - assert_graphs_equal(actual, expected) - actual = nx.from_scipy_sparse_matrix(A, parallel_edges=False, - create_using=nx.DiGraph) - assert_graphs_equal(actual, expected) - # Now each integer entry in the adjacency matrix is interpreted as the - # number of parallel edges in the graph if the appropriate keyword - # argument is specified. - edges = [(0, 0), (0, 1), (1, 0), (1, 1), (1, 1)] - expected = nx.MultiDiGraph() - expected.add_weighted_edges_from([(u, v, 1) for (u, v) in edges]) - actual = nx.from_scipy_sparse_matrix(A, parallel_edges=True, - create_using=nx.MultiDiGraph) - assert_graphs_equal(actual, expected) - expected = nx.MultiDiGraph() - expected.add_edges_from(set(edges), weight=1) - # The sole self-loop (edge 0) on vertex 1 should have weight 2. - expected[1][1][0]['weight'] = 2 - actual = nx.from_scipy_sparse_matrix(A, parallel_edges=False, - create_using=nx.MultiDiGraph) - assert_graphs_equal(actual, expected) - - def test_symmetric(self): - """Tests that a symmetric matrix has edges added only once to an - undirected multigraph when using - :func:`networkx.from_scipy_sparse_matrix`. - - """ - A = sparse.csr_matrix([[0, 1], [1, 0]]) - G = nx.from_scipy_sparse_matrix(A, create_using=nx.MultiGraph) - expected = nx.MultiGraph() - expected.add_edge(0, 1, weight=1) - assert_graphs_equal(G, expected) diff --git a/extensions/fablabchemnitz/networkx/tests/test_exceptions.py b/extensions/fablabchemnitz/networkx/tests/test_exceptions.py deleted file mode 100644 index 980a2f0f..00000000 --- a/extensions/fablabchemnitz/networkx/tests/test_exceptions.py +++ /dev/null @@ -1,39 +0,0 @@ -import pytest -import networkx as nx - -# smoke tests for exceptions - - -def test_raises_networkxexception(): - with pytest.raises(nx.NetworkXException): - raise nx.NetworkXException - - -def test_raises_networkxerr(): - with pytest.raises(nx.NetworkXError): - raise nx.NetworkXError - - -def test_raises_networkx_pointless_concept(): - with pytest.raises(nx.NetworkXPointlessConcept): - raise nx.NetworkXPointlessConcept - - -def test_raises_networkxalgorithmerr(): - with pytest.raises(nx.NetworkXAlgorithmError): - raise nx.NetworkXAlgorithmError - - -def test_raises_networkx_unfeasible(): - with pytest.raises(nx.NetworkXUnfeasible): - raise nx.NetworkXUnfeasible - - -def test_raises_networkx_no_path(): - with pytest.raises(nx.NetworkXNoPath): - raise nx.NetworkXNoPath - - -def test_raises_networkx_unbounded(): - with pytest.raises(nx.NetworkXUnbounded): - raise nx.NetworkXUnbounded diff --git a/extensions/fablabchemnitz/networkx/tests/test_relabel.py b/extensions/fablabchemnitz/networkx/tests/test_relabel.py deleted file mode 100644 index f9c14380..00000000 --- a/extensions/fablabchemnitz/networkx/tests/test_relabel.py +++ /dev/null @@ -1,184 +0,0 @@ -#!/usr/bin/env python -import pytest -import networkx as nx -from networkx.algorithms.operators import * -from networkx.generators.classic import empty_graph -from networkx.testing import assert_nodes_equal, assert_edges_equal - - -class TestRelabel(): - def test_convert_node_labels_to_integers(self): - # test that empty graph converts fine for all options - G = empty_graph() - H = nx.convert_node_labels_to_integers(G, 100) - assert list(H.nodes()) == [] - assert list(H.edges()) == [] - - for opt in ["default", "sorted", "increasing degree", "decreasing degree"]: - G = empty_graph() - H = nx.convert_node_labels_to_integers(G, 100, ordering=opt) - assert list(H.nodes()) == [] - assert list(H.edges()) == [] - - G = empty_graph() - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'C'), ('C', 'D')]) - H = nx.convert_node_labels_to_integers(G) - degH = (d for n, d in H.degree()) - degG = (d for n, d in G.degree()) - assert sorted(degH) == sorted(degG) - - H = nx.convert_node_labels_to_integers(G, 1000) - degH = (d for n, d in H.degree()) - degG = (d for n, d in G.degree()) - assert sorted(degH) == sorted(degG) - assert_nodes_equal(H.nodes(), [1000, 1001, 1002, 1003]) - - H = nx.convert_node_labels_to_integers(G, ordering="increasing degree") - degH = (d for n, d in H.degree()) - degG = (d for n, d in G.degree()) - assert sorted(degH) == sorted(degG) - assert H.degree(0) == 1 - assert H.degree(1) == 2 - assert H.degree(2) == 2 - assert H.degree(3) == 3 - - H = nx.convert_node_labels_to_integers(G, ordering="decreasing degree") - degH = (d for n, d in H.degree()) - degG = (d for n, d in G.degree()) - assert sorted(degH) == sorted(degG) - assert H.degree(0) == 3 - assert H.degree(1) == 2 - assert H.degree(2) == 2 - assert H.degree(3) == 1 - - H = nx.convert_node_labels_to_integers(G, ordering="increasing degree", - label_attribute='label') - degH = (d for n, d in H.degree()) - degG = (d for n, d in G.degree()) - assert sorted(degH) == sorted(degG) - assert H.degree(0) == 1 - assert H.degree(1) == 2 - assert H.degree(2) == 2 - assert H.degree(3) == 3 - - # check mapping - assert H.nodes[3]['label'] == 'C' - assert H.nodes[0]['label'] == 'D' - assert H.nodes[1]['label'] == 'A' or H.nodes[2]['label'] == 'A' - assert H.nodes[1]['label'] == 'B' or H.nodes[2]['label'] == 'B' - - def test_convert_to_integers2(self): - G = empty_graph() - G.add_edges_from([('C', 'D'), ('A', 'B'), ('A', 'C'), ('B', 'C')]) - H = nx.convert_node_labels_to_integers(G, ordering="sorted") - degH = (d for n, d in H.degree()) - degG = (d for n, d in G.degree()) - assert sorted(degH) == sorted(degG) - - H = nx.convert_node_labels_to_integers(G, ordering="sorted", - label_attribute='label') - assert H.nodes[0]['label'] == 'A' - assert H.nodes[1]['label'] == 'B' - assert H.nodes[2]['label'] == 'C' - assert H.nodes[3]['label'] == 'D' - - def test_convert_to_integers_raise(self): - with pytest.raises(nx.NetworkXError): - G = nx.Graph() - H = nx.convert_node_labels_to_integers(G, ordering="increasing age") - - def test_relabel_nodes_copy(self): - G = nx.empty_graph() - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'C'), ('C', 'D')]) - mapping = {'A': 'aardvark', 'B': 'bear', 'C': 'cat', 'D': 'dog'} - H = nx.relabel_nodes(G, mapping) - assert_nodes_equal(H.nodes(), ['aardvark', 'bear', 'cat', 'dog']) - - def test_relabel_nodes_function(self): - G = nx.empty_graph() - G.add_edges_from([('A', 'B'), ('A', 'C'), ('B', 'C'), ('C', 'D')]) - # function mapping no longer encouraged but works - - def mapping(n): - return ord(n) - H = nx.relabel_nodes(G, mapping) - assert_nodes_equal(H.nodes(), [65, 66, 67, 68]) - - def test_relabel_nodes_graph(self): - G = nx.Graph([('A', 'B'), ('A', 'C'), ('B', 'C'), ('C', 'D')]) - mapping = {'A': 'aardvark', 'B': 'bear', 'C': 'cat', 'D': 'dog'} - H = nx.relabel_nodes(G, mapping) - assert_nodes_equal(H.nodes(), ['aardvark', 'bear', 'cat', 'dog']) - - def test_relabel_nodes_orderedgraph(self): - G = nx.OrderedGraph() - G.add_nodes_from([1, 2, 3]) - G.add_edges_from([(1, 3), (2, 3)]) - mapping = {1: 'a', 2: 'b', 3: 'c'} - H = nx.relabel_nodes(G, mapping) - assert list(H.nodes) == ['a', 'b', 'c'] - - def test_relabel_nodes_digraph(self): - G = nx.DiGraph([('A', 'B'), ('A', 'C'), ('B', 'C'), ('C', 'D')]) - mapping = {'A': 'aardvark', 'B': 'bear', 'C': 'cat', 'D': 'dog'} - H = nx.relabel_nodes(G, mapping, copy=False) - assert_nodes_equal(H.nodes(), ['aardvark', 'bear', 'cat', 'dog']) - - def test_relabel_nodes_multigraph(self): - G = nx.MultiGraph([('a', 'b'), ('a', 'b')]) - mapping = {'a': 'aardvark', 'b': 'bear'} - G = nx.relabel_nodes(G, mapping, copy=False) - assert_nodes_equal(G.nodes(), ['aardvark', 'bear']) - assert_edges_equal(G.edges(), [('aardvark', 'bear'), ('aardvark', 'bear')]) - - def test_relabel_nodes_multidigraph(self): - G = nx.MultiDiGraph([('a', 'b'), ('a', 'b')]) - mapping = {'a': 'aardvark', 'b': 'bear'} - G = nx.relabel_nodes(G, mapping, copy=False) - assert_nodes_equal(G.nodes(), ['aardvark', 'bear']) - assert_edges_equal(G.edges(), [('aardvark', 'bear'), ('aardvark', 'bear')]) - - def test_relabel_isolated_nodes_to_same(self): - G = nx.Graph() - G.add_nodes_from(range(4)) - mapping = {1: 1} - H = nx.relabel_nodes(G, mapping, copy=False) - assert_nodes_equal(H.nodes(), list(range(4))) - - def test_relabel_nodes_missing(self): - with pytest.raises(KeyError): - G = nx.Graph([('A', 'B'), ('A', 'C'), ('B', 'C'), ('C', 'D')]) - mapping = {0: 'aardvark'} - G = nx.relabel_nodes(G, mapping, copy=False) - - def test_relabel_copy_name(self): - G = nx.Graph() - H = nx.relabel_nodes(G, {}, copy=True) - assert H.graph == G.graph - H = nx.relabel_nodes(G, {}, copy=False) - assert H.graph == G.graph - G.name = "first" - H = nx.relabel_nodes(G, {}, copy=True) - assert H.graph == G.graph - H = nx.relabel_nodes(G, {}, copy=False) - assert H.graph == G.graph - - def test_relabel_toposort(self): - K5 = nx.complete_graph(4) - G = nx.complete_graph(4) - G = nx.relabel_nodes(G, dict([(i, i + 1) for i in range(4)]), copy=False) - nx.is_isomorphic(K5, G) - G = nx.complete_graph(4) - G = nx.relabel_nodes(G, dict([(i, i - 1) for i in range(4)]), copy=False) - nx.is_isomorphic(K5, G) - - def test_relabel_selfloop(self): - G = nx.DiGraph([(1, 1), (1, 2), (2, 3)]) - G = nx.relabel_nodes(G, {1: 'One', 2: 'Two', 3: 'Three'}, copy=False) - assert_nodes_equal(G.nodes(), ['One', 'Three', 'Two']) - G = nx.MultiDiGraph([(1, 1), (1, 2), (2, 3)]) - G = nx.relabel_nodes(G, {1: 'One', 2: 'Two', 3: 'Three'}, copy=False) - assert_nodes_equal(G.nodes(), ['One', 'Three', 'Two']) - G = nx.MultiDiGraph([(1, 1)]) - G = nx.relabel_nodes(G, {1: 0}, copy=False) - assert_nodes_equal(G.nodes(), [0]) diff --git a/extensions/fablabchemnitz/networkx/utils/__init__.py b/extensions/fablabchemnitz/networkx/utils/__init__.py deleted file mode 100644 index 9f168ded..00000000 --- a/extensions/fablabchemnitz/networkx/utils/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from networkx.utils.misc import * -from networkx.utils.decorators import * -from networkx.utils.random_sequence import * -from networkx.utils.union_find import * -from networkx.utils.rcm import * -from networkx.utils.heaps import * -from networkx.utils.contextmanagers import * diff --git a/extensions/fablabchemnitz/networkx/utils/contextmanagers.py b/extensions/fablabchemnitz/networkx/utils/contextmanagers.py deleted file mode 100644 index 550a3996..00000000 --- a/extensions/fablabchemnitz/networkx/utils/contextmanagers.py +++ /dev/null @@ -1,31 +0,0 @@ - -from contextlib import contextmanager - -__all__ = [ - 'reversed', -] - - -@contextmanager -def reversed(G): - """A context manager for temporarily reversing a directed graph in place. - - This is a no-op for undirected graphs. - - Parameters - ---------- - G : graph - A NetworkX graph. - """ - directed = G.is_directed() - if directed: - G._pred, G._succ = G._succ, G._pred - G._adj = G._succ - - try: - yield - finally: - if directed: - # Reverse the reverse. - G._pred, G._succ = G._succ, G._pred - G._adj = G._succ diff --git a/extensions/fablabchemnitz/networkx/utils/decorators.py b/extensions/fablabchemnitz/networkx/utils/decorators.py deleted file mode 100644 index 75813d70..00000000 --- a/extensions/fablabchemnitz/networkx/utils/decorators.py +++ /dev/null @@ -1,465 +0,0 @@ -import sys -from warnings import warn - -from collections import defaultdict -from os.path import splitext -from contextlib import contextmanager -try: - from pathlib import Path -except ImportError: - # Use Path to indicate if pathlib exists (like numpy does) - Path = None - -import networkx as nx -from decorator import decorator -from networkx.utils import is_string_like, create_random_state, \ - create_py_random_state - -__all__ = [ - 'not_implemented_for', - 'open_file', - 'nodes_or_number', - 'preserve_random_state', - 'random_state', - 'np_random_state', - 'py_random_state', -] - - -def not_implemented_for(*graph_types): - """Decorator to mark algorithms as not implemented - - Parameters - ---------- - graph_types : container of strings - Entries must be one of 'directed','undirected', 'multigraph', 'graph'. - - Returns - ------- - _require : function - The decorated function. - - Raises - ------ - NetworkXNotImplemented - If any of the packages cannot be imported - - Notes - ----- - Multiple types are joined logically with "and". - For "or" use multiple @not_implemented_for() lines. - - Examples - -------- - Decorate functions like this:: - - @not_implemnted_for('directed') - def sp_function(G): - pass - - @not_implemnted_for('directed','multigraph') - def sp_np_function(G): - pass - """ - @decorator - def _not_implemented_for(not_implement_for_func, *args, **kwargs): - graph = args[0] - terms = {'directed': graph.is_directed(), - 'undirected': not graph.is_directed(), - 'multigraph': graph.is_multigraph(), - 'graph': not graph.is_multigraph()} - match = True - try: - for t in graph_types: - match = match and terms[t] - except KeyError: - raise KeyError('use one or more of ', - 'directed, undirected, multigraph, graph') - if match: - msg = 'not implemented for %s type' % ' '.join(graph_types) - raise nx.NetworkXNotImplemented(msg) - else: - return not_implement_for_func(*args, **kwargs) - return _not_implemented_for - - -def _open_gz(path, mode): - import gzip - return gzip.open(path, mode=mode) - - -def _open_bz2(path, mode): - import bz2 - return bz2.BZ2File(path, mode=mode) - - -# To handle new extensions, define a function accepting a `path` and `mode`. -# Then add the extension to _dispatch_dict. -_dispatch_dict = defaultdict(lambda: open) -_dispatch_dict['.gz'] = _open_gz -_dispatch_dict['.bz2'] = _open_bz2 -_dispatch_dict['.gzip'] = _open_gz - - -def open_file(path_arg, mode='r'): - """Decorator to ensure clean opening and closing of files. - - Parameters - ---------- - path_arg : int - Location of the path argument in args. Even if the argument is a - named positional argument (with a default value), you must specify its - index as a positional argument. - mode : str - String for opening mode. - - Returns - ------- - _open_file : function - Function which cleanly executes the io. - - Examples - -------- - Decorate functions like this:: - - @open_file(0,'r') - def read_function(pathname): - pass - - @open_file(1,'w') - def write_function(G,pathname): - pass - - @open_file(1,'w') - def write_function(G, pathname='graph.dot') - pass - - @open_file('path', 'w+') - def another_function(arg, **kwargs): - path = kwargs['path'] - pass - """ - # Note that this decorator solves the problem when a path argument is - # specified as a string, but it does not handle the situation when the - # function wants to accept a default of None (and then handle it). - # Here is an example: - # - # @open_file('path') - # def some_function(arg1, arg2, path=None): - # if path is None: - # fobj = tempfile.NamedTemporaryFile(delete=False) - # close_fobj = True - # else: - # # `path` could have been a string or file object or something - # # similar. In any event, the decorator has given us a file object - # # and it will close it for us, if it should. - # fobj = path - # close_fobj = False - # - # try: - # fobj.write('blah') - # finally: - # if close_fobj: - # fobj.close() - # - # Normally, we'd want to use "with" to ensure that fobj gets closed. - # However, recall that the decorator will make `path` a file object for - # us, and using "with" would undesirably close that file object. Instead, - # you use a try block, as shown above. When we exit the function, fobj will - # be closed, if it should be, by the decorator. - - @decorator - def _open_file(func_to_be_decorated, *args, **kwargs): - - # Note that since we have used @decorator, *args, and **kwargs have - # already been resolved to match the function signature of func. This - # means default values have been propagated. For example, the function - # func(x, y, a=1, b=2, **kwargs) if called as func(0,1,b=5,c=10) would - # have args=(0,1,1,5) and kwargs={'c':10}. - - # First we parse the arguments of the decorator. The path_arg could - # be an positional argument or a keyword argument. Even if it is - try: - # path_arg is a required positional argument - # This works precisely because we are using @decorator - path = args[path_arg] - except TypeError: - # path_arg is a keyword argument. It is "required" in the sense - # that it must exist, according to the decorator specification, - # It can exist in `kwargs` by a developer specified default value - # or it could have been explicitly set by the user. - try: - path = kwargs[path_arg] - except KeyError: - # Could not find the keyword. Thus, no default was specified - # in the function signature and the user did not provide it. - msg = 'Missing required keyword argument: {0}' - raise nx.NetworkXError(msg.format(path_arg)) - else: - is_kwarg = True - except IndexError: - # A "required" argument was missing. This can only happen if - # the decorator of the function was incorrectly specified. - # So this probably is not a user error, but a developer error. - msg = "path_arg of open_file decorator is incorrect" - raise nx.NetworkXError(msg) - else: - is_kwarg = False - - # Now we have the path_arg. There are two types of input to consider: - # 1) string representing a path that should be opened - # 2) an already opened file object - if is_string_like(path): - ext = splitext(path)[1] - fobj = _dispatch_dict[ext](path, mode=mode) - close_fobj = True - elif hasattr(path, 'read'): - # path is already a file-like object - fobj = path - close_fobj = False - elif Path is not None and isinstance(path, Path): - # path is a pathlib reference to a filename - fobj = _dispatch_dict[path.suffix](str(path), mode=mode) - close_fobj = True - else: - # could be None, in which case the algorithm will deal with it - fobj = path - close_fobj = False - - # Insert file object into args or kwargs. - if is_kwarg: - new_args = args - kwargs[path_arg] = fobj - else: - # args is a tuple, so we must convert to list before modifying it. - new_args = list(args) - new_args[path_arg] = fobj - - # Finally, we call the original function, making sure to close the fobj - try: - result = func_to_be_decorated(*new_args, **kwargs) - finally: - if close_fobj: - fobj.close() - - return result - - return _open_file - - -def nodes_or_number(which_args): - """Decorator to allow number of nodes or container of nodes. - - Parameters - ---------- - which_args : int or sequence of ints - Location of the node arguments in args. Even if the argument is a - named positional argument (with a default value), you must specify its - index as a positional argument. - If more than one node argument is allowed, can be a list of locations. - - Returns - ------- - _nodes_or_numbers : function - Function which replaces int args with ranges. - - Examples - -------- - Decorate functions like this:: - - @nodes_or_number(0) - def empty_graph(nodes): - pass - - @nodes_or_number([0,1]) - def grid_2d_graph(m1, m2, periodic=False): - pass - - @nodes_or_number(1) - def full_rary_tree(r, n) - # r is a number. n can be a number of a list of nodes - pass - """ - @decorator - def _nodes_or_number(func_to_be_decorated, *args, **kw): - # form tuple of arg positions to be converted. - try: - iter_wa = iter(which_args) - except TypeError: - iter_wa = (which_args,) - # change each argument in turn - new_args = list(args) - for i in iter_wa: - n = args[i] - try: - nodes = list(range(n)) - except TypeError: - nodes = tuple(n) - else: - if n < 0: - msg = "Negative number of nodes not valid: %i" % n - raise nx.NetworkXError(msg) - new_args[i] = (n, nodes) - return func_to_be_decorated(*new_args, **kw) - return _nodes_or_number - - -def preserve_random_state(func): - """ Decorator to preserve the numpy.random state during a function. - - Parameters - ---------- - func : function - function around which to preserve the random state. - - Returns - ------- - wrapper : function - Function which wraps the input function by saving the state before - calling the function and restoring the function afterward. - - Examples - -------- - Decorate functions like this:: - - @preserve_random_state - def do_random_stuff(x, y): - return x + y * numpy.random.random() - - Notes - ----- - If numpy.random is not importable, the state is not saved or restored. - """ - try: - from numpy.random import get_state, seed, set_state - - @contextmanager - def save_random_state(): - state = get_state() - try: - yield - finally: - set_state(state) - - def wrapper(*args, **kwargs): - with save_random_state(): - seed(1234567890) - return func(*args, **kwargs) - wrapper.__name__ = func.__name__ - return wrapper - except ImportError: - return func - - -def random_state(random_state_index): - """Decorator to generate a numpy.random.RandomState instance. - - Argument position `random_state_index` is processed by create_random_state. - The result is a numpy.random.RandomState instance. - - Parameters - ---------- - random_state_index : int - Location of the random_state argument in args that is to be used to - generate the numpy.random.RandomState instance. Even if the argument is - a named positional argument (with a default value), you must specify - its index as a positional argument. - - Returns - ------- - _random_state : function - Function whose random_state keyword argument is a RandomState instance. - - Examples - -------- - Decorate functions like this:: - - @np_random_state(0) - def random_float(random_state=None): - return random_state.rand() - - @np_random_state(1) - def random_array(dims, random_state=1): - return random_state.rand(*dims) - - See Also - -------- - py_random_state - """ - @decorator - def _random_state(func, *args, **kwargs): - # Parse the decorator arguments. - try: - random_state_arg = args[random_state_index] - except TypeError: - raise nx.NetworkXError("random_state_index must be an integer") - except IndexError: - raise nx.NetworkXError("random_state_index is incorrect") - - # Create a numpy.random.RandomState instance - random_state = create_random_state(random_state_arg) - - # args is a tuple, so we must convert to list before modifying it. - new_args = list(args) - new_args[random_state_index] = random_state - return func(*new_args, **kwargs) - return _random_state - - -np_random_state = random_state - - -def py_random_state(random_state_index): - """Decorator to generate a random.Random instance (or equiv). - - Argument position `random_state_index` processed by create_py_random_state. - The result is either a random.Random instance, or numpy.random.RandomState - instance with additional attributes to mimic basic methods of Random. - - Parameters - ---------- - random_state_index : int - Location of the random_state argument in args that is to be used to - generate the numpy.random.RandomState instance. Even if the argument is - a named positional argument (with a default value), you must specify - its index as a positional argument. - - Returns - ------- - _random_state : function - Function whose random_state keyword argument is a RandomState instance. - - Examples - -------- - Decorate functions like this:: - - @py_random_state(0) - def random_float(random_state=None): - return random_state.rand() - - @py_random_state(1) - def random_array(dims, random_state=1): - return random_state.rand(*dims) - - See Also - -------- - np_random_state - """ - @decorator - def _random_state(func, *args, **kwargs): - # Parse the decorator arguments. - try: - random_state_arg = args[random_state_index] - except TypeError: - raise nx.NetworkXError("random_state_index must be an integer") - except IndexError: - raise nx.NetworkXError("random_state_index is incorrect") - - # Create a numpy.random.RandomState instance - random_state = create_py_random_state(random_state_arg) - - # args is a tuple, so we must convert to list before modifying it. - new_args = list(args) - new_args[random_state_index] = random_state - return func(*new_args, **kwargs) - return _random_state diff --git a/extensions/fablabchemnitz/networkx/utils/heaps.py b/extensions/fablabchemnitz/networkx/utils/heaps.py deleted file mode 100644 index ecf12408..00000000 --- a/extensions/fablabchemnitz/networkx/utils/heaps.py +++ /dev/null @@ -1,369 +0,0 @@ -""" -Min-heaps. -""" - -__author__ = """ysitu """ -# Copyright (C) 2014 ysitu -# All rights reserved. -# BSD license. - -from heapq import heappop, heappush -from itertools import count -import networkx as nx - -__all__ = ['MinHeap', 'PairingHeap', 'BinaryHeap'] - - -class MinHeap(object): - """Base class for min-heaps. - - A MinHeap stores a collection of key-value pairs ordered by their values. - It supports querying the minimum pair, inserting a new pair, decreasing the - value in an existing pair and deleting the minimum pair. - """ - - class _Item(object): - """Used by subclassess to represent a key-value pair. - """ - __slots__ = ('key', 'value') - - def __init__(self, key, value): - self.key = key - self.value = value - - def __repr__(self): - return repr((self.key, self.value)) - - def __init__(self): - """Initialize a new min-heap. - """ - self._dict = {} - - def min(self): - """Query the minimum key-value pair. - - Returns - ------- - key, value : tuple - The key-value pair with the minimum value in the heap. - - Raises - ------ - NetworkXError - If the heap is empty. - """ - raise NotImplementedError - - def pop(self): - """Delete the minimum pair in the heap. - - Returns - ------- - key, value : tuple - The key-value pair with the minimum value in the heap. - - Raises - ------ - NetworkXError - If the heap is empty. - """ - raise NotImplementedError - - def get(self, key, default=None): - """Returns the value associated with a key. - - Parameters - ---------- - key : hashable object - The key to be looked up. - - default : object - Default value to return if the key is not present in the heap. - Default value: None. - - Returns - ------- - value : object. - The value associated with the key. - """ - raise NotImplementedError - - def insert(self, key, value, allow_increase=False): - """Insert a new key-value pair or modify the value in an existing - pair. - - Parameters - ---------- - key : hashable object - The key. - - value : object comparable with existing values. - The value. - - allow_increase : bool - Whether the value is allowed to increase. If False, attempts to - increase an existing value have no effect. Default value: False. - - Returns - ------- - decreased : bool - True if a pair is inserted or the existing value is decreased. - """ - raise NotImplementedError - - def __nonzero__(self): - """Returns whether the heap if empty. - """ - return bool(self._dict) - - def __bool__(self): - """Returns whether the heap if empty. - """ - return bool(self._dict) - - def __len__(self): - """Returns the number of key-value pairs in the heap. - """ - return len(self._dict) - - def __contains__(self, key): - """Returns whether a key exists in the heap. - - Parameters - ---------- - key : any hashable object. - The key to be looked up. - """ - return key in self._dict - - -def _inherit_doc(cls): - """Decorator for inheriting docstrings from base classes. - """ - def func(fn): - fn.__doc__ = cls.__dict__[fn.__name__].__doc__ - return fn - return func - - -class PairingHeap(MinHeap): - """A pairing heap. - """ - - class _Node(MinHeap._Item): - """A node in a pairing heap. - - A tree in a pairing heap is stored using the left-child, right-sibling - representation. - """ - __slots__ = ('left', 'next', 'prev', 'parent') - - def __init__(self, key, value): - super(PairingHeap._Node, self).__init__(key, value) - # The leftmost child. - self.left = None - # The next sibling. - self.next = None - # The previous sibling. - self.prev = None - # The parent. - self.parent = None - - def __init__(self): - """Initialize a pairing heap. - """ - super(PairingHeap, self).__init__() - self._root = None - - @_inherit_doc(MinHeap) - def min(self): - if self._root is None: - raise nx.NetworkXError('heap is empty.') - return (self._root.key, self._root.value) - - @_inherit_doc(MinHeap) - def pop(self): - if self._root is None: - raise nx.NetworkXError('heap is empty.') - min_node = self._root - self._root = self._merge_children(self._root) - del self._dict[min_node.key] - return (min_node.key, min_node.value) - - @_inherit_doc(MinHeap) - def get(self, key, default=None): - node = self._dict.get(key) - return node.value if node is not None else default - - @_inherit_doc(MinHeap) - def insert(self, key, value, allow_increase=False): - node = self._dict.get(key) - root = self._root - if node is not None: - if value < node.value: - node.value = value - if node is not root and value < node.parent.value: - self._cut(node) - self._root = self._link(root, node) - return True - elif allow_increase and value > node.value: - node.value = value - child = self._merge_children(node) - # Nonstandard step: Link the merged subtree with the root. See - # below for the standard step. - if child is not None: - self._root = self._link(self._root, child) - # Standard step: Perform a decrease followed by a pop as if the - # value were the smallest in the heap. Then insert the new - # value into the heap. - # if node is not root: - # self._cut(node) - # if child is not None: - # root = self._link(root, child) - # self._root = self._link(root, node) - # else: - # self._root = (self._link(node, child) - # if child is not None else node) - return False - else: - # Insert a new key. - node = self._Node(key, value) - self._dict[key] = node - self._root = self._link(root, node) if root is not None else node - return True - - def _link(self, root, other): - """Link two nodes, making the one with the smaller value the parent of - the other. - """ - if other.value < root.value: - root, other = other, root - next = root.left - other.next = next - if next is not None: - next.prev = other - other.prev = None - root.left = other - other.parent = root - return root - - def _merge_children(self, root): - """Merge the subtrees of the root using the standard two-pass method. - The resulting subtree is detached from the root. - """ - node = root.left - root.left = None - if node is not None: - link = self._link - # Pass 1: Merge pairs of consecutive subtrees from left to right. - # At the end of the pass, only the prev pointers of the resulting - # subtrees have meaningful values. The other pointers will be fixed - # in pass 2. - prev = None - while True: - next = node.next - if next is None: - node.prev = prev - break - next_next = next.next - node = link(node, next) - node.prev = prev - prev = node - if next_next is None: - break - node = next_next - # Pass 2: Successively merge the subtrees produced by pass 1 from - # right to left with the rightmost one. - prev = node.prev - while prev is not None: - prev_prev = prev.prev - node = link(prev, node) - prev = prev_prev - # Now node can become the new root. Its has no parent nor siblings. - node.prev = None - node.next = None - node.parent = None - return node - - def _cut(self, node): - """Cut a node from its parent. - """ - prev = node.prev - next = node.next - if prev is not None: - prev.next = next - else: - node.parent.left = next - node.prev = None - if next is not None: - next.prev = prev - node.next = None - node.parent = None - - -class BinaryHeap(MinHeap): - """A binary heap. - """ - - def __init__(self): - """Initialize a binary heap. - """ - super(BinaryHeap, self).__init__() - self._heap = [] - self._count = count() - - @_inherit_doc(MinHeap) - def min(self): - dict = self._dict - if not dict: - raise nx.NetworkXError('heap is empty') - heap = self._heap - pop = heappop - # Repeatedly remove stale key-value pairs until a up-to-date one is - # met. - while True: - value, _, key = heap[0] - if key in dict and value == dict[key]: - break - pop(heap) - return (key, value) - - @_inherit_doc(MinHeap) - def pop(self): - dict = self._dict - if not dict: - raise nx.NetworkXError('heap is empty') - heap = self._heap - pop = heappop - # Repeatedly remove stale key-value pairs until a up-to-date one is - # met. - while True: - value, _, key = heap[0] - pop(heap) - if key in dict and value == dict[key]: - break - del dict[key] - return (key, value) - - @_inherit_doc(MinHeap) - def get(self, key, default=None): - return self._dict.get(key, default) - - @_inherit_doc(MinHeap) - def insert(self, key, value, allow_increase=False): - dict = self._dict - if key in dict: - old_value = dict[key] - if value < old_value or (allow_increase and value > old_value): - # Since there is no way to efficiently obtain the location of a - # key-value pair in the heap, insert a new pair even if ones - # with the same key may already be present. Deem the old ones - # as stale and skip them when the minimum pair is queried. - dict[key] = value - heappush(self._heap, (value, next(self._count), key)) - return value < old_value - return False - else: - dict[key] = value - heappush(self._heap, (value, next(self._count), key)) - return True diff --git a/extensions/fablabchemnitz/networkx/utils/mapped_queue.py b/extensions/fablabchemnitz/networkx/utils/mapped_queue.py deleted file mode 100644 index 888a310b..00000000 --- a/extensions/fablabchemnitz/networkx/utils/mapped_queue.py +++ /dev/null @@ -1,196 +0,0 @@ -# -*- coding: utf-8 -*- -# -# priorityq: An object-oriented priority queue with updatable priorities. -# -# Copyright 2018 Edward L. Platt -# -# This file is part of NetworkX -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -# -# Authors: -# Edward L. Platt -# -"""Priority queue class with updatable priorities. -""" - -import heapq - -__all__ = ['MappedQueue'] - - -class MappedQueue(object): - """The MappedQueue class implements an efficient minimum heap. The - smallest element can be popped in O(1) time, new elements can be pushed - in O(log n) time, and any element can be removed or updated in O(log n) - time. The queue cannot contain duplicate elements and an attempt to push an - element already in the queue will have no effect. - - MappedQueue complements the heapq package from the python standard - library. While MappedQueue is designed for maximum compatibility with - heapq, it has slightly different functionality. - - Examples - -------- - - A `MappedQueue` can be created empty or optionally given an array of - initial elements. Calling `push()` will add an element and calling `pop()` - will remove and return the smallest element. - - >>> q = MappedQueue([916, 50, 4609, 493, 237]) - >>> q.push(1310) - True - >>> x = [q.pop() for i in range(len(q.h))] - >>> x - [50, 237, 493, 916, 1310, 4609] - - Elements can also be updated or removed from anywhere in the queue. - - >>> q = MappedQueue([916, 50, 4609, 493, 237]) - >>> q.remove(493) - >>> q.update(237, 1117) - >>> x = [q.pop() for i in range(len(q.h))] - >>> x - [50, 916, 1117, 4609] - - References - ---------- - .. [1] Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2001). - Introduction to algorithms second edition. - .. [2] Knuth, D. E. (1997). The art of computer programming (Vol. 3). - Pearson Education. - """ - - def __init__(self, data=[]): - """Priority queue class with updatable priorities. - """ - self.h = list(data) - self.d = dict() - self._heapify() - - def __len__(self): - return len(self.h) - - def _heapify(self): - """Restore heap invariant and recalculate map.""" - heapq.heapify(self.h) - self.d = dict([(elt, pos) for pos, elt in enumerate(self.h)]) - if len(self.h) != len(self.d): - raise AssertionError("Heap contains duplicate elements") - - def push(self, elt): - """Add an element to the queue.""" - # If element is already in queue, do nothing - if elt in self.d: - return False - # Add element to heap and dict - pos = len(self.h) - self.h.append(elt) - self.d[elt] = pos - # Restore invariant by sifting down - self._siftdown(pos) - return True - - def pop(self): - """Remove and return the smallest element in the queue.""" - # Remove smallest element - elt = self.h[0] - del self.d[elt] - # If elt is last item, remove and return - if len(self.h) == 1: - self.h.pop() - return elt - # Replace root with last element - last = self.h.pop() - self.h[0] = last - self.d[last] = 0 - # Restore invariant by sifting up, then down - pos = self._siftup(0) - self._siftdown(pos) - # Return smallest element - return elt - - def update(self, elt, new): - """Replace an element in the queue with a new one.""" - # Replace - pos = self.d[elt] - self.h[pos] = new - del self.d[elt] - self.d[new] = pos - # Restore invariant by sifting up, then down - pos = self._siftup(pos) - self._siftdown(pos) - - def remove(self, elt): - """Remove an element from the queue.""" - # Find and remove element - try: - pos = self.d[elt] - del self.d[elt] - except KeyError: - # Not in queue - raise - # If elt is last item, remove and return - if pos == len(self.h) - 1: - self.h.pop() - return - # Replace elt with last element - last = self.h.pop() - self.h[pos] = last - self.d[last] = pos - # Restore invariant by sifting up, then down - pos = self._siftup(pos) - self._siftdown(pos) - - def _siftup(self, pos): - """Move element at pos down to a leaf by repeatedly moving the smaller - child up.""" - h, d = self.h, self.d - elt = h[pos] - # Continue until element is in a leaf - end_pos = len(h) - left_pos = (pos << 1) + 1 - while left_pos < end_pos: - # Left child is guaranteed to exist by loop predicate - left = h[left_pos] - try: - right_pos = left_pos + 1 - right = h[right_pos] - # Out-of-place, swap with left unless right is smaller - if right < left: - h[pos], h[right_pos] = right, elt - pos, right_pos = right_pos, pos - d[elt], d[right] = pos, right_pos - else: - h[pos], h[left_pos] = left, elt - pos, left_pos = left_pos, pos - d[elt], d[left] = pos, left_pos - except IndexError: - # Left leaf is the end of the heap, swap - h[pos], h[left_pos] = left, elt - pos, left_pos = left_pos, pos - d[elt], d[left] = pos, left_pos - # Update left_pos - left_pos = (pos << 1) + 1 - return pos - - def _siftdown(self, pos): - """Restore invariant by repeatedly replacing out-of-place element with - its parent.""" - h, d = self.h, self.d - elt = h[pos] - # Continue until element is at root - while pos > 0: - parent_pos = (pos - 1) >> 1 - parent = h[parent_pos] - if parent > elt: - # Swap out-of-place element with parent - h[parent_pos], h[pos] = elt, parent - parent_pos, pos = pos, parent_pos - d[elt] = pos - d[parent] = parent_pos - else: - # Invariant is satisfied - break - return pos diff --git a/extensions/fablabchemnitz/networkx/utils/misc.py b/extensions/fablabchemnitz/networkx/utils/misc.py deleted file mode 100644 index a0e85bdb..00000000 --- a/extensions/fablabchemnitz/networkx/utils/misc.py +++ /dev/null @@ -1,450 +0,0 @@ -""" -Miscellaneous Helpers for NetworkX. - -These are not imported into the base networkx namespace but -can be accessed, for example, as - ->>> import networkx ->>> networkx.utils.is_string_like('spam') -True -""" -# Authors: Aric Hagberg (hagberg@lanl.gov), -# Dan Schult(dschult@colgate.edu), -# Ben Edwards(bedwards@cs.unm.edu) - -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -from collections import defaultdict -from collections import deque -import warnings -import sys -import uuid -from itertools import tee, chain -import networkx as nx - -# itertools.accumulate is only available on Python 3.2 or later. -# -# Once support for Python versions less than 3.2 is dropped, this code should -# be removed. -try: - from itertools import accumulate -except ImportError: - import operator - - # The code for this function is from the Python 3.5 documentation, - # distributed under the PSF license: - # - def accumulate(iterable, func=operator.add): - it = iter(iterable) - try: - total = next(it) - except StopIteration: - return - yield total - for element in it: - total = func(total, element) - yield total - -# 2.x/3.x compatibility -try: - basestring -except NameError: - basestring = str - unicode = str - -# some cookbook stuff -# used in deciding whether something is a bunch of nodes, edges, etc. -# see G.add_nodes and others in Graph Class in networkx/base.py - - -def is_string_like(obj): # from John Hunter, types-free version - """Check if obj is string.""" - return isinstance(obj, basestring) - - -def iterable(obj): - """ Return True if obj is iterable with a well-defined len().""" - if hasattr(obj, "__iter__"): - return True - try: - len(obj) - except: - return False - return True - - -def flatten(obj, result=None): - """ Return flattened version of (possibly nested) iterable object. """ - if not iterable(obj) or is_string_like(obj): - return obj - if result is None: - result = [] - for item in obj: - if not iterable(item) or is_string_like(item): - result.append(item) - else: - flatten(item, result) - return obj.__class__(result) - - -def make_list_of_ints(sequence): - """Return list of ints from sequence of integral numbers. - - All elements of the sequence must satisfy int(element) == element - or a ValueError is raised. Sequence is iterated through once. - - If sequence is a list, the non-int values are replaced with ints. - So, no new list is created - """ - msg = 'sequence is not all integers: %s' - if not isinstance(sequence, list): - result = [] - for i in sequence: - try: - ii = int(i) - except ValueError: - raise nx.NetworkXError(msg % i) from None - if ii != i: - raise nx.NetworkXError(msg % i) - result.append(ii) - return result - # original sequence is a list... in-place conversion to ints - for indx, i in enumerate(sequence): - if isinstance(i, int): - continue - try: - ii = int(i) - except ValueError: - raise nx.NetworkXError(msg % i) from None - if ii != i: - raise nx.NetworkXError(msg % i) - sequence[indx] = ii - return sequence - - -def is_list_of_ints(intlist): - """ Return True if list is a list of ints. """ - if not isinstance(intlist, list): - return False - for i in intlist: - if not isinstance(i, int): - return False - return True - - -PY2 = sys.version_info[0] == 2 -if PY2: - def make_str(x): - """Returns the string representation of t.""" - if isinstance(x, unicode): - return x - else: - # Note, this will not work unless x is ascii-encoded. - # That is good, since we should be working with unicode anyway. - # Essentially, unless we are reading a file, we demand that users - # convert any encoded strings to unicode before using the library. - # - # Also, the str() is necessary to convert integers, etc. - # unicode(3) works, but unicode(3, 'unicode-escape') wants a buffer - # - return unicode(str(x), 'unicode-escape') -else: - def make_str(x): - """Returns the string representation of t.""" - return str(x) - - -def generate_unique_node(): - """ Generate a unique node label.""" - return str(uuid.uuid1()) - - -def default_opener(filename): - """Opens `filename` using system's default program. - - Parameters - ---------- - filename : str - The path of the file to be opened. - - """ - from subprocess import call - - cmds = {'darwin': ['open'], - 'linux': ['xdg-open'], - 'linux2': ['xdg-open'], - 'win32': ['cmd.exe', '/C', 'start', '']} - cmd = cmds[sys.platform] + [filename] - call(cmd) - - -def dict_to_numpy_array(d, mapping=None): - """Convert a dictionary of dictionaries to a numpy array - with optional mapping.""" - try: - return dict_to_numpy_array2(d, mapping) - except (AttributeError, TypeError): - # AttributeError is when no mapping was provided and v.keys() fails. - # TypeError is when a mapping was provided and d[k1][k2] fails. - return dict_to_numpy_array1(d, mapping) - - -def dict_to_numpy_array2(d, mapping=None): - """Convert a dictionary of dictionaries to a 2d numpy array - with optional mapping. - - """ - import numpy - if mapping is None: - s = set(d.keys()) - for k, v in d.items(): - s.update(v.keys()) - mapping = dict(zip(s, range(len(s)))) - n = len(mapping) - a = numpy.zeros((n, n)) - for k1, i in mapping.items(): - for k2, j in mapping.items(): - try: - a[i, j] = d[k1][k2] - except KeyError: - pass - return a - - -def dict_to_numpy_array1(d, mapping=None): - """Convert a dictionary of numbers to a 1d numpy array - with optional mapping. - - """ - import numpy - if mapping is None: - s = set(d.keys()) - mapping = dict(zip(s, range(len(s)))) - n = len(mapping) - a = numpy.zeros(n) - for k1, i in mapping.items(): - i = mapping[k1] - a[i] = d[k1] - return a - - -def is_iterator(obj): - """Returns True if and only if the given object is an iterator - object. - - """ - has_next_attr = hasattr(obj, '__next__') or hasattr(obj, 'next') - return iter(obj) is obj and has_next_attr - - -def arbitrary_element(iterable): - """Returns an arbitrary element of `iterable` without removing it. - - This is most useful for "peeking" at an arbitrary element of a set, - but can be used for any list, dictionary, etc., as well:: - - >>> arbitrary_element({3, 2, 1}) - 1 - >>> arbitrary_element('hello') - 'h' - - This function raises a :exc:`ValueError` if `iterable` is an - iterator (because the current implementation of this function would - consume an element from the iterator):: - - >>> iterator = iter([1, 2, 3]) - >>> arbitrary_element(iterator) - Traceback (most recent call last): - ... - ValueError: cannot return an arbitrary item from an iterator - - """ - if is_iterator(iterable): - raise ValueError('cannot return an arbitrary item from an iterator') - # Another possible implementation is ``for x in iterable: return x``. - return next(iter(iterable)) - - -# Recipe from the itertools documentation. -def consume(iterator): - "Consume the iterator entirely." - # Feed the entire iterator into a zero-length deque. - deque(iterator, maxlen=0) - - -# Recipe from the itertools documentation. -def pairwise(iterable, cyclic=False): - "s -> (s0, s1), (s1, s2), (s2, s3), ..." - a, b = tee(iterable) - first = next(b, None) - if cyclic is True: - return zip(a, chain(b, (first,))) - return zip(a, b) - - -def groups(many_to_one): - """Converts a many-to-one mapping into a one-to-many mapping. - - `many_to_one` must be a dictionary whose keys and values are all - :term:`hashable`. - - The return value is a dictionary mapping values from `many_to_one` - to sets of keys from `many_to_one` that have that value. - - For example:: - - >>> from networkx.utils import groups - >>> many_to_one = {'a': 1, 'b': 1, 'c': 2, 'd': 3, 'e': 3} - >>> groups(many_to_one) # doctest: +SKIP - {1: {'a', 'b'}, 2: {'c'}, 3: {'d', 'e'}} - - """ - one_to_many = defaultdict(set) - for v, k in many_to_one.items(): - one_to_many[k].add(v) - return dict(one_to_many) - - -def to_tuple(x): - """Converts lists to tuples. - - For example:: - - >>> from networkx.utils import to_tuple - >>> a_list = [1, 2, [1, 4]] - >>> to_tuple(a_list) - (1, 2, (1, 4)) - - """ - if not isinstance(x, (tuple, list)): - return x - return tuple(map(to_tuple, x)) - - -def create_random_state(random_state=None): - """Returns a numpy.random.RandomState instance depending on input. - - Parameters - ---------- - random_state : int or RandomState instance or None optional (default=None) - If int, return a numpy.random.RandomState instance set with seed=int. - if numpy.random.RandomState instance, return it. - if None or numpy.random, return the global random number generator used - by numpy.random. - """ - import numpy as np - - if random_state is None or random_state is np.random: - return np.random.mtrand._rand - if isinstance(random_state, np.random.RandomState): - return random_state - if isinstance(random_state, int): - return np.random.RandomState(random_state) - msg = '%r cannot be used to generate a numpy.random.RandomState instance' - raise ValueError(msg % random_state) - - -class PythonRandomInterface(object): - try: - def __init__(self, rng=None): - import numpy - if rng is None: - self._rng = numpy.random.mtrand._rand - self._rng = rng - except ImportError: - msg = 'numpy not found, only random.random available.' - warnings.warn(msg, ImportWarning) - - def random(self): - return self._rng.random_sample() - - def uniform(self, a, b): - return a + (b - a) * self._rng.random_sample() - - def randrange(self, a, b=None): - return self._rng.randint(a, b) - - def choice(self, seq): - return seq[self._rng.randint(0, len(seq))] - - def gauss(self, mu, sigma): - return self._rng.normal(mu, sigma) - - def shuffle(self, seq): - return self._rng.shuffle(seq) - -# Some methods don't match API for numpy RandomState. -# Commented out versions are not used by NetworkX - - def sample(self, seq, k): - return self._rng.choice(list(seq), size=(k,), replace=False) - - def randint(self, a, b): - return self._rng.randint(a, b + 1) - -# exponential as expovariate with 1/argument, - def expovariate(self, scale): - return self._rng.exponential(1/scale) - -# pareto as paretovariate with 1/argument, - def paretovariate(self, shape): - return self._rng.pareto(shape) - -# weibull as weibullvariate multiplied by beta, -# def weibullvariate(self, alpha, beta): -# return self._rng.weibull(alpha) * beta -# -# def triangular(self, low, high, mode): -# return self._rng.triangular(low, mode, high) -# -# def choices(self, seq, weights=None, cum_weights=None, k=1): -# return self._rng.choice(seq - - -def create_py_random_state(random_state=None): - """Returns a random.Random instance depending on input. - - Parameters - ---------- - random_state : int or random number generator or None (default=None) - If int, return a random.Random instance set with seed=int. - if random.Random instance, return it. - if None or the `random` package, return the global random number - generator used by `random`. - if np.random package, return the global numpy random number - generator wrapped in a PythonRandomInterface class. - if np.random.RandomState instance, return it wrapped in - PythonRandomInterface - if a PythonRandomInterface instance, return it - """ - import random - try: - import numpy as np - if random_state is np.random: - return PythonRandomInterface(np.random.mtrand._rand) - if isinstance(random_state, np.random.RandomState): - return PythonRandomInterface(random_state) - if isinstance(random_state, PythonRandomInterface): - return random_state - has_numpy = True - except ImportError: - has_numpy = False - - if random_state is None or random_state is random: - return random._inst - if isinstance(random_state, random.Random): - return random_state - if isinstance(random_state, int): - return random.Random(random_state) - msg = '%r cannot be used to generate a random.Random instance' - raise ValueError(msg % random_state) - - -# fixture for pytest -def setup_module(module): - import pytest - numpy = pytest.importorskip('numpy') diff --git a/extensions/fablabchemnitz/networkx/utils/random_sequence.py b/extensions/fablabchemnitz/networkx/utils/random_sequence.py deleted file mode 100644 index ef365eb7..00000000 --- a/extensions/fablabchemnitz/networkx/utils/random_sequence.py +++ /dev/null @@ -1,164 +0,0 @@ -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -# -# Authors: Aric Hagberg (hagberg@lanl.gov) -# Dan Schult (dschult@colgate.edu) -# Ben Edwards (bedwards@cs.unm.edu) -""" -Utilities for generating random numbers, random sequences, and -random selections. -""" - -import random -import sys -import networkx as nx -from networkx.utils import py_random_state - - -# The same helpers for choosing random sequences from distributions -# uses Python's random module -# https://docs.python.org/2/library/random.html - -@py_random_state(2) -def powerlaw_sequence(n, exponent=2.0, seed=None): - """ - Return sample sequence of length n from a power law distribution. - """ - return [seed.paretovariate(exponent - 1) for i in range(n)] - - -@py_random_state(2) -def zipf_rv(alpha, xmin=1, seed=None): - r"""Returns a random value chosen from the Zipf distribution. - - The return value is an integer drawn from the probability distribution - - .. math:: - - p(x)=\frac{x^{-\alpha}}{\zeta(\alpha, x_{\min})}, - - where $\zeta(\alpha, x_{\min})$ is the Hurwitz zeta function. - - Parameters - ---------- - alpha : float - Exponent value of the distribution - xmin : int - Minimum value - seed : integer, random_state, or None (default) - Indicator of random number generation state. - See :ref:`Randomness`. - - Returns - ------- - x : int - Random value from Zipf distribution - - Raises - ------ - ValueError: - If xmin < 1 or - If alpha <= 1 - - Notes - ----- - The rejection algorithm generates random values for a the power-law - distribution in uniformly bounded expected time dependent on - parameters. See [1]_ for details on its operation. - - Examples - -------- - >>> nx.zipf_rv(alpha=2, xmin=3, seed=42) # doctest: +SKIP - - References - ---------- - .. [1] Luc Devroye, Non-Uniform Random Variate Generation, - Springer-Verlag, New York, 1986. - """ - if xmin < 1: - raise ValueError("xmin < 1") - if alpha <= 1: - raise ValueError("a <= 1.0") - a1 = alpha - 1.0 - b = 2**a1 - while True: - u = 1.0 - seed.random() # u in (0,1] - v = seed.random() # v in [0,1) - x = int(xmin * u**-(1.0 / a1)) - t = (1.0 + (1.0 / x))**a1 - if v * x * (t - 1.0) / (b - 1.0) <= t / b: - break - return x - - -def cumulative_distribution(distribution): - """Returns normalized cumulative distribution from discrete distribution.""" - - cdf = [0.0] - psum = float(sum(distribution)) - for i in range(0, len(distribution)): - cdf.append(cdf[i] + distribution[i] / psum) - return cdf - - -@py_random_state(3) -def discrete_sequence(n, distribution=None, cdistribution=None, seed=None): - """ - Return sample sequence of length n from a given discrete distribution - or discrete cumulative distribution. - - One of the following must be specified. - - distribution = histogram of values, will be normalized - - cdistribution = normalized discrete cumulative distribution - - """ - import bisect - - if cdistribution is not None: - cdf = cdistribution - elif distribution is not None: - cdf = cumulative_distribution(distribution) - else: - raise nx.NetworkXError( - "discrete_sequence: distribution or cdistribution missing") - - # get a uniform random number - inputseq = [seed.random() for i in range(n)] - - # choose from CDF - seq = [bisect.bisect_left(cdf, s) - 1 for s in inputseq] - return seq - - -@py_random_state(2) -def random_weighted_sample(mapping, k, seed=None): - """Returns k items without replacement from a weighted sample. - - The input is a dictionary of items with weights as values. - """ - if k > len(mapping): - raise ValueError("sample larger than population") - sample = set() - while len(sample) < k: - sample.add(weighted_choice(mapping, seed)) - return list(sample) - - -@py_random_state(1) -def weighted_choice(mapping, seed=None): - """Returns a single element from a weighted sample. - - The input is a dictionary of items with weights as values. - """ - # use roulette method - rnd = seed.random() * sum(mapping.values()) - for k, w in mapping.items(): - rnd -= w - if rnd < 0: - return k diff --git a/extensions/fablabchemnitz/networkx/utils/rcm.py b/extensions/fablabchemnitz/networkx/utils/rcm.py deleted file mode 100644 index 8939d8b3..00000000 --- a/extensions/fablabchemnitz/networkx/utils/rcm.py +++ /dev/null @@ -1,165 +0,0 @@ -""" -Cuthill-McKee ordering of graph nodes to produce sparse matrices -""" -# Copyright (C) 2011-2014 by -# Aric Hagberg -# All rights reserved. -# BSD license. -from collections import deque -from operator import itemgetter - -import networkx as nx -from ..utils import arbitrary_element - -__author__ = """\n""".join(['Aric Hagberg ']) -__all__ = ['cuthill_mckee_ordering', - 'reverse_cuthill_mckee_ordering'] - - -def cuthill_mckee_ordering(G, heuristic=None): - """Generate an ordering (permutation) of the graph nodes to make - a sparse matrix. - - Uses the Cuthill-McKee heuristic (based on breadth-first search) [1]_. - - Parameters - ---------- - G : graph - A NetworkX graph - - heuristic : function, optional - Function to choose starting node for RCM algorithm. If None - a node from a pseudo-peripheral pair is used. A user-defined function - can be supplied that takes a graph object and returns a single node. - - Returns - ------- - nodes : generator - Generator of nodes in Cuthill-McKee ordering. - - Examples - -------- - >>> from networkx.utils import cuthill_mckee_ordering - >>> G = nx.path_graph(4) - >>> rcm = list(cuthill_mckee_ordering(G)) - >>> A = nx.adjacency_matrix(G, nodelist=rcm) # doctest: +SKIP - - Smallest degree node as heuristic function: - - >>> def smallest_degree(G): - ... return min(G, key=G.degree) - >>> rcm = list(cuthill_mckee_ordering(G, heuristic=smallest_degree)) - - - See Also - -------- - reverse_cuthill_mckee_ordering - - Notes - ----- - The optimal solution the the bandwidth reduction is NP-complete [2]_. - - - References - ---------- - .. [1] E. Cuthill and J. McKee. - Reducing the bandwidth of sparse symmetric matrices, - In Proc. 24th Nat. Conf. ACM, pages 157-172, 1969. - http://doi.acm.org/10.1145/800195.805928 - .. [2] Steven S. Skiena. 1997. The Algorithm Design Manual. - Springer-Verlag New York, Inc., New York, NY, USA. - """ - for c in nx.connected_components(G): - for n in connected_cuthill_mckee_ordering(G.subgraph(c), heuristic): - yield n - - -def reverse_cuthill_mckee_ordering(G, heuristic=None): - """Generate an ordering (permutation) of the graph nodes to make - a sparse matrix. - - Uses the reverse Cuthill-McKee heuristic (based on breadth-first search) - [1]_. - - Parameters - ---------- - G : graph - A NetworkX graph - - heuristic : function, optional - Function to choose starting node for RCM algorithm. If None - a node from a pseudo-peripheral pair is used. A user-defined function - can be supplied that takes a graph object and returns a single node. - - Returns - ------- - nodes : generator - Generator of nodes in reverse Cuthill-McKee ordering. - - Examples - -------- - >>> from networkx.utils import reverse_cuthill_mckee_ordering - >>> G = nx.path_graph(4) - >>> rcm = list(reverse_cuthill_mckee_ordering(G)) - >>> A = nx.adjacency_matrix(G, nodelist=rcm) # doctest: +SKIP - - Smallest degree node as heuristic function: - - >>> def smallest_degree(G): - ... return min(G, key=G.degree) - >>> rcm = list(reverse_cuthill_mckee_ordering(G, heuristic=smallest_degree)) - - - See Also - -------- - cuthill_mckee_ordering - - Notes - ----- - The optimal solution the the bandwidth reduction is NP-complete [2]_. - - References - ---------- - .. [1] E. Cuthill and J. McKee. - Reducing the bandwidth of sparse symmetric matrices, - In Proc. 24th Nat. Conf. ACM, pages 157-72, 1969. - http://doi.acm.org/10.1145/800195.805928 - .. [2] Steven S. Skiena. 1997. The Algorithm Design Manual. - Springer-Verlag New York, Inc., New York, NY, USA. - """ - return reversed(list(cuthill_mckee_ordering(G, heuristic=heuristic))) - - -def connected_cuthill_mckee_ordering(G, heuristic=None): - # the cuthill mckee algorithm for connected graphs - if heuristic is None: - start = pseudo_peripheral_node(G) - else: - start = heuristic(G) - visited = {start} - queue = deque([start]) - while queue: - parent = queue.popleft() - yield parent - nd = sorted(list(G.degree(set(G[parent]) - visited)), - key=itemgetter(1)) - children = [n for n, d in nd] - visited.update(children) - queue.extend(children) - - -def pseudo_peripheral_node(G): - # helper for cuthill-mckee to find a node in a "pseudo peripheral pair" - # to use as good starting node - u = arbitrary_element(G) - lp = 0 - v = u - while True: - spl = dict(nx.shortest_path_length(G, v)) - l = max(spl.values()) - if l <= lp: - break - lp = l - farthest = (n for n, dist in spl.items() if dist == l) - v, deg = min(G.degree(farthest), key=itemgetter(1)) - return v diff --git a/extensions/fablabchemnitz/networkx/utils/tests/__init__.py b/extensions/fablabchemnitz/networkx/utils/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/extensions/fablabchemnitz/networkx/utils/tests/test_contextmanager.py b/extensions/fablabchemnitz/networkx/utils/tests/test_contextmanager.py deleted file mode 100644 index 6d163016..00000000 --- a/extensions/fablabchemnitz/networkx/utils/tests/test_contextmanager.py +++ /dev/null @@ -1,20 +0,0 @@ - - -import networkx as nx - - -def test_reversed(): - G = nx.DiGraph() - G.add_edge('A', 'B') - - # no exception - with nx.utils.reversed(G): - pass - assert 'B' in G['A'] - - # exception - try: - with nx.utils.reversed(G): - raise Exception - except: - assert 'B' in G['A'] diff --git a/extensions/fablabchemnitz/networkx/utils/tests/test_decorators.py b/extensions/fablabchemnitz/networkx/utils/tests/test_decorators.py deleted file mode 100644 index aec968d0..00000000 --- a/extensions/fablabchemnitz/networkx/utils/tests/test_decorators.py +++ /dev/null @@ -1,283 +0,0 @@ -import tempfile -import os -import random - -import pytest - -import networkx as nx -from networkx.utils.decorators import open_file, not_implemented_for -from networkx.utils.decorators import nodes_or_number, preserve_random_state, \ - py_random_state, np_random_state, random_state -from networkx.utils.misc import PythonRandomInterface - -def test_not_implemented_decorator(): - @not_implemented_for('directed') - def test1(G): - pass - test1(nx.Graph()) - - -def test_not_implemented_decorator_key(): - with pytest.raises(KeyError): - @not_implemented_for('foo') - def test1(G): - pass - test1(nx.Graph()) - - -def test_not_implemented_decorator_raise(): - with pytest.raises(nx.NetworkXNotImplemented): - @not_implemented_for('graph') - def test1(G): - pass - test1(nx.Graph()) - - -class TestOpenFileDecorator(object): - def setup_method(self): - self.text = ['Blah... ', 'BLAH ', 'BLAH!!!!'] - self.fobj = tempfile.NamedTemporaryFile('wb+', delete=False) - self.name = self.fobj.name - - def write(self, path): - for text in self.text: - path.write(text.encode('ascii')) - - @open_file(1, 'r') - def read(self, path): - return path.readlines()[0] - - @staticmethod - @open_file(0, 'wb') - def writer_arg0(path): - path.write('demo'.encode('ascii')) - - @open_file(1, 'wb+') - def writer_arg1(self, path): - self.write(path) - - @open_file(2, 'wb') - def writer_arg2default(self, x, path=None): - if path is None: - with tempfile.NamedTemporaryFile('wb+') as fh: - self.write(fh) - else: - self.write(path) - - @open_file(4, 'wb') - def writer_arg4default(self, x, y, other='hello', path=None, **kwargs): - if path is None: - with tempfile.NamedTemporaryFile('wb+') as fh: - self.write(fh) - else: - self.write(path) - - @open_file('path', 'wb') - def writer_kwarg(self, **kwargs): - path = kwargs.get('path', None) - if path is None: - with tempfile.NamedTemporaryFile('wb+') as fh: - self.write(fh) - else: - self.write(path) - - def test_writer_arg0_str(self): - self.writer_arg0(self.name) - - def test_writer_arg0_fobj(self): - self.writer_arg0(self.fobj) - - def test_writer_arg0_pathlib(self): - try: - import pathlib - self.writer_arg0(pathlib.Path(self.name)) - except ImportError: - return - - def test_writer_arg1_str(self): - self.writer_arg1(self.name) - assert self.read(self.name) == ''.join(self.text) - - def test_writer_arg1_fobj(self): - self.writer_arg1(self.fobj) - assert not self.fobj.closed - self.fobj.close() - assert self.read(self.name) == ''.join(self.text) - - def test_writer_arg2default_str(self): - self.writer_arg2default(0, path=None) - self.writer_arg2default(0, path=self.name) - assert self.read(self.name) == ''.join(self.text) - - def test_writer_arg2default_fobj(self): - self.writer_arg2default(0, path=self.fobj) - assert not self.fobj.closed - self.fobj.close() - assert self.read(self.name) == ''.join(self.text) - - def test_writer_arg2default_fobj_path_none(self): - self.writer_arg2default(0, path=None) - - def test_writer_arg4default_fobj(self): - self.writer_arg4default(0, 1, dog='dog', other='other') - self.writer_arg4default(0, 1, dog='dog', other='other', path=self.name) - assert self.read(self.name) == ''.join(self.text) - - def test_writer_kwarg_str(self): - self.writer_kwarg(path=self.name) - assert self.read(self.name) == ''.join(self.text) - - def test_writer_kwarg_fobj(self): - self.writer_kwarg(path=self.fobj) - self.fobj.close() - assert self.read(self.name) == ''.join(self.text) - - def test_writer_kwarg_path_none(self): - self.writer_kwarg(path=None) - - def tearDown(self): - self.fobj.close() - os.unlink(self.name) - - -@preserve_random_state -def test_preserve_random_state(): - try: - import numpy.random - r = numpy.random.random() - except ImportError: - return - assert(abs(r - 0.61879477158568) < 1e-16) - - -class TestRandomState(object): - @classmethod - def setup_class(cls): - global np - np = pytest.importorskip("numpy") - - @random_state(1) - def instantiate_random_state(self, random_state): - assert isinstance(random_state, np.random.RandomState) - return random_state.random_sample() - - @np_random_state(1) - def instantiate_np_random_state(self, random_state): - assert isinstance(random_state, np.random.RandomState) - return random_state.random_sample() - - @py_random_state(1) - def instantiate_py_random_state(self, random_state): - assert (isinstance(random_state, random.Random) or - isinstance(random_state, PythonRandomInterface)) - return random_state.random() - - def test_random_state_None(self): - np.random.seed(42) - rv = np.random.random_sample() - np.random.seed(42) - assert rv == self.instantiate_random_state(None) - np.random.seed(42) - assert rv == self.instantiate_np_random_state(None) - - random.seed(42) - rv = random.random() - random.seed(42) - assert rv == self.instantiate_py_random_state(None) - - def test_random_state_np_random(self): - np.random.seed(42) - rv = np.random.random_sample() - np.random.seed(42) - assert rv == self.instantiate_random_state(np.random) - np.random.seed(42) - assert rv == self.instantiate_np_random_state(np.random) - np.random.seed(42) - assert rv == self.instantiate_py_random_state(np.random) - - def test_random_state_int(self): - np.random.seed(42) - np_rv = np.random.random_sample() - random.seed(42) - py_rv = random.random() - - np.random.seed(42) - seed = 1 - rval = self.instantiate_random_state(seed) - rval_expected = np.random.RandomState(seed).rand() - assert rval, rval_expected - - rval = self.instantiate_np_random_state(seed) - rval_expected = np.random.RandomState(seed).rand() - assert rval, rval_expected - # test that global seed wasn't changed in function - assert np_rv == np.random.random_sample() - - random.seed(42) - rval = self.instantiate_py_random_state(seed) - rval_expected = random.Random(seed).random() - assert rval, rval_expected - # test that global seed wasn't changed in function - assert py_rv == random.random() - - def test_random_state_np_random_RandomState(self): - np.random.seed(42) - np_rv = np.random.random_sample() - - np.random.seed(42) - seed = 1 - rng = np.random.RandomState(seed) - rval = self.instantiate_random_state(rng) - rval_expected = np.random.RandomState(seed).rand() - assert rval, rval_expected - - rval = self.instantiate_np_random_state(seed) - rval_expected = np.random.RandomState(seed).rand() - assert rval, rval_expected - - rval = self.instantiate_py_random_state(seed) - rval_expected = np.random.RandomState(seed).rand() - assert rval, rval_expected - # test that global seed wasn't changed in function - assert np_rv == np.random.random_sample() - - def test_random_state_py_random(self): - seed = 1 - rng = random.Random(seed) - rv = self.instantiate_py_random_state(rng) - assert rv, random.Random(seed).random() - - pytest.raises(ValueError, self.instantiate_random_state, rng) - pytest.raises(ValueError, self.instantiate_np_random_state, rng) - - -def test_random_state_string_arg_index(): - with pytest.raises(nx.NetworkXError): - @random_state('a') - def make_random_state(rs): - pass - rstate = make_random_state(1) - - -def test_py_random_state_string_arg_index(): - with pytest.raises(nx.NetworkXError): - @py_random_state('a') - def make_random_state(rs): - pass - rstate = make_random_state(1) - - -def test_random_state_invalid_arg_index(): - with pytest.raises(nx.NetworkXError): - @random_state(2) - def make_random_state(rs): - pass - rstate = make_random_state(1) - - -def test_py_random_state_invalid_arg_index(): - with pytest.raises(nx.NetworkXError): - @py_random_state(2) - def make_random_state(rs): - pass - rstate = make_random_state(1) diff --git a/extensions/fablabchemnitz/networkx/utils/tests/test_heaps.py b/extensions/fablabchemnitz/networkx/utils/tests/test_heaps.py deleted file mode 100644 index e7b9ba49..00000000 --- a/extensions/fablabchemnitz/networkx/utils/tests/test_heaps.py +++ /dev/null @@ -1,130 +0,0 @@ -import pytest -import networkx as nx -from networkx.utils import * - - -class X(object): - - def __eq__(self, other): - raise self is other - - def __ne__(self, other): - raise self is not other - - def __lt__(self, other): - raise TypeError('cannot compare') - - def __le__(self, other): - raise TypeError('cannot compare') - - def __ge__(self, other): - raise TypeError('cannot compare') - - def __gt__(self, other): - raise TypeError('cannot compare') - - def __hash__(self): - return hash(id(self)) - - -x = X() - - -data = [ # min should not invent an element. - ('min', nx.NetworkXError), - # Popping an empty heap should fail. - ('pop', nx.NetworkXError), - # Getting nonexisting elements should return None. - ('get', 0, None), - ('get', x, None), - ('get', None, None), - # Inserting a new key should succeed. - ('insert', x, 1, True), - ('get', x, 1), - ('min', (x, 1)), - # min should not pop the top element. - ('min', (x, 1)), - # Inserting a new key of different type should succeed. - ('insert', 1, -2.0, True), - # int and float values should interop. - ('min', (1, -2.0)), - # pop removes minimum-valued element. - ('insert', 3, -10 ** 100, True), - ('insert', 4, 5, True), - ('pop', (3, -10 ** 100)), - ('pop', (1, -2.0)), - # Decrease-insert should succeed. - ('insert', 4, -50, True), - ('insert', 4, -60, False, True), - # Decrease-insert should not create duplicate keys. - ('pop', (4, -60)), - ('pop', (x, 1)), - # Popping all elements should empty the heap. - ('min', nx.NetworkXError), - ('pop', nx.NetworkXError), - # Non-value-changing insert should fail. - ('insert', x, 0, True), - ('insert', x, 0, False, False), - ('min', (x, 0)), - ('insert', x, 0, True, False), - ('min', (x, 0)), - # Failed insert should not create duplicate keys. - ('pop', (x, 0)), - ('pop', nx.NetworkXError), - # Increase-insert should succeed when allowed. - ('insert', None, 0, True), - ('insert', 2, -1, True), - ('min', (2, -1)), - ('insert', 2, 1, True, False), - ('min', (None, 0)), - # Increase-insert should fail when disallowed. - ('insert', None, 2, False, False), - ('min', (None, 0)), - # Failed increase-insert should not create duplicate keys. - ('pop', (None, 0)), - ('pop', (2, 1)), - ('min', nx.NetworkXError), - ('pop', nx.NetworkXError)] - - -def _test_heap_class(cls, *args, **kwargs): - heap = cls(*args, **kwargs) - # Basic behavioral test - for op in data: - if op[-1] is not nx.NetworkXError: - assert op[-1] == getattr(heap, op[0])(*op[1:-1]) - else: - pytest.raises(op[-1], getattr(heap, op[0]), *op[1:-1]) - # Coverage test. - for i in range(99, -1, -1): - assert heap.insert(i, i) - for i in range(50): - assert heap.pop() == (i, i) - for i in range(100): - assert heap.insert(i, i) == (i < 50) - for i in range(100): - assert not heap.insert(i, i + 1) - for i in range(50): - assert heap.pop() == (i, i) - for i in range(100): - assert heap.insert(i, i + 1) == (i < 50) - for i in range(49): - assert heap.pop() == (i, i + 1) - assert sorted([heap.pop(), heap.pop()]) == [(49, 50), (50, 50)] - for i in range(51, 100): - assert not heap.insert(i, i + 1, True) - for i in range(51, 70): - assert heap.pop() == (i, i + 1) - for i in range(100): - assert heap.insert(i, i) - for i in range(100): - assert heap.pop() == (i, i) - pytest.raises(nx.NetworkXError, heap.pop) - - -def test_PairingHeap(): - _test_heap_class(PairingHeap) - - -def test_BinaryHeap(): - _test_heap_class(BinaryHeap) diff --git a/extensions/fablabchemnitz/networkx/utils/tests/test_mapped_queue.py b/extensions/fablabchemnitz/networkx/utils/tests/test_mapped_queue.py deleted file mode 100644 index 85177331..00000000 --- a/extensions/fablabchemnitz/networkx/utils/tests/test_mapped_queue.py +++ /dev/null @@ -1,173 +0,0 @@ -# -*- coding: utf-8 -*- -# -# priorityq: An object-oriented priority queue with updatable priorities. -# -# Copyright 2018 Edward L. Platt -# -# This file is part of NetworkX -# -# NetworkX is distributed under a BSD license; see LICENSE.txt for more -# information. -# -# Authors: -# Edward L. Platt - - -from networkx.utils.mapped_queue import MappedQueue - - -class TestMappedQueue(object): - - def setup(self): - pass - - def _check_map(self, q): - d = dict((elt, pos) for pos, elt in enumerate(q.h)) - assert d == q.d - - def _make_mapped_queue(self, h): - q = MappedQueue() - q.h = h - q.d = dict((elt, pos) for pos, elt in enumerate(h)) - return q - - def test_heapify(self): - h = [5, 4, 3, 2, 1, 0] - q = self._make_mapped_queue(h) - q._heapify() - self._check_map(q) - - def test_init(self): - h = [5, 4, 3, 2, 1, 0] - q = MappedQueue(h) - self._check_map(q) - - def test_len(self): - h = [5, 4, 3, 2, 1, 0] - q = MappedQueue(h) - self._check_map(q) - assert len(q) == 6 - - def test_siftup_leaf(self): - h = [2] - h_sifted = [2] - q = self._make_mapped_queue(h) - q._siftup(0) - assert q.h == h_sifted - self._check_map(q) - - def test_siftup_one_child(self): - h = [2, 0] - h_sifted = [0, 2] - q = self._make_mapped_queue(h) - q._siftup(0) - assert q.h == h_sifted - self._check_map(q) - - def test_siftup_left_child(self): - h = [2, 0, 1] - h_sifted = [0, 2, 1] - q = self._make_mapped_queue(h) - q._siftup(0) - assert q.h == h_sifted - self._check_map(q) - - def test_siftup_right_child(self): - h = [2, 1, 0] - h_sifted = [0, 1, 2] - q = self._make_mapped_queue(h) - q._siftup(0) - assert q.h == h_sifted - self._check_map(q) - - def test_siftup_multiple(self): - h = [0, 1, 2, 4, 3, 5, 6] - h_sifted = [1, 3, 2, 4, 0, 5, 6] - q = self._make_mapped_queue(h) - q._siftup(0) - assert q.h == h_sifted - self._check_map(q) - - def test_siftdown_leaf(self): - h = [2] - h_sifted = [2] - q = self._make_mapped_queue(h) - q._siftdown(0) - assert q.h == h_sifted - self._check_map(q) - - def test_siftdown_single(self): - h = [1, 0] - h_sifted = [0, 1] - q = self._make_mapped_queue(h) - q._siftdown(len(h) - 1) - assert q.h == h_sifted - self._check_map(q) - - def test_siftdown_multiple(self): - h = [1, 2, 3, 4, 5, 6, 7, 0] - h_sifted = [0, 1, 3, 2, 5, 6, 7, 4] - q = self._make_mapped_queue(h) - q._siftdown(len(h) - 1) - assert q.h == h_sifted - self._check_map(q) - - def test_push(self): - to_push = [6, 1, 4, 3, 2, 5, 0] - h_sifted = [0, 2, 1, 6, 3, 5, 4] - q = MappedQueue() - for elt in to_push: - q.push(elt) - assert q.h == h_sifted - self._check_map(q) - - def test_push_duplicate(self): - to_push = [2, 1, 0] - h_sifted = [0, 2, 1] - q = MappedQueue() - for elt in to_push: - inserted = q.push(elt) - assert inserted == True - assert q.h == h_sifted - self._check_map(q) - inserted = q.push(1) - assert inserted == False - - def test_pop(self): - h = [3, 4, 6, 0, 1, 2, 5] - h_sorted = sorted(h) - q = self._make_mapped_queue(h) - q._heapify() - popped = [] - for elt in sorted(h): - popped.append(q.pop()) - assert popped == h_sorted - self._check_map(q) - - def test_remove_leaf(self): - h = [0, 2, 1, 6, 3, 5, 4] - h_removed = [0, 2, 1, 6, 4, 5] - q = self._make_mapped_queue(h) - removed = q.remove(3) - assert q.h == h_removed - - def test_remove_root(self): - h = [0, 2, 1, 6, 3, 5, 4] - h_removed = [1, 2, 4, 6, 3, 5] - q = self._make_mapped_queue(h) - removed = q.remove(0) - assert q.h == h_removed - - def test_update_leaf(self): - h = [0, 20, 10, 60, 30, 50, 40] - h_updated = [0, 15, 10, 60, 20, 50, 40] - q = self._make_mapped_queue(h) - removed = q.update(30, 15) - assert q.h == h_updated - - def test_update_root(self): - h = [0, 20, 10, 60, 30, 50, 40] - h_updated = [10, 20, 35, 60, 30, 50, 40] - q = self._make_mapped_queue(h) - removed = q.update(0, 35) - assert q.h == h_updated diff --git a/extensions/fablabchemnitz/networkx/utils/tests/test_misc.py b/extensions/fablabchemnitz/networkx/utils/tests/test_misc.py deleted file mode 100644 index 7ac29597..00000000 --- a/extensions/fablabchemnitz/networkx/utils/tests/test_misc.py +++ /dev/null @@ -1,223 +0,0 @@ -# -*- encoding: utf-8 -*- -import pytest -import networkx as nx -from networkx.utils import * - - -def test_is_string_like(): - assert is_string_like("aaaa") - assert not is_string_like(None) - assert not is_string_like(123) - - -def test_iterable(): - assert not iterable(None) - assert not iterable(10) - assert iterable([1, 2, 3]) - assert iterable((1, 2, 3)) - assert iterable({1: "A", 2: "X"}) - assert iterable("ABC") - - -def test_graph_iterable(): - K = nx.complete_graph(10) - assert iterable(K) - assert iterable(K.nodes()) - assert iterable(K.edges()) - - -def test_make_list_of_ints(): - mylist = [1, 2, 3., 42, -2] - assert make_list_of_ints(mylist) is mylist - assert make_list_of_ints(mylist) == mylist - assert type(make_list_of_ints(mylist)[2]) is int - pytest.raises(nx.NetworkXError, make_list_of_ints, [1, 2, 3, "kermit"]) - pytest.raises(nx.NetworkXError, make_list_of_ints, [1, 2, 3.1]) - - -def test_random_number_distribution(): - # smoke test only - z = powerlaw_sequence(20, exponent=2.5) - z = discrete_sequence(20, distribution=[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3]) - - -def test_make_str_with_bytes(): - import sys - PY2 = sys.version_info[0] == 2 - - x = "qualité" - y = make_str(x) - if PY2: - assert isinstance(y, unicode) - # Since file encoding is utf-8, the é will be two bytes. - assert len(y) == 8 - else: - assert isinstance(y, str) - assert len(y) == 7 - - -def test_make_str_with_unicode(): - import sys - PY2 = sys.version_info[0] == 2 - if PY2: - x = unicode("qualité", encoding='utf-8') - y = make_str(x) - assert isinstance(y, unicode) - assert len(y) == 7 - else: - x = "qualité" - y = make_str(x) - assert isinstance(y, str) - assert len(y) == 7 - - -class TestNumpyArray(object): - @classmethod - def setup_class(cls): - global numpy - global assert_allclose - numpy = pytest.importorskip("numpy") - assert_allclose = numpy.testing.assert_allclose - - def test_numpy_to_list_of_ints(self): - a = numpy.array([1, 2, 3], dtype=numpy.int64) - b = numpy.array([1., 2, 3]) - c = numpy.array([1.1, 2, 3]) - assert type(make_list_of_ints(a)) == list - assert make_list_of_ints(b) == list(b) - B = make_list_of_ints(b) - assert type(B[0]) == int - pytest.raises(nx.NetworkXError, make_list_of_ints, c) - - def test_dict_to_numpy_array1(self): - d = {'a': 1, 'b': 2} - a = dict_to_numpy_array1(d, mapping={'a': 0, 'b': 1}) - assert_allclose(a, numpy.array([1, 2])) - a = dict_to_numpy_array1(d, mapping={'b': 0, 'a': 1}) - assert_allclose(a, numpy.array([2, 1])) - - a = dict_to_numpy_array1(d) - assert_allclose(a.sum(), 3) - - def test_dict_to_numpy_array2(self): - d = {'a': {'a': 1, 'b': 2}, - 'b': {'a': 10, 'b': 20}} - - mapping = {'a': 1, 'b': 0} - a = dict_to_numpy_array2(d, mapping=mapping) - assert_allclose(a, numpy.array([[20, 10], [2, 1]])) - - a = dict_to_numpy_array2(d) - assert_allclose(a.sum(), 33) - - def test_dict_to_numpy_array_a(self): - d = {'a': {'a': 1, 'b': 2}, - 'b': {'a': 10, 'b': 20}} - - mapping = {'a': 0, 'b': 1} - a = dict_to_numpy_array(d, mapping=mapping) - assert_allclose(a, numpy.array([[1, 2], [10, 20]])) - - mapping = {'a': 1, 'b': 0} - a = dict_to_numpy_array(d, mapping=mapping) - assert_allclose(a, numpy.array([[20, 10], [2, 1]])) - - a = dict_to_numpy_array2(d) - assert_allclose(a.sum(), 33) - - def test_dict_to_numpy_array_b(self): - d = {'a': 1, 'b': 2} - - mapping = {'a': 0, 'b': 1} - a = dict_to_numpy_array(d, mapping=mapping) - assert_allclose(a, numpy.array([1, 2])) - - a = dict_to_numpy_array1(d) - assert_allclose(a.sum(), 3) - - -def test_pairwise(): - nodes = range(4) - node_pairs = [(0, 1), (1, 2), (2, 3)] - node_pairs_cycle = node_pairs + [(3, 0)] - assert list(pairwise(nodes)) == node_pairs - assert list(pairwise(iter(nodes))) == node_pairs - assert list(pairwise(nodes, cyclic=True)) == node_pairs_cycle - empty_iter = iter(()) - assert list(pairwise(empty_iter)) == [] - empty_iter = iter(()) - assert list(pairwise(empty_iter, cyclic=True)) == [] - - -def test_groups(): - many_to_one = dict(zip('abcde', [0, 0, 1, 1, 2])) - actual = groups(many_to_one) - expected = {0: {'a', 'b'}, 1: {'c', 'd'}, 2: {'e'}} - assert actual == expected - assert {} == groups({}) - - -def test_to_tuple(): - a_list = [1, 2, [1, 3]] - actual = to_tuple(a_list) - expected = (1, 2, (1, 3)) - assert actual == expected - - a_tuple = (1, 2) - actual = to_tuple(a_tuple) - expected = a_tuple - assert actual == expected - - a_mix = (1, 2, [1, 3]) - actual = to_tuple(a_mix) - expected = (1, 2, (1, 3)) - assert actual == expected - - -def test_create_random_state(): - np = pytest.importorskip('numpy') - rs = np.random.RandomState - - assert isinstance(create_random_state(1), rs) - assert isinstance(create_random_state(None), rs) - assert isinstance(create_random_state(np.random), rs) - assert isinstance(create_random_state(rs(1)), rs) - pytest.raises(ValueError, create_random_state, 'a') - - assert np.all((rs(1).rand(10) == create_random_state(1).rand(10))) - - -def test_create_py_random_state(): - pyrs = random.Random - - assert isinstance(create_py_random_state(1), pyrs) - assert isinstance(create_py_random_state(None), pyrs) - assert isinstance(create_py_random_state(pyrs(1)), pyrs) - pytest.raises(ValueError, create_py_random_state, 'a') - - np = pytest.importorskip('numpy') - - rs = np.random.RandomState - nprs = PythonRandomInterface - assert isinstance(create_py_random_state(np.random), nprs) - assert isinstance(create_py_random_state(rs(1)), nprs) - # test default rng input - assert isinstance(PythonRandomInterface(), nprs) - - -def test_PythonRandomInterface(): - np = pytest.importorskip('numpy') - rs = np.random.RandomState - rng = PythonRandomInterface(rs(42)) - rs42 = rs(42) - - # make sure these functions are same as expected outcome - assert rng.randrange(3, 5) == rs42.randint(3, 5) - assert np.all(rng.choice([1, 2, 3]) == rs42.choice([1, 2, 3])) - assert rng.gauss(0, 1) == rs42.normal(0, 1) - assert rng.expovariate(1.5) == rs42.exponential(1/1.5) - assert np.all(rng.shuffle([1, 2, 3]) == rs42.shuffle([1, 2, 3])) - assert np.all(rng.sample([1, 2, 3], 2) == - rs42.choice([1, 2, 3], (2,), replace=False)) - assert rng.randint(3, 5) == rs42.randint(3, 6) - assert rng.random() == rs42.random_sample() diff --git a/extensions/fablabchemnitz/networkx/utils/tests/test_random_sequence.py b/extensions/fablabchemnitz/networkx/utils/tests/test_random_sequence.py deleted file mode 100644 index 769f82f0..00000000 --- a/extensions/fablabchemnitz/networkx/utils/tests/test_random_sequence.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python -import pytest -from networkx.utils import powerlaw_sequence,\ - zipf_rv, random_weighted_sample,\ - weighted_choice - - -def test_degree_sequences(): - seq = powerlaw_sequence(10, seed=1) - seq = powerlaw_sequence(10) - assert len(seq) == 10 - - -def test_zipf_rv(): - r = zipf_rv(2.3, xmin=2, seed=1) - r = zipf_rv(2.3, 2, 1) - r = zipf_rv(2.3) - assert type(r), int - pytest.raises(ValueError, zipf_rv, 0.5) - pytest.raises(ValueError, zipf_rv, 2, xmin=0) - - -def test_random_weighted_sample(): - mapping = {'a': 10, 'b': 20} - s = random_weighted_sample(mapping, 2, seed=1) - s = random_weighted_sample(mapping, 2) - assert sorted(s) == sorted(mapping.keys()) - pytest.raises(ValueError, random_weighted_sample, mapping, 3) - - -def test_random_weighted_choice(): - mapping = {'a': 10, 'b': 0} - c = weighted_choice(mapping, seed=1) - c = weighted_choice(mapping) - assert c == 'a' diff --git a/extensions/fablabchemnitz/networkx/utils/tests/test_rcm.py b/extensions/fablabchemnitz/networkx/utils/tests/test_rcm.py deleted file mode 100644 index 16c1d87f..00000000 --- a/extensions/fablabchemnitz/networkx/utils/tests/test_rcm.py +++ /dev/null @@ -1,40 +0,0 @@ -from networkx.utils import reverse_cuthill_mckee_ordering -import networkx as nx - - -def test_reverse_cuthill_mckee(): - # example graph from - # http://www.boost.org/doc/libs/1_37_0/libs/graph/example/cuthill_mckee_ordering.cpp - G = nx.Graph([(0, 3), (0, 5), (1, 2), (1, 4), (1, 6), (1, 9), (2, 3), - (2, 4), (3, 5), (3, 8), (4, 6), (5, 6), (5, 7), (6, 7)]) - rcm = list(reverse_cuthill_mckee_ordering(G)) - assert rcm in [[0, 8, 5, 7, 3, 6, 2, 4, 1, 9], - [0, 8, 5, 7, 3, 6, 4, 2, 1, 9]] - - -def test_rcm_alternate_heuristic(): - # example from - G = nx.Graph([(0, 0), - (0, 4), - (1, 1), - (1, 2), - (1, 5), - (1, 7), - (2, 2), - (2, 4), - (3, 3), - (3, 6), - (4, 4), - (5, 5), - (5, 7), - (6, 6), - (7, 7)]) - - answers = [[6, 3, 5, 7, 1, 2, 4, 0], [6, 3, 7, 5, 1, 2, 4, 0], - [7, 5, 1, 2, 4, 0, 6, 3]] - - def smallest_degree(G): - deg, node = min((d, n) for n, d in G.degree()) - return node - rcm = list(reverse_cuthill_mckee_ordering(G, heuristic=smallest_degree)) - assert rcm in answers diff --git a/extensions/fablabchemnitz/networkx/utils/tests/test_unionfind.py b/extensions/fablabchemnitz/networkx/utils/tests/test_unionfind.py deleted file mode 100644 index 8620f374..00000000 --- a/extensions/fablabchemnitz/networkx/utils/tests/test_unionfind.py +++ /dev/null @@ -1,23 +0,0 @@ -import networkx as nx - - -def test_unionfind(): - # Fixed by: 2cddd5958689bdecdcd89b91ac9aaf6ce0e4f6b8 - # Previously (in 2.x), the UnionFind class could handle mixed types. - # But in Python 3.x, this causes a TypeError such as: - # TypeError: unorderable types: str() > int() - # - # Now we just make sure that no exception is raised. - x = nx.utils.UnionFind() - x.union(0, 'a') - -def test_subtree_union(): - # See https://github.com/networkx/networkx/pull/3224 - # (35db1b551ee65780794a357794f521d8768d5049). - # Test if subtree unions hare handled correctly by to_sets(). - uf = nx.utils.UnionFind() - uf.union(1, 2) - uf.union(3, 4) - uf.union(4, 5) - uf.union(1, 5) - assert list(uf.to_sets()) == [set([1, 2, 3, 4, 5])] diff --git a/extensions/fablabchemnitz/networkx/utils/union_find.py b/extensions/fablabchemnitz/networkx/utils/union_find.py deleted file mode 100644 index c0e755a4..00000000 --- a/extensions/fablabchemnitz/networkx/utils/union_find.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright 2016-2019 NetworkX developers. -# Copyright (C) 2004-2019 by -# Aric Hagberg -# Dan Schult -# Pieter Swart -# All rights reserved. -# BSD license. -""" -Union-find data structure. -""" - -from networkx.utils import groups - - -class UnionFind: - """Union-find data structure. - - Each unionFind instance X maintains a family of disjoint sets of - hashable objects, supporting the following two methods: - - - X[item] returns a name for the set containing the given item. - Each set is named by an arbitrarily-chosen one of its members; as - long as the set remains unchanged it will keep the same name. If - the item is not yet part of a set in X, a new singleton set is - created for it. - - - X.union(item1, item2, ...) merges the sets containing each item - into a single larger set. If any item is not yet part of a set - in X, it is added to X as one of the members of the merged set. - - Union-find data structure. Based on Josiah Carlson's code, - http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/215912 - with significant additional changes by D. Eppstein. - http://www.ics.uci.edu/~eppstein/PADS/UnionFind.py - - """ - - def __init__(self, elements=None): - """Create a new empty union-find structure. - - If *elements* is an iterable, this structure will be initialized - with the discrete partition on the given set of elements. - - """ - if elements is None: - elements = () - self.parents = {} - self.weights = {} - for x in elements: - self.weights[x] = 1 - self.parents[x] = x - - def __getitem__(self, object): - """Find and return the name of the set containing the object.""" - - # check for previously unknown object - if object not in self.parents: - self.parents[object] = object - self.weights[object] = 1 - return object - - # find path of objects leading to the root - path = [object] - root = self.parents[object] - while root != path[-1]: - path.append(root) - root = self.parents[root] - - # compress the path and return - for ancestor in path: - self.parents[ancestor] = root - return root - - def __iter__(self): - """Iterate through all items ever found or unioned by this structure. - - """ - return iter(self.parents) - - def to_sets(self): - """Iterates over the sets stored in this structure. - - For example:: - - >>> partition = UnionFind('xyz') - >>> sorted(map(sorted, partition.to_sets())) - [['x'], ['y'], ['z']] - >>> partition.union('x', 'y') - >>> sorted(map(sorted, partition.to_sets())) - [['x', 'y'], ['z']] - - """ - # Ensure fully pruned paths - for x in self.parents.keys(): - _ = self[x] # Evaluated for side-effect only - - # TODO In Python 3.3+, this should be `yield from ...`. - for block in groups(self.parents).values(): - yield block - - def union(self, *objects): - """Find the sets containing the objects and merge them all.""" - roots = [self[x] for x in objects] - # Find the heaviest root according to its weight. - heaviest = max(roots, key=lambda r: self.weights[r]) - for r in roots: - if r != heaviest: - self.weights[heaviest] += self.weights[r] - self.parents[r] = heaviest diff --git a/extensions/fablabchemnitz/networkx/version.py b/extensions/fablabchemnitz/networkx/version.py deleted file mode 100644 index 56a6c411..00000000 --- a/extensions/fablabchemnitz/networkx/version.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -Version information for NetworkX, created during installation. - -Do not add this file to the repository. - -""" - -import datetime - -version = '2.4' -date = 'Thu Oct 17 02:06:31 2019' - -# Was NetworkX built from a development version? If so, remember that the major -# and minor versions reference the "target" (rather than "current") release. -dev = False - -# Format: (name, major, min, revision) -version_info = ('networkx', '2', '4', None) - -# Format: a 'datetime.datetime' instance -date_info = datetime.datetime(2019, 10, 17, 2, 6, 31) - -# Format: (vcs, vcs_tuple) -vcs_info = (None, (None, None)) - diff --git a/extensions/fablabchemnitz/OrigamiPatterns/Hypar.py b/extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/Hypar.py similarity index 100% rename from extensions/fablabchemnitz/OrigamiPatterns/Hypar.py rename to extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/Hypar.py diff --git a/extensions/fablabchemnitz/OrigamiPatterns/Kresling.py b/extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/Kresling.py similarity index 100% rename from extensions/fablabchemnitz/OrigamiPatterns/Kresling.py rename to extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/Kresling.py diff --git a/extensions/fablabchemnitz/OrigamiPatterns/Kresling_full.py b/extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/Kresling_full.py similarity index 100% rename from extensions/fablabchemnitz/OrigamiPatterns/Kresling_full.py rename to extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/Kresling_full.py diff --git a/extensions/fablabchemnitz/OrigamiPatterns/Path.py b/extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/Path.py similarity index 100% rename from extensions/fablabchemnitz/OrigamiPatterns/Path.py rename to extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/Path.py diff --git a/extensions/fablabchemnitz/OrigamiPatterns/Pattern.py b/extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/Pattern.py similarity index 100% rename from extensions/fablabchemnitz/OrigamiPatterns/Pattern.py rename to extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/Pattern.py diff --git a/extensions/fablabchemnitz/OrigamiPatterns/Pleat_Circular.py b/extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/Pleat_Circular.py similarity index 100% rename from extensions/fablabchemnitz/OrigamiPatterns/Pleat_Circular.py rename to extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/Pleat_Circular.py diff --git a/extensions/fablabchemnitz/OrigamiPatterns/Template.py b/extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/Template.py similarity index 100% rename from extensions/fablabchemnitz/OrigamiPatterns/Template.py rename to extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/Template.py diff --git a/extensions/fablabchemnitz/OrigamiPatterns/Waterbomb.py b/extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/Waterbomb.py similarity index 100% rename from extensions/fablabchemnitz/OrigamiPatterns/Waterbomb.py rename to extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/Waterbomb.py diff --git a/extensions/fablabchemnitz/OrigamiPatterns/__init__.py b/extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/__init__.py similarity index 100% rename from extensions/fablabchemnitz/OrigamiPatterns/__init__.py rename to extensions/fablabchemnitz/origamipatterns/OrigamiPatterns/__init__.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_origami_patterns_kresling.inx b/extensions/fablabchemnitz/origamipatterns/fablabchemnitz_origami_patterns_kresling.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_origami_patterns_kresling.inx rename to extensions/fablabchemnitz/origamipatterns/fablabchemnitz_origami_patterns_kresling.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_origami_patterns_pleat_circular.inx b/extensions/fablabchemnitz/origamipatterns/fablabchemnitz_origami_patterns_pleat_circular.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_origami_patterns_pleat_circular.inx rename to extensions/fablabchemnitz/origamipatterns/fablabchemnitz_origami_patterns_pleat_circular.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_origami_patterns_pleat_hypar.inx b/extensions/fablabchemnitz/origamipatterns/fablabchemnitz_origami_patterns_pleat_hypar.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_origami_patterns_pleat_hypar.inx rename to extensions/fablabchemnitz/origamipatterns/fablabchemnitz_origami_patterns_pleat_hypar.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_origami_patterns_template.inx b/extensions/fablabchemnitz/origamipatterns/fablabchemnitz_origami_patterns_template.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_origami_patterns_template.inx rename to extensions/fablabchemnitz/origamipatterns/fablabchemnitz_origami_patterns_template.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_origami_patterns_waterbomb.inx b/extensions/fablabchemnitz/origamipatterns/fablabchemnitz_origami_patterns_waterbomb.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_origami_patterns_waterbomb.inx rename to extensions/fablabchemnitz/origamipatterns/fablabchemnitz_origami_patterns_waterbomb.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_papercraft_unfold_ascii.inx b/extensions/fablabchemnitz/papercraft/fablabchemnitz_papercraft_unfold_ascii.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_papercraft_unfold_ascii.inx rename to extensions/fablabchemnitz/papercraft/fablabchemnitz_papercraft_unfold_ascii.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_papercraft_unfold_ascii.py b/extensions/fablabchemnitz/papercraft/fablabchemnitz_papercraft_unfold_ascii.py similarity index 97% rename from extensions/fablabchemnitz/fablabchemnitz_papercraft_unfold_ascii.py rename to extensions/fablabchemnitz/papercraft/fablabchemnitz_papercraft_unfold_ascii.py index 97b1d433..edad2857 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_papercraft_unfold_ascii.py +++ b/extensions/fablabchemnitz/papercraft/fablabchemnitz_papercraft_unfold_ascii.py @@ -34,5 +34,6 @@ class Unfold(inkex.Effect): #inkex.utils.debug("OK") doc = etree.parse(os.getcwd() + "\\" + outname) doc.write(sys.stdout.buffer) + if __name__ == '__main__': gc = Unfold() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_papercraft_unfold_binary.inx b/extensions/fablabchemnitz/papercraft/fablabchemnitz_papercraft_unfold_binary.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_papercraft_unfold_binary.inx rename to extensions/fablabchemnitz/papercraft/fablabchemnitz_papercraft_unfold_binary.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_papercraft_unfold_binary.py b/extensions/fablabchemnitz/papercraft/fablabchemnitz_papercraft_unfold_binary.py similarity index 97% rename from extensions/fablabchemnitz/fablabchemnitz_papercraft_unfold_binary.py rename to extensions/fablabchemnitz/papercraft/fablabchemnitz_papercraft_unfold_binary.py index 4173b092..e32e15d7 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_papercraft_unfold_binary.py +++ b/extensions/fablabchemnitz/papercraft/fablabchemnitz_papercraft_unfold_binary.py @@ -30,5 +30,6 @@ class Unfold(inkex.Effect): doc = etree.parse(os.getcwd() + "\\" + outname) #inkex.utils.debug(etree.tostring(doc)) doc.write(sys.stdout.buffer) + if __name__ == '__main__': gc = Unfold() \ No newline at end of file diff --git a/extensions/fablabchemnitz/papercraft/STLConverter.exe b/extensions/fablabchemnitz/papercraft/windows/STLConverter.exe similarity index 100% rename from extensions/fablabchemnitz/papercraft/STLConverter.exe rename to extensions/fablabchemnitz/papercraft/windows/STLConverter.exe diff --git a/extensions/fablabchemnitz/papercraft/cygwin1.dll b/extensions/fablabchemnitz/papercraft/windows/cygwin1.dll similarity index 100% rename from extensions/fablabchemnitz/papercraft/cygwin1.dll rename to extensions/fablabchemnitz/papercraft/windows/cygwin1.dll diff --git a/extensions/fablabchemnitz/papercraft/unfold.exe b/extensions/fablabchemnitz/papercraft/windows/unfold.exe similarity index 100% rename from extensions/fablabchemnitz/papercraft/unfold.exe rename to extensions/fablabchemnitz/papercraft/windows/unfold.exe diff --git a/extensions/fablabchemnitz/fablabchemnitz_pathops.inx b/extensions/fablabchemnitz/pathops/fablabchemnitz_pathops.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_pathops.inx rename to extensions/fablabchemnitz/pathops/fablabchemnitz_pathops.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_pathops.py b/extensions/fablabchemnitz/pathops/fablabchemnitz_pathops.py similarity index 99% rename from extensions/fablabchemnitz/fablabchemnitz_pathops.py rename to extensions/fablabchemnitz/pathops/fablabchemnitz_pathops.py index 4fe8aae1..b3bbeba6 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_pathops.py +++ b/extensions/fablabchemnitz/pathops/fablabchemnitz_pathops.py @@ -387,4 +387,5 @@ class PathOps(inkex.Effect): """Overload Effect() method.""" pass -PathOps().run() \ No newline at end of file +if __name__ == '__main__': + PathOps().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_pathops_combine.inx b/extensions/fablabchemnitz/pathops/fablabchemnitz_pathops_combine.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_pathops_combine.inx rename to extensions/fablabchemnitz/pathops/fablabchemnitz_pathops_combine.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_pathops_cutpath.inx b/extensions/fablabchemnitz/pathops/fablabchemnitz_pathops_cutpath.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_pathops_cutpath.inx rename to extensions/fablabchemnitz/pathops/fablabchemnitz_pathops_cutpath.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_pathops_difference.inx b/extensions/fablabchemnitz/pathops/fablabchemnitz_pathops_difference.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_pathops_difference.inx rename to extensions/fablabchemnitz/pathops/fablabchemnitz_pathops_difference.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_pathops_division.inx b/extensions/fablabchemnitz/pathops/fablabchemnitz_pathops_division.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_pathops_division.inx rename to extensions/fablabchemnitz/pathops/fablabchemnitz_pathops_division.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_pathops_exclusion.inx b/extensions/fablabchemnitz/pathops/fablabchemnitz_pathops_exclusion.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_pathops_exclusion.inx rename to extensions/fablabchemnitz/pathops/fablabchemnitz_pathops_exclusion.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_pathops_intersection.inx b/extensions/fablabchemnitz/pathops/fablabchemnitz_pathops_intersection.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_pathops_intersection.inx rename to extensions/fablabchemnitz/pathops/fablabchemnitz_pathops_intersection.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_pathops_union.inx b/extensions/fablabchemnitz/pathops/fablabchemnitz_pathops_union.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_pathops_union.inx rename to extensions/fablabchemnitz/pathops/fablabchemnitz_pathops_union.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_polyhedra.py b/extensions/fablabchemnitz/polyhedra/fablabchemnitz_polyhedra.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_polyhedra.py rename to extensions/fablabchemnitz/polyhedra/fablabchemnitz_polyhedra.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_polyhedra_archimedean.inx b/extensions/fablabchemnitz/polyhedra/fablabchemnitz_polyhedra_archimedean.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_polyhedra_archimedean.inx rename to extensions/fablabchemnitz/polyhedra/fablabchemnitz_polyhedra_archimedean.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_polyhedra_archimedeandual.inx b/extensions/fablabchemnitz/polyhedra/fablabchemnitz_polyhedra_archimedeandual.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_polyhedra_archimedeandual.inx rename to extensions/fablabchemnitz/polyhedra/fablabchemnitz_polyhedra_archimedeandual.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_polyhedra_other.inx b/extensions/fablabchemnitz/polyhedra/fablabchemnitz_polyhedra_other.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_polyhedra_other.inx rename to extensions/fablabchemnitz/polyhedra/fablabchemnitz_polyhedra_other.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_polyhedra_platonic.inx b/extensions/fablabchemnitz/polyhedra/fablabchemnitz_polyhedra_platonic.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_polyhedra_platonic.inx rename to extensions/fablabchemnitz/polyhedra/fablabchemnitz_polyhedra_platonic.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_polyhedrondata.py b/extensions/fablabchemnitz/polyhedra/fablabchemnitz_polyhedrondata.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_polyhedrondata.py rename to extensions/fablabchemnitz/polyhedra/fablabchemnitz_polyhedrondata.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_primitive/fablabchemnitz_primitive.inx b/extensions/fablabchemnitz/primitive/fablabchemnitz_primitive.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_primitive/fablabchemnitz_primitive.inx rename to extensions/fablabchemnitz/primitive/fablabchemnitz_primitive.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_primitive/fablabchemnitz_primitive.py b/extensions/fablabchemnitz/primitive/fablabchemnitz_primitive.py similarity index 96% rename from extensions/fablabchemnitz/fablabchemnitz_primitive/fablabchemnitz_primitive.py rename to extensions/fablabchemnitz/primitive/fablabchemnitz_primitive.py index cd40e521..46d96347 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_primitive/fablabchemnitz_primitive.py +++ b/extensions/fablabchemnitz/primitive/fablabchemnitz_primitive.py @@ -140,12 +140,15 @@ class Primitive (inkex.Effect): "," + node.get('y') + ")" newGroup.append(doc) - # Delet the temporary svg file + # Delete the temporary svg file if os.path.exists(exportfile + ".svg"): - os.remove(exportfile + ".svg") + try: + os.remove(exportfile + ".svg") + except: + pass else: - inkex.utils.debug("Error while creating output file! :-( The \"primitive\" executable seems to be missing or platform is imcompatible.") + inkex.utils.debug("Error while creating output file! :-( The \"primitive\" executable seems to be missing, has no exec permissions or platform is imcompatible.") exit(1) #remove the old image or not if self.options.keeporiginal is not True: @@ -173,4 +176,5 @@ class Primitive (inkex.Effect): else: inkex.utils.debug("No image found for tracing. Please select an image first.") -Primitive().run() +if __name__ == '__main__': + Primitive().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_primitive/primitive b/extensions/fablabchemnitz/primitive/primitive old mode 100644 new mode 100755 similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_primitive/primitive rename to extensions/fablabchemnitz/primitive/primitive diff --git a/extensions/fablabchemnitz/fablabchemnitz_primitive/primitive.exe b/extensions/fablabchemnitz/primitive/primitive.exe similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_primitive/primitive.exe rename to extensions/fablabchemnitz/primitive/primitive.exe diff --git a/extensions/fablabchemnitz/fablabchemnitz_rotate_helper.py b/extensions/fablabchemnitz/rotate/fablabchemnitz_rotate_helper.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_rotate_helper.py rename to extensions/fablabchemnitz/rotate/fablabchemnitz_rotate_helper.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_rotate_min_all.inx b/extensions/fablabchemnitz/rotate/fablabchemnitz_rotate_min_all.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_rotate_min_all.inx rename to extensions/fablabchemnitz/rotate/fablabchemnitz_rotate_min_all.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_rotate_min_all.py b/extensions/fablabchemnitz/rotate/fablabchemnitz_rotate_min_all.py similarity index 98% rename from extensions/fablabchemnitz/fablabchemnitz_rotate_min_all.py rename to extensions/fablabchemnitz/rotate/fablabchemnitz_rotate_min_all.py index fa830a52..e4e9dbe7 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_rotate_min_all.py +++ b/extensions/fablabchemnitz/rotate/fablabchemnitz_rotate_min_all.py @@ -62,5 +62,6 @@ class RotateMinAll(inkex.Effect): else: rotate_node = node rotate_node.transform = fablabchemnitz_rotate_helper.rotate_matrix(rotate_node, angle) * rotate_node.transform + if __name__ == '__main__': RotateMinAll().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_rotate_min_bbox.inx b/extensions/fablabchemnitz/rotate/fablabchemnitz_rotate_min_bbox.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_rotate_min_bbox.inx rename to extensions/fablabchemnitz/rotate/fablabchemnitz_rotate_min_bbox.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_rotate_min_bbox.py b/extensions/fablabchemnitz/rotate/fablabchemnitz_rotate_min_bbox.py similarity index 97% rename from extensions/fablabchemnitz/fablabchemnitz_rotate_min_bbox.py rename to extensions/fablabchemnitz/rotate/fablabchemnitz_rotate_min_bbox.py index e2817f6f..8996eba2 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_rotate_min_bbox.py +++ b/extensions/fablabchemnitz/rotate/fablabchemnitz_rotate_min_bbox.py @@ -37,5 +37,6 @@ class RotateMinBBox(inkex.Effect): min_bbox_angle = fablabchemnitz_rotate_helper.optimal_rotations(node)[1] if min_bbox_angle is not None: node.transform = Transform(fablabchemnitz_rotate_helper.rotate_matrix(node, min_bbox_angle)) * node.transform + if __name__ == '__main__': RotateMinBBox().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_rotate_min_width.inx b/extensions/fablabchemnitz/rotate/fablabchemnitz_rotate_min_width.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_rotate_min_width.inx rename to extensions/fablabchemnitz/rotate/fablabchemnitz_rotate_min_width.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_rotate_min_width.py b/extensions/fablabchemnitz/rotate/fablabchemnitz_rotate_min_width.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_rotate_min_width.py rename to extensions/fablabchemnitz/rotate/fablabchemnitz_rotate_min_width.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_sewing_patterns.py b/extensions/fablabchemnitz/shirtwaist/fablabchemnitz_sewing_patterns.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_sewing_patterns.py rename to extensions/fablabchemnitz/shirtwaist/fablabchemnitz_sewing_patterns.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_shirt_waist_allington.inx b/extensions/fablabchemnitz/shirtwaist/fablabchemnitz_shirt_waist_allington.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_shirt_waist_allington.inx rename to extensions/fablabchemnitz/shirtwaist/fablabchemnitz_shirt_waist_allington.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_shirt_waist_allington.py b/extensions/fablabchemnitz/shirtwaist/fablabchemnitz_shirt_waist_allington.py similarity index 99% rename from extensions/fablabchemnitz/fablabchemnitz_shirt_waist_allington.py rename to extensions/fablabchemnitz/shirtwaist/fablabchemnitz_shirt_waist_allington.py index 776e2697..380448b1 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_shirt_waist_allington.py +++ b/extensions/fablabchemnitz/shirtwaist/fablabchemnitz_shirt_waist_allington.py @@ -456,4 +456,5 @@ class ShirtWaistAllington(inkex.Effect): addText(bodice, 'note'+str(i), x, y, item, fontsize = '28', textalign = 'center', textanchor = 'middle', reference = 'false') y = y+0.33*IN -ShirtWaistAllington().run() \ No newline at end of file +if __name__ == '__main__': + ShirtWaistAllington().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_render_sudoku/fablabchemnitz_render_sudoku.inx b/extensions/fablabchemnitz/sudoku/fablabchemnitz_render_sudoku.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_render_sudoku/fablabchemnitz_render_sudoku.inx rename to extensions/fablabchemnitz/sudoku/fablabchemnitz_render_sudoku.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_render_sudoku/fablabchemnitz_render_sudoku.py b/extensions/fablabchemnitz/sudoku/fablabchemnitz_render_sudoku.py similarity index 99% rename from extensions/fablabchemnitz/fablabchemnitz_render_sudoku/fablabchemnitz_render_sudoku.py rename to extensions/fablabchemnitz/sudoku/fablabchemnitz_render_sudoku.py index 8bf8f12e..defebf40 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_render_sudoku/fablabchemnitz_render_sudoku.py +++ b/extensions/fablabchemnitz/sudoku/fablabchemnitz_render_sudoku.py @@ -108,4 +108,5 @@ class SVGSudoku (inkex.Effect): self.draw_grid(g, col*self.shift, row*self.shift) self.fill_puzzle(g, col*self.shift, row*self.shift, data[col+row*self.options.cols].decode('UTF-8')) -SVGSudoku().run() +if __name__ == '__main__': + SVGSudoku().run() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_render_sudoku/qqwing b/extensions/fablabchemnitz/sudoku/qqwing similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_render_sudoku/qqwing rename to extensions/fablabchemnitz/sudoku/qqwing diff --git a/extensions/fablabchemnitz/fablabchemnitz_render_sudoku/qqwing.exe b/extensions/fablabchemnitz/sudoku/qqwing.exe similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_render_sudoku/qqwing.exe rename to extensions/fablabchemnitz/sudoku/qqwing.exe diff --git a/extensions/fablabchemnitz/svg2shenzhen/bitmap2component.exe b/extensions/fablabchemnitz/svg2shenzhen/bitmap2component.exe deleted file mode 100644 index 8ae2625c..00000000 Binary files a/extensions/fablabchemnitz/svg2shenzhen/bitmap2component.exe and /dev/null differ diff --git a/extensions/fablabchemnitz/fablabchemnitz_svg2shenzhen_export.inx b/extensions/fablabchemnitz/svg2shenzhen/fablabchemnitz_svg2shenzhen_export.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_svg2shenzhen_export.inx rename to extensions/fablabchemnitz/svg2shenzhen/fablabchemnitz_svg2shenzhen_export.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_svg2shenzhen_prepare.inx b/extensions/fablabchemnitz/svg2shenzhen/fablabchemnitz_svg2shenzhen_prepare.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_svg2shenzhen_prepare.inx rename to extensions/fablabchemnitz/svg2shenzhen/fablabchemnitz_svg2shenzhen_prepare.inx diff --git a/extensions/fablabchemnitz/svg2shenzhen/svg2shenzhen/bitmap2component.exe b/extensions/fablabchemnitz/svg2shenzhen/svg2shenzhen/bitmap2component.exe new file mode 100755 index 00000000..287edc67 Binary files /dev/null and b/extensions/fablabchemnitz/svg2shenzhen/svg2shenzhen/bitmap2component.exe differ diff --git a/extensions/fablabchemnitz/svg2shenzhen/svg2shenzhen/bitmap2component_linux64 b/extensions/fablabchemnitz/svg2shenzhen/svg2shenzhen/bitmap2component_linux64 new file mode 100755 index 00000000..57eca0d6 Binary files /dev/null and b/extensions/fablabchemnitz/svg2shenzhen/svg2shenzhen/bitmap2component_linux64 differ diff --git a/extensions/fablabchemnitz/svg2shenzhen/svg2shenzhen/bitmap2component_osx b/extensions/fablabchemnitz/svg2shenzhen/svg2shenzhen/bitmap2component_osx new file mode 100755 index 00000000..569806f8 Binary files /dev/null and b/extensions/fablabchemnitz/svg2shenzhen/svg2shenzhen/bitmap2component_osx differ diff --git a/extensions/fablabchemnitz/svg2shenzhen/export.py b/extensions/fablabchemnitz/svg2shenzhen/svg2shenzhen/export.py similarity index 98% rename from extensions/fablabchemnitz/svg2shenzhen/export.py rename to extensions/fablabchemnitz/svg2shenzhen/svg2shenzhen/export.py index 9fa1fd1f..f2247744 100644 --- a/extensions/fablabchemnitz/svg2shenzhen/export.py +++ b/extensions/fablabchemnitz/svg2shenzhen/svg2shenzhen/export.py @@ -14,8 +14,12 @@ import pickle from copy import deepcopy from inkex import bezier from inkex.transforms import Transform +from pathlib import Path +homePath = str() +homePath = Path.home() + EXPORT_PNG_MAX_PROCESSES = 3 EXPORT_KICAD_MAX_PROCESSES = 2 @@ -254,7 +258,7 @@ class Svg2ShenzhenExport(inkex.Effect): } def add_arguments(self, pars): - pars.add_argument("--path", default="~/") + pars.add_argument("--path", default=homePath) pars.add_argument('-f', '--filetype', default='jpeg', help='Exported file type') pars.add_argument("--crop", type=inkex.Boolean, default=False) pars.add_argument("--dpi", type=int, default=600) @@ -338,7 +342,12 @@ class Svg2ShenzhenExport(inkex.Effect): def processExportLayer(self): options = self.options - output_path = os.path.expanduser(options.path) + if os.path.dirname(os.getcwd()) == options.path: + inkex.errormsg('EXPORT ERROR! Please Select A Directory To Export To!') + exit() + else: + output_path = os.path.expanduser(options.path) + curfile = self.options.input_file layers = self.get_layers(curfile) name = self.get_name() @@ -710,7 +719,7 @@ class Svg2ShenzhenExport(inkex.Effect): kicad_drill_string += pad_template.format(x=padCoord[0], y=padCoord[1], n=count, d=drill_size) - return kicad_drill_string + return kicad_drill_string def flatten_bezier(self): layerPath = '//svg:g[@inkscape:groupmode="layer"][@inkscape:label="Edge.Cuts"]' @@ -738,4 +747,4 @@ def _main(): exit() if __name__ == "__main__": - _main() + _main() \ No newline at end of file diff --git a/extensions/fablabchemnitz/svg2shenzhen/prepare.py b/extensions/fablabchemnitz/svg2shenzhen/svg2shenzhen/prepare.py similarity index 87% rename from extensions/fablabchemnitz/svg2shenzhen/prepare.py rename to extensions/fablabchemnitz/svg2shenzhen/svg2shenzhen/prepare.py index 84b93aca..b1ebd905 100644 --- a/extensions/fablabchemnitz/svg2shenzhen/prepare.py +++ b/extensions/fablabchemnitz/svg2shenzhen/svg2shenzhen/prepare.py @@ -1,5 +1,6 @@ #! /usr/bin/env python +import warnings import sys sys.path.append('/usr/share/inkscape/extensions') import inkex @@ -17,11 +18,36 @@ from lxml import etree identity_m = [[1.0,0.0,0.0],[0.0,1.0,0.0]] +kicadLayers = { + "layerDrill" : "Drill", + "layerDwgs_user" : "Dwgs.User", + "layerF_Silks" : "F.SilkS", + "layerF_Paste" : "F.Paste", + "layerF_mask" : "F.Mask", + "layerF_cu" : "F.Cu", + "layerB_silks" : "B.SilkS", + "layerB_paste" : "B.Paste", + "layerB_mask" : "B.Mask", + "layerB_cu" : "B.Cu", + "layerEdge_Cuts" : "Edge.Cuts", + "layerF_Adhes" : "F.Adhes", + "layerB_Adhes" : "B.Adhes", + "layerCmts_User" : "Cmts.User", + "layerEco1_User" : "Eco1.User", + "layerEco2_User" : "Eco2.User", + "layerMargin" : "Margin", + "layerB_CrtYd" : "B.CrtYd", + "layerF_CrtYd" : "F.CrtYd", + "layerB_Fab" : "B.Fab", + "layerF_Fab" : "F.Fab" +} +kicadLayersSelected = {} + class Svg2ShenzhenPrepare(inkex.Effect): def __init__(self): - """init the effetc library and get options from gui""" + """init the effect library and get options from gui""" inkex.Effect.__init__(self) - + self.bb_width_center = 0 self.bb_height_center = 0 self.bb_scaling_h = 0 @@ -31,6 +57,13 @@ class Svg2ShenzhenPrepare(inkex.Effect): def add_arguments(self, pars): pars.add_argument("--docwidth", type=float, default=0.0) pars.add_argument("--docheight", type=float, default=0.0) + pars.add_argument("--name") + pars.add_argument("--docGrid") + # Prepare the Arguments for all of the Layers + for key, value in kicadLayers.items(): + argumentKey = "--" + key + pars.add_argument(argumentKey) + def coordToKicad(self,XYCoord): return [ @@ -108,7 +141,7 @@ class Svg2ShenzhenPrepare(inkex.Effect): layer.append(text) - def prepareDocument(self): + def prepareDocument(self, options): svg_layers = self.document.xpath('//svg:g[@inkscape:groupmode="layer"]', namespaces=inkex.NSS) layers = [] @@ -135,68 +168,15 @@ class Svg2ShenzhenPrepare(inkex.Effect): rect = self.createWhitebg() white_layer.append(rect) - if ("F.Cu" not in layers and "F.Cu-disabled" not in layers): - self.createLayer("F.Cu") + # Create the Selected Layers + kicadLayersArray = list(kicadLayers.items()); - if ("B.Cu-disabled" not in layers and "B.Cu" not in layers): - self.createLayer("B.Cu-disabled") + for key, value in reversed(kicadLayersArray): + disabledValue = '%s-disabled' % (value) + selectedValue = getattr(options, key) + if selectedValue == "true" and value not in layers and disabledValue not in layers: + self.createLayer(value) - if ("B.Adhes-disabled" not in layers and "B.Adhes" not in layers): - self.createLayer("B.Adhes-disabled") - - if ("F.Adhes-disabled" not in layers and "F.Adhes" not in layers): - self.createLayer("F.Adhes-disabled") - - if ("B.Paste-disabled" not in layers and "B.Paste" not in layers): - self.createLayer("B.Paste-disabled") - - if ("F.Paste-disabled" not in layers and "F.Paste" not in layers): - self.createLayer("F.Paste-disabled") - - if ("B.SilkS-disabled" not in layers and "B.SilkS" not in layers): - self.createLayer("B.SilkS-disabled") - - if ("F.SilkS-disabled" not in layers and "F.SilkS" not in layers): - self.createLayer("F.SilkS-disabled") - - if ("B.Mask-disabled" not in layers and "B.Mask" not in layers): - self.createLayer("B.Mask-disabled") - - if ("F.Mask-disabled" not in layers and "F.Mask" not in layers): - self.createLayer("F.Mask-disabled") - - if ("Dwgs.User-disabled" not in layers and "Dwgs.User" not in layers): - self.createLayer("Dwgs.User-disabled") - - if ("Cmts.User-disabled" not in layers and "Cmts.User" not in layers): - self.createLayer("Cmts.User-disabled") - - if ("Eco1.User-disabled" not in layers and "Eco1.User" not in layers): - self.createLayer("Eco1.User-disabled") - - if ("Eco2.User-disabled" not in layers and "Eco2.User" not in layers): - self.createLayer("Eco2.User-disabled") - - if ("Edge.Cuts" not in layers): - self.createLayer("Edge.Cuts") - - if ("Margin-disabled" not in layers and "Margin" not in layers): - self.createLayer("Margin-disabled") - - if ("B.CrtYd-disabled" not in layers and "B.CrtYd" not in layers): - self.createLayer("B.CrtYd-disabled") - - if ("F.CrtYd-disabled" not in layers and "F.CrtYd" not in layers): - self.createLayer("F.CrtYd-disabled") - - if ("B.Fab-disabled" not in layers and "B.Fab" not in layers): - self.createLayer("B.Fab-disabled") - - if ("F.Fab-disabled" not in layers and "F.Fab" not in layers): - self.createLayer("F.Fab-disabled") - - if ("Drill" not in layers): - self.createLayer("Drill") def setDocumentGrid(self): doc_view = self.document.xpath('//sodipodi:namedview',namespaces=inkex.NSS)[0] @@ -220,10 +200,11 @@ class Svg2ShenzhenPrepare(inkex.Effect): def effect(self): self.setDocumentSquare(self.options.docwidth, self.options.docheight) self.setInkscapeScaling() - self.prepareDocument() - self.setDocumentGrid() + self.prepareDocument(self.options) + if self.options.docGrid == "true": + self.setDocumentGrid() self.setDefaultUnits() - + #warnings.warn(getattr(self.options, "layerF_Silk")) def prepareLogo(self, lyr): logo_xml = """ @@ -338,4 +319,4 @@ def _main(): exit() if __name__ == "__main__": - _main() + _main() \ No newline at end of file diff --git a/extensions/fablabchemnitz/fablabchemnitz_svgo_inkscape.inx b/extensions/fablabchemnitz/svgo-inkscape/fablabchemnitz_svgo_inkscape.inx similarity index 98% rename from extensions/fablabchemnitz/fablabchemnitz_svgo_inkscape.inx rename to extensions/fablabchemnitz/svgo-inkscape/fablabchemnitz_svgo_inkscape.inx index deda5780..61662fb3 100644 --- a/extensions/fablabchemnitz/fablabchemnitz_svgo_inkscape.inx +++ b/extensions/fablabchemnitz/svgo-inkscape/fablabchemnitz_svgo_inkscape.inx @@ -95,6 +95,6 @@ Scalable Vector Graphics - \ No newline at end of file + diff --git a/extensions/fablabchemnitz/svgpathtools/parser.py b/extensions/fablabchemnitz/svgpathtools/parser.py index 66147b8f..3b36ef3e 100644 --- a/extensions/fablabchemnitz/svgpathtools/parser.py +++ b/extensions/fablabchemnitz/svgpathtools/parser.py @@ -15,7 +15,7 @@ COMMANDS = set('MmZzLlHhVvCcSsQqTtAa') UPPERCASE = set('MZLHVCSQTA') COMMAND_RE = re.compile("([MmZzLlHhVvCcSsQqTtAa])") -FLOAT_RE = re.compile("[-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?") +FLOAT_RE = re.compile(r"[-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?") def _tokenize_path(pathdef): diff --git a/extensions/fablabchemnitz/fablabchemnitz_visicut_export.inx b/extensions/fablabchemnitz/visicut/fablabchemnitz_visicut_export.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_visicut_export.inx rename to extensions/fablabchemnitz/visicut/fablabchemnitz_visicut_export.inx diff --git a/extensions/fablabchemnitz/fablabchemnitz_visicut_export.py b/extensions/fablabchemnitz/visicut/fablabchemnitz_visicut_export.py similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_visicut_export.py rename to extensions/fablabchemnitz/visicut/fablabchemnitz_visicut_export.py diff --git a/extensions/fablabchemnitz/fablabchemnitz_visicut_export_replace.inx b/extensions/fablabchemnitz/visicut/fablabchemnitz_visicut_export_replace.inx similarity index 100% rename from extensions/fablabchemnitz/fablabchemnitz_visicut_export_replace.inx rename to extensions/fablabchemnitz/visicut/fablabchemnitz_visicut_export_replace.inx