diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f9d0b1c76..82b591d60 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/setup-python@v4 with: python-version: 3.8 - - run: pip install -U flake8 black~=22.0 + - run: pip install -U ruff black~=22.0 - uses: dtolnay/rust-toolchain@stable with: components: rustfmt @@ -38,7 +38,7 @@ jobs: - name: Black Codestyle Format run: black --check --diff retworkx rustworkx retworkx tests - name: Python Lint - run: flake8 --per-file-ignores='retworkx/__init__.py:F405,F403' setup.py retworkx tests rustworkx + run: ruff check rustworkx retworkx setup.py tests - name: Check stray release notes run: python tools/find_stray_release_notes.py - name: rustworkx-core Rust Tests @@ -57,7 +57,7 @@ jobs: strategy: matrix: rust: [stable] - python-version: [3.8, 3.9, "3.10", "3.11"] + python-version: [3.8, 3.9, "3.10", "3.11", "3.12"] platform: [ { os: "macOS-latest", python-architecture: "x64", rust-target: "x86_64-apple-darwin" }, { os: "ubuntu-latest", python-architecture: "x64", rust-target: "x86_64-unknown-linux-gnu" }, @@ -76,19 +76,6 @@ jobs: with: python-version: ${{ matrix.python-version }} architecture: ${{ matrix.platform.python-architecture }} - if: runner.os != 'Windows' - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: 3.7 - architecture: ${{ matrix.platform.python-architecture }} - if: ${{ runner.os == 'Windows' && matrix.python-version == '3.7.16' }} - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - architecture: ${{ matrix.platform.python-architecture }} - if: ${{ runner.os == 'Windows' && matrix.python-version != '3.7.16' }} - name: Install Rust toolchain uses: dtolnay/rust-toolchain@master @@ -123,47 +110,6 @@ jobs: run: python -m pip install --upgrade tox - name: 'Run rustworkx stub tests' run: tox -estubs - tests_retworkx_compat: - if: github.repository_owner == 'Qiskit' - needs: [build_lint] - name: python${{ matrix.python-version }}-${{ matrix.platform.python-architecture }} ${{ matrix.platform.os }} ${{ matrix.msrv }} - runs-on: ${{ matrix.platform.os }} - strategy: - matrix: - rust: [stable] - python-version: ["3.10"] - platform: [ - { os: "macOS-latest", python-architecture: "x64", rust-target: "x86_64-apple-darwin" }, - { os: "ubuntu-latest", python-architecture: "x64", rust-target: "x86_64-unknown-linux-gnu" }, - { os: "windows-latest", python-architecture: "x64", rust-target: "x86_64-pc-windows-msvc" }, - ] - steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - architecture: ${{ matrix.platform.python-architecture }} - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@master - with: - toolchain: ${{ matrix.rust }} - targets: ${{ matrix.platform.rust-target }} - - name: 'Install binary dependencies' - run: sudo apt-get install -y graphviz - if: runner.os == 'Linux' - - name: 'Build rustworkx and test dependencies' - run: | - pip install -c constraints.txt -U '.[mpl,graphviz]' fixtures testtools>=2.5.0 networkx>=2.5 stestr>=4.1 - - name: 'Build retworkx' - env: - RUSTWORKX_PKG_NAME: "retworkx" - run: | - pip install -c constraints.txt -U . - - name: 'Run retworkx tests' - run: | - cd tests - stestr run -t ./retworkx_backwards_compat coverage: if: github.repository_owner == 'Qiskit' needs: [tests] diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 4312f16de..c942df586 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -55,20 +55,10 @@ jobs: - uses: dtolnay/rust-toolchain@stable - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.10.1 twine + python -m pip install cibuildwheel==2.16.2 twine - name: Build wheels run: | python -m cibuildwheel --output-dir wheelhouse - env: - CIBW_BEFORE_ALL_LINUX: "yum install -y wget && {package}/tools/install_rust.sh" - CIBW_ENVIRONMENT_LINUX: 'PATH="$PATH:$HOME/.cargo/bin"' - CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=10.9 - CIBW_MANYLINUX_X86_64_IMAGE: quay.io/pypa/manylinux2014_x86_64:latest - CIBW_MANYLINUX_I686_IMAGE: quay.io/pypa/manylinux2014_i686:latest - CIBW_SKIP: cp36-* cp37-* pp* *win32 *musl* - CIBW_BEFORE_BUILD: pip install -U setuptools-rust - CIBW_TEST_REQUIRES: networkx testtools fixtures - CIBW_TEST_COMMAND: python -m unittest discover {project}/tests/rustworkx_tests - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl @@ -97,21 +87,43 @@ jobs: platforms: all - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.10.1 twine + python -m pip install cibuildwheel==2.16.2 twine + - name: Build wheels + run: | + python -m cibuildwheel --output-dir wheelhouse + env: + CIBW_ARCHS_LINUX: aarch64 + CIBW_SKIP: cp36-* cp37-* cp311-* cp312-* pp* *musl* + - uses: actions/upload-artifact@v3 + with: + path: ./wheelhouse/*.whl + build_wheels_aarch64_part_2: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + name: Install Python + with: + python-version: '3.8' + - uses: dtolnay/rust-toolchain@stable + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + with: + platforms: all + - name: Install cibuildwheel + run: | + python -m pip install cibuildwheel==2.16.2 twine - name: Build wheels run: | python -m cibuildwheel --output-dir wheelhouse env: - CIBW_BEFORE_ALL_LINUX: "yum install -y wget && {package}/tools/install_rust.sh" - CIBW_ENVIRONMENT_LINUX: 'PATH="$PATH:$HOME/.cargo/bin" CARGO_NET_GIT_FETCH_WITH_CLI="true"' - CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=10.9 - CIBW_MANYLINUX_X86_64_IMAGE: quay.io/pypa/manylinux2014_x86_64:latest - CIBW_MANYLINUX_I686_IMAGE: quay.io/pypa/manylinux2014_i686:latest - CIBW_SKIP: cp36-* cp37-* pp* *win32 *musl* - CIBW_BEFORE_BUILD: pip install -U setuptools-rust - CIBW_TEST_REQUIRES: networkx scipy testtools fixtures - CIBW_TEST_COMMAND: python -m unittest discover {project}/tests/rustworkx_tests CIBW_ARCHS_LINUX: aarch64 + CIBW_SKIP: cp36-* cp37-* cp38-* cp39-* cp310-* pp* *musl* - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl @@ -140,20 +152,12 @@ jobs: platforms: all - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.10.1 twine + python -m pip install cibuildwheel==2.16.2 twine - name: Build wheels run: | python -m cibuildwheel --output-dir wheelhouse env: - CIBW_BEFORE_ALL_LINUX: "yum install -y wget && {package}/tools/install_rust.sh" - CIBW_ENVIRONMENT_LINUX: 'PATH="$PATH:$HOME/.cargo/bin" CARGO_NET_GIT_FETCH_WITH_CLI="true"' - CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=10.9 - CIBW_MANYLINUX_X86_64_IMAGE: quay.io/pypa/manylinux2014_x86_64:latest - CIBW_MANYLINUX_I686_IMAGE: quay.io/pypa/manylinux2014_i686:latest - CIBW_SKIP: cp36-* cp37-* cp39-* cp310-* cp311-* pp* *win32 *musl* - CIBW_BEFORE_BUILD: pip install -U setuptools-rust - CIBW_TEST_REQUIRES: networkx testtools fixtures - CIBW_TEST_COMMAND: python -m unittest discover {project}/tests/rustworkx_tests + CIBW_SKIP: cp36-* cp37-* cp39-* cp310-* cp311-* pp* *win32 CIBW_ARCHS_LINUX: ppc64le - uses: actions/upload-artifact@v3 with: @@ -183,20 +187,12 @@ jobs: platforms: all - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.10.1 twine + python -m pip install cibuildwheel==2.16.2 twine - name: Build wheels run: | python -m cibuildwheel --output-dir wheelhouse env: - CIBW_BEFORE_ALL_LINUX: "yum install -y wget && {package}/tools/install_rust.sh" - CIBW_ENVIRONMENT_LINUX: 'PATH="$PATH:$HOME/.cargo/bin" CARGO_NET_GIT_FETCH_WITH_CLI="true"' - CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=10.9 - CIBW_MANYLINUX_X86_64_IMAGE: quay.io/pypa/manylinux2014_x86_64:latest - CIBW_MANYLINUX_I686_IMAGE: quay.io/pypa/manylinux2014_i686:latest - CIBW_SKIP: cp36-* cp37-* cp38-* pp* *win32 *musl* - CIBW_BEFORE_BUILD: pip install -U setuptools-rust - CIBW_TEST_REQUIRES: networkx testtools fixtures - CIBW_TEST_COMMAND: python -m unittest discover {project}/tests/rustworkx_tests + CIBW_SKIP: cp36-* cp37-* cp38-* cp312-* pp* *win32 *musl* CIBW_ARCHS_LINUX: ppc64le - uses: actions/upload-artifact@v3 with: @@ -226,22 +222,13 @@ jobs: platforms: all - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.10.1 twine + python -m pip install cibuildwheel==2.16.2 twine - name: Build wheels run: | python -m cibuildwheel --output-dir wheelhouse env: - CIBW_BEFORE_ALL_LINUX: "yum install -y wget && {package}/tools/install_rust.sh" - CIBW_ENVIRONMENT_LINUX: 'PATH="$PATH:$HOME/.cargo/bin" CARGO_NET_GIT_FETCH_WITH_CLI="true"' - CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=10.9 - CIBW_MANYLINUX_X86_64_IMAGE: quay.io/pypa/manylinux2014_x86_64:latest - CIBW_MANYLINUX_I686_IMAGE: quay.io/pypa/manylinux2014_i686:latest CIBW_SKIP: cp36-* cp37-* cp39-* cp310-* cp311-* pp* *win32 *musl* - CIBW_BEFORE_BUILD: pip install -U setuptools-rust - CIBW_TEST_REQUIRES: networkx testtools fixtures - CIBW_TEST_COMMAND: python -m unittest discover {project}/tests/rustworkx_tests CIBW_ARCHS_LINUX: s390x - CIBW_TEST_SKIP: "*-*linux_s390x" - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl @@ -270,22 +257,13 @@ jobs: platforms: all - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.10.1 twine + python -m pip install cibuildwheel==2.16.2 twine - name: Build wheels run: | python -m cibuildwheel --output-dir wheelhouse env: - CIBW_BEFORE_ALL_LINUX: "yum install -y wget && {package}/tools/install_rust.sh" - CIBW_ENVIRONMENT_LINUX: 'PATH="$PATH:$HOME/.cargo/bin" CARGO_NET_GIT_FETCH_WITH_CLI="true"' - CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=10.9 - CIBW_MANYLINUX_X86_64_IMAGE: quay.io/pypa/manylinux2014_x86_64:latest - CIBW_MANYLINUX_I686_IMAGE: quay.io/pypa/manylinux2014_i686:latest - CIBW_SKIP: cp36-* cp37-* cp38-* pp* *win32 *musl* - CIBW_BEFORE_BUILD: pip install -U setuptools-rust - CIBW_TEST_REQUIRES: networkx testtools fixtures - CIBW_TEST_COMMAND: python -m unittest discover {project}/tests/rustworkx_tests + CIBW_SKIP: cp36-* cp37-* cp38-* cp312-* pp* *win32 *musl* CIBW_ARCHS_LINUX: s390x - CIBW_TEST_SKIP: "*-*linux_s390x" - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl @@ -300,7 +278,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Build wheels - uses: joerick/cibuildwheel@v2.10.1 + uses: joerick/cibuildwheel@v2.16.2 env: CIBW_BEFORE_ALL: rustup target add aarch64-apple-darwin CIBW_ARCHS_MACOS: arm64 universal2 @@ -338,16 +316,12 @@ jobs: run: rustup default stable-i686-pc-windows-msvc - name: Install cibuildwheel run: | - python -m pip install cibuildwheel==2.10.1 twine + python -m pip install cibuildwheel==2.16.2 twine - name: Build wheels run: | python -m cibuildwheel --output-dir wheelhouse env: - CIBW_ENVIRONMENT_MACOS: MACOSX_DEPLOYMENT_TARGET=10.9 CIBW_SKIP: cp36-* cp37-* pp* *amd64 *musl* - CIBW_BEFORE_BUILD: pip install -U setuptools-rust - CIBW_TEST_REQUIRES: networkx testtools fixtures - CIBW_TEST_COMMAND: python -m unittest discover {project}/tests/rustworkx_tests - uses: actions/upload-artifact@v3 with: path: ./wheelhouse/*.whl diff --git a/Cargo.lock b/Cargo.lock index 36b79a054..90a5de9ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,20 +128,26 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" dependencies = [ "ahash", "allocator-api2", "rayon", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "indexmap" @@ -155,20 +161,20 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.1", "rayon", ] [[package]] name = "indoc" -version = "1.0.9" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306" +checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" [[package]] name = "itertools" @@ -196,15 +202,15 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" [[package]] name = "libm" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "lock_api" @@ -218,9 +224,9 @@ dependencies = [ [[package]] name = "matrixmultiply" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090126dc04f95dc0d1c1c91f61bdd474b3930ca064c1edc8a849da2c6cbe1e77" +checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" dependencies = [ "autocfg", "rawpointer", @@ -228,9 +234,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memoffset" @@ -321,9 +327,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", "libm", @@ -341,9 +347,9 @@ dependencies = [ [[package]] name = "numpy" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "437213adf41bbccf4aeae535fbfcdad0f6fed241e1ae182ebe97fa1f3ce19389" +checksum = "bef41cbb417ea83b30525259e30ccef6af39b31c240bda578889494c5392d331" dependencies = [ "libc", "ndarray", @@ -390,7 +396,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.0.0", + "indexmap 2.0.2", ] [[package]] @@ -411,22 +417,22 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] [[package]] name = "pyo3" -version = "0.19.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e681a6cfdc4adcc93b4d3cf993749a4552018ee0a9b65fc0ccfad74352c72a38" +checksum = "04e8453b658fe480c3e70c8ed4e3d3ec33eb74988bd186561b0cc66b85c3bc4b" dependencies = [ "cfg-if", - "hashbrown 0.14.0", - "indexmap 2.0.0", + "hashbrown 0.14.1", + "indexmap 2.0.2", "indoc", "libc", "memoffset", @@ -441,9 +447,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.19.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076c73d0bc438f7a4ef6fdd0c3bb4732149136abd952b110ac93e4edb13a6ba5" +checksum = "a96fe70b176a89cff78f2fa7b3c930081e163d5379b4dcdf993e3ae29ca662e5" dependencies = [ "once_cell", "target-lexicon", @@ -451,9 +457,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.19.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e53cee42e77ebe256066ba8aa77eff722b3bb91f3419177cf4cd0f304d3284d9" +checksum = "214929900fd25e6604661ed9cf349727c8920d47deff196c4e28165a6ef2a96b" dependencies = [ "libc", "pyo3-build-config", @@ -461,25 +467,26 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.19.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfeb4c99597e136528c6dd7d5e3de5434d1ceaf487436a3f03b2d56b6fc9efd1" +checksum = "dac53072f717aa1bfa4db832b39de8c875b7c7af4f4a6fe93cdbf9264cf8383b" dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 1.0.109", + "syn", ] [[package]] name = "pyo3-macros-backend" -version = "0.19.2" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "947dc12175c254889edc0c02e399476c2f652b4b9ebd123aa655c224de259536" +checksum = "7774b5a8282bd4f25f803b1f0d945120be959a36c72e08e7cd031c792fdfd424" dependencies = [ + "heck", "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] @@ -493,9 +500,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -597,8 +604,8 @@ version = "0.14.0" dependencies = [ "ahash", "fixedbitset", - "hashbrown 0.14.0", - "indexmap 2.0.0", + "hashbrown 0.14.1", + "indexmap 2.0.2", "ndarray", "ndarray-stats", "num-bigint", @@ -623,8 +630,8 @@ version = "0.14.0" dependencies = [ "ahash", "fixedbitset", - "hashbrown 0.14.0", - "indexmap 2.0.0", + "hashbrown 0.14.1", + "indexmap 2.0.2", "num-traits", "petgraph", "priority-queue", @@ -648,22 +655,22 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.188" +version = "1.0.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn", ] [[package]] @@ -679,9 +686,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "sprs" @@ -700,20 +707,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.28" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -728,15 +724,15 @@ checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unindent" -version = "0.1.11" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c" +checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce" [[package]] name = "version_check" @@ -752,9 +748,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -767,42 +763,42 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/Cargo.toml b/Cargo.toml index eed872da0..d8fba5163 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ fixedbitset = "0.4.2" hashbrown = { version = ">=0.13, <0.15", features = ["rayon"] } indexmap = { version = ">=1.9, <3", features = ["rayon"] } num-traits = "0.2" -numpy = "0.19.0" +numpy = "0.20.0" petgraph = "0.6.4" rand = "0.8" rand_pcg = "0.3" @@ -60,7 +60,7 @@ serde_json = "1.0" rustworkx-core = { path = "rustworkx-core", version = "=0.14.0" } [dependencies.pyo3] -version = "0.19.2" +version = "0.20.0" features = ["extension-module", "hashbrown", "num-bigint", "num-complex", "indexmap"] [dependencies.ndarray] diff --git a/README.md b/README.md index 417e4ff29..5542b86af 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,7 @@ [![Zenodo](https://img.shields.io/badge/Zenodo-10.5281%2Fzenodo.5879859-blue)](https://doi.org/10.5281/zenodo.5879859) - You can see the full rendered docs at: - - -|:warning:| The retworkx project has been renamed to **rustworkx**. The use of the -retworkx package will still work for the time being but starting in the 1.0.0 -release retworkx will no longer be supported + rustworkx is a general purpose graph library for Python written in Rust to take advantage of the performance and safety that Rust provides. It is @@ -27,7 +23,7 @@ any Python application. Rustworkx was originally called retworkx and was created initially to be a replacement for [qiskit](https://qiskit.org/)'s previous (and current) -networkx usage (hence the original name). The project was originally started +NetworkX usage (hence the original name). The project was originally started to build a faster directed graph to use as the underlying data structure for the DAG at the center of [qiskit-terra](https://github.com/Qiskit/qiskit-terra/)'s transpiler. However, diff --git a/docs/source/index.rst b/docs/source/index.rst index 26ec65d00..6e5ac96ac 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -2,12 +2,6 @@ rustworkx Documentation ####################### -.. note:: - - The project has been renamed to **rustworkx**. You can still use the legacy - retworkx name for now but starting in the 1.0.0 release the retworkx name - will no longer be supported. - rustworkx is a Python package for working with graphs and complex networks. It enables the creation, interaction with, and study of graphs and networks. @@ -57,6 +51,12 @@ https://docs.rs/rustworkx-core/0.13.0/rustworkx_core/ Project history --------------- +.. note:: + + The project has been renamed to **rustworkx**. You can still use the legacy + retworkx name for now but starting in the 1.0.0 release the retworkx name + will no longer be supported. + rustworkx was originally called retworkx and was created to be a high performance replacement for the Qiskit project's internal usage of the `NetworkX `__ library (which is where the name came diff --git a/docs/source/install.rst b/docs/source/install.rst index 0b44823f7..f55bcb711 100644 --- a/docs/source/install.rst +++ b/docs/source/install.rst @@ -59,7 +59,7 @@ limitations in available testing resources and platform availability, not all platforms can be supported. Platform support for rustworkx is broken into 4 tiers with different levels of support for each tier. For platforms outside these, rustworkx is probably still installable, but it’s not tested and you will -need a Rust compiler and have to build retworkx (and likely Numpy too) from +need a Rust compiler and have to build rustworkx (and likely Numpy too) from source. .. list-table:: Platform Support @@ -89,7 +89,11 @@ source. - s390x - :ref:`tier-4` - Distributions compatible with the `manylinux 2014`_ packaging specification - * - macOS (10.9 or newer) + * - Linux (musl) + - x86_64 + - :ref:`tier-3` + - + * - macOS (10.12 or newer) - x86_64 - :ref:`tier-1` - diff --git a/pyproject.toml b/pyproject.toml index c348b0338..f2b7e468a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,4 +4,53 @@ build-backend = "setuptools.build_meta" [tool.black] line-length = 100 -target-version = ['py37', 'py38', 'py39', 'py310'] +target-version = ['py38', 'py39', 'py310', 'py311'] + +[tool.ruff] +line-length = 100 +src = ["rustworkx", "setup.py", "retworkx", "tests"] +select = [ + "E", # pycodestyle + "F", # pyflakes + "UP", # pyupgrade + "PYI", # flake8-pyi + "Q", # flake8-quotes +] +target-version = "py38" +exclude = [ + ".venv", + ".git", + ".tox", + ".eggs", + "dist", + "doc", + "build", +] + +[tool.ruff.per-file-ignores] +"rustworkx/__init__.py" = ["F405", "F403"] +"*.pyi" = ["F403", "F405", "PYI001", "PYI002"] + +[tool.cibuildwheel] +manylinux-x86_64-image = "manylinux2014" +manylinux-i686-image = "manylinux2014" +skip = "pp* cp36-* cp37-* *win32 *musllinux*i686" +test-requires = "networkx" +test-command = "python -m unittest discover {project}/tests/rustworkx_tests" +before-build = "pip install -U setuptools-rust" +test-skip = "cp38-*musllinux* *linux_s390x *ppc64le" + +[tool.cibuildwheel.linux] +before-all = "yum install -y wget && {package}/tools/install_rust.sh" +environment = 'PATH="$PATH:$HOME/.cargo/bin" CARGO_NET_GIT_FETCH_WITH_CLI="true"' + +[[tool.cibuildwheel.overrides]] +select = "*-musllinux*" +before-all = "apk add --no-cache curl gcc && curl https://sh.rustup.rs -sSf | sh -s -- -y && source $HOME/.cargo/env && rustup install stable && rustup default stable" + +[[tool.cibuildwheel.overrides]] +select = "*i686" +before-test = 'python -m pip install numpy --config-settings=setup-args="-Dallow-noblas=true"' + +[tool.cibuildwheel.macos] +environment = "MACOSX_DEPLOYMENT_TARGET=10.12" diff --git a/releasenotes/notes/add-bipartite-9df3898a156e799c.yaml b/releasenotes/notes/add-bipartite-9df3898a156e799c.yaml new file mode 100644 index 000000000..dba6c7ed3 --- /dev/null +++ b/releasenotes/notes/add-bipartite-9df3898a156e799c.yaml @@ -0,0 +1,22 @@ +--- +features: + - | + Added a new function ``two_color`` to the rustworkx-core ``rustworkx_core::coloring`` + module. This function is used to compute a two coloring of a graph and can + also be used to determine if a graph is bipartite as it returns ``None`` + when a two coloring is not possible. + - | + Added a new function, :func:`~.two_color`, which is used to compute a + two coloring for a graph. For example: + + .. jupyter-execute:: + + import rustworkx as rx + from rustworkx.visualization import mpl_draw + + graph = rx.generators.heavy_square_graph(5) + colors = rx.two_color(graph) + mpl_draw(graph, node_color=list(colors.values())) + - | + Added a new function, :func:`~.is_bipartite` to determine whether a given + graph object is bipartite or not. diff --git a/releasenotes/notes/add-clear-and-clear_edges-for-graphs-041b166aa541639c.yaml b/releasenotes/notes/add-clear-and-clear_edges-for-graphs-041b166aa541639c.yaml new file mode 100644 index 000000000..ef6931f54 --- /dev/null +++ b/releasenotes/notes/add-clear-and-clear_edges-for-graphs-041b166aa541639c.yaml @@ -0,0 +1,10 @@ +--- +features: + - | + Added a new function, :func:`clear` that clears all nodes and edges + from a :class:`rustworkx.PyGraph` or :class:`rustworkx.PyDiGraph` + + - | + Added a new function, :func:`clear_edges` that clears all edges for + :class:`rustworkx.PyGraph` or :class:`rustworkx.PyDiGraph` without + modifying nodes diff --git a/releasenotes/notes/add-isolates-edc5da3a3d8fb4fd.yaml b/releasenotes/notes/add-isolates-edc5da3a3d8fb4fd.yaml new file mode 100644 index 000000000..d1bf9272b --- /dev/null +++ b/releasenotes/notes/add-isolates-edc5da3a3d8fb4fd.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Added a new function, :func:`~.isolates`, which is used to find the isolates + (nodes with a degree of 0) in a :class:`~.PyDiGraph` or :class:`~.PyGraph`. + - | + Added a new function, ``isolates()`` to the rustworkx-core ``rustworkx_core::connectivity`` + module which is used to find the isolates (nodes with a degree of 0). diff --git a/releasenotes/notes/platform-updates-e9b296144e633c95.yaml b/releasenotes/notes/platform-updates-e9b296144e633c95.yaml new file mode 100644 index 000000000..876fabbc8 --- /dev/null +++ b/releasenotes/notes/platform-updates-e9b296144e633c95.yaml @@ -0,0 +1,26 @@ +--- +features: + - | + Added support for musl Linux platforms on x86_64 and aarch64 at :ref:`tier-3`. +upgrade: + - | + Support for the Linux ppc64le pllatform has changed from tier 3 to tier 4 + (as documented in :ref:`platform-suppport`). This is a result of no longer + being able to run tests during the pre-compiled wheel publishing jobs due + to constraints in the available CI infrastructure. There hopefully + shouldn't be any meaningful impact resulting from this change, but as there + are no longer tests being run to validate the binaries prior to publishing + them there are no longer guarantees that the wheels for ppc64le are fully + functional (although the likelihood they are is still high as it works on + other platforms). If any issues are encountered with ppc64le Linux please + open an issue. + - | + For macOS the minimum version of macOS is now 10.12. Previously, the + precompiled binary wheel packages for macOS x86_64 were published with + support for >=10.9. However, because of changes in the + `support policy `__ + for the Rust programming language the minimum version needed to raised + to macOS 10.12. If you're using Qiskit on macOS 10.9 you can probably + build Qiskit from source while the rustworkx MSRV (minimum supported Rust + version) is < 1.74, but the precompiled binaries published to PyPI will + only be compatible with macOS >= 10.12. diff --git a/releasenotes/notes/retworkx-deprecation-848bc6b41f2368cf.yaml b/releasenotes/notes/retworkx-deprecation-848bc6b41f2368cf.yaml new file mode 100644 index 000000000..87d97569a --- /dev/null +++ b/releasenotes/notes/retworkx-deprecation-848bc6b41f2368cf.yaml @@ -0,0 +1,7 @@ +--- +deprecations: + - | + The legacy ``retworkx`` package that operates as a backwards compatibility + alias for ``rustworkx`` has been marked as deprecated. If you're using + the ``retworkx`` package it will now emit a ``DeprecationWarning`` on + import. diff --git a/retworkx/__init__.py b/retworkx/__init__.py index 8113d7616..3cb4bca86 100644 --- a/retworkx/__init__.py +++ b/retworkx/__init__.py @@ -10,11 +10,18 @@ import sys +import warnings from rustworkx import * # noqa from . import namespace +warnings.warn( + "The retworkx package is deprecated and has been renamed to rustworkx. Rustworkx is a " + "drop-in replacement and can be used by replacing `import retworkx` with import `rustworkx`. ", + DeprecationWarning, + stacklevel=2, +) sys.modules["retworkx.generators"] = generators # noqa new_meta_path_finder = namespace.RetworkxImport("retworkx", "rustworkx") diff --git a/rustworkx-core/src/centrality.rs b/rustworkx-core/src/centrality.rs index c099c6304..2d856244f 100644 --- a/rustworkx-core/src/centrality.rs +++ b/rustworkx-core/src/centrality.rs @@ -738,7 +738,7 @@ where { let alpha: f64 = alpha.unwrap_or(0.1); - let mut beta: HashMap = beta_map.unwrap_or_else(HashMap::new); + let mut beta: HashMap = beta_map.unwrap_or_default(); if beta.is_empty() { // beta_map was none diff --git a/rustworkx-core/src/coloring.rs b/rustworkx-core/src/coloring.rs index 99eb27a9f..60fda14da 100644 --- a/rustworkx-core/src/coloring.rs +++ b/rustworkx-core/src/coloring.rs @@ -17,9 +17,84 @@ use crate::dictmap::*; use crate::line_graph::line_graph; use hashbrown::{HashMap, HashSet}; use petgraph::graph::NodeIndex; -use petgraph::visit::{EdgeCount, EdgeRef, IntoEdges, IntoNodeIdentifiers, NodeCount}; +use petgraph::visit::{ + EdgeCount, EdgeRef, GraphBase, GraphProp, IntoEdges, IntoNeighborsDirected, + IntoNodeIdentifiers, NodeCount, NodeIndexable, +}; +use petgraph::{Incoming, Outgoing}; use rayon::prelude::*; +/// Compute a two-coloring of a graph +/// +/// If a two coloring is not possible for the input graph (meaning it is not +/// bipartite), `None` is returned. +/// +/// Arguments: +/// +/// * `graph` - The graph to find the coloring for +/// +/// # Example +/// +/// ```rust +/// use rustworkx_core::petgraph::prelude::*; +/// use rustworkx_core::coloring::two_color; +/// use rustworkx_core::dictmap::*; +/// +/// let edge_list = vec![ +/// (0, 1), +/// (1, 2), +/// (2, 3), +/// (3, 4), +/// ]; +/// +/// let graph = UnGraph::::from_edges(&edge_list); +/// let coloring = two_color(&graph).unwrap(); +/// let mut expected_colors = DictMap::new(); +/// expected_colors.insert(NodeIndex::new(0), 1); +/// expected_colors.insert(NodeIndex::new(1), 0); +/// expected_colors.insert(NodeIndex::new(2), 1); +/// expected_colors.insert(NodeIndex::new(3), 0); +/// expected_colors.insert(NodeIndex::new(4), 1); +/// assert_eq!(coloring, expected_colors) +/// ``` +pub fn two_color(graph: G) -> Option> +where + G: NodeIndexable + + IntoNodeIdentifiers + + IntoNeighborsDirected + + GraphBase + + GraphProp + + NodeCount, + ::NodeId: std::cmp::Eq + Hash, +{ + let mut colors = DictMap::with_capacity(graph.node_count()); + for node in graph.node_identifiers() { + if colors.contains_key(&node) { + continue; + } + let mut queue = vec![node]; + colors.insert(node, 1); + while let Some(v) = queue.pop() { + let v_color: u8 = *colors.get(&v).unwrap(); + let color: u8 = 1 - v_color; + for w in graph + .neighbors_directed(v, Outgoing) + .chain(graph.neighbors_directed(v, Incoming)) + { + if let Some(color_w) = colors.get(&w) { + if *color_w == v_color { + return None; + } + } else { + colors.insert(w, color); + queue.push(w); + } + } + } + } + Some(colors) +} + /// Color a graph using a greedy graph coloring algorithm. /// /// This function uses a `largest-first` strategy as described in: @@ -150,11 +225,12 @@ where mod test_node_coloring { use crate::coloring::greedy_node_color; - use crate::dictmap::DictMap; - use crate::petgraph::Graph; + use crate::coloring::two_color; + use crate::dictmap::*; + use crate::petgraph::prelude::*; - use petgraph::graph::NodeIndex; - use petgraph::Undirected; + use crate::petgraph::graph::NodeIndex; + use crate::petgraph::Undirected; #[test] fn test_greedy_node_color_empty_graph() { @@ -201,6 +277,77 @@ mod test_node_coloring { .collect(); assert_eq!(colors, expected_colors); } + + #[test] + fn test_two_color_directed() { + let edge_list = vec![(0, 1), (1, 2), (2, 3), (3, 4)]; + + let graph = DiGraph::::from_edges(&edge_list); + let coloring = two_color(&graph).unwrap(); + let mut expected_colors = DictMap::new(); + expected_colors.insert(NodeIndex::new(0), 1); + expected_colors.insert(NodeIndex::new(1), 0); + expected_colors.insert(NodeIndex::new(2), 1); + expected_colors.insert(NodeIndex::new(3), 0); + expected_colors.insert(NodeIndex::new(4), 1); + assert_eq!(coloring, expected_colors) + } + + #[test] + fn test_two_color_directed_not_bipartite() { + let edge_list = vec![(0, 1), (1, 2), (2, 3), (3, 0), (3, 1)]; + + let graph = DiGraph::::from_edges(&edge_list); + let coloring = two_color(&graph); + assert_eq!(None, coloring) + } + + #[test] + fn test_two_color_undirected_not_bipartite() { + let edge_list = vec![(0, 1), (1, 2), (2, 3), (3, 0), (3, 1)]; + + let graph = UnGraph::::from_edges(&edge_list); + let coloring = two_color(&graph); + assert_eq!(None, coloring) + } + + #[test] + fn test_two_color_directed_with_isolates() { + let edge_list = vec![(0, 1), (1, 2), (2, 3), (3, 4)]; + + let mut graph = DiGraph::::from_edges(&edge_list); + graph.add_node(10); + graph.add_node(11); + let coloring = two_color(&graph).unwrap(); + let mut expected_colors = DictMap::new(); + expected_colors.insert(NodeIndex::new(0), 1); + expected_colors.insert(NodeIndex::new(1), 0); + expected_colors.insert(NodeIndex::new(2), 1); + expected_colors.insert(NodeIndex::new(3), 0); + expected_colors.insert(NodeIndex::new(4), 1); + expected_colors.insert(NodeIndex::new(5), 1); + expected_colors.insert(NodeIndex::new(6), 1); + assert_eq!(coloring, expected_colors) + } + + #[test] + fn test_two_color_undirected_with_isolates() { + let edge_list = vec![(0, 1), (1, 2), (2, 3), (3, 4)]; + + let mut graph = UnGraph::::from_edges(&edge_list); + graph.add_node(10); + graph.add_node(11); + let coloring = two_color(&graph).unwrap(); + let mut expected_colors = DictMap::new(); + expected_colors.insert(NodeIndex::new(0), 1); + expected_colors.insert(NodeIndex::new(1), 0); + expected_colors.insert(NodeIndex::new(2), 1); + expected_colors.insert(NodeIndex::new(3), 0); + expected_colors.insert(NodeIndex::new(4), 1); + expected_colors.insert(NodeIndex::new(5), 1); + expected_colors.insert(NodeIndex::new(6), 1); + assert_eq!(coloring, expected_colors) + } } #[cfg(test)] diff --git a/rustworkx-core/src/connectivity/isolates.rs b/rustworkx-core/src/connectivity/isolates.rs new file mode 100644 index 000000000..df1a5b7c2 --- /dev/null +++ b/rustworkx-core/src/connectivity/isolates.rs @@ -0,0 +1,144 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +use petgraph::visit::{IntoNeighborsDirected, IntoNodeIdentifiers, NodeIndexable}; +use petgraph::Direction::{Incoming, Outgoing}; + +/// Return the isolates in a graph object +/// +/// An isolate is a node without any neighbors meaning it has a degree of 0. For +/// directed graphs this means the in-degree and out-degree are both 0. +/// +/// Arguments: +/// +/// * `graph` - The graph in which to find the isolates. +/// +/// # Example +/// ```rust +/// use petgraph::prelude::*; +/// use rustworkx_core::connectivity::isolates; +/// +/// let edge_list = vec![ +/// (0, 1), +/// (3, 0), +/// (0, 5), +/// (8, 0), +/// (1, 2), +/// (1, 6), +/// (2, 3), +/// (3, 4), +/// (4, 5), +/// (6, 7), +/// (7, 8), +/// (8, 9), +/// ]; +/// let mut graph = DiGraph::::from_edges(&edge_list); +/// graph.add_node(10); +/// graph.add_node(11); +/// let res: Vec = isolates(&graph).into_iter().map(|x| x.index()).collect(); +/// assert_eq!(res, [10, 11]) +/// ``` +pub fn isolates(graph: G) -> Vec +where + G: NodeIndexable + IntoNodeIdentifiers + IntoNeighborsDirected, +{ + graph + .node_identifiers() + .filter(|x| { + graph + .neighbors_directed(*x, Incoming) + .chain(graph.neighbors_directed(*x, Outgoing)) + .next() + .is_none() + }) + .collect() +} + +#[cfg(test)] +mod tests { + use crate::connectivity::isolates; + use petgraph::prelude::*; + + #[test] + fn test_isolates_directed_empty() { + let graph = DiGraph::::new(); + let res: Vec = isolates(&graph); + assert_eq!(res, []); + } + + #[test] + fn test_isolates_undirected_empty() { + let graph = UnGraph::::default(); + let res: Vec = isolates(&graph); + assert_eq!(res, []); + } + + #[test] + fn test_isolates_directed_no_isolates() { + let graph = DiGraph::::from_edges([(0, 1), (1, 2)]); + let res: Vec = isolates(&graph); + assert_eq!(res, []); + } + + #[test] + fn test_isolates_undirected_no_isolates() { + let graph = UnGraph::::from_edges([(0, 1), (1, 2)]); + let res: Vec = isolates(&graph); + assert_eq!(res, []); + } + + #[test] + fn test_isolates_directed() { + let edge_list = vec![ + (0, 1), + (3, 0), + (0, 5), + (8, 0), + (1, 2), + (1, 6), + (2, 3), + (3, 4), + (4, 5), + (6, 7), + (7, 8), + (8, 9), + ]; + let mut graph = DiGraph::::from_edges(&edge_list); + graph.add_node(10); + graph.add_node(11); + let res: Vec = isolates(&graph).into_iter().map(|x| x.index()).collect(); + assert_eq!(res, [10, 11]) + } + + #[test] + fn test_isolates_undirected() { + let edge_list = vec![ + (0, 1), + (3, 0), + (0, 5), + (8, 0), + (1, 2), + (1, 6), + (2, 3), + (3, 4), + (4, 5), + (6, 7), + (7, 8), + (8, 9), + ]; + let mut graph = UnGraph::::from_edges(&edge_list); + graph.add_node(10); + graph.add_node(11); + let res: Vec = isolates(&graph).into_iter().map(|x| x.index()).collect(); + assert_eq!(res, [10, 11]) + } +} diff --git a/rustworkx-core/src/connectivity/mod.rs b/rustworkx-core/src/connectivity/mod.rs index b66405c55..bc5851324 100644 --- a/rustworkx-core/src/connectivity/mod.rs +++ b/rustworkx-core/src/connectivity/mod.rs @@ -19,6 +19,7 @@ mod conn_components; mod core_number; mod cycle_basis; mod find_cycle; +mod isolates; mod min_cut; pub use all_simple_paths::{ @@ -32,4 +33,5 @@ pub use conn_components::number_connected_components; pub use core_number::core_number; pub use cycle_basis::cycle_basis; pub use find_cycle::find_cycle; +pub use isolates::isolates; pub use min_cut::stoer_wagner_min_cut; diff --git a/rustworkx-core/src/token_swapper.rs b/rustworkx-core/src/token_swapper.rs index c60e31425..8e30e9a76 100644 --- a/rustworkx-core/src/token_swapper.rs +++ b/rustworkx-core/src/token_swapper.rs @@ -205,6 +205,11 @@ where } let id_node = self.rev_node_map[&node]; let id_token = self.rev_node_map[&tokens[&node]]; + + if self.graph.neighbors(id_node).next().is_none() { + return Err(MapNotPossible {}); + } + for id_neighbor in self.graph.neighbors(id_node) { let neighbor = self.node_map[&id_neighbor]; let dist_neighbor: DictMap = dijkstra( @@ -705,4 +710,19 @@ mod test_token_swapper { Err(_) => (), }; } + + #[test] + fn test_edgeless_graph_fails() { + let mut g = petgraph::graph::UnGraph::<(), ()>::new_undirected(); + let a = g.add_node(()); + let b = g.add_node(()); + let c = g.add_node(()); + let d = g.add_node(()); + g.add_edge(c, d, ()); + let mapping = HashMap::from([(a, b), (b, a)]); + match token_swapper(&g, mapping, Some(10), Some(4), Some(50)) { + Ok(_) => panic!("This should error"), + Err(_) => (), + }; + } } diff --git a/rustworkx/__init__.py b/rustworkx/__init__.py index 48f65fde0..90c83ccce 100644 --- a/rustworkx/__init__.py +++ b/rustworkx/__init__.py @@ -2054,3 +2054,51 @@ def longest_simple_path(graph): longest_simple_path.register(PyDiGraph, digraph_longest_simple_path) longest_simple_path.register(PyGraph, graph_longest_simple_path) + + +@functools.singledispatch +def isolates(graph): + """Return a list of isolates in a graph object + + An isolate is a node without any neighbors meaning it has a degree of 0. For + directed graphs this means the in-degree and out-degree are both 0. + + :param graph: The input graph to find isolates in + :returns: A list of node indices for isolates in the graph + :rtype: NodeIndices + """ + + +isolates.register(PyDiGraph, digraph_isolates) +isolates.register(PyGraph, graph_isolates) + + +@functools.singledispatch +def two_color(graph): + """Compute a two-coloring of a directed graph + + If a two coloring is not possible for the input graph (meaning it is not + bipartite), ``None`` is returned. + + :param graph: The graph to find the coloring for + :returns: If a coloring is possible return a dictionary of node indices to the color as an integer (0 or 1) + :rtype: dict + """ + + +two_color.register(PyDiGraph, digraph_two_color) +two_color.register(PyGraph, graph_two_color) + + +@functools.singledispatch +def is_bipartite(graph): + """Determine if a given graph is bipartite + + :param graph: The graph to check if it's bipartite + :returns: ``True`` if the graph is bipartite and ``False`` if it is not + :rtype: bool + """ + + +is_bipartite.register(PyDiGraph, digraph_is_bipartite) +is_bipartite.register(PyGraph, graph_is_bipartite) diff --git a/rustworkx/digraph.pyi b/rustworkx/digraph.pyi index 0c359bba4..065c0eeb3 100644 --- a/rustworkx/digraph.pyi +++ b/rustworkx/digraph.pyi @@ -9,23 +9,10 @@ # This file contains only type annotations for PyO3 functions and classes # For implementation details, see __init__.py and src/digraph.rs -from __future__ import annotations - import numpy as np from .iterators import * -from typing import ( - Any, - Callable, - Dict, - Generic, - TypeVar, - Optional, - List, - Tuple, - Sequence, - TYPE_CHECKING, -) +from typing import Any, Callable, Generic, TypeVar, Sequence, TYPE_CHECKING if TYPE_CHECKING: from .graph import PyGraph @@ -49,45 +36,45 @@ class PyDiGraph(Generic[S, T]): def add_edge(self, parent: int, child: int, edge: T, /) -> int: ... def add_edges_from( self, - obj_list: Sequence[Tuple[int, int, T]], + obj_list: Sequence[tuple[int, int, T]], /, - ) -> List[int]: ... + ) -> list[int]: ... def add_edges_from_no_data( - self: PyDiGraph[S, Optional[T]], obj_list: Sequence[Tuple[int, int]], / - ) -> List[int]: ... + self: PyDiGraph[S, T | None], obj_list: Sequence[tuple[int, int]], / + ) -> list[int]: ... def add_node(self, obj: S, /) -> int: ... def add_nodes_from(self, obj_list: Sequence[S], /) -> NodeIndices: ... def add_parent(self, child: int, obj: S, edge: T, /) -> int: ... - def adj(self, node: int, /) -> Dict[int, T]: ... - def adj_direction(self, node: int, direction: bool, /) -> Dict[int, T]: ... + def adj(self, node: int, /) -> dict[int, T]: ... + def adj_direction(self, node: int, direction: bool, /) -> dict[int, T]: ... def compose( self, other: PyDiGraph[S, T], - node_map: Dict[int, Tuple[int, T]], + node_map: dict[int, tuple[int, T]], /, - node_map_func: Optional[Callable[[S], int]] = ..., - edge_map_func: Optional[Callable[[T], int]] = ..., - ) -> Dict[int, int]: ... + node_map_func: Callable[[S], int] | None = ..., + edge_map_func: Callable[[T], int] | None = ..., + ) -> dict[int, int]: ... def contract_nodes( self, - nodes: List[int], + nodes: list[int], obj: S, /, - check_cycle: Optional[bool] = ..., - weight_combo_fn: Optional[Callable[[T, T], T]] = ..., + check_cycle: bool | None = ..., + weight_combo_fn: Callable[[T, T], T] | None = ..., ) -> int: ... def copy(self) -> PyDiGraph[S, T]: ... def edge_index_map(self) -> EdgeIndexMap[T]: ... def edge_indices(self) -> EdgeIndices: ... def edge_list(self) -> EdgeList: ... - def edges(self) -> List[T]: ... - def edge_subgraph(self, edge_list: List[Tuple[int, int]], /) -> PyDiGraph[S, T]: ... + def edges(self) -> list[T]: ... + def edge_subgraph(self, edge_list: list[tuple[int, int]], /) -> PyDiGraph[S, T]: ... def extend_from_edge_list( - self: PyDiGraph[Optional[S], Optional[T]], edge_list: Sequence[Tuple[int, int]], / + self: PyDiGraph[S | None, T | None], edge_list: Sequence[tuple[int, int]], / ) -> None: ... def extend_from_weighted_edge_list( - self: PyDiGraph[Optional[S], T], - edge_list: Sequence[Tuple[int, int, T]], + self: PyDiGraph[S | None, T], + edge_list: Sequence[tuple[int, int, T]], /, ) -> None: ... def filter_edges(self, filter_function: Callable[[T], bool]) -> EdgeIndices: ... @@ -97,12 +84,12 @@ class PyDiGraph(Generic[S, T]): self, obj: Callable[[S], bool], /, - ) -> Optional[int]: ... + ) -> int | None: ... def find_predecessors_by_edge( self, node: int, filter_fn: Callable[[T], bool], / - ) -> List[S]: ... + ) -> list[S]: ... def find_predecessor_node_by_edge(self, node: int, predicate: Callable[[T], bool], /) -> S: ... - def find_successors_by_edge(self, node: int, filter_fn: Callable[[T], bool], /) -> List[S]: ... + def find_successors_by_edge(self, node: int, filter_fn: Callable[[T], bool], /) -> list[S]: ... @staticmethod def from_adjacency_matrix( matrix: np.ndarray, /, null_value: float = ... @@ -111,11 +98,11 @@ class PyDiGraph(Generic[S, T]): def from_complex_adjacency_matrix( matrix: np.ndarray, /, null_value: complex = ... ) -> PyDiGraph[int, complex]: ... - def get_all_edge_data(self, node_a: int, node_b: int, /) -> List[T]: ... + def get_all_edge_data(self, node_a: int, node_b: int, /) -> list[T]: ... def get_edge_data(self, node_a: int, node_b: int, /) -> T: ... def get_node_data(self, node: int, /) -> S: ... def get_edge_data_by_index(self, edge_index: int, /) -> T: ... - def get_edge_endpoints_by_index(self, edge_index: int, /) -> Tuple[int, int]: ... + def get_edge_endpoints_by_index(self, edge_index: int, /) -> tuple[int, int]: ... def has_edge(self, node_a: int, node_b: int, /) -> bool: ... def has_parallel_edges(self) -> bool: ... def in_degree(self, node: int, /) -> int: ... @@ -127,36 +114,36 @@ class PyDiGraph(Generic[S, T]): def insert_node_on_out_edges(self, node: int, ref_node: int, /) -> None: ... def insert_node_on_out_edges_multiple(self, node: int, ref_nodes: Sequence[int], /) -> None: ... def is_symmetric(self) -> bool: ... - def make_symmetric(self, edge_payload_fn: Optional[Callable[[T], T]] = ...) -> None: ... + def make_symmetric(self, edge_payload_fn: Callable[[T], T] | None = ...) -> None: ... def merge_nodes(self, u: int, v: int, /) -> None: ... def neighbors(self, node: int, /) -> NodeIndices: ... def node_indexes(self) -> NodeIndices: ... def node_indices(self) -> NodeIndices: ... - def nodes(self) -> List[S]: ... + def nodes(self) -> list[S]: ... def num_edges(self) -> int: ... def num_nodes(self) -> int: ... def out_degree(self, node: int, /) -> int: ... def out_edges(self, node: int, /) -> WeightedEdgeList[T]: ... def predecessor_indices(self, node: int, /) -> NodeIndices: ... - def predecessors(self, node: int, /) -> List[S]: ... + def predecessors(self, node: int, /) -> list[S]: ... @staticmethod def read_edge_list( path: str, /, - comment: Optional[str] = ..., - deliminator: Optional[str] = ..., + comment: str | None = ..., + deliminator: str | None = ..., labels: bool = ..., ) -> PyDiGraph: ... def remove_edge(self, parent: int, child: int, /) -> None: ... def remove_edge_from_index(self, edge: int, /) -> None: ... - def remove_edges_from(self, index_list: Sequence[Tuple[int, int]], /) -> None: ... + def remove_edges_from(self, index_list: Sequence[tuple[int, int]], /) -> None: ... def remove_node(self, node: int, /) -> None: ... def remove_node_retain_edges( self, node: int, /, - use_outgoing: Optional[bool] = ..., - condition: Optional[Callable[[S, S], bool]] = ..., + use_outgoing: bool | None = ..., + condition: Callable[[S, S], bool] | None = ..., ) -> None: ... def remove_nodes_from(self, index_list: Sequence[int], /) -> None: ... def subgraph(self, nodes: Sequence[int], /, preserve_attrs: bool = ...) -> PyDiGraph[S, T]: ... @@ -164,26 +151,26 @@ class PyDiGraph(Generic[S, T]): self, node: int, other: PyDiGraph[S, T], - edge_map_fn: Callable[[int, int, T], Optional[int]], + edge_map_fn: Callable[[int, int, T], int | None], /, - node_filter: Optional[Callable[[S], bool]] = ..., - edge_weight_map: Optional[Callable[[T], T]] = ..., + node_filter: Callable[[S], bool] | None = ..., + edge_weight_map: Callable[[T], T] | None = ..., ) -> NodeMap: ... def successor_indices(self, node: int, /) -> NodeIndices: ... - def successors(self, node: int, /) -> List[S]: ... + def successors(self, node: int, /) -> list[S]: ... def to_dot( self, /, - node_attr: Optional[Callable[[S], Dict[str, str]]] = ..., - edge_attr: Optional[Callable[[T], Dict[str, str]]] = ..., - graph_attr: Optional[Dict[str, str]] = ..., - filename: Optional[str] = ..., - ) -> Optional[str]: ... + node_attr: Callable[[S], dict[str, str]] | None = ..., + edge_attr: Callable[[T], dict[str, str]] | None = ..., + graph_attr: dict[str, str] | None = ..., + filename: str | None = ..., + ) -> str | None: ... def to_undirected( self, /, multigraph: bool = ..., - weight_combo_fn: Optional[Callable[[T, T], T]] = ..., + weight_combo_fn: Callable[[T, T], T] | None = ..., ) -> PyGraph[S, T]: ... def update_edge( self, @@ -198,8 +185,8 @@ class PyDiGraph(Generic[S, T]): self, path: str, /, - deliminator: Optional[str] = ..., - weight_fn: Optional[Callable[[T], str]] = ..., + deliminator: str | None = ..., + weight_fn: Callable[[T], str] | None = ..., ) -> None: ... def reverse(self) -> None: ... def __delitem__(self, idx: int, /) -> None: ... diff --git a/rustworkx/graph.pyi b/rustworkx/graph.pyi index 80b8ebc6c..57c80b290 100644 --- a/rustworkx/graph.pyi +++ b/rustworkx/graph.pyi @@ -9,20 +9,14 @@ # This file contains only type annotations for PyO3 functions and classes # For implementation details, see __init__.py and src/graph.rs -from __future__ import annotations - import numpy as np from .iterators import * from typing import ( Any, Callable, - Dict, Generic, TypeVar, - Optional, - List, - Tuple, Sequence, TYPE_CHECKING, ) @@ -42,43 +36,43 @@ class PyGraph(Generic[S, T]): def add_edge(self, node_a: int, node_b: int, edge: T, /) -> int: ... def add_edges_from( self, - obj_list: Sequence[Tuple[int, int, T]], + obj_list: Sequence[tuple[int, int, T]], /, - ) -> List[int]: ... + ) -> list[int]: ... def add_edges_from_no_data( - self: PyGraph[S, Optional[T]], obj_list: Sequence[Tuple[int, int]], / - ) -> List[int]: ... + self: PyGraph[S, T | None], obj_list: Sequence[tuple[int, int]], / + ) -> list[int]: ... def add_node(self, obj: S, /) -> int: ... def add_nodes_from(self, obj_list: Sequence[S], /) -> NodeIndices: ... - def adj(self, node: int, /) -> Dict[int, T]: ... + def adj(self, node: int, /) -> dict[int, T]: ... def compose( self, other: PyGraph[S, T], - node_map: Dict[int, Tuple[int, T]], + node_map: dict[int, tuple[int, T]], /, - node_map_func: Optional[Callable[[S], int]] = ..., - edge_map_func: Optional[Callable[[T], int]] = ..., - ) -> Dict[int, int]: ... + node_map_func: Callable[[S], int] | None = ..., + edge_map_func: Callable[[T], int] | None = ..., + ) -> dict[int, int]: ... def contract_nodes( self, - nodes: List[int], + nodes: list[int], obj: S, /, - weight_combo_fn: Optional[Callable[[T, T], T]] = ..., + weight_combo_fn: Callable[[T, T], T] | None = ..., ) -> int: ... def copy(self) -> PyGraph[S, T]: ... def degree(self, node: int, /) -> int: ... def edge_index_map(self) -> EdgeIndexMap[T]: ... def edge_indices(self) -> EdgeIndices: ... def edge_list(self) -> EdgeList: ... - def edges(self) -> List[T]: ... - def edge_subgraph(self, edge_list: List[Tuple[int, int]], /) -> PyGraph[S, T]: ... + def edges(self) -> list[T]: ... + def edge_subgraph(self, edge_list: list[tuple[int, int]], /) -> PyGraph[S, T]: ... def extend_from_edge_list( - self: PyGraph[Optional[S], Optional[T]], edge_list: Sequence[Tuple[int, int]], / + self: PyGraph[S | None, T | None], edge_list: Sequence[tuple[int, int]], / ) -> None: ... def extend_from_weighted_edge_list( - self: PyGraph[Optional[S], T], - edge_list: Sequence[Tuple[int, int, T]], + self: PyGraph[S | None, T], + edge_list: Sequence[tuple[int, int, T]], /, ) -> None: ... def filter_edges(self, filter_function: Callable[[T], bool]) -> EdgeIndices: ... @@ -87,7 +81,7 @@ class PyGraph(Generic[S, T]): self, obj: Callable[[S], bool], /, - ) -> Optional[int]: ... + ) -> int | None: ... @staticmethod def from_adjacency_matrix( matrix: np.ndarray, /, null_value: float = ... @@ -96,10 +90,10 @@ class PyGraph(Generic[S, T]): def from_complex_adjacency_matrix( matrix: np.ndarray, /, null_value: complex = ... ) -> PyGraph[int, complex]: ... - def get_all_edge_data(self, node_a: int, node_b: int, /) -> List[T]: ... + def get_all_edge_data(self, node_a: int, node_b: int, /) -> list[T]: ... def get_edge_data(self, node_a: int, node_b: int, /) -> T: ... def get_edge_data_by_index(self, edge_index: int, /) -> T: ... - def get_edge_endpoints_by_index(self, edge_index: int, /) -> Tuple[int, int]: ... + def get_edge_endpoints_by_index(self, edge_index: int, /) -> tuple[int, int]: ... def get_node_data(self, node: int, /) -> S: ... def has_edge(self, node_a: int, node_b: int, /) -> bool: ... def has_parallel_edges(self) -> bool: ... @@ -109,7 +103,7 @@ class PyGraph(Generic[S, T]): def neighbors(self, node: int, /) -> NodeIndices: ... def node_indexes(self) -> NodeIndices: ... def node_indices(self) -> NodeIndices: ... - def nodes(self) -> List[S]: ... + def nodes(self) -> list[S]: ... def num_edges(self) -> int: ... def num_nodes(self) -> int: ... def out_edges(self, node: int, /) -> WeightedEdgeList[T]: ... @@ -117,13 +111,13 @@ class PyGraph(Generic[S, T]): def read_edge_list( path: str, /, - comment: Optional[str] = ..., - deliminator: Optional[str] = ..., + comment: str | None = ..., + deliminator: str | None = ..., labels: bool = ..., ) -> PyGraph: ... def remove_edge(self, node_a: int, node_b: int, /) -> None: ... def remove_edge_from_index(self, edge: int, /) -> None: ... - def remove_edges_from(self, index_list: Sequence[Tuple[int, int]], /) -> None: ... + def remove_edges_from(self, index_list: Sequence[tuple[int, int]], /) -> None: ... def remove_node(self, node: int, /) -> None: ... def remove_nodes_from(self, index_list: Sequence[int], /) -> None: ... def subgraph(self, nodes: Sequence[int], /, preserve_attrs: bool = ...) -> PyGraph[S, T]: ... @@ -131,19 +125,19 @@ class PyGraph(Generic[S, T]): self, node: int, other: PyGraph[S, T], - edge_map_fn: Callable[[int, int, T], Optional[int]], + edge_map_fn: Callable[[int, int, T], int | None], /, - node_filter: Optional[Callable[[S], bool]] = ..., - edge_weight_map: Optional[Callable[[T], T]] = ..., + node_filter: Callable[[S], bool] | None = ..., + edge_weight_map: Callable[[T], T] | None = ..., ) -> NodeMap: ... def to_dot( self, /, - node_attr: Optional[Callable[[S], Dict[str, str]]] = ..., - edge_attr: Optional[Callable[[T], Dict[str, str]]] = ..., - graph_attr: Optional[Dict[str, str]] = ..., - filename: Optional[str] = ..., - ) -> Optional[str]: ... + node_attr: Callable[[S], dict[str, str]] | None = ..., + edge_attr: Callable[[T], dict[str, str]] | None = ..., + graph_attr: dict[str, str] | None = ..., + filename: str | None = ..., + ) -> str | None: ... def to_directed(self) -> PyDiGraph[S, T]: ... def update_edge( self, @@ -158,8 +152,8 @@ class PyGraph(Generic[S, T]): self, path: str, /, - deliminator: Optional[str] = ..., - weight_fn: Optional[Callable[[T], str]] = ..., + deliminator: str | None = ..., + weight_fn: Callable[[T], str] | None = ..., ) -> None: ... def __delitem__(self, idx: int, /) -> None: ... def __getitem__(self, idx: int, /) -> S: ... diff --git a/rustworkx/iterators.pyi b/rustworkx/iterators.pyi index e0d32c2f8..20779aa18 100644 --- a/rustworkx/iterators.pyi +++ b/rustworkx/iterators.pyi @@ -12,18 +12,14 @@ from typing import ( Any, Generic, - List, - Dict, ItemsView, KeysView, ValuesView, Iterator, Mapping, TypeVar, - Tuple, overload, final, - Optional, ) from abc import ABC from collections.abc import Sequence @@ -65,11 +61,10 @@ class RustworkxCustomVecIter(Generic[T_co], Sequence[T_co], ABC): def __getitem__(self: Self, index: slice) -> Self: ... def __getstate__(self) -> Any: ... def __hash__(self) -> int: ... - def __str__(self) -> str: ... def __len__(self) -> int: ... def __ne__(self, other: object) -> bool: ... def __setstate__(self, state: Sequence[T_co]) -> None: ... - def __array__(self, _dt: Optional[np.dtype] = ...) -> np.ndarray: ... + def __array__(self, _dt: np.dtype | None = ...) -> np.ndarray: ... class RustworkxCustomHashMapIter(Generic[S, T_co], Mapping[S, T_co], ABC): def __init__(self) -> None: ... @@ -81,7 +76,6 @@ class RustworkxCustomHashMapIter(Generic[S, T_co], Mapping[S, T_co], ABC): def __getitem__(self, index: S) -> T_co: ... def __getstate__(self) -> Any: ... def __hash__(self) -> int: ... - def __str__(self) -> str: ... def __iter__(self) -> Iterator[S]: ... def __len__(self) -> int: ... def __ne__(self, other: object) -> bool: ... @@ -103,10 +97,10 @@ class AllPairsPathLengthMapping(RustworkxCustomHashMapIter[int, PathLengthMappin class AllPairsPathMapping(RustworkxCustomHashMapIter[int, PathMapping]): ... @final -class BFSSuccessors(Generic[T_co], RustworkxCustomVecIter[Tuple[T_co, List[T_co]]]): ... +class BFSSuccessors(Generic[T_co], RustworkxCustomVecIter[tuple[T_co, list[T_co]]]): ... @final -class EdgeIndexMap(Generic[T_co], RustworkxCustomHashMapIter[int, Tuple[int, int, T_co]]): ... +class EdgeIndexMap(Generic[T_co], RustworkxCustomHashMapIter[int, tuple[int, int, T_co]]): ... @final class EdgeIndices(RustworkxCustomVecIter[int]): ... @@ -115,7 +109,7 @@ class EdgeIndices(RustworkxCustomVecIter[int]): ... class Chains(RustworkxCustomVecIter[EdgeIndices]): ... @final -class EdgeList(RustworkxCustomVecIter[Tuple[int, int]]): ... +class EdgeList(RustworkxCustomVecIter[tuple[int, int]]): ... @final class NodeMap(RustworkxCustomHashMapIter[int, int]): ... @@ -124,22 +118,22 @@ class NodeMap(RustworkxCustomHashMapIter[int, int]): ... class NodesCountMapping(RustworkxCustomHashMapIter[int, int]): ... @final -class Pos2DMapping(RustworkxCustomHashMapIter[int, Tuple[float, float]]): ... +class Pos2DMapping(RustworkxCustomHashMapIter[int, tuple[float, float]]): ... @final -class WeightedEdgeList(Generic[T_co], RustworkxCustomVecIter[Tuple[int, int, T_co]]): ... +class WeightedEdgeList(Generic[T_co], RustworkxCustomVecIter[tuple[int, int, T_co]]): ... @final class CentralityMapping(RustworkxCustomHashMapIter[int, float]): ... @final -class BiconnectedComponents(RustworkxCustomHashMapIter[Tuple[int, int], int]): ... +class BiconnectedComponents(RustworkxCustomHashMapIter[tuple[int, int], int]): ... @final -class ProductNodeMap(RustworkxCustomHashMapIter[Tuple[int, int], int]): ... +class ProductNodeMap(RustworkxCustomHashMapIter[tuple[int, int], int]): ... @final -class MultiplePathMapping(RustworkxCustomHashMapIter[int, List[List[int]]]): ... +class MultiplePathMapping(RustworkxCustomHashMapIter[int, list[list[int]]]): ... @final class AllPairsMultiplePathMapping(RustworkxCustomHashMapIter[int, MultiplePathMapping]): ... diff --git a/setup.py b/setup.py index 815f17538..7c0eac95d 100644 --- a/setup.py +++ b/setup.py @@ -18,17 +18,17 @@ def readme(): - with open('README.md') as f: + with open("README.md") as f: return f.read() -mpl_extras = ['matplotlib>=3.0'] -graphviz_extras = ['pillow>=5.4'] +mpl_extras = ["matplotlib>=3.0"] +graphviz_extras = ["pillow>=5.4"] -PKG_NAME = os.getenv('RUSTWORKX_PKG_NAME', "rustworkx") +PKG_NAME = os.getenv("RUSTWORKX_PKG_NAME", "rustworkx") PKG_VERSION = "0.14.0" PKG_PACKAGES = ["rustworkx", "rustworkx.visualization"] -PKG_INSTALL_REQUIRES = ['numpy>=1.16.0'] +PKG_INSTALL_REQUIRES = ["numpy>=1.16.0"] RUST_EXTENSIONS = [RustExtension("rustworkx.rustworkx", "Cargo.toml", binding=Binding.PyO3, debug=rustworkx_debug)] @@ -46,6 +46,7 @@ def readme(): if PKG_NAME == "retworkx": README = retworkx_readme_compat + README PKG_PACKAGES = ["retworkx"] + # TODO: For final retworkx release change this to < 1. PKG_INSTALL_REQUIRES.append(f"rustworkx=={PKG_VERSION}") RUST_EXTENSIONS = [] @@ -54,7 +55,7 @@ def readme(): version=PKG_VERSION, description="A python graph library implemented in Rust", long_description=README, - long_description_content_type='text/markdown', + long_description_content_type="text/markdown", author="Matthew Treinish", author_email="mtreinish@kortar.org", license="Apache 2.0", @@ -68,6 +69,7 @@ def readme(): "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Operating System :: MacOS :: MacOS X", "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", @@ -86,8 +88,8 @@ def readme(): python_requires=">=3.8", install_requires=PKG_INSTALL_REQUIRES, extras_require={ - 'mpl': mpl_extras, - 'graphviz': graphviz_extras, - 'all': mpl_extras + graphviz_extras, + "mpl": mpl_extras, + "graphviz": graphviz_extras, + "all": mpl_extras + graphviz_extras, } ) diff --git a/src/coloring.rs b/src/coloring.rs index 9440bd9e4..83eca1c49 100644 --- a/src/coloring.rs +++ b/src/coloring.rs @@ -10,9 +10,9 @@ // License for the specific language governing permissions and limitations // under the License. -use crate::graph; +use crate::{digraph, graph}; -use rustworkx_core::coloring::{greedy_edge_color, greedy_node_color}; +use rustworkx_core::coloring::{greedy_edge_color, greedy_node_color, two_color}; use pyo3::prelude::*; use pyo3::types::PyDict; @@ -88,3 +88,51 @@ pub fn graph_greedy_edge_color(py: Python, graph: &graph::PyGraph) -> PyResult

PyResult> { + match two_color(&graph.graph) { + Some(colors) => { + let out_dict = PyDict::new(py); + for (node, color) in colors { + out_dict.set_item(node.index(), color)?; + } + Ok(Some(out_dict.into())) + } + None => Ok(None), + } +} + +/// Compute a two-coloring of a directed graph +/// +/// If a two coloring is not possible for the input graph (meaning it is not +/// bipartite), ``None`` is returned. +/// +/// :param PyDiGraph graph: The graph to find the coloring for +/// +/// :returns: If a coloring is possible return a dictionary of node indices to the color as an +/// integer (0 or 1) +/// :rtype: dict +#[pyfunction] +pub fn digraph_two_color(py: Python, graph: &digraph::PyDiGraph) -> PyResult> { + match two_color(&graph.graph) { + Some(colors) => { + let out_dict = PyDict::new(py); + for (node, color) in colors { + out_dict.set_item(node.index(), color)?; + } + Ok(Some(out_dict.into())) + } + None => Ok(None), + } +} diff --git a/src/connectivity/mod.rs b/src/connectivity/mod.rs index 7d38b3cf9..11c49c951 100644 --- a/src/connectivity/mod.rs +++ b/src/connectivity/mod.rs @@ -39,6 +39,7 @@ use crate::iterators::{ }; use crate::{EdgeType, StablePyGraph}; +use rustworkx_core::coloring::two_color; use rustworkx_core::connectivity; /// Return a list of cycles which form a basis for cycles of a given PyGraph @@ -1000,3 +1001,58 @@ pub fn chain_decomposition(graph: graph::PyGraph, source: Option) -> Chai .collect(), } } + +/// Return a list of isolates in a :class:`~.PyGraph` object +/// +/// An isolate is a node without any neighbors meaning it has a degree of 0. +/// +/// :param PyGraph graph: The input graph to find isolates in +/// :returns: A list of node indices for isolates in the graph +/// :rtype: NodeIndices +#[pyfunction] +pub fn graph_isolates(graph: graph::PyGraph) -> NodeIndices { + NodeIndices { + nodes: connectivity::isolates(&graph.graph) + .into_iter() + .map(|x| x.index()) + .collect(), + } +} + +/// Return a list of isolates in a :class:`~.PyGraph` object +/// +/// An isolate is a node without any neighbors meaning it has an in-degree +/// and out-degree of 0. +/// +/// :param PyGraph graph: The input graph to find isolates in +/// :returns: A list of node indices for isolates in the graph +/// :rtype: NodeIndices +#[pyfunction] +pub fn digraph_isolates(graph: digraph::PyDiGraph) -> NodeIndices { + NodeIndices { + nodes: connectivity::isolates(&graph.graph) + .into_iter() + .map(|x| x.index()) + .collect(), + } +} + +/// Determine if a given graph is bipartite +/// +/// :param PyGraph graph: The graph to check if it's bipartite +/// :returns: ``True`` if the graph is bipartite and ``False`` if it is not +/// :rtype: bool +#[pyfunction] +pub fn graph_is_bipartite(graph: graph::PyGraph) -> bool { + two_color(&graph.graph).is_some() +} + +/// Determine if a given graph is bipartite +/// +/// :param PyDiGraph graph: The graph to check if it's bipartite +/// :returns: ``True`` if the graph is bipartite and ``False`` if it is not +/// :rtype: bool +#[pyfunction] +pub fn digraph_is_bipartite(graph: digraph::PyDiGraph) -> bool { + two_color(&graph.graph).is_some() +} diff --git a/src/dag_algo/mod.rs b/src/dag_algo/mod.rs index 489cf2344..04068342d 100644 --- a/src/dag_algo/mod.rs +++ b/src/dag_algo/mod.rs @@ -628,7 +628,6 @@ pub fn collect_bicolor_runs( } } else { for color in colors { - let color = color; ensure_vector_has_index!(pending_list, block_id, color); if let Some(color_block_id) = block_id[color] { block_list[color_block_id].append(&mut pending_list[color]); diff --git a/src/digraph.rs b/src/digraph.rs index 0fe27c4c3..02de16885 100644 --- a/src/digraph.rs +++ b/src/digraph.rs @@ -332,27 +332,33 @@ impl PyDiGraph { fn __setstate__(&mut self, py: Python, state: PyObject) -> PyResult<()> { let dict_state = state.downcast::(py)?; - let nodes_lst = dict_state.get_item("nodes").unwrap().downcast::()?; - let edges_lst = dict_state.get_item("edges").unwrap().downcast::()?; + let nodes_lst = dict_state + .get_item("nodes")? + .unwrap() + .downcast::()?; + let edges_lst = dict_state + .get_item("edges")? + .unwrap() + .downcast::()?; self.graph = StablePyGraph::::new(); let dict_state = state.downcast::(py)?; self.multigraph = dict_state - .get_item("multigraph") + .get_item("multigraph")? .unwrap() .downcast::()? .extract()?; self.node_removed = dict_state - .get_item("nodes_removed") + .get_item("nodes_removed")? .unwrap() .downcast::()? .extract()?; - let attrs = match dict_state.get_item("attrs") { + let attrs = match dict_state.get_item("attrs")? { Some(attr) => attr.into(), None => py.None(), }; self.attrs = attrs; self.check_cycle = dict_state - .get_item("check_cycle") + .get_item("check_cycle")? .unwrap() .downcast::()? .extract()?; @@ -492,6 +498,20 @@ impl PyDiGraph { } false } + + /// Clear all nodes and edges + #[pyo3(text_signature = "(self)")] + pub fn clear(&mut self) { + self.graph.clear(); + self.node_removed = true; + } + + /// Clears all edges, leaves nodes intact + #[pyo3(text_signature = "(self)")] + pub fn clear_edges(&mut self) { + self.graph.clear_edges(); + } + /// Return the number of nodes in the graph #[pyo3(text_signature = "(self)")] pub fn num_nodes(&self) -> usize { diff --git a/src/graph.rs b/src/graph.rs index 1d97404c5..45d8902a7 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -229,21 +229,27 @@ impl PyGraph { fn __setstate__(&mut self, py: Python, state: PyObject) -> PyResult<()> { let dict_state = state.downcast::(py)?; - let nodes_lst = dict_state.get_item("nodes").unwrap().downcast::()?; - let edges_lst = dict_state.get_item("edges").unwrap().downcast::()?; + let nodes_lst = dict_state + .get_item("nodes")? + .unwrap() + .downcast::()?; + let edges_lst = dict_state + .get_item("edges")? + .unwrap() + .downcast::()?; self.graph = StablePyGraph::::default(); self.multigraph = dict_state - .get_item("multigraph") + .get_item("multigraph")? .unwrap() .downcast::()? .extract()?; self.node_removed = dict_state - .get_item("nodes_removed") + .get_item("nodes_removed")? .unwrap() .downcast::()? .extract()?; - self.attrs = match dict_state.get_item("attrs") { + self.attrs = match dict_state.get_item("attrs")? { Some(attr) => attr.into(), None => py.None(), }; @@ -368,6 +374,19 @@ impl PyGraph { false } + /// Clears all nodes and edges + #[pyo3(text_signature = "(self)")] + pub fn clear(&mut self) { + self.graph.clear(); + self.node_removed = true; + } + + /// Clears all edges, leaves nodes intact + #[pyo3(text_signature = "(self)")] + pub fn clear_edges(&mut self) { + self.graph.clear_edges(); + } + /// Return the number of nodes in the graph #[pyo3(text_signature = "(self)")] pub fn num_nodes(&self) -> usize { diff --git a/src/lib.rs b/src/lib.rs index d34e31f10..bae7d05d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -442,6 +442,10 @@ fn rustworkx(py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_wrapped(wrap_pyfunction!(digraph_astar_shortest_path))?; m.add_wrapped(wrap_pyfunction!(graph_greedy_color))?; m.add_wrapped(wrap_pyfunction!(graph_greedy_edge_color))?; + m.add_wrapped(wrap_pyfunction!(graph_two_color))?; + m.add_wrapped(wrap_pyfunction!(digraph_two_color))?; + m.add_wrapped(wrap_pyfunction!(graph_is_bipartite))?; + m.add_wrapped(wrap_pyfunction!(digraph_is_bipartite))?; m.add_wrapped(wrap_pyfunction!(graph_line_graph))?; m.add_wrapped(wrap_pyfunction!(graph_tensor_product))?; m.add_wrapped(wrap_pyfunction!(digraph_tensor_product))?; @@ -498,6 +502,8 @@ fn rustworkx(py: Python<'_>, m: &PyModule) -> PyResult<()> { m.add_wrapped(wrap_pyfunction!(articulation_points))?; m.add_wrapped(wrap_pyfunction!(biconnected_components))?; m.add_wrapped(wrap_pyfunction!(chain_decomposition))?; + m.add_wrapped(wrap_pyfunction!(graph_isolates))?; + m.add_wrapped(wrap_pyfunction!(digraph_isolates))?; m.add_wrapped(wrap_pyfunction!(is_planar))?; m.add_wrapped(wrap_pyfunction!(read_graphml))?; m.add_wrapped(wrap_pyfunction!(digraph_node_link_json))?; diff --git a/src/matching/mod.rs b/src/matching/mod.rs index fac47e973..af9740ad9 100644 --- a/src/matching/mod.rs +++ b/src/matching/mod.rs @@ -92,7 +92,7 @@ fn _inner_is_matching(graph: &graph::PyGraph, matching: &HashSet<(usize, usize)> .contains_edge(NodeIndex::new(e.0), NodeIndex::new(e.1)) }; - if !matching.iter().all(|e| has_edge(e)) { + if !matching.iter().all(has_edge) { return false; } let mut found: HashSet = HashSet::with_capacity(2 * matching.len()); diff --git a/src/score.rs b/src/score.rs index 4dc888c5b..95e0d5bea 100644 --- a/src/score.rs +++ b/src/score.rs @@ -10,6 +10,7 @@ // License for the specific language governing permissions and limitations // under the License. #![allow(clippy::derive_partial_eq_without_eq)] +#![allow(clippy::incorrect_partial_ord_impl_on_ord_type)] use std::cmp::Ordering; use std::ops::{Add, AddAssign}; diff --git a/tests/retworkx_backwards_compat/__init__.py b/tests/retworkx_backwards_compat/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/retworkx_backwards_compat/digraph/__init__.py b/tests/retworkx_backwards_compat/digraph/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/retworkx_backwards_compat/digraph/test_adj.py b/tests/retworkx_backwards_compat/digraph/test_adj.py deleted file mode 100644 index e09a00872..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_adj.py +++ /dev/null @@ -1,102 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestAdj(unittest.TestCase): - def test_single_neighbor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - res = dag.adj(node_a) - self.assertEqual({node_b: {"a": 1}, node_c: {"a": 2}}, res) - - def test_in_and_out_adj_neighbor(self): - dag = retworkx.PyDAG() - dag.extend_from_weighted_edge_list([(0, 1, "a"), (1, 2, "b")]) - res = dag.adj(1) - self.assertEqual({0: "a", 2: "b"}, res) - - def test_single_neighbor_dir(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - res = dag.adj_direction(node_a, False) - self.assertEqual({node_b: {"a": 1}, node_c: {"a": 2}}, res) - res = dag.adj_direction(node_a, True) - self.assertEqual({}, res) - - def test_neighbor_dir_surrounded(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - res = dag.adj_direction(node_b, False) - self.assertEqual({node_c: {"a": 2}}, res) - res = dag.adj_direction(node_b, True) - self.assertEqual({node_a: {"a": 1}}, res) - - def test_single_neighbor_dir_out_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - res = dag.out_edges(node_a) - self.assertEqual([(node_a, node_c, {"a": 2}), (node_a, node_b, {"a": 1})], res) - - def test_neighbor_dir_surrounded_in_out_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - res = dag.out_edges(node_b) - self.assertEqual([(node_b, node_c, {"a": 2})], res) - res = dag.in_edges(node_b) - self.assertEqual([(node_a, node_b, {"a": 1})], res) - - def test_no_neighbor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - self.assertEqual({}, dag.adj(node_a)) - - def test_in_direction(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(5): - dag.add_parent(node_a, i, None) - self.assertEqual(5, dag.in_degree(node_a)) - - def test_in_direction_none(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(5): - dag.add_child(node_a, i, None) - self.assertEqual(0, dag.in_degree(node_a)) - - def test_out_direction(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(5): - dag.add_parent(node_a, i, None) - self.assertEqual(0, dag.out_degree(node_a)) - - def test_out_direction_none(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(5): - dag.add_child(node_a, i, None) - self.assertEqual(5, dag.out_degree(node_a)) diff --git a/tests/retworkx_backwards_compat/digraph/test_adjacency_matrix.py b/tests/retworkx_backwards_compat/digraph/test_adjacency_matrix.py deleted file mode 100644 index e62535f56..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_adjacency_matrix.py +++ /dev/null @@ -1,264 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx -import numpy as np - - -class TestDAGAdjacencyMatrix(unittest.TestCase): - def test_single_neighbor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"a": 1}) - dag.add_child(node_a, "c", {"a": 2}) - res = retworkx.digraph_adjacency_matrix(dag, lambda x: 1) - self.assertIsInstance(res, np.ndarray) - self.assertTrue( - np.array_equal( - np.array( - [[0.0, 1.0, 1.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], - dtype=np.float64, - ), - res, - ) - ) - - def test_no_weight_fn(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"a": 1}) - dag.add_child(node_a, "c", {"a": 2}) - res = retworkx.digraph_adjacency_matrix(dag) - self.assertIsInstance(res, np.ndarray) - self.assertTrue( - np.array_equal( - np.array( - [[0.0, 1.0, 1.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], - dtype=np.float64, - ), - res, - ) - ) - - def test_default_weight(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"a": 1}) - dag.add_child(node_a, "c", {"a": 2}) - res = retworkx.digraph_adjacency_matrix(dag, default_weight=4) - self.assertIsInstance(res, np.ndarray) - self.assertTrue( - np.array_equal( - np.array( - [[0.0, 4.0, 4.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]], - dtype=np.float64, - ), - res, - ) - ) - - def test_float_cast_weight_func(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", 7.0) - res = retworkx.digraph_adjacency_matrix(dag, lambda x: float(x)) - self.assertIsInstance(res, np.ndarray) - self.assertTrue(np.array_equal(np.array([[0.0, 7.0], [0.0, 0.0]]), res)) - - def test_multigraph_sum_cast_weight_func(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", 7.0) - dag.add_edge(node_a, node_b, 0.5) - res = retworkx.digraph_adjacency_matrix(dag, lambda x: float(x)) - self.assertIsInstance(res, np.ndarray) - self.assertTrue(np.array_equal(np.array([[0.0, 7.5], [0.0, 0.0]]), res)) - - def test_multigraph_sum_cast_weight_func_non_zero_null(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, 7.0) - graph.add_edge(node_a, node_b, 0.5) - res = retworkx.adjacency_matrix(graph, lambda x: float(x), null_value=np.inf) - self.assertIsInstance(res, np.ndarray) - self.assertTrue(np.array_equal(np.array([[np.inf, 7.5], [np.inf, np.inf]]), res)) - - def test_graph_to_digraph_adjacency_matrix(self): - graph = retworkx.PyGraph() - self.assertRaises(TypeError, retworkx.digraph_adjacency_matrix, graph) - - def test_no_edge_digraph_adjacency_matrix(self): - dag = retworkx.PyDAG() - for i in range(50): - dag.add_node(i) - res = retworkx.digraph_adjacency_matrix(dag, lambda x: 1) - self.assertTrue(np.array_equal(np.zeros([50, 50]), res)) - - def test_digraph_with_index_holes(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", 1) - dag.add_child(node_a, "c", 1) - dag.remove_node(node_b) - res = retworkx.digraph_adjacency_matrix(dag, lambda x: 1) - self.assertIsInstance(res, np.ndarray) - self.assertTrue(np.array_equal(np.array([[0, 1], [0, 0]]), res)) - - def test_from_adjacency_matrix(self): - input_array = np.array( - [[0.0, 4.0, 0.0], [4.0, 0.0, 4.0], [0.0, 4.0, 0.0]], - dtype=np.float64, - ) - graph = retworkx.PyDiGraph.from_adjacency_matrix(input_array) - out_array = retworkx.digraph_adjacency_matrix(graph, lambda x: x) - self.assertTrue(np.array_equal(input_array, out_array)) - - def test_random_graph_full_path(self): - graph = retworkx.directed_gnp_random_graph(100, 0.95, seed=42) - adjacency_matrix = retworkx.digraph_adjacency_matrix(graph) - new_graph = retworkx.PyDiGraph.from_adjacency_matrix(adjacency_matrix) - new_adjacency_matrix = retworkx.digraph_adjacency_matrix(new_graph) - self.assertTrue(np.array_equal(adjacency_matrix, new_adjacency_matrix)) - - def test_random_graph_different_dtype(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.int64) - with self.assertRaises(TypeError): - retworkx.PyDiGraph.from_adjacency_matrix(input_matrix) - - def test_random_graph_different_dtype_astype_no_copy(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.int64) - graph = retworkx.PyDiGraph.from_adjacency_matrix( - input_matrix.astype(np.float64, copy=False) - ) - adj_matrix = retworkx.digraph_adjacency_matrix(graph, lambda x: x) - self.assertTrue(np.array_equal(adj_matrix, input_matrix)) - - def test_random_graph_float_dtype(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=float) - graph = retworkx.PyDiGraph.from_adjacency_matrix(input_matrix) - adj_matrix = retworkx.digraph_adjacency_matrix(graph, lambda x: x) - self.assertTrue(np.array_equal(adj_matrix, input_matrix)) - - def test_non_zero_null(self): - input_matrix = np.array( - [[np.Inf, 1, np.Inf], [1, np.Inf, 1], [np.Inf, 1, np.Inf]], - dtype=np.float64, - ) - graph = retworkx.PyDiGraph.from_adjacency_matrix(input_matrix, null_value=np.Inf) - adj_matrix = retworkx.adjacency_matrix(graph, float) - expected_matrix = np.array( - [[0.0, 1.0, 0.0], [1.0, 0.0, 1.0], [0.0, 1.0, 0.0]], - dtype=np.float64, - ) - self.assertTrue(np.array_equal(adj_matrix, expected_matrix)) - - def test_negative_weight(self): - input_matrix = np.array([[0, 1, 0], [-1, 0, -1], [0, 1, 0]], dtype=float) - graph = retworkx.PyDiGraph.from_adjacency_matrix(input_matrix) - adj_matrix = retworkx.digraph_adjacency_matrix(graph, lambda x: x) - self.assertTrue(np.array_equal(adj_matrix, input_matrix)) - self.assertEqual( - [(0, 1, 1), (1, 0, -1), (1, 2, -1), (2, 1, 1)], - graph.weighted_edge_list(), - ) - - def test_nan_null(self): - input_matrix = np.array( - [[np.nan, 1, np.nan], [1, np.nan, 1], [np.nan, 1, np.nan]], - dtype=np.float64, - ) - graph = retworkx.PyDiGraph.from_adjacency_matrix(input_matrix, null_value=np.nan) - adj_matrix = retworkx.adjacency_matrix(graph, float) - expected_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.float64) - self.assertTrue(np.array_equal(adj_matrix, expected_matrix)) - - -class TestFromComplexAdjacencyMatrix(unittest.TestCase): - def test_from_adjacency_matrix(self): - input_array = np.array( - [[0.0, 4.0, 0.0], [4.0, 0.0, 4.0], [0.0, 4.0, 0.0]], - dtype=np.complex128, - ) - graph = retworkx.PyDiGraph.from_complex_adjacency_matrix(input_array) - expected = [ - (0, 1, 4 + 0j), - (1, 0, 4 + 0j), - (1, 2, 4 + 0j), - (2, 1, 4 + 0j), - ] - self.assertEqual(graph.weighted_edge_list(), expected) - - def test_random_graph_different_dtype(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.int64) - with self.assertRaises(TypeError): - retworkx.PyDiGraph.from_complex_adjacency_matrix(input_matrix) - - def test_random_graph_different_dtype_astype_no_copy(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.int64) - graph = retworkx.PyDiGraph.from_complex_adjacency_matrix( - input_matrix.astype(np.complex128, copy=False) - ) - expected = [ - (0, 1, 1 + 0j), - (1, 0, 1 + 0j), - (1, 2, 1 + 0j), - (2, 1, 1 + 0j), - ] - self.assertEqual(graph.weighted_edge_list(), expected) - - def test_random_graph_complex_dtype(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=complex) - graph = retworkx.PyDiGraph.from_complex_adjacency_matrix(input_matrix) - expected = [ - (0, 1, 1 + 0j), - (1, 0, 1 + 0j), - (1, 2, 1 + 0j), - (2, 1, 1 + 0j), - ] - self.assertEqual(graph.weighted_edge_list(), expected) - - def test_non_zero_null(self): - input_matrix = np.array( - [[np.Inf, 1, np.Inf], [1, np.Inf, 1], [np.Inf, 1, np.Inf]], - dtype=np.complex128, - ) - graph = retworkx.PyDiGraph.from_complex_adjacency_matrix(input_matrix, null_value=np.Inf) - expected = [ - (0, 1, 1 + 0j), - (1, 0, 1 + 0j), - (1, 2, 1 + 0j), - (2, 1, 1 + 0j), - ] - self.assertEqual(graph.weighted_edge_list(), expected) - - def test_negative_weight(self): - input_matrix = np.array([[0, 1, 0], [-1, 0, -1], [0, 1, 0]], dtype=complex) - graph = retworkx.PyDiGraph.from_complex_adjacency_matrix(input_matrix) - self.assertEqual( - [(0, 1, 1), (1, 0, -1), (1, 2, -1), (2, 1, 1)], - graph.weighted_edge_list(), - ) - - def test_nan_null(self): - input_matrix = np.array( - [[np.nan, 1, np.nan], [1, np.nan, 1], [np.nan, 1, np.nan]], - dtype=np.complex128, - ) - graph = retworkx.PyDiGraph.from_complex_adjacency_matrix(input_matrix, null_value=np.nan) - edge_list = graph.weighted_edge_list() - self.assertEqual( - edge_list, - [(0, 1, 1 + 0j), (1, 0, 1 + 0j), (1, 2, 1 + 0j), (2, 1, 1 + 0j)], - ) diff --git a/tests/retworkx_backwards_compat/digraph/test_all_simple_paths.py b/tests/retworkx_backwards_compat/digraph/test_all_simple_paths.py deleted file mode 100644 index 8d2b8e2aa..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_all_simple_paths.py +++ /dev/null @@ -1,307 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestDAGAllSimplePaths(unittest.TestCase): - def setUp(self): - super().setUp() - self.edges = [ - (0, 1), - (0, 2), - (0, 3), - (1, 2), - (1, 3), - (2, 3), - (2, 4), - (3, 2), - (3, 4), - (4, 2), - (4, 5), - (5, 2), - (5, 3), - ] - - def test_all_simple_paths(self): - dag = retworkx.PyDAG() - for i in range(6): - dag.add_node(i) - dag.add_edges_from_no_data(self.edges) - paths = retworkx.digraph_all_simple_paths(dag, 0, 5) - expected = [ - [0, 1, 2, 3, 4, 5], - [0, 1, 2, 4, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 3, 4, 5], - [0, 2, 3, 4, 5], - [0, 2, 4, 5], - [0, 3, 2, 4, 5], - [0, 3, 4, 5], - ] - for i in expected: - self.assertIn(i, paths) - - def test_all_simple_paths_min_depth(self): - dag = retworkx.PyDAG() - for i in range(6): - dag.add_node(i) - dag.add_edges_from_no_data(self.edges) - paths = retworkx.digraph_all_simple_paths(dag, 0, 5, min_depth=6) - expected = [ - [0, 1, 2, 3, 4, 5], - [0, 1, 3, 2, 4, 5], - ] - for i in expected: - self.assertIn(i, paths) - - def test_all_simple_paths_with_cutoff(self): - dag = retworkx.PyDAG() - for i in range(6): - dag.add_node(i) - dag.add_edges_from_no_data(self.edges) - paths = retworkx.digraph_all_simple_paths(dag, 0, 5, cutoff=4) - expected = [[0, 2, 4, 5], [0, 3, 4, 5]] - self.assertEqual(len(expected), len(paths)) - for i in expected: - self.assertIn(i, paths) - - def test_all_simple_paths_with_min_depth_and_cutoff(self): - dag = retworkx.PyDAG() - for i in range(6): - dag.add_node(i) - dag.add_edges_from_no_data(self.edges) - paths = retworkx.digraph_all_simple_paths(dag, 0, 5, min_depth=5, cutoff=5) - expected = [ - [0, 3, 2, 4, 5], - [0, 2, 3, 4, 5], - [0, 1, 3, 4, 5], - [0, 1, 2, 4, 5], - ] - self.assertEqual(len(expected), len(paths)) - for i in expected: - self.assertIn(i, paths) - - def test_all_simple_path_no_path(self): - dag = retworkx.PyDAG() - dag.add_node(0) - dag.add_node(1) - self.assertEqual([], retworkx.digraph_all_simple_paths(dag, 0, 1)) - - def test_all_simple_path_invalid_node_index(self): - dag = retworkx.PyDAG() - dag.add_node(0) - dag.add_node(1) - with self.assertRaises(retworkx.InvalidNode): - retworkx.digraph_all_simple_paths(dag, 0, 5) - - def test_graph_digraph_all_simple_paths(self): - dag = retworkx.PyGraph() - dag.add_node(0) - dag.add_node(1) - self.assertRaises(TypeError, retworkx.digraph_all_simple_paths, (dag, 0, 1)) - - -class TestDiGraphAllSimplePathsAllPairs(unittest.TestCase): - def setUp(self): - super().setUp() - self.edges = [ - (0, 1), - (0, 2), - (0, 3), - (1, 2), - (1, 3), - (2, 3), - (2, 4), - (3, 2), - (3, 4), - (4, 2), - (4, 5), - (5, 2), - (5, 3), - ] - - def test_all_simple_paths(self): - dag = retworkx.PyDAG() - for i in range(6): - dag.add_node(i) - dag.add_edges_from_no_data(self.edges) - paths = retworkx.all_pairs_all_simple_paths(dag) - expected = { - 0: { - 1: [[0, 1]], - 2: [ - [0, 3, 4, 5, 2], - [0, 3, 4, 2], - [0, 3, 2], - [0, 2], - [0, 1, 3, 4, 5, 2], - [0, 1, 3, 4, 2], - [0, 1, 3, 2], - [0, 1, 2], - ], - 3: [ - [0, 3], - [0, 2, 4, 5, 3], - [0, 2, 3], - [0, 1, 3], - [0, 1, 2, 4, 5, 3], - [0, 1, 2, 3], - ], - 4: [ - [0, 3, 4], - [0, 3, 2, 4], - [0, 2, 4], - [0, 2, 3, 4], - [0, 1, 3, 4], - [0, 1, 3, 2, 4], - [0, 1, 2, 4], - [0, 1, 2, 3, 4], - ], - 5: [ - [0, 3, 4, 5], - [0, 3, 2, 4, 5], - [0, 2, 4, 5], - [0, 2, 3, 4, 5], - [0, 1, 3, 4, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 2, 4, 5], - [0, 1, 2, 3, 4, 5], - ], - }, - 1: { - 2: [[1, 3, 4, 5, 2], [1, 3, 4, 2], [1, 3, 2], [1, 2]], - 3: [[1, 3], [1, 2, 4, 5, 3], [1, 2, 3]], - 4: [[1, 3, 4], [1, 3, 2, 4], [1, 2, 4], [1, 2, 3, 4]], - 5: [[1, 3, 4, 5], [1, 3, 2, 4, 5], [1, 2, 4, 5], [1, 2, 3, 4, 5]], - }, - 2: { - 3: [[2, 4, 5, 3], [2, 3]], - 4: [[2, 4], [2, 3, 4]], - 5: [[2, 4, 5], [2, 3, 4, 5]], - }, - 3: { - 2: [[3, 4, 5, 2], [3, 4, 2], [3, 2]], - 4: [[3, 4], [3, 2, 4]], - 5: [[3, 4, 5], [3, 2, 4, 5]], - }, - 4: { - 2: [[4, 5, 3, 2], [4, 5, 2], [4, 2]], - 3: [[4, 5, 3], [4, 5, 2, 3], [4, 2, 3]], - 5: [[4, 5]], - }, - 5: { - 2: [[5, 3, 4, 2], [5, 3, 2], [5, 2]], - 3: [[5, 3], [5, 2, 3]], - 4: [[5, 3, 4], [5, 3, 2, 4], [5, 2, 4], [5, 2, 3, 4]], - }, - } - self.assertEqual(expected, paths) - - def test_all_simple_paths_min_depth(self): - dag = retworkx.PyDAG() - for i in range(6): - dag.add_node(i) - dag.add_edges_from_no_data(self.edges) - paths = retworkx.all_pairs_all_simple_paths(dag, min_depth=6) - expected = { - 0: { - 2: [[0, 1, 3, 4, 5, 2]], - 3: [[0, 1, 2, 4, 5, 3]], - 5: [[0, 1, 3, 2, 4, 5], [0, 1, 2, 3, 4, 5]], - }, - 1: {}, - 2: {}, - 3: {}, - 4: {}, - 5: {}, - } - self.assertEqual(expected, paths) - - def test_all_simple_paths_with_cutoff(self): - dag = retworkx.PyDAG() - for i in range(6): - dag.add_node(i) - dag.add_edges_from_no_data(self.edges) - paths = retworkx.all_pairs_all_simple_paths(dag, cutoff=4) - expected = { - 0: { - 1: [[0, 1]], - 2: [[0, 3, 4, 2], [0, 3, 2], [0, 2], [0, 1, 3, 2], [0, 1, 2]], - 3: [[0, 3], [0, 2, 3], [0, 1, 3], [0, 1, 2, 3]], - 4: [[0, 3, 4], [0, 3, 2, 4], [0, 2, 4], [0, 2, 3, 4], [0, 1, 3, 4], [0, 1, 2, 4]], - 5: [[0, 3, 4, 5], [0, 2, 4, 5]], - }, - 1: { - 2: [[1, 3, 4, 2], [1, 3, 2], [1, 2]], - 3: [[1, 3], [1, 2, 3]], - 4: [[1, 3, 4], [1, 3, 2, 4], [1, 2, 4], [1, 2, 3, 4]], - 5: [[1, 3, 4, 5], [1, 2, 4, 5]], - }, - 2: { - 3: [[2, 4, 5, 3], [2, 3]], - 4: [[2, 4], [2, 3, 4]], - 5: [[2, 4, 5], [2, 3, 4, 5]], - }, - 3: { - 2: [[3, 4, 5, 2], [3, 4, 2], [3, 2]], - 4: [[3, 4], [3, 2, 4]], - 5: [[3, 4, 5], [3, 2, 4, 5]], - }, - 4: { - 2: [[4, 5, 3, 2], [4, 5, 2], [4, 2]], - 3: [[4, 5, 3], [4, 5, 2, 3], [4, 2, 3]], - 5: [[4, 5]], - }, - 5: { - 2: [[5, 3, 4, 2], [5, 3, 2], [5, 2]], - 3: [[5, 3], [5, 2, 3]], - 4: [[5, 3, 4], [5, 3, 2, 4], [5, 2, 4], [5, 2, 3, 4]], - }, - } - self.assertEqual(paths, expected) - - def test_all_simple_paths_with_min_depth_and_cutoff(self): - dag = retworkx.PyDAG() - for i in range(6): - dag.add_node(i) - dag.add_edges_from_no_data(self.edges) - paths = retworkx.all_pairs_all_simple_paths(dag, min_depth=5, cutoff=5) - expected = { - 0: { - 2: [[0, 3, 4, 5, 2], [0, 1, 3, 4, 2]], - 5: [[0, 3, 2, 4, 5], [0, 2, 3, 4, 5], [0, 1, 3, 4, 5], [0, 1, 2, 4, 5]], - 3: [[0, 2, 4, 5, 3]], - 4: [[0, 1, 3, 2, 4], [0, 1, 2, 3, 4]], - }, - 1: { - 2: [[1, 3, 4, 5, 2]], - 5: [[1, 3, 2, 4, 5], [1, 2, 3, 4, 5]], - 3: [[1, 2, 4, 5, 3]], - }, - 2: {}, - 3: {}, - 4: {}, - 5: {}, - } - self.assertEqual(expected, paths) - - def test_all_simple_path_no_path(self): - dag = retworkx.PyDAG() - dag.add_node(0) - dag.add_node(1) - self.assertEqual({0: {}, 1: {}}, retworkx.all_pairs_all_simple_paths(dag)) - - def test_all_simple_paths_empty(self): - self.assertEqual({}, retworkx.all_pairs_all_simple_paths(retworkx.PyDiGraph())) diff --git a/tests/retworkx_backwards_compat/digraph/test_ancestors_descendants.py b/tests/retworkx_backwards_compat/digraph/test_ancestors_descendants.py deleted file mode 100644 index 0db8d72ac..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_ancestors_descendants.py +++ /dev/null @@ -1,64 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestAncestors(unittest.TestCase): - def test_ancestors(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - res = retworkx.ancestors(dag, node_c) - self.assertEqual({node_a, node_b}, res) - - def test_no_ancestors(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"a": 1}) - res = retworkx.ancestors(dag, node_a) - self.assertEqual(set(), res) - - def test_ancestors_no_descendants(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - dag.add_child(node_b, "c", {"b": 1}) - res = retworkx.ancestors(dag, node_b) - self.assertEqual({node_a}, res) - - -class TestDescendants(unittest.TestCase): - def test_descendants(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - res = retworkx.descendants(dag, node_a) - self.assertEqual({node_b, node_c}, res) - - def test_no_descendants(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - res = retworkx.descendants(dag, node_a) - self.assertEqual(set(), res) - - def test_descendants_no_ancestors(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"b": 1}) - res = retworkx.descendants(dag, node_b) - self.assertEqual({node_c}, res) diff --git a/tests/retworkx_backwards_compat/digraph/test_astar.py b/tests/retworkx_backwards_compat/digraph/test_astar.py deleted file mode 100644 index 7c03ea119..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_astar.py +++ /dev/null @@ -1,114 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestAstarDigraph(unittest.TestCase): - def test_astar_null_heuristic(self): - g = retworkx.PyDAG() - a = g.add_node("A") - b = g.add_node("B") - c = g.add_node("C") - d = g.add_node("D") - e = g.add_node("E") - f = g.add_node("F") - g.add_edge(a, b, 7) - g.add_edge(c, a, 9) - g.add_edge(a, d, 14) - g.add_edge(b, c, 10) - g.add_edge(d, c, 2) - g.add_edge(d, e, 9) - g.add_edge(b, f, 15) - g.add_edge(c, f, 11) - g.add_edge(e, f, 6) - path = retworkx.digraph_astar_shortest_path( - g, a, lambda goal: goal == "E", lambda x: float(x), lambda y: 0 - ) - expected = [a, d, e] - self.assertEqual(expected, path) - - def test_astar_manhattan_heuristic(self): - g = retworkx.PyDAG() - a = g.add_node((0.0, 0.0)) - b = g.add_node((2.0, 0.0)) - c = g.add_node((1.0, 1.0)) - d = g.add_node((0.0, 2.0)) - e = g.add_node((3.0, 3.0)) - f = g.add_node((4.0, 2.0)) - no_path = g.add_node((5.0, 5.0)) # no path to node - g.add_edge(a, b, 2.0) - g.add_edge(a, d, 4.0) - g.add_edge(b, c, 1.0) - g.add_edge(b, f, 7.0) - g.add_edge(c, e, 5.0) - g.add_edge(e, f, 1.0) - g.add_edge(d, e, 1.0) - - def heuristic_func(f): - x1, x2 = f - return abs(x2 - x1) - - def finish_func(node, x): - return x == g.get_node_data(node) - - expected = [ - [0], - [0, 1], - [0, 1, 2], - [0, 3], - [0, 3, 4], - [0, 3, 4, 5], - ] - - for index, end in enumerate([a, b, c, d, e, f]): - path = retworkx.digraph_astar_shortest_path( - g, - a, - lambda finish: finish_func(end, finish), - lambda x: float(x), - heuristic_func, - ) - self.assertEqual(expected[index], path) - - with self.assertRaises(retworkx.NoPathFound): - retworkx.digraph_astar_shortest_path( - g, - a, - lambda finish: finish_func(no_path, finish), - lambda x: float(x), - heuristic_func, - ) - - def test_astar_digraph_with_graph_input(self): - g = retworkx.PyGraph() - g.add_node(0) - with self.assertRaises(TypeError): - retworkx.digraph_astar_shortest_path(g, 0, lambda x: x, lambda y: 1, lambda z: 0) - - def test_astar_with_invalid_weights(self): - g = retworkx.PyDAG() - a = g.add_node("A") - b = g.add_node("B") - g.add_edge(a, b, 7) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.digraph_astar_shortest_path( - g, - a, - goal_fn=lambda goal: goal == "B", - edge_cost_fn=lambda _: invalid_weight, - estimate_cost_fn=lambda _: 0, - ) diff --git a/tests/retworkx_backwards_compat/digraph/test_avg_shortest_path.py b/tests/retworkx_backwards_compat/digraph/test_avg_shortest_path.py deleted file mode 100644 index a5f04c999..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_avg_shortest_path.py +++ /dev/null @@ -1,169 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import math -import unittest - -import retworkx - - -class TestAvgShortestPath(unittest.TestCase): - def test_simple_example(self): - # Graph is not strongly connected. - edge_list = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (3, 6), (6, 7)] - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list(edge_list) - res = retworkx.digraph_unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isinf(res), "Output is not infinity") - - def test_cycle_graph(self): - graph = retworkx.generators.directed_cycle_graph(7) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertAlmostEqual(3.5, res, delta=1e-7) - - def test_path_graph(self): - # Graph is not strongly connected. - graph = retworkx.generators.directed_path_graph(5) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isinf(res), "Output is not infinity") - - def test_parallel_grid(self): - # Graph is not strongly connected. - graph = retworkx.generators.directed_grid_graph(30, 11) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isinf(res), "Output is not infinity") - - def test_empty(self): - graph = retworkx.PyDiGraph() - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_single_node(self): - graph = retworkx.PyDiGraph() - graph.add_node(0) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_single_node_self_edge(self): - graph = retworkx.PyDiGraph() - node = graph.add_node(0) - graph.add_edge(node, node, 0) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_disconnected_graph(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(32))) - with self.subTest(disconnected=False): - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isinf(res), "Output is not infinity") - - with self.subTest(disconnected=True): - res = retworkx.unweighted_average_shortest_path_length(graph, disconnected=True) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_partially_connected_graph(self): - graph = retworkx.generators.directed_cycle_graph(32) - graph.add_nodes_from(list(range(32))) - with self.subTest(disconnected=False): - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isinf(res), "Output is not infinity") - - with self.subTest(disconnected=True): - s = 15872 - den = 992 # n*(n-1), n=32 (only connected pairs considered) - res = retworkx.unweighted_average_shortest_path_length(graph, disconnected=True) - self.assertAlmostEqual(s / den, res, delta=1e-7) - - def test_connected_cycle_graph(self): - graph = retworkx.generators.directed_cycle_graph(32) - res = retworkx.unweighted_average_shortest_path_length(graph) - s = 15872 - den = 992 # n*(n-1) - self.assertAlmostEqual(s / den, res, delta=1e-7) - - -class TestAvgShortestPathAsUndirected(unittest.TestCase): - def test_simple_example(self): - edge_list = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (3, 6), (6, 7)] - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list(edge_list) - res = retworkx.digraph_unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertAlmostEqual(2.5714285714285716, res, delta=1e-7) - - def test_cycle_graph(self): - graph = retworkx.generators.directed_cycle_graph(7) - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertAlmostEqual(2, res, delta=1e-7) - - def test_path_graph(self): - graph = retworkx.generators.directed_path_graph(5) - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertAlmostEqual(2, res, delta=1e-7) - - def test_parallel_grid(self): - graph = retworkx.generators.directed_grid_graph(30, 11) - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertAlmostEqual(13.666666666666666, res, delta=1e-7) - - def test_empty(self): - graph = retworkx.PyDiGraph() - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_single_node(self): - graph = retworkx.PyDiGraph() - graph.add_node(0) - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_single_node_self_edge(self): - graph = retworkx.PyDiGraph() - node = graph.add_node(0) - graph.add_edge(node, node, 0) - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_disconnected_graph(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(32))) - with self.subTest(disconnected=False): - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertTrue(math.isinf(res), "Output is not infinity") - - with self.subTest(disconnected=True): - res = retworkx.unweighted_average_shortest_path_length( - graph, as_undirected=True, disconnected=True - ) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_partially_connected_graph(self): - graph = retworkx.generators.directed_cycle_graph(32) - graph.add_nodes_from(list(range(32))) - with self.subTest(disconnected=False): - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - self.assertTrue(math.isinf(res), "Output is not infinity") - - with self.subTest(disconnected=True): - s = 8192 - den = 992 # n*(n-1), n=32 (only connected pairs considered) - res = retworkx.unweighted_average_shortest_path_length( - graph, as_undirected=True, disconnected=True - ) - self.assertAlmostEqual(s / den, res, delta=1e-7) - - def test_connected_cycle_graph(self): - graph = retworkx.generators.directed_cycle_graph(32) - res = retworkx.unweighted_average_shortest_path_length(graph, as_undirected=True) - s = 8192 - den = 992 # n*(n-1) - self.assertAlmostEqual(s / den, res, delta=1e-7) diff --git a/tests/retworkx_backwards_compat/digraph/test_bellman_ford.py b/tests/retworkx_backwards_compat/digraph/test_bellman_ford.py deleted file mode 100644 index 3d5a9ef24..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_bellman_ford.py +++ /dev/null @@ -1,438 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestBellmanFordDiGraph(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - self.d = self.graph.add_node("D") - self.e = self.graph.add_node("E") - self.f = self.graph.add_node("F") - edge_list = [ - (self.a, self.b, 7), - (self.c, self.a, 9), - (self.a, self.d, 14), - (self.b, self.c, 10), - (self.d, self.c, 2), - (self.d, self.e, 9), - (self.b, self.f, 15), - (self.c, self.f, 11), - (self.e, self.f, 6), - ] - self.graph.add_edges_from(edge_list) - - def test_bellman_ford(self): - path = retworkx.digraph_bellman_ford_shortest_path_lengths( - self.graph, self.a, lambda x: float(x) - ) - expected = {1: 7.0, 2: 16.0, 3: 14.0, 4: 23.0, 5: 22.0} - self.assertEqual(expected, path) - - def test_bellman_ford_length_with_no_path(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - g.add_node("B") - path_lenghts = retworkx.digraph_bellman_ford_shortest_path_lengths(g, a, edge_cost_fn=float) - expected = {} - self.assertEqual(expected, path_lenghts) - - def test_bellman_ford_path(self): - paths = retworkx.digraph_bellman_ford_shortest_paths(self.graph, self.a) - expected = { - # a -> b - 1: [0, 1], - # a -> c: a, d, c - 2: [0, 3, 2], - # a -> d - 3: [0, 3], - # a -> e: a, d, e - 4: [0, 3, 4], - # a -> f: a, b, f - 5: [0, 1, 5], - } - self.assertEqual(expected, paths) - - def test_bellman_ford_path_with_weight_fn(self): - paths = retworkx.digraph_bellman_ford_shortest_paths( - self.graph, self.a, weight_fn=lambda x: x - ) - expected = { - 1: [0, 1], - 2: [0, 3, 2], - 3: [0, 3], - 4: [0, 3, 4], - 5: [0, 1, 5], - } - self.assertEqual(expected, paths) - - def test_bellman_ford_path_undirected(self): - paths = retworkx.digraph_bellman_ford_shortest_paths(self.graph, self.a, as_undirected=True) - expected = { - 1: [0, 1], - 2: [0, 2], - 3: [0, 3], - 4: [0, 3, 4], - 5: [0, 1, 5], - } - self.assertEqual(expected, paths) - - def test_bellman_ford_path_undirected_with_weight_fn(self): - paths = retworkx.digraph_bellman_ford_shortest_paths( - self.graph, self.a, weight_fn=lambda x: x, as_undirected=True - ) - expected = { - 1: [0, 1], - 2: [0, 2], - 3: [0, 2, 3], - 4: [0, 2, 3, 4], - 5: [0, 2, 5], - } - self.assertEqual(expected, paths) - - def test_bellman_ford_with_no_goal_set(self): - path = retworkx.digraph_bellman_ford_shortest_path_lengths(self.graph, self.a, lambda x: 1) - expected = {1: 1.0, 2: 2.0, 3: 1.0, 4: 2.0, 5: 2.0} - self.assertEqual(expected, path) - - def test_bellman_path(self): - path = retworkx.digraph_bellman_ford_shortest_paths( - self.graph, self.a, weight_fn=lambda x: float(x), target=self.e - ) - expected = retworkx.digraph_dijkstra_shortest_paths( - self.graph, self.a, weight_fn=lambda x: float(x), target=self.e - ) - self.assertEqual(expected, path) - - def test_bellman_path_lengths(self): - path = retworkx.digraph_bellman_ford_shortest_path_lengths( - self.graph, self.a, lambda x: float(x), goal=self.e - ) - expected = retworkx.digraph_dijkstra_shortest_path_lengths( - self.graph, self.a, lambda x: float(x), goal=self.e - ) - self.assertEqual(expected, path) - - def test_bellman_ford_length_with_no_path_and_goal(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - b = g.add_node("B") - path_lenghts = retworkx.digraph_bellman_ford_shortest_path_lengths( - g, a, edge_cost_fn=float, goal=b - ) - expected = retworkx.digraph_dijkstra_shortest_path_lengths(g, a, edge_cost_fn=float, goal=b) - self.assertEqual(expected, path_lenghts) - - def test_bellman_ford_with_no_path(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - g.add_node("B") - path = retworkx.digraph_bellman_ford_shortest_path_lengths(g, a, lambda x: float(x)) - expected = {} - self.assertEqual(expected, path) - - def test_bellman_ford_path_with_no_path(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - g.add_node("B") - path = retworkx.digraph_bellman_ford_shortest_paths(g, a) - expected = {} - self.assertEqual(expected, path) - - def test_bellman_ford_with_disconnected_nodes(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - b = g.add_child(a, "B", 1.2) - g.add_node("C") - g.add_parent(b, "D", 2.4) - path = retworkx.digraph_bellman_ford_shortest_path_lengths(g, a, lambda x: x) - expected = {1: 1.2} - self.assertEqual(expected, path) - - def test_bellman_ford_with_graph_input(self): - g = retworkx.PyGraph() - g.add_node(0) - with self.assertRaises(TypeError): - retworkx.digraph_bellman_ford_shortest_path_lengths(g, 0, lambda x: x) - - def bellman_ford_with_invalid_weights(self): - graph = retworkx.generators.directed_path_graph(2) - - for as_undirected in [False, True]: - with self.subTest(as_undirected=as_undirected): - with self.assertRaises(ValueError): - retworkx.digraph_bellman_ford_shortest_paths( - graph, - source=0, - weight_fn=lambda _: float("nan"), - as_undirected=as_undirected, - ) - - def bellman_ford_lengths_with_invalid_weights(self): - graph = retworkx.generators.directed_path_graph(2) - - with self.assertRaises(ValueError): - retworkx.digraph_bellman_ford_shortest_path_lengths( - graph, node=0, edge_cost_fn=lambda _: float("nan") - ) - - def test_raises_negative_cycle_bellman_ford_paths(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - with self.assertRaises(retworkx.NegativeCycle): - retworkx.bellman_ford_shortest_paths(graph, 0, weight_fn=float) - - def test_raises_negative_cycle_bellman_ford_path_lenghts(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - with self.assertRaises(retworkx.NegativeCycle): - retworkx.bellman_ford_shortest_path_lengths(graph, 0, edge_cost_fn=float) - - def test_negative_edges_but_no_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, 1), - ] - ) - - result = retworkx.bellman_ford_shortest_path_lengths(graph, 0, edge_cost_fn=float) - - expected = {k: v for k, v in retworkx.floyd_warshall(graph, float)[0].items() if k != 0} - - self.assertEqual(result, expected) - - def test_negative_edge_cycle_true_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - self.assertTrue(retworkx.negative_edge_cycle(graph, float)) - - def test_negative_edge_cycle_no_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, 1), - ] - ) - - self.assertFalse(retworkx.negative_edge_cycle(graph, float)) - - def test_find_negative_cycle_true_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - cycle = retworkx.find_negative_cycle(graph, edge_cost_fn=float) - cycle_weight = 0 - - for i in range(len(cycle) - 1): - cycle_weight += graph.get_edge_data(cycle[i], cycle[i + 1]) - - self.assertTrue(cycle_weight < 0) - - def test_find_negative_cycle_self_loop_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from([(0, 1, 1), (1, 0, 1), (0, 0, -1)]) - - cycle = retworkx.find_negative_cycle(graph, edge_cost_fn=float) - cycle_weight = 0 - - for i in range(len(cycle) - 1): - cycle_weight += graph.get_edge_data(cycle[i], cycle[i + 1]) - - self.assertTrue(cycle_weight < 0) - - def test_find_negative_cycle_no_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, 1), - ] - ) - - with self.assertRaises(ValueError): - retworkx.find_negative_cycle(graph, edge_cost_fn=float) - - def test_bellman_ford_all_pair_path_lengths(self): - lengths = retworkx.digraph_all_pairs_bellman_ford_path_lengths(self.graph, float) - expected = { - 0: {1: 7.0, 2: 16.0, 3: 14.0, 4: 23.0, 5: 22.0}, - 1: {0: 19.0, 2: 10.0, 3: 33.0, 4: 42.0, 5: 15.0}, - 2: {0: 9.0, 1: 16.0, 3: 23.0, 4: 32.0, 5: 11.0}, - 3: {0: 11.0, 1: 18.0, 2: 2.0, 4: 9.0, 5: 13.0}, - 4: {5: 6.0}, - 5: {}, - } - self.assertEqual(expected, lengths) - - def test_bellman_ford_all_pair_paths(self): - paths = retworkx.digraph_all_pairs_bellman_ford_shortest_paths(self.graph, float) - expected = { - 0: {1: [0, 1], 2: [0, 3, 2], 3: [0, 3], 4: [0, 3, 4], 5: [0, 1, 5]}, - 1: { - 0: [1, 2, 0], - 2: [1, 2], - 3: [1, 2, 0, 3], - 4: [1, 2, 0, 3, 4], - 5: [1, 5], - }, - 2: { - 0: [2, 0], - 1: [2, 0, 1], - 3: [2, 0, 3], - 4: [2, 0, 3, 4], - 5: [2, 5], - }, - 3: { - 0: [3, 2, 0], - 1: [3, 2, 0, 1], - 2: [3, 2], - 4: [3, 4], - 5: [3, 2, 5], - }, - 4: {5: [4, 5]}, - 5: {}, - } - self.assertEqual(expected, paths) - - def test_bellman_ford_all_pair_path_lengths_with_node_removal(self): - self.graph.remove_node(3) - lengths = retworkx.digraph_all_pairs_bellman_ford_path_lengths(self.graph, float) - expected = { - 0: {1: 7.0, 2: 17.0, 5: 22.0}, - 1: {0: 19.0, 2: 10.0, 5: 15.0}, - 2: {0: 9.0, 1: 16.0, 5: 11.0}, - 4: {5: 6.0}, - 5: {}, - } - self.assertEqual(expected, lengths) - - def test_bellman_ford_all_pair_paths_with_node_removal(self): - self.graph.remove_node(3) - lengths = retworkx.digraph_all_pairs_bellman_ford_shortest_paths(self.graph, float) - expected = { - 0: {1: [0, 1], 2: [0, 1, 2], 5: [0, 1, 5]}, - 1: {0: [1, 2, 0], 2: [1, 2], 5: [1, 5]}, - 2: {0: [2, 0], 1: [2, 0, 1], 5: [2, 5]}, - 4: {5: [4, 5]}, - 5: {}, - } - self.assertEqual(expected, lengths) - - def test_bellman_ford_all_pair_path_lengths_empty_graph(self): - graph = retworkx.PyDiGraph() - self.assertEqual({}, retworkx.digraph_all_pairs_bellman_ford_path_lengths(graph, float)) - - def test_bellman_ford_all_pair_shortest_paths_empty_graph(self): - graph = retworkx.PyDiGraph() - self.assertEqual({}, retworkx.digraph_all_pairs_bellman_ford_shortest_paths(graph, float)) - - def test_bellman_ford_all_pair_path_lengths_graph_no_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.digraph_all_pairs_bellman_ford_path_lengths(graph, float), - ) - - def test_bellman_ford_all_pair_shortest_paths_no_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.digraph_all_pairs_bellman_ford_shortest_paths(graph, float), - ) - - def test_raises_negative_cycle_all_pairs_bellman_ford_paths(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - with self.assertRaises(retworkx.NegativeCycle): - retworkx.all_pairs_bellman_ford_shortest_paths(graph, float) - - def test_raises_negative_cycle_all_pairs_bellman_ford_path_lenghts(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - with self.assertRaises(retworkx.NegativeCycle): - retworkx.all_pairs_bellman_ford_path_lengths(graph, float) diff --git a/tests/retworkx_backwards_compat/digraph/test_bfs_search.py b/tests/retworkx_backwards_compat/digraph/test_bfs_search.py deleted file mode 100644 index 999f8422d..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_bfs_search.py +++ /dev/null @@ -1,162 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestBfsSearch(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.graph.extend_from_edge_list( - [ - (0, 1), - (0, 2), - (1, 3), - (2, 1), - (2, 5), - (2, 6), - (5, 3), - (4, 7), - ] - ) - - def test_digraph_bfs_tree_edges(self): - class TreeEdgesRecorder(retworkx.visit.BFSVisitor): - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - self.edges.append((edge[0], edge[1])) - - vis = TreeEdgesRecorder() - retworkx.digraph_bfs_search(self.graph, [0], vis) - self.assertEqual(vis.edges, [(0, 2), (0, 1), (2, 6), (2, 5), (1, 3)]) - - def test_digraph_bfs_tree_edges_no_starting_point(self): - class TreeEdgesRecorder(retworkx.visit.BFSVisitor): - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - self.edges.append((edge[0], edge[1])) - - vis = TreeEdgesRecorder() - retworkx.digraph_bfs_search(self.graph, None, vis) - self.assertEqual(vis.edges, [(0, 2), (0, 1), (2, 6), (2, 5), (1, 3), (4, 7)]) - - def test_digraph_bfs_tree_edges_restricted(self): - class TreeEdgesRecorderRestricted(retworkx.visit.BFSVisitor): - - prohibited = [(0, 2), (1, 2)] - - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - edge = (edge[0], edge[1]) - if edge in self.prohibited: - raise retworkx.visit.PruneSearch - self.edges.append(edge) - - vis = TreeEdgesRecorderRestricted() - retworkx.digraph_bfs_search(self.graph, [0], vis) - self.assertEqual(vis.edges, [(0, 1), (1, 3)]) - - def test_digraph_bfs_goal_search_with_stop_search_exception(self): - class GoalSearch(retworkx.visit.BFSVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - - def tree_edge(self, edge): - u, v, _ = edge - self.parents[v] = u - - if v == self.goal: - raise retworkx.visit.StopSearch - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - retworkx.digraph_bfs_search(self.graph, [0], vis) - self.assertEqual(vis.reconstruct_path(), [0, 1, 3]) - - def test_digraph_bfs_goal_search_with_custom_exception(self): - class StopIfGoalFound(Exception): - pass - - class GoalSearch(retworkx.visit.BFSVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - - def tree_edge(self, edge): - u, v, _ = edge - self.parents[v] = u - - if v == self.goal: - raise StopIfGoalFound - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - try: - retworkx.digraph_bfs_search(self.graph, [0], vis) - except StopIfGoalFound: - pass - self.assertEqual(vis.reconstruct_path(), [0, 1, 3]) - - def test_graph_prune_non_tree_edge(self): - class PruneNonTreeEdge(retworkx.visit.BFSVisitor): - def non_tree_edge(self, _): - raise retworkx.visit.PruneSearch - - vis = PruneNonTreeEdge() - retworkx.digraph_bfs_search(self.graph, [0], vis) - - def test_graph_prune_black_target_edge(self): - class PruneBlackTargetEdge(retworkx.visit.BFSVisitor): - def black_target_edge(self, _): - raise retworkx.visit.PruneSearch - - vis = PruneBlackTargetEdge() - retworkx.digraph_bfs_search(self.graph, [0], vis) - - def test_graph_prune_gray_target_edge(self): - class PruneGrayTargetEdge(retworkx.visit.BFSVisitor): - def gray_target_edge(self, _): - raise retworkx.visit.PruneSearch - - vis = PruneGrayTargetEdge() - retworkx.digraph_bfs_search(self.graph, [0], vis) diff --git a/tests/retworkx_backwards_compat/digraph/test_cartesian_product.py b/tests/retworkx_backwards_compat/digraph/test_cartesian_product.py deleted file mode 100644 index 9117abf6e..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_cartesian_product.py +++ /dev/null @@ -1,60 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest -import retworkx - - -class TestCartesianProduct(unittest.TestCase): - def test_null_cartesian_null(self): - graph_1 = retworkx.PyDiGraph() - graph_2 = retworkx.PyDiGraph() - - graph_product, _ = retworkx.digraph_cartesian_product(graph_1, graph_2) - self.assertEqual(len(graph_product.nodes()), 0) - self.assertEqual(len(graph_product.edge_list()), 0) - - def test_directed_path_2_cartesian_path_2(self): - graph_1 = retworkx.generators.directed_path_graph(2) - graph_2 = retworkx.generators.directed_path_graph(2) - - graph_product, _ = retworkx.digraph_cartesian_product(graph_1, graph_2) - self.assertEqual(len(graph_product.nodes()), 4) - self.assertEqual(len(graph_product.edge_list()), 4) - - def test_directed_path_2_cartesian_path_3(self): - graph_1 = retworkx.generators.directed_path_graph(2) - graph_2 = retworkx.generators.directed_path_graph(3) - - graph_product, _ = retworkx.digraph_cartesian_product(graph_1, graph_2) - self.assertEqual(len(graph_product.nodes()), 6) - self.assertEqual(len(graph_product.edge_list()), 7) - - def test_directed_node_weights_cartesian(self): - graph_1 = retworkx.PyDiGraph() - graph_1.add_node("a_1") - graph_2 = retworkx.PyDiGraph() - graph_2.add_node(0) - - graph_product, _ = retworkx.digraph_cartesian_product(graph_1, graph_2) - self.assertEqual([("a_1", 0)], graph_product.nodes()) - - def test_directed_edge_weights_cartesian(self): - graph_1 = retworkx.PyDiGraph() - graph_1.add_nodes_from([0, 1]) - graph_1.add_edge(0, 1, "w_1") - graph_2 = retworkx.PyDiGraph() - graph_2.add_nodes_from([0, 1]) - graph_1.add_edge(0, 1, "w_2") - - graph_product, _ = retworkx.digraph_cartesian_product(graph_1, graph_2) - self.assertEqual(["w_1", "w_1", "w_2", "w_2"], graph_product.edges()) diff --git a/tests/retworkx_backwards_compat/digraph/test_centrality.py b/tests/retworkx_backwards_compat/digraph/test_centrality.py deleted file mode 100644 index eadb47614..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_centrality.py +++ /dev/null @@ -1,162 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import math -import unittest - -import retworkx - - -class TestCentralityDiGraph(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - self.d = self.graph.add_node("D") - edge_list = [ - (self.a, self.b, 1), - (self.b, self.c, 1), - (self.c, self.d, 1), - ] - self.graph.add_edges_from(edge_list) - - def test_betweenness_centrality(self): - betweenness = retworkx.digraph_betweenness_centrality(self.graph) - expected = { - 0: 0.0, - 1: 0.3333333333333333, - 2: 0.3333333333333333, - 3: 0.0, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_endpoints(self): - betweenness = retworkx.digraph_betweenness_centrality(self.graph, endpoints=True) - expected = { - 0: 0.25, - 1: 0.41666666666666663, - 2: 0.41666666666666663, - 3: 0.25, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_unnormalized(self): - betweenness = retworkx.digraph_betweenness_centrality( - self.graph, endpoints=False, normalized=False - ) - expected = {0: 0.0, 1: 2.0, 2: 2.0, 3: 0.0} - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_parallel(self): - betweenness = retworkx.digraph_betweenness_centrality(self.graph, parallel_threshold=1) - expected = { - 0: 0.0, - 1: 0.3333333333333333, - 2: 0.3333333333333333, - 3: 0.0, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_endpoints_parallel(self): - betweenness = retworkx.digraph_betweenness_centrality( - self.graph, endpoints=True, parallel_threshold=1 - ) - expected = { - 0: 0.25, - 1: 0.41666666666666663, - 2: 0.41666666666666663, - 3: 0.25, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_unnormalized_parallel(self): - betweenness = retworkx.digraph_betweenness_centrality( - self.graph, endpoints=False, normalized=False, parallel_threshold=1 - ) - expected = {0: 0.0, 1: 2.0, 2: 2.0, 3: 0.0} - self.assertEqual(expected, betweenness) - - def test_closeness_centrality(self): - closeness = retworkx.digraph_closeness_centrality(self.graph) - expected = {0: 0.0, 1: 1.0 / 3.0, 2: 4.0 / 9.0, 3: 0.5} - self.assertEqual(expected, closeness) - - def test_closeness_centrality_wf_improved(self): - closeness = retworkx.digraph_closeness_centrality(self.graph, wf_improved=False) - expected = {0: 0.0, 1: 1.0, 2: 2.0 / 3.0, 3: 0.5} - self.assertEqual(expected, closeness) - - -class TestCentralityDiGraphDeletedNode(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - c0 = self.graph.add_node("C0") - self.d = self.graph.add_node("D") - edge_list = [ - (self.a, self.b, 1), - (self.b, self.c, 1), - (self.c, self.d, 1), - ] - self.graph.add_edges_from(edge_list) - self.graph.remove_node(c0) - - def test_betweenness_centrality(self): - betweenness = retworkx.digraph_betweenness_centrality(self.graph) - expected = { - 0: 0.0, - 1: 0.3333333333333333, - 2: 0.3333333333333333, - 4: 0.0, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_endpoints(self): - betweenness = retworkx.digraph_betweenness_centrality(self.graph, endpoints=True) - expected = { - 0: 0.25, - 1: 0.41666666666666663, - 2: 0.41666666666666663, - 4: 0.25, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_unnormalized(self): - betweenness = retworkx.digraph_betweenness_centrality( - self.graph, endpoints=False, normalized=False - ) - expected = {0: 0.0, 1: 2.0, 2: 2.0, 4: 0.0} - self.assertEqual(expected, betweenness) - - -class TestEigenvectorCentrality(unittest.TestCase): - def test_complete_graph(self): - graph = retworkx.generators.directed_mesh_graph(5) - centrality = retworkx.eigenvector_centrality(graph) - expected_value = math.sqrt(1.0 / 5.0) - for value in centrality.values(): - self.assertAlmostEqual(value, expected_value) - - def test_path_graph(self): - graph = retworkx.generators.directed_path_graph(3, bidirectional=True) - centrality = retworkx.eigenvector_centrality(graph) - expected = [0.5, 0.7071, 0.5] - for k, v in centrality.items(): - self.assertAlmostEqual(v, expected[k], 4) - - def test_no_convergence(self): - graph = retworkx.PyDiGraph() - with self.assertRaises(retworkx.FailedToConverge): - retworkx.eigenvector_centrality(graph, max_iter=0) diff --git a/tests/retworkx_backwards_compat/digraph/test_collect_bicolor_runs.py b/tests/retworkx_backwards_compat/digraph/test_collect_bicolor_runs.py deleted file mode 100644 index f0f6de149..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_collect_bicolor_runs.py +++ /dev/null @@ -1,350 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestCollectBicolorRuns(unittest.TestCase): - def test_cycle(self): - dag = retworkx.PyDiGraph() - dag.extend_from_edge_list([(0, 1), (1, 2), (2, 0)]) - with self.assertRaises(retworkx.DAGHasCycle): - retworkx.collect_bicolor_runs(dag, lambda _: True, lambda _: None) - - def test_filter_function_inner_exception(self): - dag = retworkx.PyDiGraph() - dag.add_node("a") - dag.add_child(0, "b", None) - dag.add_child(1, "c", None) - - def fail_function(node): - raise IndexError("Things fail from time to time") - - with self.assertRaises(IndexError): - retworkx.collect_bicolor_runs(dag, fail_function, lambda _: None) - - with self.assertRaises(IndexError): - retworkx.collect_bicolor_runs(dag, lambda _: True, fail_function) - - def test_empty(self): - dag = retworkx.PyDAG() - self.assertEqual( - [], - retworkx.collect_bicolor_runs(dag, lambda _: True, lambda _: None), - ) - - def test_two_colors(self): - """ - Input: - ┌─────────────┐ ┌─────────────┐ - │ │ │ │ - │ q0 │ │ q1 │ - │ │ │ │ - └───┬─────────┘ └──────┬──────┘ - │ ┌─────────────┐ │ - q0 │ │ │ │ q1 - │ │ │ │ - └─────────►│ cx │◄────────┘ - ┌──────────┤ ├─────────┐ - │ │ │ │ - q0 │ └─────────────┘ │ q1 - │ │ - │ ┌─────────────┐ │ - │ │ │ │ - └─────────►│ cz │◄────────┘ - ┌─────────┤ ├─────────┐ - │ └─────────────┘ │ - q0 │ │ q1 - │ │ - ┌───▼─────────┐ ┌──────▼──────┐ - │ │ │ │ - │ q0 │ │ q1 │ - │ │ │ │ - └─────────────┘ └─────────────┘ - - Expected: [[cx, cz]] - """ - dag = retworkx.PyDAG() - q0_list = [] - q1_list = [] - for _ in range(2): - q0_list.append(dag.add_node("q0")) - q1_list.append(dag.add_node("q1")) - - cx_gate = dag.add_node("cx") - cz_gate = dag.add_node("cz") - - dag.add_edge(q0_list[0], cx_gate, "q0") - dag.add_edge(q1_list[0], cx_gate, "q1") - dag.add_edge(cx_gate, cz_gate, "q0") - dag.add_edge(cx_gate, cz_gate, "q1") - dag.add_edge(cz_gate, q0_list[1], "q0") - dag.add_edge(cz_gate, q1_list[1], "q1") - - def filter_function(node): - if node in ["cx", "cz"]: - return True - else: - return None - - def color_function(node): - if "q" in node: - return int(node[1:]) - else: - return None - - self.assertEqual( - [["cx", "cz"]], - retworkx.collect_bicolor_runs(dag, filter_function, color_function), - ) - - def test_two_colors_with_pending(self): - """ - Input: - ┌─────────────┐ - │ │ - │ q0 │ - │ │ - └───┬─────────┘ - | q0 - │ - ┌───▼─────────┐ - │ │ - │ h │ - │ │ - └───┬─────────┘ - | q0 - │ ┌─────────────┐ - │ │ │ - │ │ q1 │ - │ │ │ - | └──────┬──────┘ - │ ┌─────────────┐ │ - q0 │ │ │ │ q1 - │ │ │ │ - └─────────►│ cx │◄────────┘ - ┌──────────┤ ├─────────┐ - │ │ │ │ - q0 │ └─────────────┘ │ q1 - │ │ - │ ┌─────────────┐ │ - │ │ │ │ - └─────────►│ cz │◄────────┘ - ┌─────────┤ ├─────────┐ - │ └─────────────┘ │ - q0 │ │ q1 - │ │ - ┌───▼─────────┐ ┌──────▼──────┐ - │ │ │ │ - │ q0 │ │ y │ - │ │ │ │ - └─────────────┘ └─────────────┘ - | q1 - │ - ┌───▼─────────┐ - │ │ - │ q1 │ - │ │ - └─────────────┘ - - Expected: [[h, cx, cz, y]] - """ - dag = retworkx.PyDAG() - q0_list = [] - q1_list = [] - for _ in range(2): - q0_list.append(dag.add_node("q0")) - q1_list.append(dag.add_node("q1")) - - h_gate = dag.add_node("h") - cx_gate = dag.add_node("cx") - cz_gate = dag.add_node("cz") - y_gate = dag.add_node("y") - - dag.add_edge(q0_list[0], h_gate, "q0") - dag.add_edge(h_gate, cx_gate, "q0") - dag.add_edge(q1_list[0], cx_gate, "q1") - dag.add_edge(cx_gate, cz_gate, "q0") - dag.add_edge(cx_gate, cz_gate, "q1") - dag.add_edge(cz_gate, q0_list[1], "q0") - dag.add_edge(cz_gate, y_gate, "q1") - dag.add_edge(y_gate, q1_list[1], "q1") - - def filter_function(node): - if node in ["cx", "cz", "h", "y"]: - return True - else: - return None - - def color_function(node): - if "q" in node: - return int(node[1:]) - else: - return None - - self.assertEqual( - [["h", "cx", "cz", "y"]], - retworkx.collect_bicolor_runs(dag, filter_function, color_function), - ) - - def test_two_colors_with_barrier(self): - """ - Input: - ┌─────────────┐ ┌─────────────┐ - │ │ │ │ - │ q0 │ │ q1 │ - │ │ │ │ - └───┬─────────┘ └──────┬──────┘ - │ ┌─────────────┐ │ - q0 │ │ │ │ q1 - └─────────►│ cx │◄────────┘ - ┌──────────┤ ├─────────┐ - q0 │ └─────────────┘ │ q1 - │ │ - │ ┌─────────────┐ │ - │ │ │ │ - └─────────►│ barrier │◄────────┘ - ┌─────────┤ ├─────────┐ - │ └─────────────┘ │ - q0 │ │ q1 - │ │ - │ ┌─────────────┐ │ - │ │ │ │ - └────────►│ cz │◄────────┘ - ┌──────────┤ ├─────────┐ - q0 │ └─────────────┘ │ q1 - │ │ - ┌───▼─────────┐ ┌──────▼──────┐ - │ │ │ │ - │ q0 │ │ q1 │ - │ │ │ │ - └─────────────┘ └─────────────┘ - - Expected: [[cx], [cz]] - """ - dag = retworkx.PyDAG() - q0_list = [] - q1_list = [] - for _ in range(2): - q0_list.append(dag.add_node("q0")) - q1_list.append(dag.add_node("q1")) - - cx_gate = dag.add_node("cx") - barrier = dag.add_node("barrier") - cz_gate = dag.add_node("cz") - - # CX - dag.add_edge(q0_list[0], cx_gate, "q0") - dag.add_edge(q1_list[0], cx_gate, "q1") - # Barrier - dag.add_edge(cx_gate, barrier, "q0") - dag.add_edge(cx_gate, barrier, "q1") - # CZ - dag.add_edge(barrier, cz_gate, "q0") - dag.add_edge(barrier, cz_gate, "q1") - dag.add_edge(cz_gate, q0_list[1], "q0") - dag.add_edge(cz_gate, q1_list[1], "q1") - - def filter_function(node): - if node in ["cx", "cz"]: - return True - elif node == "barrier": - return False - else: - return None - - def color_function(node): - if "q" in node: - return int(node[1:]) - else: - return None - - self.assertEqual( - [["cx"], ["cz"]], - retworkx.collect_bicolor_runs(dag, filter_function, color_function), - ) - - def test_color_with_ignored_edge(self): - """ - Input: - ┌─────────────┐ ┌─────────────┐ - │ │ │ │ - │ q0 │ │ c0 │ - │ │ │ │ - └───┬─────────┘ └──────┬──────┘ - │ ┌─────────────┐ │ - q0 │ │ │ │ c0 - └─────────►│ rx │◄────────┘ - ┌──────────┤ ├─────────┐ - q0 │ └─────────────┘ │ c0 - │ │ - │ ┌─────────────┐ │ - │ │ │ │ - └─────────►│ barrier │ │ - ┌─────────┤ │ │ - │ └─────────────┘ │ - q0 │ │ c0 - │ │ - │ ┌─────────────┐ │ - │ │ │ │ - └────────►│ rz │◄────────┘ - ┌──────────┤ ├─────────┐ - q0 │ └─────────────┘ │ c0 - │ │ - ┌───▼─────────┐ ┌──────▼──────┐ - │ │ │ │ - │ q0 │ │ c0 │ - │ │ │ │ - └─────────────┘ └─────────────┘ - - Expected: [] - """ - dag = retworkx.PyDAG() - q0_list = [] - c0_list = [] - for _ in range(2): - q0_list.append(dag.add_node("q0")) - c0_list.append(dag.add_node("c0")) - - rx_gate = dag.add_node("rx") - barrier = dag.add_node("barrier") - rz_gate = dag.add_node("rz") - - # RX - dag.add_edge(q0_list[0], rx_gate, "q0") - dag.add_edge(c0_list[0], rx_gate, "c0") - # Barrier - dag.add_edge(rx_gate, barrier, "q0") - # RZ - dag.add_edge(barrier, rz_gate, "q0") - dag.add_edge(rx_gate, rz_gate, "c0") - dag.add_edge(rz_gate, q0_list[1], "q0") - dag.add_edge(rz_gate, c0_list[1], "c0") - - def filter_function(node): - if node == "barrier": - return False - else: - return None - - def color_function(node): - if "q" in node: - return int(node[1:]) - else: - return None - - self.assertEqual( - [], - retworkx.collect_bicolor_runs(dag, filter_function, color_function), - ) diff --git a/tests/retworkx_backwards_compat/digraph/test_collect_runs.py b/tests/retworkx_backwards_compat/digraph/test_collect_runs.py deleted file mode 100644 index 2e8ea2006..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_collect_runs.py +++ /dev/null @@ -1,138 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestCollectRuns(unittest.TestCase): - def test_dagcircuit_basic(self): - dag = retworkx.PyDAG() - qr_0_in = dag.add_node("qr[0]") - qr_0_out = dag.add_node("qr[0]") - qr_1_in = dag.add_node("qr[1]") - qr_1_out = dag.add_node("qr[1]") - cr_0_in = dag.add_node("cr[0]") - cr_0_out = dag.add_node("cr[0]") - cr_1_in = dag.add_node("cr[1]") - cr_1_out = dag.add_node("cr[1]") - - h_gate = dag.add_child(qr_0_in, "h", "qr[0]") - x_gate = dag.add_child(h_gate, "x", "qr[0]") - cx_gate = dag.add_child(x_gate, "cx", "qr[0]") - dag.add_edge(qr_1_in, cx_gate, "qr[1]") - - measure_qr_1 = dag.add_child(cx_gate, "measure", "qr[1]") - dag.add_edge(cr_1_in, measure_qr_1, "cr[1]") - x_gate = dag.add_child(measure_qr_1, "x", "qr[1]") - dag.add_edge(measure_qr_1, x_gate, "cr[1]") - dag.add_edge(cr_0_in, x_gate, "cr[0]") - - measure_qr_0 = dag.add_child(cx_gate, "measure", "qr[0]") - dag.add_edge(measure_qr_0, qr_0_out, "qr[0]") - dag.add_edge(measure_qr_0, cr_0_out, "cr[0]") - dag.add_edge(x_gate, measure_qr_0, "cr[0]") - - measure_qr_1_out = dag.add_child(x_gate, "measure", "cr[1]") - dag.add_edge(x_gate, measure_qr_1_out, "qr[1]") - dag.add_edge(measure_qr_1_out, qr_1_out, "qr[1]") - dag.add_edge(measure_qr_1_out, cr_1_out, "cr[1]") - - def filter_function(node): - return node in ["h", "x"] - - res = retworkx.collect_runs(dag, filter_function) - expected = [["h", "x"], ["x"]] - self.assertEqual(expected, res) - - def test_multiple_successor_edges(self): - dag = retworkx.PyDiGraph() - q0, q1 = dag.add_nodes_from(["q0", "q1"]) - cx_1 = dag.add_child(q0, "cx", "q0") - dag.add_edge(q1, cx_1, "q1") - cx_2 = dag.add_child(cx_1, "cx", "q0") - dag.add_edge(q1, cx_2, "q1") - cx_3 = dag.add_child(cx_2, "cx", "q0") - dag.add_edge(q1, cx_3, "q1") - - def filter_function(node): - return node == "cx" - - res = retworkx.collect_runs(dag, filter_function) - self.assertEqual([["cx", "cx", "cx"]], res) - - def test_cycle(self): - dag = retworkx.PyDiGraph() - dag.extend_from_edge_list([(0, 1), (1, 2), (2, 0)]) - with self.assertRaises(retworkx.DAGHasCycle): - retworkx.collect_runs(dag, lambda _: True) - - def test_filter_function_inner_exception(self): - dag = retworkx.PyDiGraph() - dag.add_node("a") - dag.add_child(0, "b", None) - - def filter_function(node): - raise IndexError("Things fail from time to time") - - with self.assertRaises(IndexError): - retworkx.collect_runs(dag, filter_function) - - def test_empty(self): - dag = retworkx.PyDAG() - self.assertEqual([], retworkx.collect_runs(dag, lambda _: True)) - - def test_h_h_cx(self): - dag = retworkx.PyDiGraph() - q0, q1 = dag.add_nodes_from(["q0", "q1"]) - h_1 = dag.add_child(q0, "h", "q0") - h_2 = dag.add_child(q1, "h", "q1") - cx_2 = dag.add_child(h_1, "cx", "q0") - dag.add_edge(h_2, cx_2, "q1") - - def filter_function(node): - return node in ["cx", "h"] - - res = retworkx.collect_runs(dag, filter_function) - self.assertEqual([["h", "cx"], ["h"]], res) - - def test_cx_h_h_cx(self): - dag = retworkx.PyDiGraph() - q0, q1 = dag.add_nodes_from(["q0", "q1"]) - cx_1 = dag.add_child(q0, "cx", "q0") - dag.add_edge(q1, cx_1, "q1") - h_1 = dag.add_child(cx_1, "h", "q0") - h_2 = dag.add_child(cx_1, "h", "q1") - cx_2 = dag.add_child(h_1, "cx", "q0") - dag.add_edge(h_2, cx_2, "q1") - - def filter_function(node): - return node in ["cx", "h"] - - res = retworkx.collect_runs(dag, filter_function) - self.assertEqual([["cx"], ["h", "cx"], ["h"]], res) - - def test_cx_h_cx(self): - dag = retworkx.PyDiGraph() - q0, q1 = dag.add_nodes_from(["q0", "q1"]) - cx_1 = dag.add_child(q0, "cx", "q0") - dag.add_edge(q1, cx_1, "q1") - h_1 = dag.add_child(cx_1, "h", "q0") - cx_2 = dag.add_child(h_1, "cx", "q0") - dag.add_edge(cx_1, cx_2, "q1") - - def filter_function(node): - return node in ["cx", "h"] - - res = retworkx.collect_runs(dag, filter_function) - self.assertEqual([["cx"], ["h", "cx"]], res) diff --git a/tests/retworkx_backwards_compat/digraph/test_complement.py b/tests/retworkx_backwards_compat/digraph/test_complement.py deleted file mode 100644 index ef5eccc82..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_complement.py +++ /dev/null @@ -1,68 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestComplement(unittest.TestCase): - def test_null_graph(self): - graph = retworkx.PyDiGraph() - complement_graph = retworkx.complement(graph) - self.assertEqual(0, len(complement_graph.nodes())) - self.assertEqual(0, len(complement_graph.edges())) - - def test_clique_directed(self): - N = 5 - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list([(i, j) for i in range(N) for j in range(N) if i != j]) - - complement_graph = retworkx.complement(graph) - self.assertEqual(graph.nodes(), complement_graph.nodes()) - self.assertEqual(0, len(complement_graph.edges())) - - def test_empty_directed(self): - N = 5 - graph = retworkx.PyDiGraph() - graph.add_nodes_from([i for i in range(N)]) - - expected_graph = retworkx.PyDiGraph() - expected_graph.extend_from_edge_list([(i, j) for i in range(N) for j in range(N) if i != j]) - - complement_graph = retworkx.complement(graph) - self.assertTrue( - retworkx.is_isomorphic( - expected_graph, - complement_graph, - ) - ) - - def test_complement_directed(self): - N = 8 - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list( - [(i, j) for i in range(N) for j in range(N) if i != j and (i + j) % 3 == 0] - ) - - expected_graph = retworkx.PyDiGraph() - expected_graph.extend_from_edge_list( - [(i, j) for i in range(N) for j in range(N) if i != j and (i + j) % 3 != 0] - ) - - complement_graph = retworkx.complement(graph) - self.assertTrue( - retworkx.is_isomorphic( - expected_graph, - complement_graph, - ) - ) diff --git a/tests/retworkx_backwards_compat/digraph/test_compose.py b/tests/retworkx_backwards_compat/digraph/test_compose.py deleted file mode 100644 index 86268dda7..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_compose.py +++ /dev/null @@ -1,95 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestCompose(unittest.TestCase): - def test_simple_dag_composition(self): - dag = retworkx.PyDAG() - dag.check_cycle = True - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - dag_other = retworkx.PyDAG() - node_d = dag_other.add_node("d") - dag_other.add_child(node_d, "e", {"a": 3}) - res = dag.compose(dag_other, {node_c: (node_d, {"b": 1})}) - self.assertEqual({0: 3, 1: 4}, res) - self.assertEqual([0, 1, 2, 3, 4], retworkx.topological_sort(dag)) - - def test_compose_graph_onto_digraph_error(self): - digraph = retworkx.PyDiGraph() - graph = retworkx.PyGraph() - with self.assertRaises(TypeError): - digraph.compose(graph, {}) - - def test_edge_map_and_node_map_funcs_digraph_compose(self): - digraph = retworkx.PyDiGraph() - original_input_nodes = digraph.add_nodes_from(["qr[0]", "qr[1]"]) - original_op_nodes = digraph.add_nodes_from(["h"]) - output_nodes = digraph.add_nodes_from(["qr[0]", "qr[1]"]) - digraph.add_edge(original_input_nodes[0], original_op_nodes[0], "qr[0]") - digraph.add_edge(original_op_nodes[0], output_nodes[0], "qr[0]") - # Setup other graph - other_digraph = retworkx.PyDiGraph() - input_nodes = other_digraph.add_nodes_from(["qr[2]", "qr[3]"]) - op_nodes = other_digraph.add_nodes_from(["cx"]) - other_output_nodes = other_digraph.add_nodes_from(["qr[2]", "qr[3]"]) - other_digraph.add_edges_from( - [ - (input_nodes[0], op_nodes[0], "qr[2]"), - (input_nodes[1], op_nodes[0], "qr[3]"), - ] - ) - other_digraph.add_edges_from( - [ - (op_nodes[0], other_output_nodes[0], "qr[2]"), - (op_nodes[0], other_output_nodes[1], "qr[3]"), - ] - ) - - def map_fn(weight): - if weight == "qr[2]": - return "qr[0]" - elif weight == "qr[3]": - return "qr[1]" - else: - return weight - - digraph.remove_nodes_from(output_nodes) - other_digraph.remove_nodes_from(input_nodes) - node_map = { - original_op_nodes[0]: (op_nodes[0], "qr[0]"), - original_input_nodes[1]: (op_nodes[0], "qr[1]"), - } - res = digraph.compose(other_digraph, node_map, node_map_func=map_fn, edge_map_func=map_fn) - self.assertEqual({2: 4, 3: 3, 4: 5}, res) - self.assertEqual(digraph[res[other_output_nodes[0]]], "qr[0]") - self.assertEqual(digraph[res[other_output_nodes[1]]], "qr[1]") - # qr[0] -> h - self.assertTrue(digraph.has_edge(0, 2)) - self.assertTrue(digraph.get_all_edge_data(0, 2), ["qr[0]"]) - # qr[1] -> cx - self.assertTrue(digraph.has_edge(1, 4)) - self.assertTrue(digraph.get_all_edge_data(1, 4), ["qr[1]"]) - # h -> cx - self.assertTrue(digraph.has_edge(2, 4)) - self.assertTrue(digraph.get_all_edge_data(0, 2), ["qr[0]"]) - # cx -> qr[2] - self.assertTrue(digraph.has_edge(4, 3)) - self.assertTrue(digraph.get_all_edge_data(0, 2), ["qr[0]"]) - # cx -> qr[3] - self.assertTrue(digraph.has_edge(4, 5)) - self.assertTrue(digraph.get_all_edge_data(0, 2), ["qr[1]"]) diff --git a/tests/retworkx_backwards_compat/digraph/test_contract_nodes.py b/tests/retworkx_backwards_compat/digraph/test_contract_nodes.py deleted file mode 100644 index 8caf5580b..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_contract_nodes.py +++ /dev/null @@ -1,265 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestContractNodesCheckCycleSwitch(unittest.TestCase): - def setUp(self): - super().setUp() - self.dag = retworkx.PyDAG() - self.node_a = self.dag.add_node("a") - self.node_b = self.dag.add_child(self.node_a, "b", "b") - self.node_c = self.dag.add_child(self.node_b, "c", "c") - - self.new_weight = "m" - - def contract(self, **kwargs): - """ - ┌─┐ ┌─┐ - ┌─┤a│ ┌─────────┤m│ - │ └─┘ │ └▲┘ - ┌▼┐ ┌▼┐ │ - │b│ ───► │b├─────────┘ - └┬┘ └─┘ - │ ┌─┐ - └─►┤c│ - └─┘ - """ - self.dag.contract_nodes([self.node_a, self.node_c], self.new_weight, **kwargs) - - def test_cycle_check_enable_local(self): - # Disable at class level. - self.dag.check_cycle = False - - # Check removal is not allowed with explicit check_cycle=True. - self.assertRaises(retworkx.DAGWouldCycle, self.contract, check_cycle=True) - - def test_cycle_check_disable_local(self): - # Enable at class level. - self.dag.check_cycle = True - - # Check removal is allowed for check_cycle=False - self.contract(check_cycle=False) - self.assertEqual(set(self.dag.nodes()), {"b", "m"}) - - def test_cycle_check_inherit_class_enable(self): - # Enable at class level. - self.dag.check_cycle = True - - # Check removal is not allowed. - self.assertRaises(retworkx.DAGWouldCycle, self.contract) - - def test_cycle_check_inherit_class_disable(self): - # Disable at class level. - self.dag.check_cycle = False - - # Check removal is allowed. - self.contract() - self.assertEqual(set(self.dag.nodes()), {"b", "m"}) - - -class TestContractNodes(unittest.TestCase): - def test_empty_nodes(self): - """Replacing empty nodes is functionally equivalent to add_node.""" - dag = retworkx.PyDAG() - dag.contract_nodes([], "m") - - self.assertEqual(set(dag.nodes()), {"m"}) - - def test_unknown_nodes(self): - """ - Replacing all unknown nodes is functionally equivalent to add_node, - since unknown nodes should be ignored. - """ - dag = retworkx.PyDAG() - dag.contract_nodes([0, 1, 2], "m") - - self.assertEqual(set(dag.nodes()), {"m"}) - - def test_cycle_path_len_gt_1(self): - """ - ┌─┐ ┌─┐ - ┌4─┤a├─1┐ │m├──1───┐ - │ └─┘ │ └▲┘ │ - ┌▼┐ ┌▼┐ │ ┌▼┐ - │d│ │b│ ───► │ │b│ - └▲┘ └┬┘ │ └┬┘ - │ ┌─┐ 2 │ ┌─┐ 2 - └3─┤c│◄─┘ └3─┤c│◄─┘ - └─┘ └─┘ - """ - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", 1) - node_c = dag.add_child(node_b, "c", 2) - node_d = dag.add_child(node_c, "c", 3) - dag.add_edge(node_a, node_d, 4) - - with self.assertRaises(retworkx.DAGWouldCycle): - dag.contract_nodes([node_a, node_d], "m", check_cycle=True) - - # Proceed, ignoring cycles. - node_m = dag.contract_nodes([node_a, node_d], "m") - - self.assertEqual([node_b, node_c, node_m], dag.node_indexes()) - self.assertEqual( - {(node_b, node_c), (node_c, node_m), (node_m, node_b)}, - set(dag.edge_list()), - ) - - def test_multiple_paths_would_cycle(self): - """ - ┌─┐ ┌─┐ ┌─┐ ┌─┐ - ┌3─┤c│ │e├─5┐ ┌──┤c│ │e├──┐ - │ └▲┘ └▲┘ │ │ └▲┘ └▲┘ │ - ┌▼┐ 2 ┌─┐ 4 ┌▼┐ │ 2 ┌─┐ 4 │ - │d│ └──┤b├──┘ │f│ ───► │ └──┤b├──┘ │ - └─┘ └▲┘ └─┘ 3 └▲┘ 5 - 1 │ 1 │ - ┌┴┐ │ ┌┴┐ │ - │a│ └─────►│m│◄─────┘ - └─┘ └─┘ - """ - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", 1) - node_c = dag.add_child(node_b, "c", 2) - node_d = dag.add_child(node_c, "d", 3) - node_e = dag.add_child(node_b, "e", 4) - node_f = dag.add_child(node_e, "f", 5) - - with self.assertRaises(retworkx.DAGWouldCycle): - dag.contract_nodes([node_a, node_d, node_f], "m", check_cycle=True) - - # Proceed, ignoring cycles. - node_m = dag.contract_nodes([node_a, node_d, node_f], "m") - - self.assertEqual([node_b, node_c, node_e, node_m], dag.node_indexes()) - self.assertEqual( - { - (node_b, node_c), - (node_c, node_m), - (node_e, node_m), - (node_b, node_e), - (node_m, node_b), - }, - set(dag.edge_list()), - ) - - def test_replace_node_no_neighbors(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_m = dag.contract_nodes([node_a], "m", check_cycle=True) - self.assertEqual([node_m], dag.node_indexes()) - self.assertEqual(set(), set(dag.edge_list())) - - def test_keep_edges_multigraph(self): - """ - ┌─┐ ┌─┐ - ┌─┤a│◄┐ ┌─┤a│◄┐ - │ └─┘ │ │ └─┘ │ - 1 2 ──► 1 2 - ┌▼┐ ┌┴┐ │ ┌─┐ │ - │b│ │c│ └►│m├─┘ - └─┘ └─┘ └─┘ - """ - dag = retworkx.PyDiGraph() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - node_c = dag.add_node("c") - - dag.add_edge(node_a, node_b, 1) - dag.add_edge(node_c, node_a, 2) - - with self.assertRaises(retworkx.DAGWouldCycle): - dag.contract_nodes([node_b, node_c], "m", check_cycle=True) - - # Proceed, ignoring cycles. - node_m = dag.contract_nodes([node_b, node_c], "m") - self.assertEqual([node_a, node_m], dag.node_indexes()) - self.assertEqual( - {(node_a, node_m, 1), (node_m, node_a, 2)}, - set(dag.weighted_edge_list()), - ) - - -class TestContractNodesSimpleGraph(unittest.TestCase): - def setUp(self): - super().setUp() - self.dag = retworkx.PyDAG(multigraph=False) - self.node_a = self.dag.add_node("a") - self.node_b = self.dag.add_child(self.node_a, "b", 1) - self.node_c = self.dag.add_child(self.node_a, "c", 2) - self.node_d = self.dag.add_child(self.node_a, "d", 3) - self.node_e = self.dag.add_node("e") - self.dag.add_edge(self.node_b, self.node_e, 4) - self.dag.add_edge(self.node_c, self.node_e, 5) - self.dag.add_edge(self.node_d, self.node_e, 6) - - def test_collapse_parallel_edges_no_combo_fn(self): - """ - Parallel edges are collapsed arbitrarily when weight_combo_fn is None. - ┌─┐ ┌─┐ - │a│ │a│ - ┌──┴┬┴──┐ └┬┘ - 1 2 3 1 or 2 or 3 - ┌▼┐ ┌▼┐ ┌▼┐ ┌▼┐ - │b│ │c│ │d│ ──► │m│ - └┬┘ └┬┘ └┬┘ └┬┘ - 4 5 6 4 or 5 or 6 - └──►▼◄──┘ ┌▼┐ - │e│ │e│ - └─┘ └─┘ - """ - self.dag.contract_nodes([self.node_b, self.node_c, self.node_d], "m") - - self.assertEqual(set(self.dag.nodes()), {"a", "e", "m"}) - self.assertEqual(len(self.dag.edges()), 2) - - # Should have one incoming edge, one outgoing - self.assertTrue(any(e in self.dag.edges() for e in {1, 2, 3})) - self.assertTrue(any(e in self.dag.edges() for e in {4, 5, 6})) - - def test_collapse_parallel_edges(self): - """ - Parallel edges are collapsed using weight_combo_fn. - ┌─┐ ┌─┐ - │a│ │a│ - ┌──┴┬┴──┐ └┬┘ - 1 2 3 6 - ┌▼┐ ┌▼┐ ┌▼┐ ┌▼┐ - │b│ │c│ │d│ ──► │m│ - └┬┘ └┬┘ └┬┘ └┬┘ - 4 5 6 15 - └──►▼◄──┘ ┌▼┐ - │e│ │e│ - └─┘ └─┘ - """ - self.dag.contract_nodes( - [self.node_b, self.node_c, self.node_d], - "m", - weight_combo_fn=lambda w1, w2: w1 + w2, - ) - - self.assertEqual(set(self.dag.nodes()), {"a", "e", "m"}) - self.assertEqual(len(self.dag.edges()), 2) - - # Should have one incoming edge, one outgoing - self.assertEqual(set(self.dag.edges()), {6, 15}) - - def test_replace_all_nodes(self): - self.dag.contract_nodes(self.dag.node_indexes(), "m") - self.assertEqual(set(self.dag.nodes()), {"m"}) - self.assertFalse(self.dag.edges()) diff --git a/tests/retworkx_backwards_compat/digraph/test_copy.py b/tests/retworkx_backwards_compat/digraph/test_copy.py deleted file mode 100644 index 18e12b203..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_copy.py +++ /dev/null @@ -1,55 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestCopy(unittest.TestCase): - def test_copy_returns_graph(self): - graph_a = retworkx.PyDiGraph() - node_a = graph_a.add_node("a_1") - node_b = graph_a.add_node("a_2") - graph_a.add_edge(node_a, node_b, "edge_1") - node_c = graph_a.add_node("a_3") - graph_a.add_edge(node_b, node_c, "edge_2") - graph_b = graph_a.copy() - self.assertIsInstance(graph_b, retworkx.PyDiGraph) - - def test_copy_with_holes_returns_graph(self): - graph_a = retworkx.PyDiGraph() - node_a = graph_a.add_node("a_1") - node_b = graph_a.add_node("a_2") - graph_a.add_edge(node_a, node_b, "edge_1") - node_c = graph_a.add_node("a_3") - graph_a.add_edge(node_b, node_c, "edge_2") - graph_a.remove_node(node_b) - graph_b = graph_a.copy() - self.assertIsInstance(graph_b, retworkx.PyDiGraph) - self.assertEqual([node_a, node_c], graph_b.node_indexes()) - - def test_copy_empty(self): - graph = retworkx.PyDiGraph() - empty_copy = graph.copy() - self.assertEqual(len(empty_copy), 0) - - def test_copy_shared_ref(self): - graph_a = retworkx.PyDiGraph() - node_a = graph_a.add_node({"a": 1}) - node_b = graph_a.add_node({"b": 2}) - graph_a.add_edge(node_a, node_b, {"edge": 1}) - graph_b = graph_a.copy() - graph_a[0]["a"] = 42 - graph_b.get_edge_data(0, 1)["edge"] = 162 - self.assertEqual(graph_b[0]["a"], 42) - self.assertEqual(graph_a.get_edge_data(0, 1), {"edge": 162}) diff --git a/tests/retworkx_backwards_compat/digraph/test_core_number.py b/tests/retworkx_backwards_compat/digraph/test_core_number.py deleted file mode 100644 index b13a9a35b..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_core_number.py +++ /dev/null @@ -1,96 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestCoreNumber(unittest.TestCase): - def setUp(self): - # This 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 0-7, the 2-core by nodes - # 8-15, the 1-core by nodes 16-19 and node 20 is in the - # 0-core. - self.example_edges = [ - (0, 2), - (0, 3), - (0, 5), - (1, 4), - (1, 6), - (1, 7), - (2, 3), - (3, 5), - (2, 5), - (5, 6), - (4, 6), - (4, 7), - (6, 7), - (5, 8), - (6, 8), - (6, 9), - (8, 9), - (0, 10), - (1, 10), - (1, 11), - (10, 11), - (12, 13), - (13, 15), - (14, 15), - (12, 14), - (8, 19), - (11, 16), - (11, 17), - (12, 18), - ] - - example_core = {} - for i in range(8): - example_core[i] = 3 - for i in range(8, 16): - example_core[i] = 2 - for i in range(16, 20): - example_core[i] = 1 - example_core[20] = 0 - self.example_core = example_core - - def test_directed_empty(self): - digraph = retworkx.PyDiGraph() - res = retworkx.core_number(digraph) - self.assertIsInstance(res, dict) - self.assertEqual(res, {}) - - def test_directed_all_0(self): - digraph = retworkx.PyDiGraph() - digraph.add_nodes_from(list(range(4))) - res = retworkx.core_number(digraph) - self.assertIsInstance(res, dict) - self.assertEqual(res, {0: 0, 1: 0, 2: 0, 3: 0}) - - def test_directed_all_3(self): - digraph = retworkx.PyDiGraph() - digraph.add_nodes_from(list(range(4))) - digraph.add_edges_from_no_data([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]) - res = retworkx.core_number(digraph) - self.assertIsInstance(res, dict) - self.assertEqual(res, {0: 3, 1: 3, 2: 3, 3: 3}) - - def test_directed_paper_example(self): - digraph = retworkx.PyDiGraph() - digraph.add_nodes_from(list(range(21))) - digraph.add_edges_from_no_data(self.example_edges) - res = retworkx.core_number(digraph) - self.assertIsInstance(res, dict) - self.assertEqual(res, self.example_core) diff --git a/tests/retworkx_backwards_compat/digraph/test_deepcopy.py b/tests/retworkx_backwards_compat/digraph/test_deepcopy.py deleted file mode 100644 index cdd41b14a..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_deepcopy.py +++ /dev/null @@ -1,48 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import unittest - -import retworkx - - -class TestDeepcopy(unittest.TestCase): - def test_isomorphic_compare_nodes_identical(self): - dag_a = retworkx.PyDAG() - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "a_1") - dag_a.add_child(node_a, "a_3", "a_2") - dag_b = copy.deepcopy(dag_a) - self.assertTrue(retworkx.is_isomorphic_node_match(dag_a, dag_b, lambda x, y: x == y)) - - def test_deepcopy_with_holes(self): - dag_a = retworkx.PyDAG() - node_a = dag_a.add_node("a_1") - node_b = dag_a.add_node("a_2") - dag_a.add_edge(node_a, node_b, "edge_1") - node_c = dag_a.add_node("a_3") - dag_a.add_edge(node_b, node_c, "edge_2") - dag_a.remove_node(node_b) - dag_b = copy.deepcopy(dag_a) - self.assertIsInstance(dag_b, retworkx.PyDAG) - self.assertEqual([node_a, node_c], dag_b.node_indexes()) - - def test_deepcopy_empty(self): - dag = retworkx.PyDAG() - empty_copy = copy.deepcopy(dag) - self.assertEqual(len(empty_copy), 0) - - def test_deepcopy_attrs(self): - graph = retworkx.PyDiGraph(attrs="abc") - graph_copy = copy.deepcopy(graph) - self.assertEqual(graph.attrs, graph_copy.attrs) diff --git a/tests/retworkx_backwards_compat/digraph/test_depth.py b/tests/retworkx_backwards_compat/digraph/test_depth.py deleted file mode 100644 index 601bd5102..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_depth.py +++ /dev/null @@ -1,297 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestLongestPath(unittest.TestCase): - def test_linear(self): - """Longest depth for a simple dag. - - a - | - b - |\ - c d - |\ - e | - | | - f g - """ - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - node_c = dag.add_child(node_b, "c", {}) - dag.add_child(node_b, "d", {}) - node_e = dag.add_child(node_c, "e", {}) - node_f = dag.add_child(node_e, "f", {}) - dag.add_child(node_c, "g", {}) - self.assertEqual(4, retworkx.dag_longest_path_length(dag)) - self.assertEqual( - [node_a, node_b, node_c, node_e, node_f], - retworkx.dag_longest_path(dag), - ) - - def test_less_linear(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - node_c = dag.add_child(node_b, "c", {}) - node_d = dag.add_child(node_c, "d", {}) - node_e = dag.add_child(node_d, "e", {}) - dag.add_edge(node_a, node_c, {}) - dag.add_edge(node_a, node_e, {}) - dag.add_edge(node_c, node_e, {}) - self.assertEqual(4, retworkx.dag_longest_path_length(dag)) - self.assertEqual( - [node_a, node_b, node_c, node_d, node_e], - retworkx.dag_longest_path(dag), - ) - - def test_degenerate_graph(self): - dag = retworkx.PyDAG() - dag.add_node(0) - self.assertEqual(0, retworkx.dag_longest_path_length(dag)) - self.assertEqual([0], retworkx.dag_longest_path(dag)) - - def test_empty_graph(self): - dag = retworkx.PyDAG() - self.assertEqual(0, retworkx.dag_longest_path_length(dag)) - self.assertEqual([], retworkx.dag_longest_path(dag)) - - def test_parallel_edges(self): - dag = retworkx.PyDiGraph() - dag.extend_from_weighted_edge_list( - [ - (0, 1, 1), - (0, 3, 1), - (3, 4, 1), - (4, 5, 1), - (1, 2, 1), - (0, 1, 3), - ] - ) - self.assertEqual( - [0, 3, 4, 5], - retworkx.dag_longest_path(dag), - ) - - def test_linear_with_weight(self): - """Longest depth for a simple dag. - - a - | - b - |\ - c d - |\ - e | - | | - f g - """ - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", 4) - node_c = dag.add_child(node_b, "c", 4) - dag.add_child(node_b, "d", 5) - node_e = dag.add_child(node_c, "e", 2) - dag.add_child(node_e, "f", 2) - node_g = dag.add_child(node_c, "g", 15) - self.assertEqual( - [node_a, node_b, node_c, node_g], - retworkx.dag_longest_path(dag, lambda _, __, weight: weight), - ) - self.assertEqual( - 23, - retworkx.dag_longest_path_length(dag, lambda _, __, weight: weight), - ) - - def test_parallel_edges_with_weights(self): - dag = retworkx.PyDiGraph() - dag.extend_from_weighted_edge_list( - [ - (0, 1, 1), - (0, 3, 1), - (3, 4, 1), - (4, 5, 1), - (1, 2, 1), - (0, 1, 3), - ] - ) - self.assertEqual( - [0, 1, 2], - retworkx.dag_longest_path(dag, lambda _, __, weight: weight), - ) - self.assertEqual( - 4, - retworkx.dag_longest_path_length(dag, weight_fn=lambda _, __, weight: weight), - ) - - def test_less_linear_with_weight(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", 1) - node_c = dag.add_child(node_b, "c", 1) - node_d = dag.add_child(node_c, "d", 1) - node_e = dag.add_child(node_d, "e", 1) - dag.add_edge(node_a, node_c, 3) - dag.add_edge(node_a, node_e, 3) - dag.add_edge(node_c, node_e, 3) - self.assertEqual( - 6, - retworkx.dag_longest_path_length(dag, weight_fn=lambda _, __, weight: weight), - ) - self.assertEqual( - [node_a, node_c, node_e], - retworkx.dag_longest_path(dag, weight_fn=lambda _, __, weight: weight), - ) - - def test_degenerate_graph_with_weight(self): - dag = retworkx.PyDAG() - dag.add_node(0) - self.assertEqual([0], retworkx.dag_longest_path(dag, weight_fn=weight_fn)) - self.assertEqual(0, retworkx.dag_longest_path_length(dag, weight_fn=weight_fn)) - - def test_empty_graph_with_weights(self): - dag = retworkx.PyDAG() - self.assertEqual([], retworkx.dag_longest_path(dag, weight_fn=weight_fn)) - self.assertEqual(0, retworkx.dag_longest_path_length(dag, weight_fn=weight_fn)) - - def test_cycle(self): - not_a_dag = retworkx.generators.directed_cycle_graph(250) - with self.assertRaises(retworkx.DAGHasCycle): - retworkx.dag_longest_path_length(not_a_dag, lambda *_: 1.0) - with self.assertRaises(retworkx.DAGHasCycle): - retworkx.dag_longest_path(not_a_dag, lambda *_: 1.0) - - -def weight_fn(_, __, weight): - return int(weight) - - -class TestWeightedLongestPath(unittest.TestCase): - def test_linear_with_weight(self): - """Longest depth for a simple dag. - - a - | - b - |\ - c d - |\ - e | - | | - f g - """ - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", 4) - node_c = dag.add_child(node_b, "c", 4) - dag.add_child(node_b, "d", 5) - node_e = dag.add_child(node_c, "e", 2) - dag.add_child(node_e, "f", 2) - node_g = dag.add_child(node_c, "g", 15) - self.assertEqual( - 23.0, - retworkx.dag_weighted_longest_path_length(dag, lambda _, __, weight: float(weight)), - ) - self.assertEqual( - [node_a, node_b, node_c, node_g], - retworkx.dag_weighted_longest_path(dag, lambda _, __, weight: float(weight)), - ) - - def test_parallel_edges_with_weights(self): - dag = retworkx.PyDiGraph() - dag.extend_from_weighted_edge_list( - [ - (0, 1, 1), - (0, 3, 1), - (3, 4, 1), - (4, 5, 1), - (1, 2, 1), - (0, 1, 3), - ] - ) - self.assertEqual( - 4.0, - retworkx.dag_weighted_longest_path_length( - dag, weight_fn=lambda _, __, weight: float(weight) - ), - ) - self.assertEqual( - [0, 1, 2], - retworkx.dag_weighted_longest_path(dag, lambda _, __, weight: float(weight)), - ) - - def test_less_linear_with_weight(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", 1) - node_c = dag.add_child(node_b, "c", 1) - node_d = dag.add_child(node_c, "d", 1) - node_e = dag.add_child(node_d, "e", 1) - dag.add_edge(node_a, node_c, 3) - dag.add_edge(node_a, node_e, 3) - dag.add_edge(node_c, node_e, 3) - self.assertEqual( - 6.0, - retworkx.dag_weighted_longest_path_length( - dag, weight_fn=lambda _, __, weight: float(weight) - ), - ) - self.assertEqual( - [node_a, node_c, node_e], - retworkx.dag_weighted_longest_path(dag, weight_fn=lambda _, __, weight: float(weight)), - ) - - def test_degenerate_graph_with_weight(self): - dag = retworkx.PyDAG() - dag.add_node(0) - self.assertEqual( - 0.0, - retworkx.dag_weighted_longest_path_length(dag, lambda x: float(weight_fn(x))), - ) - self.assertEqual( - [0], - retworkx.dag_weighted_longest_path(dag, lambda x: float(weight_fn(x))), - ) - - def test_empty_graph_with_weights(self): - dag = retworkx.PyDAG() - self.assertEqual( - 0.0, - retworkx.dag_weighted_longest_path_length(dag, lambda x: float(weight_fn(x))), - ) - self.assertEqual( - [], - retworkx.dag_weighted_longest_path(dag, lambda x: float(weight_fn(x))), - ) - - def test_nan_not_valid_weight(self): - dag = retworkx.generators.directed_path_graph(526) - - def weight_fn(*_): - return float("nan") - - with self.assertRaises(ValueError): - retworkx.dag_weighted_longest_path_length(dag, weight_fn) - with self.assertRaises(ValueError): - retworkx.dag_weighted_longest_path(dag, weight_fn) - - def test_cycle(self): - not_a_dag = retworkx.generators.directed_cycle_graph(250) - with self.assertRaises(retworkx.DAGHasCycle): - retworkx.dag_weighted_longest_path_length(not_a_dag, lambda *_: 1.0) - with self.assertRaises(retworkx.DAGHasCycle): - retworkx.dag_weighted_longest_path(not_a_dag, lambda *_: 1.0) diff --git a/tests/retworkx_backwards_compat/digraph/test_dfs_edges.py b/tests/retworkx_backwards_compat/digraph/test_dfs_edges.py deleted file mode 100644 index 054e170ec..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_dfs_edges.py +++ /dev/null @@ -1,31 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestDfsEdges(unittest.TestCase): - def test_digraph_disconnected_dfs_edges(self): - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list([(0, 1), (2, 3)]) - edges = retworkx.digraph_dfs_edges(graph) - expected = [(0, 1), (2, 3)] - self.assertEqual(expected, edges) - - def test_digraph_dfs_edges(self): - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4)]) - edges = retworkx.digraph_dfs_edges(graph, 0) - expected = [(0, 1), (1, 2), (2, 4), (1, 3)] - self.assertEqual(expected, edges) diff --git a/tests/retworkx_backwards_compat/digraph/test_dfs_search.py b/tests/retworkx_backwards_compat/digraph/test_dfs_search.py deleted file mode 100644 index 8c099ae2e..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_dfs_search.py +++ /dev/null @@ -1,106 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestDfsSearch(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.graph.extend_from_edge_list( - [ - (0, 1), - (0, 2), - (1, 3), - (2, 1), - (2, 5), - (2, 6), - (5, 3), - (4, 7), - ] - ) - - def test_digraph_dfs_tree_edges(self): - class TreeEdgesRecorder(retworkx.visit.DFSVisitor): - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - self.edges.append((edge[0], edge[1])) - - vis = TreeEdgesRecorder() - retworkx.digraph_dfs_search(self.graph, [0], vis) - self.assertEqual(vis.edges, [(0, 2), (2, 6), (2, 5), (5, 3), (2, 1)]) - - def test_digraph_dfs_tree_edges_no_starting_point(self): - class TreeEdgesRecorder(retworkx.visit.DFSVisitor): - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - self.edges.append((edge[0], edge[1])) - - vis = TreeEdgesRecorder() - retworkx.digraph_dfs_search(self.graph, None, vis) - self.assertEqual(vis.edges, [(0, 2), (2, 6), (2, 5), (5, 3), (2, 1), (4, 7)]) - - def test_digraph_dfs_tree_edges_restricted(self): - class TreeEdgesRecorderRestricted(retworkx.visit.DFSVisitor): - - prohibited = [(0, 1), (5, 3)] - - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - edge = (edge[0], edge[1]) - if edge in self.prohibited: - raise retworkx.visit.PruneSearch - self.edges.append(edge) - - vis = TreeEdgesRecorderRestricted() - retworkx.digraph_dfs_search(self.graph, [0], vis) - self.assertEqual(vis.edges, [(0, 2), (2, 6), (2, 5), (2, 1), (1, 3)]) - - def test_digraph_dfs_goal_search(self): - class GoalSearch(retworkx.visit.DFSVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - - def tree_edge(self, edge): - u, v, _ = edge - self.parents[v] = u - - if v == self.goal: - raise retworkx.visit.StopSearch - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - try: - retworkx.digraph_dfs_search(self.graph, [0], vis) - except retworkx.visit.StopSearch: - pass - self.assertEqual(vis.reconstruct_path(), [0, 2, 5, 3]) diff --git a/tests/retworkx_backwards_compat/digraph/test_dijkstra.py b/tests/retworkx_backwards_compat/digraph/test_dijkstra.py deleted file mode 100644 index 0d7c6d47a..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_dijkstra.py +++ /dev/null @@ -1,313 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestDijkstraDiGraph(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - self.d = self.graph.add_node("D") - self.e = self.graph.add_node("E") - self.f = self.graph.add_node("F") - edge_list = [ - (self.a, self.b, 7), - (self.c, self.a, 9), - (self.a, self.d, 14), - (self.b, self.c, 10), - (self.d, self.c, 2), - (self.d, self.e, 9), - (self.b, self.f, 15), - (self.c, self.f, 11), - (self.e, self.f, 6), - ] - self.graph.add_edges_from(edge_list) - - def test_dijkstra(self): - path = retworkx.digraph_dijkstra_shortest_path_lengths( - self.graph, self.a, lambda x: float(x), self.e - ) - expected = {4: 23.0} - self.assertEqual(expected, path) - - def test_dijkstra_length_with_no_path(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - b = g.add_node("B") - path_lenghts = retworkx.digraph_dijkstra_shortest_path_lengths( - g, a, edge_cost_fn=float, goal=b - ) - expected = {} - self.assertEqual(expected, path_lenghts) - - def test_dijkstra_path(self): - paths = retworkx.digraph_dijkstra_shortest_paths(self.graph, self.a) - expected = { - # a -> b - 1: [0, 1], - # a -> c: a, d, c - 2: [0, 3, 2], - # a -> d - 3: [0, 3], - # a -> e: a, d, e - 4: [0, 3, 4], - # a -> f: a, b, f - 5: [0, 1, 5], - } - self.assertEqual(expected, paths) - - def test_dijkstra_path_with_weight_fn(self): - paths = retworkx.digraph_dijkstra_shortest_paths(self.graph, self.a, weight_fn=lambda x: x) - expected = { - 1: [0, 1], - 2: [0, 3, 2], - 3: [0, 3], - 4: [0, 3, 4], - 5: [0, 1, 5], - } - self.assertEqual(expected, paths) - - def test_dijkstra_path_with_target(self): - paths = retworkx.digraph_dijkstra_shortest_paths(self.graph, self.a, target=self.e) - expected = { - 4: [0, 3, 4], - } - self.assertEqual(expected, paths) - - def test_dijkstra_path_with_weight_fn_and_target(self): - paths = retworkx.digraph_dijkstra_shortest_paths( - self.graph, self.a, target=self.e, weight_fn=lambda x: x - ) - expected = { - 4: [0, 3, 4], - } - self.assertEqual(expected, paths) - - def test_dijkstra_path_undirected(self): - paths = retworkx.digraph_dijkstra_shortest_paths(self.graph, self.a, as_undirected=True) - expected = { - 1: [0, 1], - 2: [0, 2], - 3: [0, 3], - 4: [0, 3, 4], - 5: [0, 1, 5], - } - self.assertEqual(expected, paths) - - def test_dijkstra_path_undirected_with_weight_fn(self): - paths = retworkx.digraph_dijkstra_shortest_paths( - self.graph, self.a, weight_fn=lambda x: x, as_undirected=True - ) - expected = { - 1: [0, 1], - 2: [0, 2], - 3: [0, 2, 3], - 4: [0, 2, 3, 4], - 5: [0, 2, 5], - } - self.assertEqual(expected, paths) - - def test_dijkstra_path_undirected_with_target(self): - paths = retworkx.digraph_dijkstra_shortest_paths( - self.graph, self.a, target=self.e, as_undirected=True - ) - expected = { - 4: [0, 3, 4], - } - self.assertEqual(expected, paths) - - def test_dijkstra_path_undirected_with_weight_fn_and_target(self): - paths = retworkx.digraph_dijkstra_shortest_paths( - self.graph, - self.a, - target=self.e, - weight_fn=lambda x: x, - as_undirected=True, - ) - expected = { - 4: [0, 2, 3, 4], - } - self.assertEqual(expected, paths) - - def test_dijkstra_with_no_goal_set(self): - path = retworkx.digraph_dijkstra_shortest_path_lengths(self.graph, self.a, lambda x: 1) - expected = {1: 1.0, 2: 2.0, 3: 1.0, 4: 2.0, 5: 2.0} - self.assertEqual(expected, path) - - def test_dijkstra_with_no_path(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - g.add_node("B") - path = retworkx.digraph_dijkstra_shortest_path_lengths(g, a, lambda x: float(x)) - expected = {} - self.assertEqual(expected, path) - - def test_dijkstra_path_with_no_path(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - g.add_node("B") - path = retworkx.digraph_dijkstra_shortest_paths(g, a) - expected = {} - self.assertEqual(expected, path) - - def test_dijkstra_with_disconnected_nodes(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - b = g.add_child(a, "B", 1.2) - g.add_node("C") - g.add_parent(b, "D", 2.4) - path = retworkx.digraph_dijkstra_shortest_path_lengths(g, a, lambda x: x) - expected = {1: 1.2} - self.assertEqual(expected, path) - - def test_dijkstra_with_graph_input(self): - g = retworkx.PyGraph() - g.add_node(0) - with self.assertRaises(TypeError): - retworkx.digraph_dijkstra_shortest_path_lengths(g, 0, lambda x: x) - - def test_dijkstra_all_pair_path_lengths(self): - lengths = retworkx.digraph_all_pairs_dijkstra_path_lengths(self.graph, float) - expected = { - 0: {1: 7.0, 2: 16.0, 3: 14.0, 4: 23.0, 5: 22.0}, - 1: {0: 19.0, 2: 10.0, 3: 33.0, 4: 42.0, 5: 15.0}, - 2: {0: 9.0, 1: 16.0, 3: 23.0, 4: 32.0, 5: 11.0}, - 3: {0: 11.0, 1: 18.0, 2: 2.0, 4: 9.0, 5: 13.0}, - 4: {5: 6.0}, - 5: {}, - } - self.assertEqual(expected, lengths) - - def test_dijkstra_all_pair_paths(self): - paths = retworkx.digraph_all_pairs_dijkstra_shortest_paths(self.graph, float) - expected = { - 0: {1: [0, 1], 2: [0, 3, 2], 3: [0, 3], 4: [0, 3, 4], 5: [0, 1, 5]}, - 1: { - 0: [1, 2, 0], - 2: [1, 2], - 3: [1, 2, 0, 3], - 4: [1, 2, 0, 3, 4], - 5: [1, 5], - }, - 2: { - 0: [2, 0], - 1: [2, 0, 1], - 3: [2, 0, 3], - 4: [2, 0, 3, 4], - 5: [2, 5], - }, - 3: { - 0: [3, 2, 0], - 1: [3, 2, 0, 1], - 2: [3, 2], - 4: [3, 4], - 5: [3, 2, 5], - }, - 4: {5: [4, 5]}, - 5: {}, - } - self.assertEqual(expected, paths) - - def test_dijkstra_all_pair_path_lengths_with_node_removal(self): - self.graph.remove_node(3) - lengths = retworkx.digraph_all_pairs_dijkstra_path_lengths(self.graph, float) - expected = { - 0: {1: 7.0, 2: 17.0, 5: 22.0}, - 1: {0: 19.0, 2: 10.0, 5: 15.0}, - 2: {0: 9.0, 1: 16.0, 5: 11.0}, - 4: {5: 6.0}, - 5: {}, - } - self.assertEqual(expected, lengths) - - def test_dijkstra_all_pair_paths_with_node_removal(self): - self.graph.remove_node(3) - lengths = retworkx.digraph_all_pairs_dijkstra_shortest_paths(self.graph, float) - expected = { - 0: {1: [0, 1], 2: [0, 1, 2], 5: [0, 1, 5]}, - 1: {0: [1, 2, 0], 2: [1, 2], 5: [1, 5]}, - 2: {0: [2, 0], 1: [2, 0, 1], 5: [2, 5]}, - 4: {5: [4, 5]}, - 5: {}, - } - self.assertEqual(expected, lengths) - - def test_dijkstra_all_pair_path_lengths_empty_graph(self): - graph = retworkx.PyDiGraph() - self.assertEqual({}, retworkx.digraph_all_pairs_dijkstra_path_lengths(graph, float)) - - def test_dijkstra_all_pair_shortest_paths_empty_graph(self): - graph = retworkx.PyDiGraph() - self.assertEqual({}, retworkx.digraph_all_pairs_dijkstra_shortest_paths(graph, float)) - - def test_dijkstra_all_pair_path_lengths_graph_no_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.digraph_all_pairs_dijkstra_path_lengths(graph, float), - ) - - def test_dijkstra_all_pair_shortest_paths_no_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.digraph_all_pairs_dijkstra_shortest_paths(graph, float), - ) - - def dijkstra_with_invalid_weights(self): - graph = retworkx.generators.directed_path_graph(2) - for invalid_weight in [float("nan"), -1]: - for as_undirected in [False, True]: - with self.subTest(invalid_weight=invalid_weight, as_undirected=as_undirected): - with self.assertRaises(ValueError): - retworkx.digraph_dijkstra_shortest_paths( - graph, - source=0, - weight_fn=lambda _: invalid_weight, - as_undirected=as_undirected, - ) - - def dijkstra_lengths_with_invalid_weights(self): - graph = retworkx.generators.directed_path_graph(2) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.digraph_dijkstra_shortest_path_lengths( - graph, node=0, edge_cost_fn=lambda _: invalid_weight - ) - - def all_pairs_dijkstra_with_invalid_weights(self): - graph = retworkx.generators.directed_path_graph(2) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.digraph_all_pairs_dijkstra_shortest_paths( - graph, edge_cost_fn=lambda _: invalid_weight - ) - - def all_pairs_dijkstra_lenghts_with_invalid_weights(self): - graph = retworkx.generators.directed_path_graph(2) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.digraph_all_pairs_dijkstra_path_lengths( - graph, edge_cost_fn=lambda _: invalid_weight - ) diff --git a/tests/retworkx_backwards_compat/digraph/test_dijkstra_search.py b/tests/retworkx_backwards_compat/digraph/test_dijkstra_search.py deleted file mode 100644 index 9cd8e6d0e..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_dijkstra_search.py +++ /dev/null @@ -1,189 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestDijkstraSearch(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.graph.extend_from_weighted_edge_list( - [ - (0, 1, 1), - (0, 2, 2), - (1, 3, 10), - (2, 1, 1), - (2, 5, 1), - (2, 6, 1), - (5, 3, 1), - (4, 7, 1), - ] - ) - - def test_digraph_dijkstra_tree_edges(self): - class DijkstraTreeEdgesRecorder(retworkx.visit.DijkstraVisitor): - def __init__(self): - self.edges = [] - self.parents = dict() - - def discover_vertex(self, v, _): - u = self.parents.get(v, None) - if u is not None: - self.edges.append((u, v)) - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - vis = DijkstraTreeEdgesRecorder() - retworkx.digraph_dijkstra_search(self.graph, [0], float, vis) - self.assertEqual(vis.edges, [(0, 1), (0, 2), (2, 6), (2, 5), (5, 3)]) - - def test_digraph_dijkstra_tree_edges_no_starting_point(self): - class DijkstraTreeEdgesRecorder(retworkx.visit.DijkstraVisitor): - def __init__(self): - self.edges = [] - self.parents = dict() - - def discover_vertex(self, v, _): - u = self.parents.get(v, None) - if u is not None: - self.edges.append((u, v)) - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - vis = DijkstraTreeEdgesRecorder() - retworkx.digraph_dijkstra_search(self.graph, None, float, vis) - self.assertEqual(vis.edges, [(0, 1), (0, 2), (2, 6), (2, 5), (5, 3), (4, 7)]) - - def test_digraph_dijkstra_goal_search_with_stop_search_exception(self): - class GoalSearch(retworkx.visit.DijkstraVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - self.opt_goal_cost = None - - def discover_vertex(self, v, score): - if v == self.goal: - self.opt_goal_cost = score - raise retworkx.visit.StopSearch - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - retworkx.digraph_dijkstra_search(self.graph, [0], float, vis) - self.assertEqual(vis.reconstruct_path(), [0, 2, 5, 3]) - self.assertEqual(vis.opt_goal_cost, 4.0) - - def test_digraph_dijkstra_goal_search_with_custom_exception(self): - class StopIfGoalFound(Exception): - pass - - class GoalSearch(retworkx.visit.DijkstraVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - self.opt_goal_cost = None - - def discover_vertex(self, v, score): - if v == self.goal: - self.opt_goal_cost = score - raise StopIfGoalFound - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - try: - retworkx.digraph_dijkstra_search(self.graph, [0], float, vis) - except StopIfGoalFound: - pass - self.assertEqual(vis.reconstruct_path(), [0, 2, 5, 3]) - self.assertEqual(vis.opt_goal_cost, 4.0) - - def test_digraph_dijkstra_goal_search_with_prohibited_edges(self): - class GoalSearch(retworkx.visit.DijkstraVisitor): - - goal = 3 - prohibited = [(5, 3)] - - def __init__(self): - self.parents = {} - self.opt_goal_cost = None - - def discover_vertex(self, v, score): - if v == self.goal: - self.opt_goal_cost = score - raise retworkx.visit.StopSearch - - def examine_edge(self, edge): - u, v, _ = edge - if (u, v) in self.prohibited: - raise retworkx.visit.PruneSearch - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - retworkx.digraph_dijkstra_search(self.graph, [0], float, vis) - self.assertEqual(vis.reconstruct_path(), [0, 1, 3]) - self.assertEqual(vis.opt_goal_cost, 11.0) - - def test_digraph_prune_edge_not_relaxed(self): - class PruneEdgeNotRelaxed(retworkx.visit.DijkstraVisitor): - def edge_not_relaxed(self, _): - raise retworkx.visit.PruneSearch - - vis = PruneEdgeNotRelaxed() - retworkx.digraph_dijkstra_search(self.graph, [0], float, vis) diff --git a/tests/retworkx_backwards_compat/digraph/test_dist_matrix.py b/tests/retworkx_backwards_compat/digraph/test_dist_matrix.py deleted file mode 100644 index 05459c4f2..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_dist_matrix.py +++ /dev/null @@ -1,140 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import numpy as np - -import retworkx - - -class TestDistanceMatrix(unittest.TestCase): - def test_digraph_distance_matrix(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.digraph_distance_matrix(graph) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 1.0], - [0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0], - [0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0], - [0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0], - [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.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], - ] - ) - self.assertTrue(np.array_equal(dist, expected)) - - def test_digraph_distance_matrix_parallel(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.digraph_distance_matrix(graph, parallel_threshold=5) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 1.0], - [0.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0], - [0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0], - [0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0], - [0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 2.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], - ] - ) - self.assertTrue(np.array_equal(dist, expected)) - - def test_digraph_distance_matrix_as_undirected(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.digraph_distance_matrix(graph, as_undirected=True) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0], - ] - ) - self.assertTrue(np.array_equal(dist, expected)) - - def test_digraph_distance_matrix_parallel_as_undirected(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.digraph_distance_matrix(graph, parallel_threshold=5, as_undirected=True) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0], - ] - ) - self.assertTrue(np.array_equal(dist, expected)) - - def test_digraph_distance_matrix_non_zero_null(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - graph.add_node(7) - dist = retworkx.distance_matrix(graph, as_undirected=True, null_value=np.nan) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0, np.nan], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0, np.nan], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0, np.nan], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0, np.nan], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0, np.nan], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0, np.nan], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0, np.nan], - [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, 0.0], - ] - ) - self.assertTrue(np.array_equal(dist, expected, equal_nan=True)) - - def test_digraph_distance_matrix_parallel_non_zero_null(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - graph.add_node(7) - dist = retworkx.distance_matrix( - graph, as_undirected=True, parallel_threshold=5, null_value=np.nan - ) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0, np.nan], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0, np.nan], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0, np.nan], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0, np.nan], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0, np.nan], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0, np.nan], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0, np.nan], - [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, 0.0], - ] - ) - self.assertTrue(np.array_equal(dist, expected, equal_nan=True)) - - def test_digraph_distance_matrix_node_hole(self): - graph = retworkx.generators.directed_path_graph(4) - graph.remove_node(0) - dist = retworkx.digraph_distance_matrix(graph) - expected = np.array([[0.0, 1.0, 2.0], [0.0, 0.0, 1.0], [0.0, 0.0, 0.0]]) - self.assertTrue(np.array_equal(dist, expected)) diff --git a/tests/retworkx_backwards_compat/digraph/test_dot.py b/tests/retworkx_backwards_compat/digraph/test_dot.py deleted file mode 100644 index fb2211c43..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_dot.py +++ /dev/null @@ -1,73 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import tempfile -import unittest - -import retworkx - - -class TestDot(unittest.TestCase): - def setUp(self): - fd, self.path = tempfile.mkstemp() - os.close(fd) - os.remove(self.path) - - def test_digraph_to_dot_to_file(self): - graph = retworkx.PyDiGraph() - graph.add_node( - { - "color": "black", - "fillcolor": "green", - "label": "a", - "style": "filled", - } - ) - graph.add_node( - { - "color": "black", - "fillcolor": "red", - "label": "a", - "style": "filled", - } - ) - graph.add_edge(0, 1, dict(label="1", name="1")) - expected = ( - 'digraph {\n0 [color=black, fillcolor=green, label="a", ' - 'style=filled];\n1 [color=black, fillcolor=red, label="a", ' - 'style=filled];\n0 -> 1 [label="1", name=1];\n}\n' - ) - res = graph.to_dot(lambda node: node, lambda edge: edge, filename=self.path) - self.addCleanup(os.remove, self.path) - self.assertIsNone(res) - with open(self.path, "r") as fd: - res = fd.read() - self.assertEqual(expected, res) - - def test_digraph_empty_dicts(self): - graph = retworkx.directed_gnp_random_graph(3, 0.9, seed=42) - dot_str = graph.to_dot(lambda _: {}, lambda _: {}) - self.assertEqual("digraph {\n0 ;\n1 ;\n2 ;\n0 -> 1 ;\n0 -> 2 ;\n}\n", dot_str) - - def test_digraph_graph_attrs(self): - graph = retworkx.directed_gnp_random_graph(3, 0.9, seed=42) - dot_str = graph.to_dot(lambda _: {}, lambda _: {}, {"bgcolor": "red"}) - self.assertEqual( - "digraph {\nbgcolor=red ;\n0 ;\n1 ;\n2 ;\n0 -> 1 ;\n" "0 -> 2 ;\n}\n", - dot_str, - ) - - def test_digraph_no_args(self): - graph = retworkx.directed_gnp_random_graph(3, 0.95, seed=24) - dot_str = graph.to_dot() - self.assertEqual("digraph {\n0 ;\n1 ;\n2 ;\n0 -> 1 ;\n0 -> 2 ;\n}\n", dot_str) diff --git a/tests/retworkx_backwards_compat/digraph/test_edgelist.py b/tests/retworkx_backwards_compat/digraph/test_edgelist.py deleted file mode 100644 index 45ae47091..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_edgelist.py +++ /dev/null @@ -1,213 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import tempfile -import unittest - -import retworkx - - -class TestEdgeList(unittest.TestCase): - def test_empty_edge_list_digraph(self): - with tempfile.NamedTemporaryFile() as fd: - graph = retworkx.PyDiGraph.read_edge_list(fd.name) - self.assertEqual(graph.nodes(), []) - - def test_invalid_path_digraph(self): - path = os.path.join(tempfile.gettempdir(), "fake_file_name.txt") - with self.assertRaises(FileNotFoundError): - retworkx.PyDiGraph.read_edge_list(path) - - def test_simple_example_digraph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1\n") - fd.write("1 2\n") - fd.flush() - graph = retworkx.PyDiGraph.read_edge_list(fd.name) - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(1, 0)) - self.assertFalse(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - - def test_blank_line_digraph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1\n") - fd.write("\n") - fd.write("1 2\n") - fd.flush() - graph = retworkx.PyDiGraph.read_edge_list(fd.name) - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(1, 0)) - self.assertFalse(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - - def test_comment_digraph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1 // test a comment\n") - fd.write("1 2\n") - fd.write("//2 3\n") - fd.flush() - graph = retworkx.PyDiGraph.read_edge_list(fd.name, comment="//") - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(1, 0)) - self.assertFalse(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - - def test_comment_leading_space_digraph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1 // test a comment\n") - fd.write("1 2\n") - fd.write(" //2 3\n") - fd.flush() - graph = retworkx.PyDiGraph.read_edge_list(fd.name, comment="//") - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(1, 0)) - self.assertFalse(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - - def test_weight_digraph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1 0// test a comment\n") - fd.write("1 2 1\n") - fd.write("//2 3\n") - fd.flush() - graph = retworkx.PyDiGraph.read_edge_list(fd.name, comment="//") - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(1, 0)) - self.assertFalse(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - self.assertEqual(graph.edges(), ["0", "1"]) - - def test_delim_digraph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0|1|0// test a comment\n") - fd.write("1|2|1\n") - fd.write("//2|3\n") - fd.flush() - graph = retworkx.PyDiGraph.read_edge_list(fd.name, comment="//", deliminator="|") - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(1, 0)) - self.assertFalse(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - self.assertEqual(graph.edges(), ["0", "1"]) - - def test_labels_digraph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("a|b|0// test a comment\n") - fd.write("b|c|1\n") - fd.write("//c|d\n") - fd.flush() - graph = retworkx.PyDiGraph.read_edge_list( - fd.name, comment="//", deliminator="|", labels=True - ) - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(1, 0)) - self.assertFalse(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - self.assertEqual(graph.edges(), ["0", "1"]) - - def test_labels_digraph_target_existing(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("a|b|0// test a comment\n") - fd.write("b|c|1\n") - fd.write("a|c\n") - fd.flush() - graph = retworkx.PyDiGraph.read_edge_list( - fd.name, comment="//", deliminator="|", labels=True - ) - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(1, 0)) - self.assertFalse(graph.has_edge(2, 1)) - self.assertTrue(graph.has_edge(0, 2)) - self.assertEqual(graph.edges(), ["0", "1", None]) - - def test_write_edge_list_empty_digraph(self): - path = os.path.join(tempfile.gettempdir(), "empty.txt") - graph = retworkx.PyDiGraph() - graph.write_edge_list(path) - self.addCleanup(os.remove, path) - with open(path, "rt") as edge_file: - self.assertEqual("", edge_file.read()) - - def test_write_edge_list_round_trip(self): - path = os.path.join(tempfile.gettempdir(), "round_trip.txt") - graph = retworkx.generators.directed_star_graph(5) - count = iter(range(5)) - - def weight_fn(edge): - return str(next(count)) - - graph.write_edge_list(path, weight_fn=weight_fn) - self.addCleanup(os.remove, path) - new_graph = retworkx.PyDiGraph.read_edge_list(path) - expected = [ - (0, 1, "0"), - (0, 2, "1"), - (0, 3, "2"), - (0, 4, "3"), - ] - self.assertEqual(expected, new_graph.weighted_edge_list()) - - def test_custom_delim(self): - path = os.path.join(tempfile.gettempdir(), "custom_delim.txt") - graph = retworkx.generators.directed_path_graph(5) - graph.write_edge_list(path, deliminator=",") - self.addCleanup(os.remove, path) - expected = """0,1 -1,2 -2,3 -3,4 -""" - with open(path, "rt") as edge_file: - self.assertEqual(edge_file.read(), expected) - - def test_invalid_return_type_weight_fn(self): - path = os.path.join(tempfile.gettempdir(), "fail.txt") - graph = retworkx.directed_gnm_random_graph(5, 4) - self.addCleanup(cleanup_file, path) - with self.assertRaises(TypeError): - graph.write_edge_list(path, weight_fn=lambda _: 4.5) - - def test_weight_fn_raises(self): - path = os.path.join(tempfile.gettempdir(), "fail.txt") - graph = retworkx.directed_gnm_random_graph(5, 4) - - def weight_fn(edge): - raise KeyError - - self.addCleanup(cleanup_file, path) - with self.assertRaises(KeyError): - graph.write_edge_list(path, weight_fn=weight_fn) - - -def cleanup_file(path): - try: - os.remove(path) - except Exception: - pass diff --git a/tests/retworkx_backwards_compat/digraph/test_edges.py b/tests/retworkx_backwards_compat/digraph/test_edges.py deleted file mode 100644 index 1552b3d50..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_edges.py +++ /dev/null @@ -1,938 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestEdges(unittest.TestCase): - def test_get_edge_data(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - res = dag.get_edge_data(node_a, node_b) - self.assertEqual("Edgy", res) - - def test_get_all_edge_data(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_edge(node_a, node_b, "b") - res = dag.get_all_edge_data(node_a, node_b) - self.assertIn("b", res) - self.assertIn("Edgy", res) - - def test_no_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, dag.get_edge_data, node_a, node_b) - - def test_num_edges(self): - graph = retworkx.PyDiGraph() - graph.add_node(1) - graph.add_node(42) - graph.add_node(146) - graph.add_edges_from_no_data([(0, 1), (1, 2)]) - self.assertEqual(2, graph.num_edges()) - - def test_num_edges_no_edges(self): - graph = retworkx.PyDiGraph() - graph.add_node(1) - graph.add_node(42) - self.assertEqual(0, graph.num_edges()) - - def test_update_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "not edgy") - dag.update_edge(node_a, node_b, "Edgy") - self.assertEqual([(0, 1, "Edgy")], dag.weighted_edge_list()) - - def test_update_edge_no_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, dag.update_edge, node_a, node_b, None) - - def test_update_edge_by_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", "not edgy") - dag.update_edge_by_index(0, "Edgy") - self.assertEqual([(0, 1, "Edgy")], dag.weighted_edge_list()) - - def test_update_edge_invalid_index(self): - dag = retworkx.PyDAG() - dag.add_node("a") - dag.add_node("b") - self.assertRaises(IndexError, dag.update_edge_by_index, 0, None) - - def test_update_edge_parallel_edges(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "not edgy") - edge_index = graph.add_edge(node_a, node_b, "not edgy") - graph.update_edge_by_index(edge_index, "Edgy") - self.assertEqual( - [(0, 1, "not edgy"), (0, 1, "Edgy")], - list(graph.weighted_edge_list()), - ) - - def test_has_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - self.assertTrue(dag.has_edge(node_a, node_b)) - - def test_has_edge_no_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - self.assertFalse(dag.has_edge(node_a, node_b)) - - def test_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_child(node_b, "c", "Super edgy") - self.assertEqual(["Edgy", "Super edgy"], dag.edges()) - - def test_edges_empty(self): - dag = retworkx.PyDAG() - dag.add_node("a") - self.assertEqual([], dag.edges()) - - def test_edge_indices(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_child(node_b, "c", "Super edgy") - self.assertEqual([0, 1], dag.edge_indices()) - - def test_edge_indices_empty(self): - dag = retworkx.PyDAG() - dag.add_node("a") - self.assertEqual([], dag.edge_indices()) - - def test_add_duplicates(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "a", "a") - dag.add_edge(node_a, node_b, "b") - self.assertEqual(["a", "b"], dag.edges()) - - def test_remove_no_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, dag.remove_edge, node_a, node_b) - - def test_remove_edge_single(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "edgy") - dag.remove_edge(node_a, node_b) - self.assertEqual([], dag.edges()) - - def test_remove_multiple(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "edgy") - dag.add_edge(node_a, node_b, "super_edgy") - dag.remove_edge_from_index(0) - self.assertEqual(["super_edgy"], dag.edges()) - - def test_remove_edges_from(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - node_c = graph.add_node("c") - graph.add_edge(node_a, node_b, "edgy") - graph.add_edge(node_a, node_c, "super_edgy") - graph.remove_edges_from([(node_a, node_b), (node_a, node_c)]) - self.assertEqual([], graph.edges()) - - def test_remove_edges_from_invalid(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - node_c = graph.add_node("c") - graph.add_edge(node_a, node_b, "edgy") - graph.add_edge(node_a, node_c, "super_edgy") - with self.assertRaises(retworkx.NoEdgeBetweenNodes): - graph.remove_edges_from([(node_b, node_c), (node_a, node_c)]) - - def test_remove_edge_from_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", "edgy") - dag.remove_edge_from_index(0) - self.assertEqual([], dag.edges()) - - def test_remove_edge_no_edge(self): - dag = retworkx.PyDAG() - dag.add_node("a") - dag.remove_edge_from_index(0) - self.assertEqual([], dag.edges()) - - def test_add_cycle(self): - dag = retworkx.PyDAG() - dag.check_cycle = True - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - self.assertRaises(retworkx.DAGWouldCycle, dag.add_edge, node_b, node_a, {}) - - def test_add_edge_with_cycle_check_enabled(self): - dag = retworkx.PyDAG(True) - node_a = dag.add_node("a") - node_c = dag.add_node("c") - node_b = dag.add_child(node_a, "b", {}) - dag.add_edge(node_c, node_b, {}) - self.assertTrue(dag.has_edge(node_c, node_b)) - - def test_enable_cycle_checking_after_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - dag.add_edge(node_b, node_a, {}) - with self.assertRaises(retworkx.DAGHasCycle): - dag.check_cycle = True - - def test_cycle_checking_at_init(self): - dag = retworkx.PyDAG(True) - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - with self.assertRaises(retworkx.DAGWouldCycle): - dag.add_edge(node_b, node_a, {}) - - def test_find_adjacent_node_by_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"weights": [1, 2]}) - dag.add_child(node_a, "c", {"weights": [3, 4]}) - - def compare_edges(edge): - return 4 in edge["weights"] - - res = dag.find_adjacent_node_by_edge(node_a, compare_edges) - self.assertEqual("c", res) - - def test_find_adjacent_node_by_edge_no_match(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"weights": [1, 2]}) - dag.add_child(node_a, "c", {"weights": [3, 4]}) - - def compare_edges(edge): - return 5 in edge["weights"] - - with self.assertRaises(retworkx.NoSuitableNeighbors): - dag.find_adjacent_node_by_edge(node_a, compare_edges) - - def test_add_edge_from(self): - dag = retworkx.PyDAG() - nodes = list(range(4)) - dag.add_nodes_from(nodes) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - res = dag.add_edges_from(edge_list) - self.assertEqual(len(res), 5) - self.assertEqual(["a", "b", "c", "d", "e"], dag.edges()) - self.assertEqual(3, dag.out_degree(0)) - self.assertEqual(0, dag.in_degree(0)) - self.assertEqual(1, dag.out_degree(1)) - self.assertEqual(1, dag.out_degree(2)) - self.assertEqual(2, dag.in_degree(3)) - - def test_add_edge_from_empty(self): - dag = retworkx.PyDAG() - res = dag.add_edges_from([]) - self.assertEqual([], res) - - def test_cycle_checking_at_init_nodes_from(self): - dag = retworkx.PyDAG(True) - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - node_c = dag.add_child(node_b, "c", {}) - with self.assertRaises(retworkx.DAGWouldCycle): - dag.add_edges_from([(node_a, node_c, {}), (node_c, node_b, {})]) - - def test_is_directed_acyclic_graph(self): - dag = retworkx.generators.directed_path_graph(1000) - res = retworkx.is_directed_acyclic_graph(dag) - self.assertTrue(res) - - def test_is_directed_acyclic_graph_false(self): - digraph = retworkx.generators.directed_cycle_graph(1000) - self.assertFalse(retworkx.is_directed_acyclic_graph(digraph)) - - def test_add_edge_from_no_data(self): - dag = retworkx.PyDAG() - nodes = list(range(4)) - dag.add_nodes_from(nodes) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - res = dag.add_edges_from_no_data(edge_list) - self.assertEqual(len(res), 5) - self.assertEqual([None, None, None, None, None], dag.edges()) - self.assertEqual(3, dag.out_degree(0)) - self.assertEqual(0, dag.in_degree(0)) - self.assertEqual(1, dag.out_degree(1)) - self.assertEqual(1, dag.out_degree(2)) - self.assertEqual(2, dag.in_degree(3)) - - def test_add_edge_from_empty_no_data(self): - dag = retworkx.PyDAG() - res = dag.add_edges_from_no_data([]) - self.assertEqual([], res) - - def test_cycle_checking_at_init_nodes_from_no_data(self): - dag = retworkx.PyDAG(True) - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - node_c = dag.add_child(node_b, "c", {}) - with self.assertRaises(retworkx.DAGWouldCycle): - dag.add_edges_from_no_data([(node_a, node_c), (node_c, node_b)]) - - def test_edge_list(self): - dag = retworkx.PyDiGraph() - dag.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - dag.add_edges_from(edge_list) - self.assertEqual([(x[0], x[1]) for x in edge_list], dag.edge_list()) - - def test_edge_list_empty(self): - dag = retworkx.PyDiGraph() - self.assertEqual([], dag.edge_list()) - - def test_weighted_edge_list(self): - dag = retworkx.PyDiGraph() - dag.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - dag.add_edges_from(edge_list) - self.assertEqual(edge_list, dag.weighted_edge_list()) - - def test_weighted_edge_list_empty(self): - dag = retworkx.PyDiGraph() - self.assertEqual([], dag.weighted_edge_list()) - - def test_extend_from_edge_list(self): - dag = retworkx.PyDAG() - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - dag.extend_from_edge_list(edge_list) - self.assertEqual(len(dag), 4) - self.assertEqual([None] * 5, dag.edges()) - self.assertEqual(3, dag.out_degree(0)) - self.assertEqual(0, dag.in_degree(0)) - self.assertEqual(1, dag.out_degree(1)) - self.assertEqual(1, dag.out_degree(2)) - self.assertEqual(2, dag.in_degree(3)) - - def test_extend_from_edge_list_empty(self): - dag = retworkx.PyDAG() - dag.extend_from_edge_list([]) - self.assertEqual(0, len(dag)) - - def test_cycle_checking_at_init_extend_from_weighted_edge_list(self): - dag = retworkx.PyDAG(True) - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - node_c = dag.add_child(node_b, "c", {}) - with self.assertRaises(retworkx.DAGWouldCycle): - dag.extend_from_weighted_edge_list([(node_a, node_c, {}), (node_c, node_b, {})]) - - def test_extend_from_edge_list_nodes_exist(self): - dag = retworkx.PyDiGraph() - dag.add_nodes_from(list(range(4))) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - dag.extend_from_edge_list(edge_list) - self.assertEqual(len(dag), 4) - self.assertEqual([None] * 5, dag.edges()) - self.assertEqual(3, dag.out_degree(0)) - self.assertEqual(0, dag.in_degree(0)) - self.assertEqual(1, dag.out_degree(1)) - self.assertEqual(1, dag.out_degree(2)) - self.assertEqual(2, dag.in_degree(3)) - - def test_extend_from_weighted_edge_list(self): - dag = retworkx.PyDAG() - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - dag.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(dag), 4) - self.assertEqual(["a", "b", "c", "d", "e"], dag.edges()) - self.assertEqual(3, dag.out_degree(0)) - self.assertEqual(0, dag.in_degree(0)) - self.assertEqual(1, dag.out_degree(1)) - self.assertEqual(1, dag.out_degree(2)) - self.assertEqual(2, dag.in_degree(3)) - - def test_extend_from_weighted_edge_list_empty(self): - dag = retworkx.PyDAG() - dag.extend_from_weighted_edge_list([]) - self.assertEqual(0, len(dag)) - - def test_cycle_checking_at_init_nodes_extend_from_edge_list(self): - dag = retworkx.PyDAG(True) - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - node_c = dag.add_child(node_b, "c", {}) - with self.assertRaises(retworkx.DAGWouldCycle): - dag.extend_from_edge_list([(node_a, node_c), (node_c, node_b)]) - - def test_extend_from_weighted_edge_list_nodes_exist(self): - dag = retworkx.PyDiGraph() - dag.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - dag.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(dag), 4) - self.assertEqual(["a", "b", "c", "d", "e"], dag.edges()) - self.assertEqual(3, dag.out_degree(0)) - self.assertEqual(0, dag.in_degree(0)) - self.assertEqual(1, dag.out_degree(1)) - self.assertEqual(1, dag.out_degree(2)) - self.assertEqual(2, dag.in_degree(3)) - - def test_insert_node_on_in_edges(self): - graph = retworkx.PyDiGraph() - in_node = graph.add_node("qr[0]") - out_node = graph.add_child(in_node, "qr[0]", "qr[0]") - h_gate = graph.add_node("h") - graph.insert_node_on_in_edges(h_gate, out_node) - self.assertEqual( - [(in_node, h_gate, "qr[0]"), (h_gate, out_node, "qr[0]")], - graph.weighted_edge_list(), - ) - - def test_insert_node_on_in_edges_multiple(self): - graph = retworkx.PyDiGraph() - in_node_0 = graph.add_node("qr[0]") - out_node_0 = graph.add_child(in_node_0, "qr[0]", "qr[0]") - in_node_1 = graph.add_node("qr[1]") - out_node_1 = graph.add_child(in_node_1, "qr[1]", "qr[1]") - cx_gate = graph.add_node("cx") - graph.insert_node_on_in_edges_multiple(cx_gate, [out_node_0, out_node_1]) - self.assertEqual( - { - (in_node_0, cx_gate, "qr[0]"), - (cx_gate, out_node_0, "qr[0]"), - (in_node_1, cx_gate, "qr[1]"), - (cx_gate, out_node_1, "qr[1]"), - }, - set(graph.weighted_edge_list()), - ) - - def test_insert_node_on_in_edges_double(self): - graph = retworkx.PyDiGraph() - in_node = graph.add_node("qr[0]") - out_node = graph.add_child(in_node, "qr[0]", "qr[0]") - h_gate = graph.add_node("h") - z_gate = graph.add_node("z") - graph.insert_node_on_in_edges(h_gate, out_node) - graph.insert_node_on_in_edges(z_gate, out_node) - self.assertEqual( - { - (in_node, h_gate, "qr[0]"), - (h_gate, z_gate, "qr[0]"), - (z_gate, out_node, "qr[0]"), - }, - set(graph.weighted_edge_list()), - ) - - def test_insert_node_on_in_edges_multiple_double(self): - graph = retworkx.PyDiGraph() - in_node_0 = graph.add_node("qr[0]") - out_node_0 = graph.add_child(in_node_0, "qr[0]", "qr[0]") - in_node_1 = graph.add_node("qr[1]") - out_node_1 = graph.add_child(in_node_1, "qr[1]", "qr[1]") - cx_gate = graph.add_node("cx") - cz_gate = graph.add_node("cz") - graph.insert_node_on_in_edges_multiple(cx_gate, [out_node_0, out_node_1]) - graph.insert_node_on_in_edges_multiple(cz_gate, [out_node_0, out_node_1]) - self.assertEqual( - { - (in_node_0, cx_gate, "qr[0]"), - (cx_gate, cz_gate, "qr[0]"), - (in_node_1, cx_gate, "qr[1]"), - (cx_gate, cz_gate, "qr[1]"), - (cz_gate, out_node_0, "qr[0]"), - (cz_gate, out_node_1, "qr[1]"), - }, - set(graph.weighted_edge_list()), - ) - - def test_insert_node_on_out_edges(self): - graph = retworkx.PyDiGraph() - in_node = graph.add_node("qr[0]") - out_node = graph.add_child(in_node, "qr[0]", "qr[0]") - h_gate = graph.add_node("h") - graph.insert_node_on_out_edges(h_gate, in_node) - self.assertEqual( - {(in_node, h_gate, "qr[0]"), (h_gate, out_node, "qr[0]")}, - set(graph.weighted_edge_list()), - ) - - def test_insert_node_on_out_edges_multiple(self): - graph = retworkx.PyDiGraph() - in_node_0 = graph.add_node("qr[0]") - out_node_0 = graph.add_child(in_node_0, "qr[0]", "qr[0]") - in_node_1 = graph.add_node("qr[1]") - out_node_1 = graph.add_child(in_node_1, "qr[1]", "qr[1]") - cx_gate = graph.add_node("cx") - graph.insert_node_on_out_edges_multiple(cx_gate, [in_node_0, in_node_1]) - self.assertEqual( - { - (in_node_0, cx_gate, "qr[0]"), - (cx_gate, out_node_0, "qr[0]"), - (in_node_1, cx_gate, "qr[1]"), - (cx_gate, out_node_1, "qr[1]"), - }, - set(graph.weighted_edge_list()), - ) - - def test_insert_node_on_out_edges_double(self): - graph = retworkx.PyDiGraph() - in_node = graph.add_node("qr[0]") - out_node = graph.add_child(in_node, "qr[0]", "qr[0]") - h_gate = graph.add_node("h") - z_gate = graph.add_node("z") - graph.insert_node_on_out_edges(h_gate, in_node) - graph.insert_node_on_out_edges(z_gate, in_node) - self.assertEqual( - { - (in_node, z_gate, "qr[0]"), - (z_gate, h_gate, "qr[0]"), - (h_gate, out_node, "qr[0]"), - }, - set(graph.weighted_edge_list()), - ) - - def test_insert_node_on_out_edges_multiple_double(self): - graph = retworkx.PyDiGraph() - in_node_0 = graph.add_node("qr[0]") - out_node_0 = graph.add_child(in_node_0, "qr[0]", "qr[0]") - in_node_1 = graph.add_node("qr[1]") - out_node_1 = graph.add_child(in_node_1, "qr[1]", "qr[1]") - cx_gate = graph.add_node("cx") - cz_gate = graph.add_node("cz") - graph.insert_node_on_out_edges_multiple(cx_gate, [in_node_0, in_node_1]) - graph.insert_node_on_out_edges_multiple(cz_gate, [in_node_0, in_node_1]) - self.assertEqual( - { - (in_node_0, cz_gate, "qr[0]"), - (cz_gate, cx_gate, "qr[0]"), - (in_node_1, cz_gate, "qr[1]"), - (cz_gate, cx_gate, "qr[1]"), - (cx_gate, out_node_0, "qr[0]"), - (cx_gate, out_node_1, "qr[1]"), - }, - set(graph.weighted_edge_list()), - ) - - def test_insert_node_on_in_edges_no_edges(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(None) - node_b = graph.add_node(None) - graph.insert_node_on_in_edges(node_b, node_a) - self.assertEqual([], graph.edge_list()) - - def test_insert_node_on_in_edges_multiple_no_edges(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(None) - node_b = graph.add_node(None) - graph.insert_node_on_in_edges_multiple(node_b, [node_a]) - self.assertEqual([], graph.edge_list()) - - def test_insert_node_on_out_edges_no_edges(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(None) - node_b = graph.add_node(None) - graph.insert_node_on_out_edges(node_b, node_a) - self.assertEqual([], graph.edge_list()) - - def test_insert_node_on_out_edges_multiple_no_edges(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(None) - node_b = graph.add_node(None) - graph.insert_node_on_out_edges_multiple(node_b, [node_a]) - self.assertEqual([], graph.edge_list()) - - def test_edge_index_map(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(0) - node_b = graph.add_node(1) - node_c = graph.add_child(node_a, "c", "edge a") - node_d = graph.add_parent(node_b, "d", "edge_b") - graph.add_edge(node_c, node_d, "edge c") - self.assertEqual( - { - 0: (node_a, node_c, "edge a"), - 1: (node_d, node_b, "edge_b"), - 2: (node_c, node_d, "edge c"), - }, - graph.edge_index_map(), - ) - - def test_edge_index_map_empty(self): - graph = retworkx.PyDiGraph() - self.assertEqual({}, graph.edge_index_map()) - - def test_has_parallel_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from([0, 1]) - graph.add_edge(0, 1, None) - graph.add_edge(0, 1, 0) - self.assertTrue(graph.has_parallel_edges()) - - def test_has_parallel_edges_no_parallel_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from([0, 1]) - graph.add_edge(0, 1, None) - self.assertFalse(graph.has_parallel_edges()) - - def test_has_parallel_edges_empty(self): - graph = retworkx.PyDiGraph() - self.assertFalse(graph.has_parallel_edges()) - - def test_get_edge_data_by_index(self): - graph = retworkx.PyDiGraph() - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - res = graph.get_edge_data_by_index(2) - self.assertEqual("c", res) - - def test_get_edge_data_by_index_invalid_index(self): - graph = retworkx.PyDiGraph() - with self.assertRaisesRegex( - IndexError, "Provided edge index 2 is not present in the graph" - ): - graph.get_edge_data_by_index(2) - - def test_get_edge_endpoints_by_index(self): - graph = retworkx.PyDiGraph() - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - res = graph.get_edge_endpoints_by_index(2) - self.assertEqual((0, 2), res) - - def test_get_edge_endpoints_by_index_invalid_index(self): - graph = retworkx.PyDiGraph() - with self.assertRaisesRegex( - IndexError, "Provided edge index 2 is not present in the graph" - ): - graph.get_edge_endpoints_by_index(2) - - def test_incident_edges(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(0) - node_b = graph.add_node(1) - node_c = graph.add_node("c") - node_d = graph.add_node("d") - graph.add_edge(node_a, node_c, "edge a") - graph.add_edge(node_b, node_d, "edge_b") - graph.add_edge(node_d, node_c, "edge c") - res = graph.incident_edges(node_d) - self.assertEqual([2], res) - - def test_incident_edges_invalid_node(self): - graph = retworkx.PyDiGraph() - res = graph.incident_edges(42) - self.assertEqual([], res) - - def test_incident_edges_all_edges(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(0) - node_b = graph.add_node(1) - node_c = graph.add_node("c") - node_d = graph.add_node("d") - graph.add_edge(node_a, node_c, "edge a") - graph.add_edge(node_b, node_d, "edge_b") - graph.add_edge(node_d, node_c, "edge c") - res = graph.incident_edges(node_d, all_edges=True) - self.assertEqual([2, 1], res) - - def test_incident_edge_index_map(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(0) - node_b = graph.add_node(1) - node_c = graph.add_node("c") - node_d = graph.add_node("d") - graph.add_edge(node_a, node_c, "edge a") - graph.add_edge(node_b, node_d, "edge_b") - graph.add_edge(node_d, node_c, "edge c") - res = graph.incident_edge_index_map(node_d) - self.assertEqual({2: (3, 2, "edge c")}, res) - - def test_incident_edge_index_map_invalid_node(self): - graph = retworkx.PyDiGraph() - res = graph.incident_edge_index_map(42) - self.assertEqual([], res) - - def test_incident_edge_index_map_all_edges(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(0) - node_b = graph.add_node(1) - node_c = graph.add_node("c") - node_d = graph.add_node("d") - graph.add_edge(node_a, node_c, "edge a") - graph.add_edge(node_b, node_d, "edge_b") - graph.add_edge(node_d, node_c, "edge c") - res = graph.incident_edge_index_map(node_d, all_edges=True) - self.assertEqual({2: (3, 2, "edge c"), 1: (1, 3, "edge_b")}, res) - - -class TestEdgesMultigraphFalse(unittest.TestCase): - def test_multigraph_attr(self): - graph = retworkx.PyDiGraph(multigraph=False) - self.assertFalse(graph.multigraph) - - def test_has_parallel_edges(self): - graph = retworkx.PyDiGraph(multigraph=False) - graph.add_nodes_from([0, 1]) - graph.add_edge(0, 1, None) - graph.add_edge(0, 1, 0) - self.assertFalse(graph.has_parallel_edges()) - - def test_get_edge_data(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - res = graph.get_edge_data(node_a, node_b) - self.assertEqual("Edgy", res) - - def test_get_all_edge_data(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - graph.add_edge(node_a, node_b, "b") - res = graph.get_all_edge_data(node_a, node_b) - self.assertIn("b", res) - self.assertNotIn("Edgy", res) - - def test_no_edge(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.get_edge_data, node_a, node_b) - - def test_no_edge_get_all_edge_data(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.get_all_edge_data, node_a, node_b) - - def test_has_edge(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, {}) - self.assertTrue(graph.has_edge(node_a, node_b)) - - def test_has_edge_no_edge(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertFalse(graph.has_edge(node_a, node_b)) - - def test_edges(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Super edgy") - self.assertEqual(["Edgy", "Super edgy"], graph.edges()) - - def test_edges_empty(self): - graph = retworkx.PyDiGraph(multigraph=False) - graph.add_node("a") - self.assertEqual([], graph.edges()) - - def test_add_duplicates(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "a") - graph.add_edge(node_a, node_b, "b") - self.assertEqual(["b"], graph.edges()) - - def test_remove_no_edge(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.remove_edge, node_a, node_b) - - def test_remove_edge_single(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.remove_edge(node_a, node_b) - self.assertEqual([], graph.edges()) - - def test_remove_multiple(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.add_edge(node_a, node_b, "super_edgy") - graph.remove_edge_from_index(0) - self.assertEqual([], graph.edges()) - - def test_remove_edge_from_index(self): - graph = retworkx.PyDiGraph(multigraph=False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.remove_edge_from_index(0) - self.assertEqual([], graph.edges()) - - def test_remove_edge_no_edge(self): - graph = retworkx.PyDiGraph(multigraph=False) - graph.add_node("a") - graph.remove_edge_from_index(0) - self.assertEqual([], graph.edges()) - - def test_add_edge_from_empty(self): - graph = retworkx.PyDiGraph(multigraph=False) - res = graph.add_edges_from([]) - self.assertEqual([], res) - - def test_add_edge_from_empty_no_data(self): - graph = retworkx.PyDiGraph(multigraph=False) - res = graph.add_edges_from_no_data([]) - self.assertEqual([], res) - - def test_add_edges_from_parallel_edges(self): - graph = retworkx.PyDiGraph(multigraph=False) - graph.add_nodes_from([0, 1]) - res = graph.add_edges_from([(0, 1, False), (0, 1, True)]) - self.assertEqual([0, 0], res) - self.assertEqual([True], graph.edges()) - - def test_add_edges_from_no_data_parallel_edges(self): - graph = retworkx.PyDiGraph(multigraph=False) - graph.add_nodes_from([0, 1]) - res = graph.add_edges_from_no_data([(0, 1), (0, 1)]) - self.assertEqual([0, 0], res) - self.assertEqual([None], graph.edges()) - - def test_extend_from_weighted_edge_list_empty(self): - graph = retworkx.PyDiGraph() - graph.extend_from_weighted_edge_list([]) - self.assertEqual(0, len(graph)) - - def test_extend_from_weighted_edge_list_nodes_exist(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual(["a", "b", "c", "d", "e"], graph.edges()) - - def test_extend_from_weighted_edge_list_edges_exist(self): - graph = retworkx.PyDiGraph(multigraph=False) - graph.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - (0, 1, "not_a"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual(["not_a", "b", "c", "d", "e"], graph.edges()) - - def test_extend_from_edge_list(self): - graph = retworkx.PyDiGraph(multigraph=False) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - graph.extend_from_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual([None] * 5, graph.edges()) - - def test_extend_from_edge_list_empty(self): - graph = retworkx.PyDiGraph(multigraph=False) - graph.extend_from_edge_list([]) - self.assertEqual(0, len(graph)) - - def test_extend_from_edge_list_existing_edge(self): - graph = retworkx.PyDiGraph(multigraph=False) - graph.add_nodes_from(list(range(4))) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3), (0, 1)] - graph.extend_from_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual([None] * 5, graph.edges()) - - def test_extend_from_weighted_edge_list(self): - graph = retworkx.PyDiGraph(multigraph=False) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual(["a", "b", "c", "d", "e"], graph.edges()) diff --git a/tests/retworkx_backwards_compat/digraph/test_find_cycle.py b/tests/retworkx_backwards_compat/digraph/test_find_cycle.py deleted file mode 100644 index 6ecdf77e3..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_find_cycle.py +++ /dev/null @@ -1,72 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestFindCycle(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.graph.add_nodes_from(list(range(10))) - self.graph.add_edges_from_no_data( - [ - (0, 1), - (3, 0), - (0, 5), - (8, 0), - (1, 2), - (1, 6), - (2, 3), - (3, 4), - (4, 5), - (6, 7), - (7, 8), - (8, 9), - ] - ) - - def test_find_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(6))) - graph.add_edges_from_no_data( - [(0, 1), (0, 3), (0, 5), (1, 2), (2, 3), (3, 4), (4, 5), (4, 0)] - ) - res = retworkx.digraph_find_cycle(graph, 0) - self.assertEqual([(0, 1), (1, 2), (2, 3), (3, 4), (4, 0)], res) - - def test_find_cycle_multiple_roots_same_cycles(self): - res = retworkx.digraph_find_cycle(self.graph, 0) - self.assertEqual(res, [(0, 1), (1, 2), (2, 3), (3, 0)]) - res = retworkx.digraph_find_cycle(self.graph, 1) - self.assertEqual(res, [(1, 2), (2, 3), (3, 0), (0, 1)]) - res = retworkx.digraph_find_cycle(self.graph, 5) - self.assertEqual(res, []) - - def test_find_cycle_disconnected_graphs(self): - self.graph.add_nodes_from(["A", "B", "C"]) - self.graph.add_edges_from_no_data([(10, 11), (12, 10), (11, 12)]) - res = retworkx.digraph_find_cycle(self.graph, 0) - self.assertEqual(res, [(0, 1), (1, 2), (2, 3), (3, 0)]) - res = retworkx.digraph_find_cycle(self.graph, 10) - self.assertEqual(res, [(10, 11), (11, 12), (12, 10)]) - - def test_invalid_types(self): - graph = retworkx.PyGraph() - with self.assertRaises(TypeError): - retworkx.digraph_find_cycle(graph) - - def test_self_loop(self): - self.graph.add_edge(1, 1, None) - res = retworkx.digraph_find_cycle(self.graph, 0) - self.assertEqual([(1, 1)], res) diff --git a/tests/retworkx_backwards_compat/digraph/test_floyd_warshall.py b/tests/retworkx_backwards_compat/digraph/test_floyd_warshall.py deleted file mode 100644 index 1643eb5dc..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_floyd_warshall.py +++ /dev/null @@ -1,294 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import numpy - -import retworkx - - -class TestFloydWarshall(unittest.TestCase): - parallel_threshold = 300 - - def test_floyd_warshall(self): - """Test the algorithm on a 5q x 4 depth circuit.""" - dag = retworkx.PyDAG() - # inputs - qr_0 = dag.add_node("qr[0]") - qr_1 = dag.add_node("qr[1]") - qr_2 = dag.add_node("qr[2]") - cr_0 = dag.add_node("cr[0]") - cr_1 = dag.add_node("cr[1]") - # wires - cx_1 = dag.add_node("cx_1") - dag.add_edge(qr_0, cx_1, "qr[0]") - dag.add_edge(qr_1, cx_1, "qr[1]") - h_1 = dag.add_node("h_1") - dag.add_edge(cx_1, h_1, "qr[0]") - cx_2 = dag.add_node("cx_2") - dag.add_edge(cx_1, cx_2, "qr[1]") - dag.add_edge(qr_2, cx_2, "qr[2]") - cx_3 = dag.add_node("cx_3") - dag.add_edge(h_1, cx_3, "qr[0]") - dag.add_edge(cx_2, cx_3, "qr[2]") - h_2 = dag.add_node("h_2") - dag.add_edge(cx_3, h_2, "qr[2]") - # # outputs - qr_0_out = dag.add_node("qr[0]_out") - dag.add_edge(cx_3, qr_0_out, "qr[0]") - qr_1_out = dag.add_node("qr[1]_out") - dag.add_edge(cx_2, qr_1_out, "qr[1]") - qr_2_out = dag.add_node("qr[2]_out") - dag.add_edge(h_2, qr_2_out, "qr[2]") - cr_0_out = dag.add_node("cr[0]_out") - dag.add_edge(cr_0, cr_0_out, "qr[2]") - cr_1_out = dag.add_node("cr[1]_out") - dag.add_edge(cr_1, cr_1_out, "cr[1]") - - result = retworkx.floyd_warshall(dag) - expected = { - 0: {0: 0, 5: 1, 6: 2, 7: 2, 8: 3, 9: 4, 10: 4, 11: 3, 12: 5}, - 1: {1: 0, 5: 1, 6: 2, 7: 2, 8: 3, 9: 4, 10: 4, 11: 3, 12: 5}, - 2: {2: 0, 7: 1, 8: 2, 9: 3, 10: 3, 11: 2, 12: 4}, - 3: {3: 0, 13: 1}, - 4: {4: 0, 14: 1}, - 5: {5: 0, 6: 1, 7: 1, 8: 2, 9: 3, 10: 3, 11: 2, 12: 4}, - 6: {6: 0, 8: 1, 9: 2, 10: 2, 12: 3}, - 7: {7: 0, 8: 1, 9: 2, 10: 2, 11: 1, 12: 3}, - 8: {8: 0, 9: 1, 10: 1, 12: 2}, - 9: {9: 0, 12: 1}, - 10: {10: 0}, - 11: {11: 0}, - 12: {12: 0}, - 13: {13: 0}, - 14: {14: 0}, - } - - self.assertEqual(result, expected) - - def test_vs_dijkstra_all_pairs(self): - graph = retworkx.PyDiGraph() - a = graph.add_node("A") - b = graph.add_node("B") - c = graph.add_node("C") - d = graph.add_node("D") - e = graph.add_node("E") - f = graph.add_node("F") - edge_list = [ - (a, b, 7), - (c, a, 9), - (a, d, 14), - (b, c, 10), - (d, c, 2), - (d, e, 9), - (b, f, 15), - (c, f, 11), - (e, f, 6), - ] - graph.add_edges_from(edge_list) - - dijkstra_lengths = retworkx.digraph_all_pairs_dijkstra_path_lengths(graph, float) - - expected = {k: {**v, k: 0.0} for k, v in dijkstra_lengths.items()} - - result = retworkx.digraph_floyd_warshall( - graph, float, parallel_threshold=self.parallel_threshold - ) - - self.assertEqual(result, expected) - - def test_vs_dijkstra_all_pairs_with_node_removal(self): - graph = retworkx.PyDiGraph() - a = graph.add_node("A") - b = graph.add_node("B") - c = graph.add_node("C") - d = graph.add_node("D") - e = graph.add_node("E") - f = graph.add_node("F") - edge_list = [ - (a, b, 7), - (c, a, 9), - (a, d, 14), - (b, c, 10), - (d, c, 2), - (d, e, 9), - (b, f, 15), - (c, f, 11), - (e, f, 6), - ] - graph.add_edges_from(edge_list) - graph.remove_node(d) - - dijkstra_lengths = retworkx.digraph_all_pairs_dijkstra_path_lengths(graph, float) - - expected = {k: {**v, k: 0.0} for k, v in dijkstra_lengths.items()} - - result = retworkx.digraph_floyd_warshall( - graph, float, parallel_threshold=self.parallel_threshold - ) - - self.assertEqual(result, expected) - - def test_floyd_warshall_empty_graph(self): - graph = retworkx.PyDiGraph() - self.assertEqual({}, retworkx.digraph_floyd_warshall(graph, float)) - - def test_floyd_warshall_graph_no_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.digraph_floyd_warshall(graph, float), - ) - - def test_directed_floyd_warshall_cycle_as_undirected(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.digraph_floyd_warshall( - graph, - lambda _: 1, - as_undirected=True, - parallel_threshold=self.parallel_threshold, - ) - expected = { - 0: {0: 0.0, 1: 1.0, 2: 2.0, 3: 3.0, 4: 3.0, 5: 2.0, 6: 1.0}, - 1: {0: 1.0, 1: 0.0, 2: 1.0, 3: 2.0, 4: 3.0, 5: 3.0, 6: 2.0}, - 2: {0: 2.0, 1: 1.0, 2: 0.0, 3: 1.0, 4: 2.0, 5: 3.0, 6: 3.0}, - 3: {0: 3.0, 1: 2.0, 2: 1.0, 3: 0.0, 4: 1.0, 5: 2.0, 6: 3.0}, - 4: {0: 3.0, 1: 3.0, 2: 2.0, 3: 1.0, 4: 0.0, 5: 1.0, 6: 2.0}, - 5: {0: 2.0, 1: 3.0, 2: 3.0, 3: 2.0, 4: 1.0, 5: 0.0, 6: 1.0}, - 6: {0: 1.0, 1: 2.0, 2: 3.0, 3: 3.0, 4: 2.0, 5: 1.0, 6: 0.0}, - } - self.assertEqual(dist, expected) - - def test_directed_floyd_warshall_numpy_cycle_as_undirected(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.digraph_floyd_warshall_numpy(graph, lambda x: 1, as_undirected=True) - expected = numpy.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0], - ] - ) - self.assertTrue(numpy.array_equal(dist, expected)) - - def test_floyd_warshall_numpy_digraph_three_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(6))) - weights = [2, 12, 1, 5, 1] - graph.add_edges_from([(i, i + 1, weights[i]) for i in range(5)]) - graph.add_edge(5, 0, 10) - dist = retworkx.digraph_floyd_warshall_numpy( - graph, lambda x: x, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 3], 15) - self.assertEqual(dist[3, 0], 16) - - def test_weighted_numpy_digraph_two_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(8))) - graph.add_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 = retworkx.digraph_floyd_warshall_numpy( - graph, lambda x: x, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 2], 4) - self.assertEqual(dist[2, 0], 6) - - def test_floyd_warshall_numpy_digraph_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.digraph_floyd_warshall_numpy( - graph, lambda x: 1, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 3], 3) - self.assertEqual(dist[0, 4], 4) - - def test_weighted_numpy_directed_negative_cycle(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - dist = retworkx.digraph_floyd_warshall_numpy(graph, lambda x: x) - self.assertTrue(numpy.all(numpy.diag(dist) < 0)) - - def test_numpy_directed_no_edges(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - dist = retworkx.digraph_floyd_warshall_numpy( - graph, lambda x: x, parallel_threshold=self.parallel_threshold - ) - expected = numpy.full((4, 4), numpy.inf) - numpy.fill_diagonal(expected, 0) - self.assertTrue(numpy.array_equal(dist, expected)) - - def test_floyd_warshall_numpy_digraph_cycle_with_removals(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(8))) - graph.remove_node(0) - graph.add_edges_from_no_data([(1, 2), (1, 7), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]) - dist = retworkx.digraph_floyd_warshall_numpy( - graph, lambda x: 1, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 3], 3) - self.assertEqual(dist[0, 4], 4) - - def test_floyd_warshall_numpy_digraph_cycle_no_weight_fn(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(8))) - graph.remove_node(0) - graph.add_edges_from_no_data([(1, 2), (1, 7), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]) - dist = retworkx.digraph_floyd_warshall_numpy(graph) - self.assertEqual(dist[0, 3], 3) - self.assertEqual(dist[0, 4], 4) - - def test_floyd_warshall_numpy_digraph_cycle_default_weight(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(8))) - graph.remove_node(0) - graph.add_edges_from_no_data([(1, 2), (1, 7), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]) - dist = retworkx.digraph_floyd_warshall_numpy( - graph, default_weight=2, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 3], 6) - self.assertEqual(dist[0, 4], 8) - - -class TestParallelFloydWarshall(TestFloydWarshall): - parallel_threshold = 0 diff --git a/tests/retworkx_backwards_compat/digraph/test_graph_attrs.py b/tests/retworkx_backwards_compat/digraph/test_graph_attrs.py deleted file mode 100644 index 348ef3e88..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_graph_attrs.py +++ /dev/null @@ -1,31 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestAttributes(unittest.TestCase): - def test_no_attrs(self): - graph = retworkx.PyDiGraph() - self.assertIsNone(graph.attrs) - - def test_attrs_set_at_init(self): - graph = retworkx.PyDiGraph(attrs=dict(foo="bar")) - self.assertEqual({"foo": "bar"}, graph.attrs) - - def test_attrs_set_at_init_override(self): - graph = retworkx.PyDiGraph(attrs=dict(foo="bar")) - self.assertEqual({"foo": "bar"}, graph.attrs) - graph.attrs = "ABC" - self.assertEqual("ABC", graph.attrs) diff --git a/tests/retworkx_backwards_compat/digraph/test_isomorphic.py b/tests/retworkx_backwards_compat/digraph/test_isomorphic.py deleted file mode 100644 index ce1e06785..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_isomorphic.py +++ /dev/null @@ -1,350 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import unittest - -import retworkx - - -class TestIsomorphic(unittest.TestCase): - def test_empty_isomorphic(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_isomorphic(dag_a, dag_b, id_order=id_order)) - - def test_empty_isomorphic_compare_nodes(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic(dag_a, dag_b, lambda x, y: x == y, id_order=id_order) - ) - - def test_isomorphic_identical(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "a_1") - dag_a.add_child(node_a, "a_3", "a_2") - - node_b = dag_b.add_node("a_1") - dag_b.add_child(node_b, "a_2", "a_1") - dag_b.add_child(node_b, "a_3", "a_2") - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_isomorphic(dag_a, dag_b, id_order=id_order)) - - def test_isomorphic_mismatch_node_data(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "a_1") - dag_a.add_child(node_a, "a_3", "a_2") - - node_b = dag_b.add_node("b_1") - dag_b.add_child(node_b, "b_2", "b_1") - dag_b.add_child(node_b, "b_3", "b_2") - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_isomorphic(dag_a, dag_b, id_order=id_order)) - - def test_isomorphic_compare_nodes_mismatch_node_data(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "a_1") - dag_a.add_child(node_a, "a_3", "a_2") - - node_b = dag_b.add_node("b_1") - dag_b.add_child(node_b, "b_2", "b_1") - dag_b.add_child(node_b, "b_3", "b_2") - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertFalse( - retworkx.is_isomorphic(dag_a, dag_b, lambda x, y: x == y, id_order=id_order) - ) - - def test_is_isomorphic_nodes_compare_raises(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "a_1") - dag_a.add_child(node_a, "a_3", "a_2") - - node_b = dag_b.add_node("b_1") - dag_b.add_child(node_b, "b_2", "b_1") - dag_b.add_child(node_b, "b_3", "b_2") - - def compare_nodes(a, b): - raise TypeError("Failure") - - self.assertRaises(TypeError, retworkx.is_isomorphic, (dag_a, dag_b, compare_nodes)) - - def test_isomorphic_compare_nodes_identical(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "a_1") - dag_a.add_child(node_a, "a_3", "a_2") - - node_b = dag_b.add_node("a_1") - dag_b.add_child(node_b, "a_2", "a_1") - dag_b.add_child(node_b, "a_3", "a_2") - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic(dag_a, dag_b, lambda x, y: x == y, id_order=id_order) - ) - - def test_isomorphic_compare_edges_identical(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "a_1") - dag_a.add_child(node_a, "a_3", "a_2") - - node_b = dag_b.add_node("a_1") - dag_b.add_child(node_b, "a_2", "a_1") - dag_b.add_child(node_b, "a_3", "a_2") - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic( - dag_a, - dag_b, - edge_matcher=lambda x, y: x == y, - id_order=id_order, - ) - ) - - def test_isomorphic_compare_nodes_with_removals(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - qr_0_in = dag_a.add_node("qr[0]") - qr_1_in = dag_a.add_node("qr[1]") - cr_0_in = dag_a.add_node("cr[0]") - qr_0_out = dag_a.add_node("qr[0]") - qr_1_out = dag_a.add_node("qr[1]") - cr_0_out = dag_a.add_node("qr[0]") - cu1 = dag_a.add_child(qr_0_in, "cu1", "qr[0]") - dag_a.add_edge(qr_1_in, cu1, "qr[1]") - measure_0 = dag_a.add_child(cr_0_in, "measure", "cr[0]") - dag_a.add_edge(cu1, measure_0, "qr[0]") - measure_1 = dag_a.add_child(cu1, "measure", "qr[1]") - dag_a.add_edge(measure_0, measure_1, "cr[0]") - dag_a.add_edge(measure_1, qr_1_out, "qr[1]") - dag_a.add_edge(measure_1, cr_0_out, "cr[0]") - dag_a.add_edge(measure_0, qr_0_out, "qr[0]") - dag_a.remove_node(cu1) - dag_a.add_edge(qr_0_in, measure_0, "qr[0]") - dag_a.add_edge(qr_1_in, measure_1, "qr[1]") - - qr_0_in = dag_b.add_node("qr[0]") - qr_1_in = dag_b.add_node("qr[1]") - cr_0_in = dag_b.add_node("cr[0]") - qr_0_out = dag_b.add_node("qr[0]") - qr_1_out = dag_b.add_node("qr[1]") - cr_0_out = dag_b.add_node("qr[0]") - measure_0 = dag_b.add_child(cr_0_in, "measure", "cr[0]") - dag_b.add_edge(qr_0_in, measure_0, "qr[0]") - measure_1 = dag_b.add_child(qr_1_in, "measure", "qr[1]") - dag_b.add_edge(measure_1, qr_1_out, "qr[1]") - dag_b.add_edge(measure_1, cr_0_out, "cr[0]") - dag_b.add_edge(measure_0, measure_1, "cr[0]") - dag_b.add_edge(measure_0, qr_0_out, "qr[0]") - - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic(dag_a, dag_b, lambda x, y: x == y, id_order=id_order) - ) - - def test_isomorphic_compare_nodes_with_removals_deepcopy(self): - dag_a = retworkx.PyDAG() - dag_b = retworkx.PyDAG() - - qr_0_in = dag_a.add_node("qr[0]") - qr_1_in = dag_a.add_node("qr[1]") - cr_0_in = dag_a.add_node("cr[0]") - qr_0_out = dag_a.add_node("qr[0]") - qr_1_out = dag_a.add_node("qr[1]") - cr_0_out = dag_a.add_node("qr[0]") - cu1 = dag_a.add_child(qr_0_in, "cu1", "qr[0]") - dag_a.add_edge(qr_1_in, cu1, "qr[1]") - measure_0 = dag_a.add_child(cr_0_in, "measure", "cr[0]") - dag_a.add_edge(cu1, measure_0, "qr[0]") - measure_1 = dag_a.add_child(cu1, "measure", "qr[1]") - dag_a.add_edge(measure_0, measure_1, "cr[0]") - dag_a.add_edge(measure_1, qr_1_out, "qr[1]") - dag_a.add_edge(measure_1, cr_0_out, "cr[0]") - dag_a.add_edge(measure_0, qr_0_out, "qr[0]") - dag_a.remove_node(cu1) - dag_a.add_edge(qr_0_in, measure_0, "qr[0]") - dag_a.add_edge(qr_1_in, measure_1, "qr[1]") - - qr_0_in = dag_b.add_node("qr[0]") - qr_1_in = dag_b.add_node("qr[1]") - cr_0_in = dag_b.add_node("cr[0]") - qr_0_out = dag_b.add_node("qr[0]") - qr_1_out = dag_b.add_node("qr[1]") - cr_0_out = dag_b.add_node("qr[0]") - measure_0 = dag_b.add_child(cr_0_in, "measure", "cr[0]") - dag_b.add_edge(qr_0_in, measure_0, "qr[0]") - measure_1 = dag_b.add_child(qr_1_in, "measure", "qr[1]") - dag_b.add_edge(measure_1, qr_1_out, "qr[1]") - dag_b.add_edge(measure_1, cr_0_out, "cr[0]") - dag_b.add_edge(measure_0, measure_1, "cr[0]") - dag_b.add_edge(measure_0, qr_0_out, "qr[0]") - - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic( - copy.deepcopy(dag_a), - copy.deepcopy(dag_b), - lambda x, y: x == y, - id_order=id_order, - ) - ) - - def test_digraph_isomorphic_parallel_edges_with_edge_matcher(self): - graph = retworkx.PyDiGraph() - graph.extend_from_weighted_edge_list([(0, 1, "a"), (0, 1, "b"), (1, 2, "c")]) - self.assertTrue(retworkx.is_isomorphic(graph, graph, edge_matcher=lambda x, y: x == y)) - - def test_digraph_isomorphic_self_loop(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from([0]) - graph.add_edges_from([(0, 0, "a")]) - self.assertTrue(retworkx.is_isomorphic(graph, graph)) - - def test_digraph_non_isomorphic_edge_mismatch_self_loop(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from([0]) - graph.add_edges_from([(0, 0, "a")]) - second_graph = retworkx.PyDiGraph() - second_graph.add_nodes_from([0]) - second_graph.add_edges_from([(0, 0, "b")]) - self.assertFalse( - retworkx.is_isomorphic(graph, second_graph, edge_matcher=lambda x, y: x == y) - ) - - def test_digraph_non_isomorphic_rule_out_incoming(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from([0, 1, 2, 3]) - graph.add_edges_from_no_data([(0, 1), (0, 2), (2, 1)]) - second_graph = retworkx.PyDiGraph() - second_graph.add_nodes_from([0, 1, 2, 3]) - second_graph.add_edges_from_no_data([(0, 1), (0, 2), (3, 1)]) - self.assertFalse(retworkx.is_isomorphic(graph, second_graph, id_order=True)) - - def test_digraph_non_isomorphic_rule_ins_outgoing(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from([0, 1, 2, 3]) - graph.add_edges_from_no_data([(1, 0), (2, 0), (1, 2)]) - second_graph = retworkx.PyDiGraph() - second_graph.add_nodes_from([0, 1, 2, 3]) - second_graph.add_edges_from_no_data([(1, 0), (2, 0), (1, 3)]) - self.assertFalse(retworkx.is_isomorphic(graph, second_graph, id_order=True)) - - def test_digraph_non_isomorphic_rule_ins_incoming(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from([0, 1, 2, 3]) - graph.add_edges_from_no_data([(1, 0), (2, 0), (2, 1)]) - second_graph = retworkx.PyDiGraph() - second_graph.add_nodes_from([0, 1, 2, 3]) - second_graph.add_edges_from_no_data([(1, 0), (2, 0), (3, 1)]) - self.assertFalse(retworkx.is_isomorphic(graph, second_graph, id_order=True)) - - def test_isomorphic_parallel_edges(self): - first = retworkx.PyDiGraph() - first.extend_from_edge_list([(0, 1), (0, 1), (1, 2), (2, 3)]) - second = retworkx.PyDiGraph() - second.extend_from_edge_list([(0, 1), (1, 2), (1, 2), (2, 3)]) - self.assertFalse(retworkx.is_isomorphic(first, second)) - - def test_digraph_isomorphic_insufficient_call_limit(self): - graph = retworkx.generators.directed_path_graph(5) - self.assertFalse(retworkx.is_isomorphic(graph, graph, call_limit=2)) - - def test_digraph_vf2_mapping_identical(self): - graph = retworkx.generators.directed_grid_graph(2, 2) - second_graph = retworkx.generators.directed_grid_graph(2, 2) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph) - self.assertEqual(next(mapping), {0: 0, 1: 1, 2: 2, 3: 3}) - - def test_digraph_vf2_mapping_identical_removals(self): - graph = retworkx.generators.directed_path_graph(2) - second_graph = retworkx.generators.directed_path_graph(4) - second_graph.remove_nodes_from([1, 2]) - second_graph.add_edge(0, 3, None) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph) - self.assertEqual({0: 0, 1: 3}, next(mapping)) - - def test_digraph_vf2_mapping_identical_removals_first(self): - second_graph = retworkx.generators.directed_path_graph(2) - graph = retworkx.generators.directed_path_graph(4) - graph.remove_nodes_from([1, 2]) - graph.add_edge(0, 3, None) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph) - self.assertEqual({0: 0, 3: 1}, next(mapping)) - - def test_digraph_vf2_mapping_identical_vf2pp(self): - graph = retworkx.generators.directed_grid_graph(2, 2) - second_graph = retworkx.generators.directed_grid_graph(2, 2) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph, id_order=False) - self.assertEqual(next(mapping), {0: 0, 1: 1, 2: 2, 3: 3}) - - def test_digraph_vf2_mapping_identical_removals_vf2pp(self): - graph = retworkx.generators.directed_path_graph(2) - second_graph = retworkx.generators.directed_path_graph(4) - second_graph.remove_nodes_from([1, 2]) - second_graph.add_edge(0, 3, None) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph, id_order=False) - self.assertEqual({0: 0, 1: 3}, next(mapping)) - - def test_digraph_vf2_mapping_identical_removals_first_vf2pp(self): - second_graph = retworkx.generators.directed_path_graph(2) - graph = retworkx.generators.directed_path_graph(4) - graph.remove_nodes_from([1, 2]) - graph.add_edge(0, 3, None) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph, id_order=False) - self.assertEqual({0: 0, 3: 1}, next(mapping)) - - def test_digraph_vf2_number_of_valid_mappings(self): - graph = retworkx.generators.directed_mesh_graph(3) - mapping = retworkx.digraph_vf2_mapping(graph, graph, id_order=True) - total = 0 - for _ in mapping: - total += 1 - self.assertEqual(total, 6) - - def test_empty_digraph_vf2_mapping(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - mapping = retworkx.digraph_vf2_mapping(g_a, g_b, id_order=id_order, subgraph=False) - self.assertEqual({}, next(mapping)) diff --git a/tests/retworkx_backwards_compat/digraph/test_k_shortest_path.py b/tests/retworkx_backwards_compat/digraph/test_k_shortest_path.py deleted file mode 100644 index 1a788441b..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_k_shortest_path.py +++ /dev/null @@ -1,96 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestKShortestpath(unittest.TestCase): - def test_digraph_k_shortest_path_lengths(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(8))) - graph.add_edges_from_no_data( - [ - (0, 1), - (1, 2), - (2, 3), - (3, 0), - (4, 5), - (1, 4), - (5, 6), - (6, 7), - (7, 5), - ] - ) - res = retworkx.digraph_k_shortest_path_lengths(graph, 1, 2, lambda _: 1) - expected = { - 0: 7.0, - 1: 4.0, - 2: 5.0, - 3: 6.0, - 4: 5.0, - 5: 5.0, - 6: 6.0, - 7: 7.0, - } - self.assertEqual(res, expected) - - def test_digraph_k_shortest_path_lengths_with_goal(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(8))) - graph.add_edges_from_no_data( - [ - (0, 1), - (1, 2), - (2, 3), - (3, 0), - (4, 5), - (1, 4), - (5, 6), - (6, 7), - (7, 5), - ] - ) - res = retworkx.digraph_k_shortest_path_lengths(graph, 1, 2, lambda _: 1, 3) - self.assertEqual(res, {3: 6}) - - def test_digraph_k_shortest_path_with_goal_node_hole(self): - graph = retworkx.generators.directed_path_graph(4) - graph.remove_node(0) - res = retworkx.digraph_k_shortest_path_lengths( - graph, start=1, k=1, edge_cost=lambda _: 1, goal=3 - ) - self.assertEqual({3: 2}, res) - - def test_digraph_k_shortest_path_with_invalid_weight(self): - graph = retworkx.generators.directed_path_graph(4) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.digraph_k_shortest_path_lengths( - graph, - start=1, - k=1, - edge_cost=lambda _: invalid_weight, - goal=3, - ) - - def test_k_shortest_path_with_no_path(self): - g = retworkx.PyDiGraph() - a = g.add_node("A") - b = g.add_node("B") - path_lenghts = retworkx.digraph_k_shortest_path_lengths( - g, start=a, k=1, edge_cost=float, goal=b - ) - expected = {} - self.assertEqual(expected, path_lenghts) diff --git a/tests/retworkx_backwards_compat/digraph/test_layers.py b/tests/retworkx_backwards_compat/digraph/test_layers.py deleted file mode 100644 index 720c1f0fb..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_layers.py +++ /dev/null @@ -1,65 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestLayers(unittest.TestCase): - def test_dagcircuit_basic(self): - dag = retworkx.PyDAG() - qr_0_in = dag.add_node("qr[0]") - qr_0_out = dag.add_node("qr[0]") - qr_1_in = dag.add_node("qr[1]") - qr_1_out = dag.add_node("qr[1]") - cr_0_in = dag.add_node("cr[0]") - cr_0_out = dag.add_node("cr[0]") - cr_1_in = dag.add_node("cr[1]") - cr_1_out = dag.add_node("cr[1]") - input_nodes = [qr_0_in, qr_1_in, cr_0_in, cr_1_in] - - h_gate = dag.add_child(qr_0_in, "h", "qr[0]") - cx_gate = dag.add_child(h_gate, "cx", "qr[0]") - dag.add_edge(qr_1_in, cx_gate, "qr[1]") - measure_qr_1 = dag.add_child(cx_gate, "measure", "qr[1]") - dag.add_edge(cr_1_in, measure_qr_1, "cr[1]") - x_gate = dag.add_child(measure_qr_1, "x", "qr[1]") - dag.add_edge(measure_qr_1, x_gate, "cr[1]") - dag.add_edge(cr_0_in, x_gate, "cr[0]") - - measure_qr_0 = dag.add_child(cx_gate, "measure", "qr[0]") - dag.add_edge(measure_qr_0, qr_0_out, "qr[0]") - dag.add_edge(measure_qr_0, cr_0_out, "cr[0]") - dag.add_edge(x_gate, measure_qr_0, "cr[0]") - - measure_qr_1_out = dag.add_child(x_gate, "measure", "cr[1]") - dag.add_edge(x_gate, measure_qr_1_out, "qr[1]") - dag.add_edge(measure_qr_1_out, qr_1_out, "qr[1]") - dag.add_edge(measure_qr_1_out, cr_1_out, "cr[1]") - - res = retworkx.layers(dag, input_nodes) - expected = [ - ["qr[0]", "qr[1]", "cr[0]", "cr[1]"], - ["h"], - ["cx"], - ["measure"], - ["x"], - ["measure", "measure"], - ["cr[1]", "qr[1]", "cr[0]", "qr[0]"], - ] - self.assertEqual(expected, res) - - def test_first_layer_invalid_node(self): - dag = retworkx.PyDAG() - with self.assertRaises(retworkx.InvalidNode): - retworkx.layers(dag, [42]) diff --git a/tests/retworkx_backwards_compat/digraph/test_layout.py b/tests/retworkx_backwards_compat/digraph/test_layout.py deleted file mode 100644 index 1017f4f91..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_layout.py +++ /dev/null @@ -1,477 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class LayoutTest(unittest.TestCase): - thres = 1e-6 - - def assertLayoutEquiv(self, exp, res): - for k in exp: - ev = exp[k] - rv = res[k] - if abs(ev[0] - rv[0]) > self.thres or abs(ev[1] - rv[1]) > self.thres: - self.fail( - "The position for node %s, %s, differs from the expected " - "position, %s by more than the allowed threshold of %s" - % (k, rv, ev, self.thres) - ) - - -class TestRandomLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.directed_path_graph(10) - - def test_random_layout(self): - res = retworkx.digraph_random_layout(self.graph, seed=42) - expected = { - 0: (0.2265125179283135, 0.23910669031859955), - 4: (0.8025885957751138, 0.37085692752109345), - 5: (0.23635127852185123, 0.9286365888207462), - 1: (0.760833410686741, 0.5278396573581516), - 3: (0.1879083014236631, 0.524657662927804), - 2: (0.9704763177409157, 0.37546268141451944), - 6: (0.462700947802672, 0.44025745918644743), - 7: (0.3125895420208278, 0.0893209773065271), - 8: (0.5567725240957387, 0.21079648777222115), - 9: (0.7586719404939911, 0.43090704138697045), - } - self.assertEqual(expected, res) - - def test_random_layout_center(self): - res = retworkx.digraph_random_layout(self.graph, center=(0.5, 0.5), seed=42) - expected = { - 1: [1.260833410686741, 1.0278396573581516], - 5: [0.7363512785218512, 1.4286365888207462], - 7: [0.8125895420208278, 0.5893209773065271], - 4: [1.3025885957751138, 0.8708569275210934], - 8: [1.0567725240957389, 0.7107964877722212], - 9: [1.2586719404939912, 0.9309070413869704], - 0: [0.7265125179283135, 0.7391066903185995], - 2: [1.4704763177409157, 0.8754626814145194], - 6: [0.962700947802672, 0.9402574591864474], - 3: [0.6879083014236631, 1.0246576629278041], - } - self.assertEqual(expected, res) - - def test_random_layout_no_seed(self): - res = retworkx.digraph_random_layout(self.graph) - # Random output, just assert structurally correct - self.assertIsInstance(res, retworkx.Pos2DMapping) - self.assertEqual(len(res), 10) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - -class TestBipartiteLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.directed_path_graph(10) - - def test_bipartite_layout_empty(self): - res = retworkx.bipartite_layout(retworkx.PyDiGraph(), set()) - self.assertEqual({}, res) - - def test_bipartite_layout_hole(self): - g = retworkx.generators.directed_path_graph(5) - g.remove_nodes_from([1]) - res = retworkx.bipartite_layout(g, set()) - expected = { - 0: (0.0, -1.0), - 2: (0.0, -0.3333333333333333), - 3: (0.0, 0.3333333333333333), - 4: (0.0, 1.0), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout(self): - res = retworkx.bipartite_layout(self.graph, {0, 1, 2, 3, 4}) - expected = { - 0: (-1.0, -0.75), - 1: (-1.0, -0.375), - 2: (-1.0, 0.0), - 3: (-1.0, 0.375), - 4: (-1.0, 0.75), - 5: (1.0, -0.75), - 6: (1.0, -0.375), - 7: (1.0, 0.0), - 8: (1.0, 0.375), - 9: (1.0, 0.75), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout_horizontal(self): - res = retworkx.bipartite_layout(self.graph, {0, 1, 2, 3}, horizontal=True) - expected = { - 0: (1.0, -0.9), - 1: (0.3333333333333333, -0.9), - 2: (-0.333333333333333, -0.9), - 3: (-1.0, -0.9), - 4: (1.0, 0.6), - 5: (0.6, 0.6), - 6: (0.2, 0.6), - 7: (-0.2, 0.6), - 8: (-0.6, 0.6), - 9: (-1.0, 0.6), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout_scale(self): - res = retworkx.bipartite_layout(self.graph, {0, 1, 2}, scale=2) - expected = { - 0: (-2.0, -1.0714285714285714), - 1: (-2.0, 2.3790493384824785e-17), - 2: (-2.0, 1.0714285714285714), - 3: (0.8571428571428571, -1.0714285714285714), - 4: (0.8571428571428571, -0.7142857142857143), - 5: (0.8571428571428571, -0.35714285714285715), - 6: (0.8571428571428571, 2.3790493384824785e-17), - 7: (0.8571428571428571, 0.35714285714285704), - 8: (0.8571428571428571, 0.7142857142857141), - 9: (0.8571428571428571, 1.0714285714285714), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout_center(self): - res = retworkx.bipartite_layout(self.graph, {4, 5, 6}, center=(0.5, 0.5)) - expected = { - 4: (-0.5, -0.0357142857142857), - 5: (-0.5, 0.5), - 6: (-0.5, 1.0357142857142856), - 0: (0.9285714285714286, -0.0357142857142857), - 1: (0.9285714285714286, 0.14285714285714285), - 2: (0.9285714285714286, 0.3214285714285714), - 3: (0.9285714285714286, 0.5), - 7: (0.9285714285714286, 0.6785714285714285), - 8: (0.9285714285714286, 0.857142857142857), - 9: (0.9285714285714286, 1.0357142857142856), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout_ratio(self): - res = retworkx.bipartite_layout(self.graph, {2, 4, 8}, aspect_ratio=4) - expected = { - 8: [-1.0, 0.17857142857142858], - 2: [-1.0, -0.17857142857142858], - 4: [-1.0, 0], - 0: [0.42857142857142855, -0.17857142857142858], - 1: [0.42857142857142855, -0.11904761904761907], - 3: [0.42857142857142855, -0.05952380952380952], - 5: [0.42857142857142855, 0], - 6: [0.42857142857142855, 0.05952380952380952], - 7: [0.42857142857142855, 0.11904761904761903], - 9: [0.42857142857142855, 0.17857142857142858], - } - self.assertLayoutEquiv(expected, res) - - -class TestCircularLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.directed_path_graph(10) - - def test_circular_layout_empty(self): - res = retworkx.circular_layout(retworkx.PyDiGraph()) - self.assertEqual({}, res) - - def test_circular_layout_one_node(self): - res = retworkx.circular_layout(retworkx.generators.directed_path_graph(1)) - self.assertEqual({0: (0.0, 0.0)}, res) - - def test_circular_layout_hole(self): - g = retworkx.generators.directed_path_graph(5) - g.remove_nodes_from([1]) - res = retworkx.circular_layout(g) - expected = { - 0: (0.999999986090933, 2.1855693665697608e-08), - 2: (-3.576476059301554e-08, 1.0), - 3: (-0.9999999701976796, -6.556708099709282e-08), - 4: (1.987150711625619e-08, -0.9999999562886126), - } - self.assertLayoutEquiv(expected, res) - - def test_circular_layout(self): - res = retworkx.circular_layout(self.graph) - expected = { - 0: (1.0, 2.662367085193061e-08), - 1: (0.8090170042900712, 0.5877852653564984), - 2: (0.3090169789580973, 0.9510565581329226), - 3: (-0.3090170206813483, 0.9510564985282783), - 4: (-0.8090170460133221, 0.5877852057518542), - 5: (-0.9999999821186069, -6.079910493992474e-08), - 6: (-0.8090169268040337, -0.5877853313184453), - 7: (-0.3090170802859925, -0.9510564452809367), - 8: (0.3090171279697079, -0.9510564452809367), - 9: (0.809016944685427, -0.587785271713801), - } - self.assertLayoutEquiv(expected, res) - - def test_circular_layout_scale(self): - res = retworkx.circular_layout(self.graph, scale=2) - expected = { - 0: (2.0, 5.324734170386122e-08), - 1: (1.6180340085801423, 1.1755705307129969), - 2: (0.6180339579161946, 1.9021131162658451), - 3: (-0.6180340413626966, 1.9021129970565567), - 4: (-1.6180340920266443, 1.1755704115037084), - 5: (-1.9999999642372137, -1.2159820987984948e-07), - 6: (-1.6180338536080674, -1.1755706626368907), - 7: (-0.618034160571985, -1.9021128905618734), - 8: (0.6180342559394159, -1.9021128905618734), - 9: (1.618033889370854, -1.175570543427602), - } - self.assertLayoutEquiv(expected, res) - - def test_circular_layout_center(self): - res = retworkx.circular_layout(self.graph, center=(0.5, 0.5)) - expected = { - 0: (1.5, 0.5000000266236708), - 1: (1.3090170042900713, 1.0877852653564983), - 2: (0.8090169789580973, 1.4510565581329224), - 3: (0.1909829793186517, 1.4510564985282783), - 4: (-0.30901704601332214, 1.0877852057518542), - 5: (-0.49999998211860686, 0.4999999392008951), - 6: (-0.3090169268040337, -0.08778533131844535), - 7: (0.1909829197140075, -0.4510564452809367), - 8: (0.8090171279697079, -0.4510564452809367), - 9: (1.309016944685427, -0.08778527171380102), - } - self.assertLayoutEquiv(expected, res) - - -class TestShellLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.directed_path_graph(10) - - def test_shell_layout_empty(self): - res = retworkx.circular_layout(retworkx.PyDiGraph()) - self.assertEqual({}, res) - - def test_shell_layout_one_node(self): - res = retworkx.shell_layout(retworkx.generators.directed_path_graph(1)) - self.assertEqual({0: (0.0, 0.0)}, res) - - def test_shell_layout_hole(self): - g = retworkx.generators.directed_path_graph(5) - g.remove_nodes_from([1]) - res = retworkx.shell_layout(g) - expected = { - 0: (-1.0, -8.742277657347586e-08), - 2: (1.1924880638503055e-08, -1.0), - 3: (1.0, 1.7484555314695172e-07), - 4: (-3.3776623808989825e-07, 1.0), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_hole_two_shells(self): - g = retworkx.generators.directed_path_graph(5) - g.remove_nodes_from([2]) - res = retworkx.shell_layout(g, [[0, 1], [3, 4]]) - expected = { - 0: (-2.1855694143368964e-08, 0.5), - 1: (5.962440319251527e-09, -0.5), - 3: (-1.0, -8.742277657347586e-08), - 4: (1.0, 1.7484555314695172e-07), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout(self): - res = retworkx.shell_layout(self.graph) - expected = { - 0: (-1.0, -8.742277657347586e-08), - 1: (-0.8090169429779053, -0.5877853631973267), - 2: (-0.3090170919895172, -0.9510564804077148), - 3: (0.3090171217918396, -0.9510564804077148), - 4: (0.8090172410011292, -0.5877849459648132), - 5: (1.0, 1.7484555314695172e-07), - 6: (0.80901700258255, 0.5877852439880371), - 7: (0.30901679396629333, 0.9510565996170044), - 8: (-0.30901744961738586, 0.9510563611984253), - 9: (-0.8090168833732605, 0.5877854228019714), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_nlist(self): - res = retworkx.shell_layout(self.graph, nlist=[[0, 2], [1, 3], [4, 9], [8, 7], [6, 5]]) - expected = { - 0: (0.16180340945720673, 0.11755704879760742), - 2: (-0.16180339455604553, -0.11755707114934921), - 1: (0.12360679358243942, 0.3804226219654083), - 3: (-0.123606838285923, -0.38042259216308594), - 4: (-0.18541023135185242, 0.5706338882446289), - 9: (0.185410276055336, -0.5706338882446289), - 8: (-0.6472136378288269, 0.4702281653881073), - 7: (0.6472138166427612, -0.4702279567718506), - 6: (-1.0, -8.742277657347586e-08), - 5: (1.0, 1.7484555314695172e-07), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_rotate(self): - res = retworkx.shell_layout( - self.graph, nlist=[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]], rotate=0.5 - ) - expected = { - 0: (0.21939563751220703, 0.11985638737678528), - 1: (-0.21349650621414185, 0.13007399439811707), - 2: (-0.005899117328226566, -0.24993039667606354), - 3: (0.27015113830566406, 0.4207354784011841), - 4: (-0.4994432032108307, 0.023589985445141792), - 5: (0.229292094707489, -0.4443254768848419), - 6: (0.05305289849638939, 0.7481212615966797), - 7: (-0.6744184494018555, -0.3281154930591583), - 8: (0.6213656067848206, -0.420005738735199), - 9: (-0.416146844625473, 0.9092974066734314), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_scale(self): - res = retworkx.shell_layout(self.graph, nlist=[[0, 1, 2, 3, 4], [9, 8, 7, 6, 5]], scale=2) - expected = { - 0: (-4.371138828673793e-08, 1.0), - 1: (-0.9510565996170044, 0.30901679396629333), - 2: (-0.5877850651741028, -0.8090171217918396), - 3: (0.5877854824066162, -0.8090168237686157), - 4: (0.9510564208030701, 0.30901727080345154), - 9: (-2.0, -1.7484555314695172e-07), - 8: (-0.6180341839790344, -1.9021129608154297), - 7: (1.6180344820022583, -1.1755698919296265), - 6: (1.6180340051651, 1.1755704879760742), - 5: (-0.6180348992347717, 1.9021127223968506), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_center(self): - res = retworkx.shell_layout( - self.graph, - nlist=[[0, 1, 2, 3, 4], [9, 8, 7, 6, 5]], - center=(0.5, 0.5), - ) - expected = { - 0: (0.49999997814430586, 1.0), - 1: (0.024471700191497803, 0.6545083969831467), - 2: (0.2061074674129486, 0.0954914391040802), - 3: (0.7938927412033081, 0.09549158811569214), - 4: (0.975528210401535, 0.6545086354017258), - 9: (-0.5, 0.4999999125772234), - 8: (0.1909829080104828, -0.45105648040771484), - 7: (1.3090172410011292, -0.08778494596481323), - 6: (1.30901700258255, 1.087785243988037), - 5: (0.19098255038261414, 1.4510563611984253), - } - self.assertLayoutEquiv(expected, res) - - -class TestSpiralLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.directed_path_graph(10) - - def test_spiral_layout_empty(self): - res = retworkx.spiral_layout(retworkx.PyDiGraph()) - self.assertEqual({}, res) - - def test_spiral_layout_one_node(self): - res = retworkx.spiral_layout(retworkx.generators.directed_path_graph(1)) - self.assertEqual({0: (0.0, 0.0)}, res) - - def test_spiral_layout_hole(self): - g = retworkx.generators.directed_path_graph(5) - g.remove_nodes_from([1]) - res = retworkx.spiral_layout(g) - expected = { - 0: (-0.6415327868391166, -0.6855508729419231), - 2: (-0.03307913182988828, -0.463447951079834), - 3: (0.34927952438480797, 0.1489988240217569), - 4: (0.32533239428419697, 1.0), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout(self): - res = retworkx.spiral_layout(self.graph) - expected = { - 0: (0.3083011152777303, -0.36841870322845377), - 1: (0.4448595378922136, -0.3185709877650719), - 2: (0.5306742824266687, -0.18111636841212878), - 3: (0.5252997033017661, 0.009878257518578544), - 4: (0.40713492048969163, 0.20460820654918466), - 5: (0.17874125121181098, 0.3468009691240852), - 6: (-0.1320415949011884, 0.3844997574641717), - 7: (-0.4754889029311045, 0.28057288841663486), - 8: (-0.7874803127675889, 0.021164283410983312), - 9: (-0.9999999999999999, -0.3794183030779839), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout_scale(self): - res = retworkx.spiral_layout(self.graph, scale=2) - expected = { - 0: (0.6166022305554606, -0.7368374064569075), - 1: (0.8897190757844272, -0.6371419755301438), - 2: (1.0613485648533374, -0.36223273682425755), - 3: (1.0505994066035322, 0.01975651503715709), - 4: (0.8142698409793833, 0.4092164130983693), - 5: (0.35748250242362195, 0.6936019382481704), - 6: (-0.2640831898023768, 0.7689995149283434), - 7: (-0.950977805862209, 0.5611457768332697), - 8: (-1.5749606255351778, 0.042328566821966625), - 9: (-1.9999999999999998, -0.7588366061559678), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout_center(self): - res = retworkx.spiral_layout(self.graph, center=(1, 1)) - expected = { - 0: (1.3083011152777302, 0.6315812967715462), - 1: (1.4448595378922136, 0.681429012234928), - 2: (1.5306742824266686, 0.8188836315878713), - 3: (1.5252997033017661, 1.0098782575185785), - 4: (1.4071349204896917, 1.2046082065491848), - 5: (1.178741251211811, 1.3468009691240852), - 6: (0.8679584050988116, 1.3844997574641718), - 7: (0.5245110970688955, 1.2805728884166347), - 8: (0.2125196872324111, 1.0211642834109833), - 9: (1.1102230246251565e-16, 0.6205816969220161), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout_resolution(self): - res = retworkx.spiral_layout(self.graph, resolution=0.6) - expected = { - 0: (0.14170895375949058, 0.22421978768273812), - 1: (0.2657196183870804, 0.30906004798138936), - 2: (0.2506009612140119, 0.5043065412934762), - 3: (0.039294315670400995, 0.6631957258449066), - 4: (-0.3014789232909145, 0.6301862160709318), - 5: (-0.602046830323471, 0.3302396035952633), - 6: (-0.66674476042188, -0.17472522299849289), - 7: (-0.3739394496041176, -0.6924895145748617), - 8: (0.2468861146093996, -0.9732085843739783), - 9: (1.0, -0.8207846005213728), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout_equidistant(self): - res = retworkx.spiral_layout(self.graph, equidistant=True) - expected = { - 0: (-0.13161882865656718, -0.7449342807652114), - 1: (0.7160560542246066, -0.6335352483233974), - 2: (0.6864868274284994, -0.34165899654603915), - 3: (0.5679822628330004, -0.07281296883784087), - 4: (0.375237081214659, 0.14941210155952697), - 5: (0.12730720268992277, 0.30830226777240866), - 6: (-0.15470865936858091, 0.3939608192236113), - 7: (-0.4495426197217269, 0.4027809258196645), - 8: (-0.7371993206438128, 0.33662707199446507), - 9: (-1.0, 0.2018583081028111), - } - self.assertLayoutEquiv(expected, res) diff --git a/tests/retworkx_backwards_compat/digraph/test_neighbors.py b/tests/retworkx_backwards_compat/digraph/test_neighbors.py deleted file mode 100644 index f33f49c6c..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_neighbors.py +++ /dev/null @@ -1,59 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestAdj(unittest.TestCase): - def test_single_neighbor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - res = dag.neighbors(node_a) - self.assertCountEqual([node_c, node_b], res) - - def test_unique_neighbors_on_dags(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", ["edge a->b"]) - node_c = dag.add_child(node_a, "c", ["edge a->c"]) - dag.add_edge(node_a, node_b, ["edge a->b bis"]) - res = dag.neighbors(node_a) - self.assertCountEqual([node_c, node_b], res) - - def test_single_neighbor_dir(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - res = dag.successor_indices(node_a) - self.assertEqual([node_c, node_b], res) - res = dag.predecessor_indices(node_a) - self.assertEqual([], res) - - def test_neighbor_dir_surrounded(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - res = dag.successor_indices(node_b) - self.assertEqual([node_c], res) - res = dag.predecessor_indices(node_b) - self.assertEqual([node_a], res) - - def test_no_neighbor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - self.assertEqual([], dag.neighbors(node_a)) diff --git a/tests/retworkx_backwards_compat/digraph/test_nodes.py b/tests/retworkx_backwards_compat/digraph/test_nodes.py deleted file mode 100644 index 4d9dfcd79..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_nodes.py +++ /dev/null @@ -1,403 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestNodes(unittest.TestCase): - def test_nodes(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", "Edgy") - res = dag.nodes() - self.assertEqual(["a", "b"], res) - self.assertEqual([0, 1], dag.node_indexes()) - - def test_node_indices(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node("a") - graph.add_child(node_a, "b", "Edgy") - self.assertEqual([0, 1], graph.node_indices()) - - def test_no_nodes(self): - dag = retworkx.PyDAG() - self.assertEqual([], dag.nodes()) - self.assertEqual([], dag.node_indexes()) - self.assertEqual([], dag.node_indices()) - - def test_remove_node(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_node(node_b) - res = dag.nodes() - self.assertEqual(["a", "c"], res) - self.assertEqual([0, 2], dag.node_indexes()) - - def test_remove_node_invalid_index(self): - graph = retworkx.PyDAG() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.remove_node(76) - res = graph.nodes() - self.assertEqual(["a", "b", "c"], res) - self.assertEqual([0, 1, 2], graph.node_indexes()) - - def test_remove_nodes_from(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - node_c = dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_nodes_from([node_b, node_c]) - res = dag.nodes() - self.assertEqual(["a"], res) - self.assertEqual([0], dag.node_indexes()) - - def test_remove_nodes_from_with_invalid_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - node_c = dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_nodes_from([node_b, node_c, 76]) - res = dag.nodes() - self.assertEqual(["a"], res) - self.assertEqual([0], dag.node_indexes()) - - def test_remove_nodes_retain_edges_single_edge(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - node_c = dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_node_retain_edges(node_b) - res = dag.nodes() - self.assertEqual(["a", "c"], res) - self.assertEqual([0, 2], dag.node_indexes()) - self.assertTrue(dag.has_edge(node_a, node_c)) - self.assertEqual(dag.get_all_edge_data(node_a, node_c), ["Edgy"]) - - def test_remove_nodes_retain_edges_single_edge_outgoing_weight(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - node_c = dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_node_retain_edges(node_b, use_outgoing=True) - res = dag.nodes() - self.assertEqual(["a", "c"], res) - self.assertEqual([0, 2], dag.node_indexes()) - self.assertTrue(dag.has_edge(node_a, node_c)) - self.assertEqual(dag.get_all_edge_data(node_a, node_c), ["Edgy_mk2"]) - - def test_remove_nodes_retain_edges_multiple_in_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_d = dag.add_node("d") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_edge(node_d, node_b, "Multiple in edgy") - node_c = dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_node_retain_edges(node_b) - res = dag.nodes() - self.assertEqual(["a", "d", "c"], res) - self.assertEqual([0, 1, 3], dag.node_indexes()) - self.assertTrue(dag.has_edge(node_a, node_c)) - self.assertTrue(dag.has_edge(node_d, node_c)) - - def test_remove_nodes_retain_edges_multiple_out_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_d = dag.add_node("d") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_edge(node_b, node_d, "Multiple out edgy") - node_c = dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_node_retain_edges(node_b) - res = dag.nodes() - self.assertEqual(["a", "d", "c"], res) - self.assertEqual([0, 1, 3], dag.node_indexes()) - self.assertTrue(dag.has_edge(node_a, node_c)) - self.assertTrue(dag.has_edge(node_a, node_d)) - - def test_remove_nodes_retain_edges_multiple_in_and_out_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_d = dag.add_node("d") - node_e = dag.add_node("e") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_edge(node_b, node_d, "Multiple out edgy") - dag.add_edge(node_e, node_b, "multiple in edgy") - node_c = dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_node_retain_edges(node_b) - res = dag.nodes() - self.assertEqual(["a", "d", "e", "c"], res) - self.assertEqual([0, 1, 2, 4], dag.node_indexes()) - self.assertTrue(dag.has_edge(node_a, node_c)) - self.assertTrue(dag.has_edge(node_a, node_d)) - self.assertTrue(dag.has_edge(node_e, node_c)) - self.assertTrue(dag.has_edge(node_e, node_d)) - - def test_remove_node_retain_edges_with_condition(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_d = dag.add_node("d") - node_e = dag.add_node("e") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_edge(node_b, node_d, "Multiple out edgy") - dag.add_edge(node_e, node_b, "multiple in edgy") - node_c = dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_node_retain_edges(node_b, condition=lambda a, b: a == "multiple in edgy") - res = dag.nodes() - self.assertEqual(["a", "d", "e", "c"], res) - self.assertEqual([0, 1, 2, 4], dag.node_indexes()) - self.assertFalse(dag.has_edge(node_a, node_c)) - self.assertFalse(dag.has_edge(node_a, node_d)) - self.assertTrue(dag.has_edge(node_e, node_c)) - self.assertTrue(dag.has_edge(node_e, node_d)) - - def test_remove_nodes_retain_edges_with_invalid_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_child(node_b, "c", "Edgy_mk2") - dag.remove_node_retain_edges(76) - res = dag.nodes() - self.assertEqual(["a", "b", "c"], res) - self.assertEqual([0, 1, 2], dag.node_indexes()) - - def test_topo_sort_empty(self): - dag = retworkx.PyDAG() - self.assertEqual([], retworkx.topological_sort(dag)) - - def test_topo_sort(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(5): - dag.add_child(node_a, i, None) - dag.add_parent(3, "A parent", None) - res = retworkx.topological_sort(dag) - self.assertEqual([6, 0, 5, 4, 3, 2, 1], res) - - def test_topo_sort_with_cycle(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {}) - dag.add_edge(node_b, node_a, {}) - self.assertRaises(retworkx.DAGHasCycle, retworkx.topological_sort, dag) - - def test_lexicographical_topo_sort(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(5): - dag.add_child(node_a, i, None) - dag.add_parent(3, "A parent", None) - res = retworkx.lexicographical_topological_sort(dag, lambda x: str(x)) - # Node values for nodes [6, 0, 5, 4, 3, 2, 1] - expected = ["A parent", "a", 0, 1, 2, 3, 4] - self.assertEqual(expected, res) - - def test_lexicographical_topo_sort_qiskit(self): - dag = retworkx.PyDAG() - # inputs - qr_0 = dag.add_node("qr[0]") - qr_1 = dag.add_node("qr[1]") - qr_2 = dag.add_node("qr[2]") - cr_0 = dag.add_node("cr[0]") - cr_1 = dag.add_node("cr[1]") - - # wires - cx_1 = dag.add_node("cx_1") - dag.add_edge(qr_0, cx_1, "qr[0]") - dag.add_edge(qr_1, cx_1, "qr[1]") - h_1 = dag.add_node("h_1") - dag.add_edge(cx_1, h_1, "qr[0]") - cx_2 = dag.add_node("cx_2") - dag.add_edge(cx_1, cx_2, "qr[1]") - dag.add_edge(qr_2, cx_2, "qr[2]") - cx_3 = dag.add_node("cx_3") - dag.add_edge(h_1, cx_3, "qr[0]") - dag.add_edge(cx_2, cx_3, "qr[2]") - h_2 = dag.add_node("h_2") - dag.add_edge(cx_3, h_2, "qr[2]") - - # outputs - qr_0_out = dag.add_node("qr[0]_out") - dag.add_edge(cx_3, qr_0_out, "qr[0]") - qr_1_out = dag.add_node("qr[1]_out") - dag.add_edge(cx_2, qr_1_out, "qr[1]") - qr_2_out = dag.add_node("qr[2]_out") - dag.add_edge(h_2, qr_2_out, "qr[2]") - cr_0_out = dag.add_node("cr[0]_out") - dag.add_edge(cr_0, cr_0_out, "qr[2]") - cr_1_out = dag.add_node("cr[1]_out") - dag.add_edge(cr_1, cr_1_out, "cr[1]") - - res = list(retworkx.lexicographical_topological_sort(dag, lambda x: str(x))) - expected = [ - "cr[0]", - "cr[0]_out", - "cr[1]", - "cr[1]_out", - "qr[0]", - "qr[1]", - "cx_1", - "h_1", - "qr[2]", - "cx_2", - "cx_3", - "h_2", - "qr[0]_out", - "qr[1]_out", - "qr[2]_out", - ] - self.assertEqual(expected, res) - - def test_get_node_data(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - self.assertEqual("b", dag.get_node_data(node_b)) - - def test_get_node_data_bad_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", "Edgy") - self.assertRaises(IndexError, dag.get_node_data, 42) - - def test_pydag_length(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", "Edgy") - self.assertEqual(2, len(dag)) - - def test_pydag_length_empty(self): - dag = retworkx.PyDAG() - self.assertEqual(0, len(dag)) - - def test_pydigraph_num_nodes(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "An_edge") - self.assertEqual(2, graph.num_nodes()) - - def test_pydigraph_num_nodes_empty(self): - graph = retworkx.PyDiGraph() - self.assertEqual(0, graph.num_nodes()) - - def test_add_nodes_from(self): - dag = retworkx.PyDAG() - nodes = list(range(100)) - res = dag.add_nodes_from(nodes) - self.assertEqual(len(res), 100) - self.assertEqual(res, nodes) - - def test_add_node_from_empty(self): - dag = retworkx.PyDAG() - res = dag.add_nodes_from([]) - self.assertEqual(len(res), 0) - - def test_get_node_data_getitem(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - self.assertEqual("b", dag[node_b]) - - def test_get_node_data_getitem_bad_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", "Edgy") - with self.assertRaises(IndexError): - dag[42] - - def test_set_node_data_setitem(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - dag[node_b] = "Oh so cool" - self.assertEqual("Oh so cool", dag[node_b]) - - def test_set_node_data_setitem_bad_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", "Edgy") - with self.assertRaises(IndexError): - dag[42] = "Oh so cool" - - def test_remove_node_delitem(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", "Edgy") - dag.add_child(node_b, "c", "Edgy_mk2") - del dag[node_b] - res = dag.nodes() - self.assertEqual(["a", "c"], res) - self.assertEqual([0, 2], dag.node_indexes()) - - def test_remove_node_delitem_invalid_index(self): - graph = retworkx.PyDAG() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - with self.assertRaises(IndexError): - del graph[76] - res = graph.nodes() - self.assertEqual(["a", "b", "c"], res) - self.assertEqual([0, 1, 2], graph.node_indexes()) - - def test_find_node_by_weight(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(10))) - res = graph.find_node_by_weight(9) - self.assertEqual(res, 9) - - def test_find_node_by_weight_no_match(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(10))) - res = graph.find_node_by_weight(42) - self.assertEqual(res, None) - - def test_find_node_by_weight_multiple_matches(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(["a", "a"]) - res = graph.find_node_by_weight("a") - self.assertEqual(res, 0) - - def test_merge_nodes(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(["a", "a", "b", "c"]) - graph.add_edge(0, 2, "edge0") - graph.add_edge(3, 0, "edge1") - graph.merge_nodes(0, 1) - self.assertEqual(graph.node_indexes(), [1, 2, 3]) - self.assertEqual([(3, 1, "edge1"), (1, 2, "edge0")], graph.weighted_edge_list()) - - def test_merge_nodes_no_match(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(["a", "a", "b", "c"]) - graph.add_edge(0, 2, "edge0") - graph.add_edge(3, 0, "edge1") - graph.merge_nodes(0, 2) - self.assertEqual(graph.node_indexes(), [0, 1, 2, 3]) - self.assertEqual([(0, 2, "edge0"), (3, 0, "edge1")], graph.weighted_edge_list()) - - def test_merge_nodes_invalid_node_first_index(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(["a", "b"]) - with self.assertRaises(IndexError): - graph.merge_nodes(2, 0) - - def test_merge_nodes_invalid_node_second_index(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(["a", "b"]) - with self.assertRaises(IndexError): - graph.merge_nodes(0, 3) diff --git a/tests/retworkx_backwards_compat/digraph/test_num_shortest_path.py b/tests/retworkx_backwards_compat/digraph/test_num_shortest_path.py deleted file mode 100644 index 07b9d41b8..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_num_shortest_path.py +++ /dev/null @@ -1,140 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestNumShortestpath(unittest.TestCase): - def test_num_shortest_path_unweighted(self): - graph = retworkx.PyDiGraph() - node_a = graph.add_node(0) - node_b = graph.add_node("end") - for i in range(3): - node = graph.add_child(node_a, i, None) - graph.add_edge(node, node_b, None) - res = retworkx.digraph_num_shortest_paths_unweighted(graph, node_a) - expected = {2: 1, 4: 1, 3: 1, 1: 3} - self.assertEqual(expected, res) - - def test_parallel_paths(self): - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list( - [ - (0, 1), - (1, 2), - (2, 3), - (0, 4), - (4, 5), - (5, 3), - ] - ) - res = retworkx.num_shortest_paths_unweighted(graph, 0) - expected = { - 1: 1, - 2: 1, - 3: 2, - 4: 1, - 5: 1, - } - self.assertEqual(expected, res) - - def test_grid_graph(self): - """Test num shortest paths for a 5x5 grid graph - 0 -> 1 -> 2 -> 3 -> 4 - | | | | | - v v v v v - 5 -> 6 -> 7 -> 8 -> 9 - | | | | | - v v v v v - 10-> 11-> 12-> 13-> 14 - | | | | | - v v v v v - 15-> 16-> 17-> 18-> 19 - | | | | | - v v v v v - 20-> 21-> 22-> 23-> 24 - """ - graph = retworkx.generators.directed_grid_graph(5, 5) - res = retworkx.num_shortest_paths_unweighted(graph, 0) - expected = { - 1: 1, - 2: 1, - 3: 1, - 4: 1, - 5: 1, - 6: 2, - 7: 3, - 8: 4, - 9: 5, - 10: 1, - 11: 3, - 12: 6, - 13: 10, - 14: 15, - 15: 1, - 16: 4, - 17: 10, - 18: 20, - 19: 35, - 20: 1, - 21: 5, - 22: 15, - 23: 35, - 24: 70, - } - self.assertEqual(expected, res) - - def test_node_with_no_path(self): - graph = retworkx.generators.directed_path_graph(5) - graph.extend_from_edge_list([(6, 7), (7, 8), (8, 9), (9, 10), (10, 11)]) - expected = {1: 1, 2: 1, 3: 1, 4: 1} - res = retworkx.num_shortest_paths_unweighted(graph, 0) - self.assertEqual(expected, res) - res = retworkx.num_shortest_paths_unweighted(graph, 6) - expected = {7: 1, 8: 1, 9: 1, 10: 1, 11: 1} - self.assertEqual(expected, res) - - def test_node_indices_with_holes(self): - graph = retworkx.generators.directed_path_graph(5) - graph.extend_from_edge_list([(6, 7), (7, 8), (8, 9), (9, 10), (10, 11)]) - graph.add_edge(4, 6, None) - graph.remove_node(5) - expected = { - 1: 1, - 2: 1, - 3: 1, - 4: 1, - 6: 1, - 7: 1, - 8: 1, - 9: 1, - 10: 1, - 11: 1, - } - res = retworkx.num_shortest_paths_unweighted(graph, 0) - self.assertEqual(expected, res) - - def test_no_edges(self): - graph = retworkx.PyDiGraph() - graph.add_node(0) - graph.add_node(1) - res = retworkx.num_shortest_paths_unweighted(graph, 0) - self.assertEqual({}, res) - - def test_invalid_source_index(self): - graph = retworkx.PyDiGraph() - graph.add_node(0) - graph.add_child(0, 1, None) - with self.assertRaises(IndexError): - retworkx.num_shortest_paths_unweighted(graph, 4) diff --git a/tests/retworkx_backwards_compat/digraph/test_pred_succ.py b/tests/retworkx_backwards_compat/digraph/test_pred_succ.py deleted file mode 100644 index 7f655044a..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_pred_succ.py +++ /dev/null @@ -1,385 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestPredecessors(unittest.TestCase): - def test_single_predecessor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - res = dag.predecessors(node_c) - self.assertEqual(["a"], res) - - def test_single_predecessor_multiple_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - dag.add_edge(node_a, node_c, {"a": 3}) - res = dag.predecessors(node_c) - self.assertEqual(["a"], res) - - def test_many_parents(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(10): - dag.add_parent(node_a, {"numeral": i}, {"edge": i}) - res = dag.predecessors(node_a) - self.assertEqual( - [ - {"numeral": 9}, - {"numeral": 8}, - {"numeral": 7}, - {"numeral": 6}, - {"numeral": 5}, - {"numeral": 4}, - {"numeral": 3}, - {"numeral": 2}, - {"numeral": 1}, - {"numeral": 0}, - ], - res, - ) - - -class TestSuccessors(unittest.TestCase): - def test_single_successor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - dag.add_child(node_c, "d", {"a": 1}) - res = dag.successors(node_b) - self.assertEqual(["c"], res) - - def test_single_successor_multiple_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - dag.add_child(node_c, "d", {"a": 1}) - dag.add_edge(node_b, node_c, {"a": 3}) - res = dag.successors(node_b) - self.assertEqual(["c"], res) - - def test_many_children(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(10): - dag.add_child(node_a, {"numeral": i}, {"edge": i}) - res = dag.successors(node_a) - self.assertEqual( - [ - {"numeral": 9}, - {"numeral": 8}, - {"numeral": 7}, - {"numeral": 6}, - {"numeral": 5}, - {"numeral": 4}, - {"numeral": 3}, - {"numeral": 2}, - {"numeral": 1}, - {"numeral": 0}, - ], - res, - ) - - -class TestFindPredecessorsByEdge(unittest.TestCase): - def test_single_predecessor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - - res_even = dag.find_predecessors_by_edge(node_c, lambda x: x["a"] % 2 == 0) - - res_odd = dag.find_predecessors_by_edge(node_c, lambda x: x["a"] % 2 != 0) - - self.assertEqual(["a"], res_even) - self.assertEqual([], res_odd) - - def test_single_predecessor_multiple_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_a, "c", {"a": 2}) - dag.add_edge(node_a, node_c, {"a": 3}) - - res_even = dag.find_predecessors_by_edge(node_c, lambda x: x["a"] % 2 == 0) - - res_odd = dag.find_predecessors_by_edge(node_c, lambda x: x["a"] % 2 == 0) - - self.assertEqual(["a"], res_even) - self.assertEqual(["a"], res_odd) - - def test_many_parents(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(10): - dag.add_parent(node_a, {"numeral": i}, {"edge": i}) - - res_even = dag.find_predecessors_by_edge(node_a, lambda x: x["edge"] % 2 == 0) - - res_odd = dag.find_predecessors_by_edge(node_a, lambda x: x["edge"] % 2 != 0) - - self.assertEqual( - [ - {"numeral": 8}, - {"numeral": 6}, - {"numeral": 4}, - {"numeral": 2}, - {"numeral": 0}, - ], - res_even, - ) - - self.assertEqual( - [ - {"numeral": 9}, - {"numeral": 7}, - {"numeral": 5}, - {"numeral": 3}, - {"numeral": 1}, - ], - res_odd, - ) - - def test_no_parents(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - - res = dag.find_predecessors_by_edge(node_a, lambda _: True) - - self.assertEqual([], res) - - -class TestFindSuccessorsByEdge(unittest.TestCase): - def test_single_successor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - dag.add_child(node_c, "d", {"a": 1}) - - res_even = dag.find_successors_by_edge(node_b, lambda x: x["a"] % 2 == 0) - res_odd = dag.find_successors_by_edge(node_b, lambda x: x["a"] % 2 != 0) - - self.assertEqual(["c"], res_even) - self.assertEqual([], res_odd) - - def test_single_successor_multiple_edges(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - dag.add_child(node_c, "d", {"a": 1}) - dag.add_edge(node_b, node_c, {"a": 3}) - - res_even = dag.find_successors_by_edge(node_b, lambda x: x["a"] % 2 == 0) - res_odd = dag.find_successors_by_edge(node_b, lambda x: x["a"] % 2 != 0) - - self.assertEqual(["c"], res_even) - self.assertEqual(["c"], res_odd) - - def test_many_children(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(10): - dag.add_child(node_a, {"numeral": i}, {"edge": i}) - - res_even = dag.find_successors_by_edge(node_a, lambda x: x["edge"] % 2 == 0) - - res_odd = dag.find_successors_by_edge(node_a, lambda x: x["edge"] % 2 != 0) - - self.assertEqual( - [ - {"numeral": 8}, - {"numeral": 6}, - {"numeral": 4}, - {"numeral": 2}, - {"numeral": 0}, - ], - res_even, - ) - - self.assertEqual( - [ - {"numeral": 9}, - {"numeral": 7}, - {"numeral": 5}, - {"numeral": 3}, - {"numeral": 1}, - ], - res_odd, - ) - - def test_no_children(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - - res = dag.find_successors_by_edge(node_a, lambda _: True) - - self.assertEqual([], res) - - -class TestBfsSuccessors(unittest.TestCase): - def test_single_successor(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - node_b = dag.add_child(node_a, "b", {"a": 1}) - node_c = dag.add_child(node_b, "c", {"a": 2}) - dag.add_child(node_c, "d", {"a": 1}) - res = retworkx.bfs_successors(dag, node_b) - self.assertEqual([("b", ["c"]), ("c", ["d"])], res) - - def test_many_children(self): - dag = retworkx.PyDAG() - node_a = dag.add_node("a") - for i in range(10): - dag.add_child(node_a, {"numeral": i}, {"edge": i}) - res = retworkx.bfs_successors(dag, node_a) - self.assertEqual( - [ - ( - "a", - [ - {"numeral": 9}, - {"numeral": 8}, - {"numeral": 7}, - {"numeral": 6}, - {"numeral": 5}, - {"numeral": 4}, - {"numeral": 3}, - {"numeral": 2}, - {"numeral": 1}, - {"numeral": 0}, - ], - ) - ], - res, - ) - - def test_bfs_succesors(self): - dag = retworkx.PyDAG() - node_a = dag.add_node(0) - node_b = dag.add_child(node_a, 1, {}) - node_c = dag.add_child(node_b, 2, {}) - node_d = dag.add_child(node_c, 3, {}) - node_e = dag.add_child(node_d, 4, {}) - node_f = dag.add_child(node_e, 5, {}) - dag.add_child(node_f, 6, {}) - node_h = dag.add_child(node_c, 7, {}) - node_i = dag.add_child(node_h, 8, {}) - node_j = dag.add_child(node_i, 9, {}) - dag.add_child(node_j, 10, {}) - res = {n: sorted(s) for n, s in retworkx.bfs_successors(dag, node_b)} - expected = { - 1: [2], - 2: [3, 7], - 3: [4], - 4: [5], - 5: [6], - 7: [8], - 8: [9], - 9: [10], - } - self.assertEqual(expected, res) - self.assertEqual( - [(7, [8]), (8, [9]), (9, [10])], - retworkx.bfs_successors(dag, node_h), - ) - - def test_bfs_successors_sequence(self): - dag = retworkx.PyDAG() - node_a = dag.add_node(0) - node_b = dag.add_child(node_a, 1, {}) - node_c = dag.add_child(node_b, 2, {}) - node_d = dag.add_child(node_c, 3, {}) - node_e = dag.add_child(node_d, 4, {}) - node_f = dag.add_child(node_e, 5, {}) - dag.add_child(node_f, 6, {}) - node_h = dag.add_child(node_c, 7, {}) - node_i = dag.add_child(node_h, 8, {}) - node_j = dag.add_child(node_i, 9, {}) - dag.add_child(node_j, 10, {}) - res = retworkx.bfs_successors(dag, node_b) - expected = [ - (1, [2]), - (2, [7, 3]), - (7, [8]), - (3, [4]), - (8, [9]), - (4, [5]), - (9, [10]), - (5, [6]), - ] - for index, expected_value in enumerate(expected): - self.assertEqual((res[index][0], res[index][1]), expected_value) - - def test_bfs_successors_sequence_invalid_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node(0) - node_b = dag.add_child(node_a, 1, {}) - node_c = dag.add_child(node_b, 2, {}) - node_d = dag.add_child(node_c, 3, {}) - node_e = dag.add_child(node_d, 4, {}) - node_f = dag.add_child(node_e, 5, {}) - dag.add_child(node_f, 6, {}) - node_h = dag.add_child(node_c, 7, {}) - node_i = dag.add_child(node_h, 8, {}) - node_j = dag.add_child(node_i, 9, {}) - dag.add_child(node_j, 10, {}) - res = retworkx.bfs_successors(dag, node_b) - with self.assertRaises(IndexError): - res[8] - - def test_bfs_successors_sequence_negative_index(self): - dag = retworkx.PyDAG() - node_a = dag.add_node(0) - node_b = dag.add_child(node_a, 1, {}) - node_c = dag.add_child(node_b, 2, {}) - node_d = dag.add_child(node_c, 3, {}) - node_e = dag.add_child(node_d, 4, {}) - node_f = dag.add_child(node_e, 5, {}) - dag.add_child(node_f, 6, {}) - node_h = dag.add_child(node_c, 7, {}) - node_i = dag.add_child(node_h, 8, {}) - node_j = dag.add_child(node_i, 9, {}) - dag.add_child(node_j, 10, {}) - res = retworkx.bfs_successors(dag, node_b) - self.assertEqual((5, [6]), res[-1]) - self.assertEqual((4, [5]), res[-3]) - - def test_bfs_successors_sequence_stop_iterator(self): - dag = retworkx.PyDAG() - node_a = dag.add_node(0) - node_b = dag.add_child(node_a, 1, {}) - node_c = dag.add_child(node_b, 2, {}) - node_d = dag.add_child(node_c, 3, {}) - node_e = dag.add_child(node_d, 4, {}) - node_f = dag.add_child(node_e, 5, {}) - dag.add_child(node_f, 6, {}) - node_h = dag.add_child(node_c, 7, {}) - node_i = dag.add_child(node_h, 8, {}) - node_j = dag.add_child(node_i, 9, {}) - dag.add_child(node_j, 10, {}) - res = iter(retworkx.bfs_successors(dag, node_b)) - for _ in range(8): - next(res) - with self.assertRaises(StopIteration): - next(res) diff --git a/tests/retworkx_backwards_compat/digraph/test_spring_layout.py b/tests/retworkx_backwards_compat/digraph/test_spring_layout.py deleted file mode 100644 index 13d6aa0fb..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_spring_layout.py +++ /dev/null @@ -1,73 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestSpringLayout(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - node_a = self.graph.add_node(1) - node_b = self.graph.add_node(2) - self.graph.add_edge(node_a, node_b, 1) - node_c = self.graph.add_node(3) - self.graph.add_edge(node_a, node_c, 2) - - def test_empty_graph(self): - graph = retworkx.PyGraph() - res = retworkx.spring_layout(graph) - self.assertEqual({}, res) - - def test_simple_graph(self): - res = retworkx.spring_layout(self.graph, seed=42) - self.assertEqual(len(res), 3) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - def test_simple_graph_with_edge_weights(self): - res = retworkx.spring_layout(self.graph, weight_fn=lambda e: e) - self.assertEqual(len(res), 3) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - def test_simple_graph_center(self): - res = retworkx.spring_layout(self.graph, center=[0.5, 0.5]) - self.assertEqual(len(res), 3) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - def test_simple_graph_fixed(self): - pos = {0: [0.1, 0.1]} - res = retworkx.spring_layout(self.graph, pos=pos, fixed={0}) - self.assertEqual(res[0], pos[0]) - - def test_simple_graph_fixed_not_pos(self): - with self.assertRaises(ValueError): - retworkx.spring_layout(self.graph, fixed={0}) - - def test_simple_graph_linear_cooling(self): - res = retworkx.spring_layout(self.graph, adaptive_cooling=False) - self.assertEqual(len(res), 3) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - def test_graph_with_removed_nodes(self): - graph = retworkx.PyDiGraph() - nodes = graph.add_nodes_from([0, 1, 2]) - graph.remove_node(nodes[1]) - res = retworkx.spring_layout(graph) - self.assertEqual(len(res), 2) - self.assertTrue(nodes[0] in res) - self.assertTrue(nodes[2] in res) - self.assertFalse(nodes[1] in res) diff --git a/tests/retworkx_backwards_compat/digraph/test_strongly_connected.py b/tests/retworkx_backwards_compat/digraph/test_strongly_connected.py deleted file mode 100644 index 0e1679004..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_strongly_connected.py +++ /dev/null @@ -1,67 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestStronglyConnected(unittest.TestCase): - def test_number_strongly_connected_all_strong(self): - G = retworkx.PyDiGraph() - node_a = G.add_node(1) - node_b = G.add_child(node_a, 2, {}) - node_c = G.add_child(node_b, 3, {}) - self.assertEqual( - retworkx.strongly_connected_components(G), - [[node_c], [node_b], [node_a]], - ) - - def test_number_strongly_connected(self): - G = retworkx.PyDiGraph() - node_a = G.add_node(1) - node_b = G.add_child(node_a, 2, {}) - node_c = G.add_node(3) - self.assertEqual( - retworkx.strongly_connected_components(G), - [[node_c], [node_b], [node_a]], - ) - - def test_stongly_connected_no_linear(self): - G = retworkx.PyDiGraph() - G.add_nodes_from(list(range(8))) - G.add_edges_from_no_data( - [ - (0, 1), - (1, 2), - (1, 7), - (2, 3), - (2, 6), - (3, 4), - (4, 2), - (4, 5), - (6, 3), - (6, 5), - (7, 0), - (7, 6), - ] - ) - expected = [[5], [2, 3, 4, 6], [0, 1, 7]] - components = retworkx.strongly_connected_components(G) - self.assertEqual(components, expected) - - def test_number_strongly_connected_big(self): - G = retworkx.PyDiGraph() - for i in range(100000): - node = G.add_node(i) - G.add_child(node, str(i), {}) - self.assertEqual(len(retworkx.strongly_connected_components(G)), 200000) diff --git a/tests/retworkx_backwards_compat/digraph/test_subgraph.py b/tests/retworkx_backwards_compat/digraph/test_subgraph.py deleted file mode 100644 index 2b19343f0..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_subgraph.py +++ /dev/null @@ -1,150 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestSubgraph(unittest.TestCase): - def test_subgraph(self): - graph = retworkx.PyDiGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([1, 3]) - self.assertEqual([(0, 1, 4)], subgraph.weighted_edge_list()) - self.assertEqual(["b", "d"], subgraph.nodes()) - - def test_subgraph_empty_list(self): - graph = retworkx.PyDiGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([]) - self.assertEqual([], subgraph.weighted_edge_list()) - self.assertEqual(0, len(subgraph)) - - def test_subgraph_invalid_entry(self): - graph = retworkx.PyDiGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([42]) - self.assertEqual([], subgraph.weighted_edge_list()) - self.assertEqual(0, len(subgraph)) - - def test_subgraph_pass_by_reference(self): - graph = retworkx.PyDiGraph() - graph.add_node({"a": 0}) - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([0, 1, 3]) - self.assertEqual([(0, 1, 1), (0, 2, 3), (1, 2, 4)], subgraph.weighted_edge_list()) - self.assertEqual([{"a": 0}, "b", "d"], subgraph.nodes()) - graph[0]["a"] = 4 - self.assertEqual(subgraph[0]["a"], 4) - - def test_subgraph_replace_weight_no_reference(self): - graph = retworkx.PyDiGraph() - graph.add_node({"a": 0}) - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([0, 1, 3]) - self.assertEqual([(0, 1, 1), (0, 2, 3), (1, 2, 4)], subgraph.weighted_edge_list()) - self.assertEqual([{"a": 0}, "b", "d"], subgraph.nodes()) - graph[0] = 4 - self.assertEqual(subgraph[0]["a"], 0) - - def test_edge_subgraph(self): - graph = retworkx.PyDiGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.edge_subgraph([(0, 1), (1, 3)]) - self.assertEqual(["a", "b", "d"], subgraph.nodes()) - self.assertEqual([(0, 1, 1), (1, 3, 4)], subgraph.weighted_edge_list()) - - def test_edge_subgraph_parallel_edge(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.extend_from_weighted_edge_list( - [ - (0, 1, 2), - (0, 1, 3), - (0, 2, 2), - (1, 2, 4), - (0, 3, 5), - (2, 3, 6), - ] - ) - subgraph = graph.edge_subgraph([(0, 1), (1, 2)]) - self.assertEqual([0, 1, 2], subgraph.nodes()) - self.assertEqual([(0, 1, 2), (0, 1, 3), (1, 2, 4)], subgraph.weighted_edge_list()) - - def test_edge_subgraph_empty_list(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.extend_from_weighted_edge_list( - [ - (0, 1, 2), - (0, 1, 3), - (0, 2, 2), - (1, 2, 4), - (0, 3, 5), - (2, 3, 6), - ] - ) - subgraph = graph.edge_subgraph([]) - self.assertEqual([], subgraph.nodes()) - - def test_edge_subgraph_non_edge(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(4))) - graph.extend_from_weighted_edge_list( - [ - (0, 1, 2), - (0, 1, 3), - (0, 2, 2), - (1, 2, 4), - (0, 3, 5), - (2, 3, 6), - ] - ) - # 1->3 isn't an edge in graph - subgraph = graph.edge_subgraph([(0, 1), (1, 2), (1, 3)]) - self.assertEqual([0, 1, 2], subgraph.nodes()) - self.assertEqual([(0, 1, 2), (0, 1, 3), (1, 2, 4)], subgraph.weighted_edge_list()) - - def test_preserve_attrs(self): - graph = retworkx.PyGraph(attrs="My attribute") - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([1, 3], preserve_attrs=True) - self.assertEqual([(0, 1, 4)], subgraph.weighted_edge_list()) - self.assertEqual(["b", "d"], subgraph.nodes()) - self.assertEqual(graph.attrs, subgraph.attrs) diff --git a/tests/retworkx_backwards_compat/digraph/test_subgraph_isomorphic.py b/tests/retworkx_backwards_compat/digraph/test_subgraph_isomorphic.py deleted file mode 100644 index 8bcdf61e5..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_subgraph_isomorphic.py +++ /dev/null @@ -1,266 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestSubgraphIsomorphic(unittest.TestCase): - def test_empty_subgraph_isomorphic_identical(self): - g_a = retworkx.PyDiGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_a, id_order=id_order)) - - def test_empty_subgraph_isomorphic(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order)) - - def test_empty_subgraph_isomorphic_compare_nodes(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_subgraph_isomorphic( - g_a, g_b, lambda x, y: x == y, id_order=id_order - ) - ) - - def test_subgraph_isomorphic_identical(self): - g_a = retworkx.PyDiGraph() - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_a, id_order=id_order)) - - def test_subgraph_isomorphic_mismatch_node_data(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[0], nodes[3], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["b_1", "b_2", "b_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "b_1"), (nodes[1], nodes[2], "b_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order)) - - def test_subgraph_isomorphic_compare_nodes_mismatch_node_data(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[0], nodes[3], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["b_1", "b_2", "b_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "b_1"), (nodes[1], nodes[2], "b_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertFalse( - retworkx.is_subgraph_isomorphic( - g_a, g_b, lambda x, y: x == y, id_order=id_order - ) - ) - - def test_subgraph_isomorphic_compare_nodes_identical(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[0], nodes[3], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_subgraph_isomorphic( - g_a, g_b, lambda x, y: x == y, id_order=id_order - ) - ) - - def test_is_subgraph_isomorphic_nodes_compare_raises(self): - g_a = retworkx.PyDiGraph() - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - def compare_nodes(a, b): - raise TypeError("Failure") - - self.assertRaises( - TypeError, - retworkx.is_subgraph_isomorphic, - (g_a, g_a, compare_nodes), - ) - - def test_subgraph_isomorphic_compare_edges_identical(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[0], nodes[3], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_subgraph_isomorphic( - g_a, - g_b, - edge_matcher=lambda x, y: x == y, - id_order=id_order, - ) - ) - - def test_subgraph_isomorphic_node_count_not_ge(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1")]) - - nodes = g_b.add_nodes_from(["a_0", "a_1", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertFalse(retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order)) - - def test_subgraph_isomorphic_edge_matcher(self): - first = retworkx.PyDiGraph() - first.extend_from_weighted_edge_list([(0, 1, "a"), (1, 2, "b"), (2, 0, "c")]) - second = retworkx.PyDiGraph() - second.extend_from_weighted_edge_list([(0, 1, "a"), (1, 2, "b")]) - - self.assertTrue( - retworkx.is_subgraph_isomorphic( - first, second, induced=False, edge_matcher=lambda x, y: x == y - ) - ) - - def test_subgraph_isomorphic_mismatch_edge_data_parallel_edges(self): - first = retworkx.PyDiGraph() - first.extend_from_weighted_edge_list([(0, 1, "a"), (0, 1, "f"), (1, 2, "b"), (2, 0, "c")]) - second = retworkx.PyDiGraph() - second.extend_from_weighted_edge_list([(0, 1, "a"), (0, 1, "a"), (1, 2, "b")]) - - self.assertFalse( - retworkx.is_subgraph_isomorphic( - first, second, id_order=True, edge_matcher=lambda x, y: x == y - ) - ) - - def test_non_induced_subgraph_isomorphic(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[2], nodes[0], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order, induced=True): - self.assertFalse( - retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order, induced=True) - ) - with self.subTest(id_order=id_order, induced=False): - self.assertTrue( - retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order, induced=False) - ) - - def test_non_induced_grid_subgraph_isomorphic(self): - g_a = retworkx.generators.directed_grid_graph(2, 2) - g_b = retworkx.PyDiGraph() - g_b.add_nodes_from([0, 1, 2, 3]) - g_b.add_edges_from_no_data([(0, 1), (2, 3)]) - - self.assertFalse(retworkx.is_subgraph_isomorphic(g_a, g_b, induced=True)) - - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_b, induced=False)) - - def test_subgraph_vf2_mapping(self): - graph = retworkx.generators.directed_grid_graph(10, 10) - second_graph = retworkx.generators.directed_grid_graph(2, 2) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph, subgraph=True) - self.assertEqual(next(mapping), {0: 0, 1: 1, 10: 2, 11: 3}) - - def test_subgraph_vf2_all_mappings(self): - graph = retworkx.generators.directed_path_graph(3) - second_graph = retworkx.generators.directed_path_graph(2) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph, subgraph=True, id_order=True) - self.assertEqual(next(mapping), {0: 0, 1: 1}) - self.assertEqual(next(mapping), {2: 1, 1: 0}) - - def test_subgraph_vf2_mapping_vf2pp(self): - graph = retworkx.generators.directed_grid_graph(3, 3) - second_graph = retworkx.generators.directed_grid_graph(2, 2) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph, subgraph=True, id_order=False) - self.assertEqual(next(mapping), {4: 0, 5: 1, 7: 2, 8: 3}) - - def test_vf2pp_remapping(self): - temp = retworkx.generators.directed_grid_graph(3, 3) - - graph = retworkx.PyDiGraph() - dummy = graph.add_node(0) - - graph.compose(temp, dict()) - graph.remove_node(dummy) - - second_graph = retworkx.generators.directed_grid_graph(2, 2) - mapping = retworkx.digraph_vf2_mapping(graph, second_graph, subgraph=True, id_order=False) - self.assertEqual(next(mapping), {5: 0, 6: 1, 8: 2, 9: 3}) - - def test_empty_digraph_subgraph_vf2_mapping(self): - g_a = retworkx.PyDiGraph() - g_b = retworkx.PyDiGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - mapping = retworkx.digraph_vf2_mapping(g_a, g_b, id_order=id_order, subgraph=True) - self.assertEqual({}, next(mapping)) diff --git a/tests/retworkx_backwards_compat/digraph/test_substitute_node_with_subgraph.py b/tests/retworkx_backwards_compat/digraph/test_substitute_node_with_subgraph.py deleted file mode 100644 index c6f7996bc..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_substitute_node_with_subgraph.py +++ /dev/null @@ -1,163 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest -import retworkx - - -class TestSubstitute(unittest.TestCase): - def setUp(self): - super().setUp() - self.graph = retworkx.generators.directed_path_graph(5) - - def test_empty_replacement(self): - in_graph = retworkx.PyDiGraph() - res = self.graph.substitute_node_with_subgraph(2, in_graph, lambda _, __, ___: None) - self.assertEqual(res, {}) - self.assertEqual([(0, 1), (3, 4)], self.graph.edge_list()) - - def test_single_node(self): - in_graph = retworkx.PyDiGraph() - in_graph.add_node(0) - in_graph.add_child(0, 1, "edge") - res = self.graph.substitute_node_with_subgraph(2, in_graph, lambda _, __, ___: 0) - self.assertEqual([(0, 1), (3, 4), (5, 6), (1, 5), (5, 3)], self.graph.edge_list()) - self.assertEqual("edge", self.graph.get_edge_data(5, 6)) - self.assertEqual(res, {0: 5, 1: 6}) - - def test_node_filter(self): - in_graph = retworkx.PyDiGraph() - in_graph.add_node(0) - in_graph.add_child(0, 1, "edge") - res = self.graph.substitute_node_with_subgraph( - 2, - in_graph, - lambda _, __, ___: 0, - node_filter=lambda node: node == 0, - ) - self.assertEqual([(0, 1), (3, 4), (1, 5), (5, 3)], self.graph.edge_list()) - self.assertEqual(res, {0: 5}) - - def test_edge_weight_modifier(self): - in_graph = retworkx.PyDiGraph() - in_graph.add_node(0) - in_graph.add_child(0, 1, "edge") - res = self.graph.substitute_node_with_subgraph( - 2, - in_graph, - lambda _, __, ___: 0, - edge_weight_map=lambda edge: edge + "-migrated", - ) - self.assertEqual([(0, 1), (3, 4), (5, 6), (1, 5), (5, 3)], self.graph.edge_list()) - self.assertEqual("edge-migrated", self.graph.get_edge_data(5, 6)) - self.assertEqual(res, {0: 5, 1: 6}) - - def test_none_mapping(self): - in_graph = retworkx.PyDiGraph() - in_graph.add_node(0) - in_graph.add_child(0, 1, "edge") - res = self.graph.substitute_node_with_subgraph(2, in_graph, lambda _, __, ___: None) - self.assertEqual([(0, 1), (3, 4), (5, 6)], self.graph.edge_list()) - self.assertEqual(res, {0: 5, 1: 6}) - - def test_multiple_mapping(self): - graph = retworkx.generators.directed_star_graph(5) - in_graph = retworkx.generators.directed_star_graph(3, inward=True) - - def map_function(source, target, _weight): - if target > 2: - return 2 - return 1 - - res = graph.substitute_node_with_subgraph(0, in_graph, map_function) - self.assertEqual({0: 5, 1: 6, 2: 7}, res) - expected = [(6, 5), (7, 5), (7, 4), (7, 3), (6, 2), (6, 1)] - self.assertEqual(expected, graph.edge_list()) - - def test_multiple_mapping_full(self): - graph = retworkx.generators.directed_star_graph(5) - in_graph = retworkx.generators.directed_star_graph(weights=list(range(3)), inward=True) - in_graph.add_edge(1, 2, None) - - def map_function(source, target, _weight): - if target > 2: - return 2 - return 1 - - def filter_fn(node): - return node > 0 - - def map_weight(_): - return "migrated" - - res = graph.substitute_node_with_subgraph(0, in_graph, map_function, filter_fn, map_weight) - self.assertEqual({1: 5, 2: 6}, res) - expected = [ - (5, 6, "migrated"), - (6, 4, None), - (6, 3, None), - (5, 2, None), - (5, 1, None), - ] - self.assertEqual(expected, graph.weighted_edge_list()) - - def test_invalid_target(self): - in_graph = retworkx.generators.directed_grid_graph(5, 5) - with self.assertRaises(IndexError): - self.graph.substitute_node_with_subgraph(0, in_graph, lambda *args: 42) - - def test_invalid_target_both_directions(self): - graph = retworkx.generators.directed_star_graph(4, inward=True) - in_graph = retworkx.generators.directed_grid_graph(5, 5) - with self.assertRaises(IndexError): - graph.substitute_node_with_subgraph(0, in_graph, lambda *args: 42) - graph = retworkx.generators.directed_star_graph(4, inward=False) - with self.assertRaises(IndexError): - graph.substitute_node_with_subgraph(0, in_graph, lambda *args: 42) - - def test_invalid_node_id(self): - in_graph = retworkx.generators.directed_grid_graph(5, 5) - with self.assertRaises(IndexError): - self.graph.substitute_node_with_subgraph(16, in_graph, lambda *args: None) - - def test_bidrectional(self): - graph = retworkx.generators.directed_path_graph(5, bidirectional=True) - in_graph = retworkx.generators.directed_star_graph(5, bidirectional=True) - - def map_function(source, target, _weight): - if source != 2: - return 0 - else: - return target - - res = graph.substitute_node_with_subgraph(2, in_graph, map_function) - expected_node_map = {0: 5, 1: 6, 2: 7, 3: 8, 4: 9} - self.assertEqual(expected_node_map, res) - expected_edge_list = [ - (0, 1), # From graph - (1, 0), # From graph - (3, 4), # From graph - (4, 3), # From graph - (6, 5), # From in_graph - (5, 6), # From in_graph - (7, 5), # From in_graph - (5, 7), # From in_graph - (8, 5), # From in_graph - (5, 8), # From in_graph - (9, 5), # From in_graph - (5, 9), # From in_graph - (3, 5), # output of res[map_function(3, 2, None)] -> 5 - (1, 5), # output of res[map_function(1, 2, None)] -> 5 - (8, 3), # output of res[map_function(2, 3, None)] -> 8 - (6, 1), # output of res[map_function(2, 1, None)] -> 6 - ] - self.assertEqual(expected_edge_list, graph.edge_list()) diff --git a/tests/retworkx_backwards_compat/digraph/test_symmetric.py b/tests/retworkx_backwards_compat/digraph/test_symmetric.py deleted file mode 100644 index 4cb54708e..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_symmetric.py +++ /dev/null @@ -1,39 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestSymmetric(unittest.TestCase): - def test_single_neighbor(self): - digraph = retworkx.PyDiGraph() - node_a = digraph.add_node("a") - digraph.add_child(node_a, "b", {"a": 1}) - digraph.add_child(node_a, "c", {"a": 2}) - self.assertFalse(digraph.is_symmetric()) - - def test_bidirectional_ring(self): - digraph = retworkx.PyDiGraph() - edge_list = [ - (0, 1), - (1, 0), - (1, 2), - (2, 1), - (2, 3), - (3, 2), - (3, 0), - (0, 3), - ] - digraph.extend_from_edge_list(edge_list) - self.assertTrue(digraph.is_symmetric()) diff --git a/tests/retworkx_backwards_compat/digraph/test_tensor_product.py b/tests/retworkx_backwards_compat/digraph/test_tensor_product.py deleted file mode 100644 index 8e38674c6..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_tensor_product.py +++ /dev/null @@ -1,110 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest -import retworkx - - -class TestTensorProduct(unittest.TestCase): - def test_directed_null_tensor_null(self): - graph_1 = retworkx.PyDiGraph() - graph_2 = retworkx.PyDiGraph() - - graph_product, _ = retworkx.digraph_tensor_product(graph_1, graph_2) - self.assertEqual(graph_product.num_nodes(), 0) - self.assertEqual(graph_product.num_edges(), 0) - - def test_directed_path_2_tensor_path_2(self): - graph_1 = retworkx.generators.directed_path_graph(2) - graph_2 = retworkx.generators.directed_path_graph(2) - - graph_product, node_map = retworkx.digraph_tensor_product(graph_1, graph_2) - expected_node_map = {(0, 0): 0, (0, 1): 1, (1, 0): 2, (1, 1): 3} - self.assertEqual(node_map, expected_node_map) - - expected_edges = [(0, 3)] - self.assertEqual(graph_product.num_nodes(), 4) - self.assertEqual(graph_product.num_edges(), 1) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_directed_path_2_tensor_path_3(self): - graph_1 = retworkx.generators.directed_path_graph(2) - graph_2 = retworkx.generators.directed_path_graph(3) - - graph_product, node_map = retworkx.digraph_tensor_product(graph_1, graph_2) - expected_node_map = {(0, 1): 1, (1, 0): 3, (0, 0): 0, (1, 2): 5, (0, 2): 2, (1, 1): 4} - self.assertEqual(dict(node_map), expected_node_map) - - expected_edges = [(0, 4), (1, 5)] - self.assertEqual(graph_product.num_nodes(), 6) - self.assertEqual(graph_product.num_edges(), 2) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_directed_node_weights_tensor(self): - graph_1 = retworkx.PyDiGraph() - graph_1.add_node("a_1") - graph_2 = retworkx.PyDiGraph() - graph_2.add_node(0) - - graph_product, _ = retworkx.digraph_tensor_product(graph_1, graph_2) - self.assertEqual([("a_1", 0)], graph_product.nodes()) - - def test_directed_edge_weights_tensor(self): - graph_1 = retworkx.PyDiGraph() - graph_1.add_nodes_from([0, 1]) - graph_1.add_edge(0, 1, "w_1") - graph_2 = retworkx.PyDiGraph() - graph_2.add_nodes_from([0, 1]) - graph_2.add_edge(0, 1, "w_2") - - graph_product, _ = retworkx.digraph_tensor_product(graph_1, graph_2) - self.assertEqual([("w_1", "w_2")], graph_product.edges()) - - def test_multi_graph_1(self): - graph_1 = retworkx.generators.directed_path_graph(2) - graph_1.add_edge(0, 1, None) - graph_2 = retworkx.generators.directed_path_graph(2) - - graph_product, _ = retworkx.digraph_tensor_product(graph_1, graph_2) - expected_edges = [(0, 3), (0, 3)] - self.assertEqual(graph_product.num_edges(), 2) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_multi_graph_2(self): - graph_1 = retworkx.generators.directed_path_graph(2) - graph_1.add_edge(0, 0, None) - graph_2 = retworkx.generators.directed_path_graph(2) - - graph_product, _ = retworkx.digraph_tensor_product(graph_1, graph_2) - expected_edges = [(0, 3), (0, 1)] - self.assertEqual(graph_product.num_edges(), 2) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_multi_graph_3(self): - graph_1 = retworkx.generators.directed_path_graph(2) - graph_2 = retworkx.generators.directed_path_graph(2) - graph_2.add_edge(0, 1, None) - - graph_product, _ = retworkx.digraph_tensor_product(graph_1, graph_2) - expected_edges = [(0, 3), (0, 3)] - self.assertEqual(graph_product.num_edges(), 2) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_multi_graph_4(self): - graph_1 = retworkx.generators.directed_path_graph(2) - graph_2 = retworkx.generators.directed_path_graph(2) - graph_2.add_edge(0, 0, None) - - graph_product, _ = retworkx.digraph_tensor_product(graph_1, graph_2) - expected_edges = [(0, 3), (0, 2)] - self.assertEqual(graph_product.num_edges(), 2) - self.assertEqual(graph_product.edge_list(), expected_edges) diff --git a/tests/retworkx_backwards_compat/digraph/test_to_undirected.py b/tests/retworkx_backwards_compat/digraph/test_to_undirected.py deleted file mode 100644 index 14b135dd8..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_to_undirected.py +++ /dev/null @@ -1,66 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestToUndirected(unittest.TestCase): - def test_to_undirected_empty_graph(self): - digraph = retworkx.PyDiGraph() - graph = digraph.to_undirected() - self.assertEqual(0, len(graph)) - - def test_single_direction_graph(self): - digraph = retworkx.generators.directed_path_graph(5) - graph = digraph.to_undirected() - self.assertEqual(digraph.weighted_edge_list(), graph.weighted_edge_list()) - - def test_bidirectional_graph(self): - digraph = retworkx.generators.directed_path_graph(5) - for i in range(0, 4): - digraph.add_edge(i + 1, i, None) - graph = digraph.to_undirected() - self.assertEqual(digraph.weighted_edge_list(), graph.weighted_edge_list()) - - def test_bidirectional_not_multigraph(self): - digraph = retworkx.generators.directed_path_graph(5) - for i in range(0, 4): - digraph.add_edge(i + 1, i, None) - graph = digraph.to_undirected(multigraph=False) - self.assertEqual(graph.edge_list(), [(0, 1), (1, 2), (2, 3), (3, 4)]) - - def test_multiple_edges_combo_weight_not_multigraph(self): - digraph = retworkx.PyDiGraph() - digraph.add_nodes_from([0, 1]) - digraph.add_edges_from([(0, 1, "a"), (0, 1, "b")]) - graph = digraph.to_undirected(multigraph=False, weight_combo_fn=lambda x, y: x + y) - self.assertEqual(graph.weighted_edge_list(), [(0, 1, "ab")]) - - def test_shared_ref(self): - digraph = retworkx.PyDiGraph() - node_weight = {"a": 1} - node_a = digraph.add_node(node_weight) - edge_weight = {"a": 1} - digraph.add_child(node_a, "b", edge_weight) - graph = digraph.to_undirected() - self.assertEqual(digraph[node_a], {"a": 1}) - self.assertEqual(graph[node_a], {"a": 1}) - node_weight["b"] = 2 - self.assertEqual(digraph[node_a], {"a": 1, "b": 2}) - self.assertEqual(graph[node_a], {"a": 1, "b": 2}) - self.assertEqual(digraph.get_edge_data(0, 1), {"a": 1}) - self.assertEqual(graph.get_edge_data(0, 1), {"a": 1}) - edge_weight["b"] = 2 - self.assertEqual(digraph.get_edge_data(0, 1), {"a": 1, "b": 2}) - self.assertEqual(graph.get_edge_data(0, 1), {"a": 1, "b": 2}) diff --git a/tests/retworkx_backwards_compat/digraph/test_toposort.py b/tests/retworkx_backwards_compat/digraph/test_toposort.py deleted file mode 100644 index 08acd6352..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_toposort.py +++ /dev/null @@ -1,84 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestTopologicalSorter(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyDiGraph() - self.graph.extend_from_edge_list( - [ - (0, 2), - (1, 2), - (2, 3), - (2, 4), - (3, 5), - ] - ) - - def test_topo_sort(self): - sorter = retworkx.TopologicalSorter(self.graph) - nodes = sorter.get_ready() - self.assertEqual(nodes, [0, 1]) - sorter.done(nodes) - nodes = sorter.get_ready() - self.assertEqual(nodes, [2]) - sorter.done(nodes) - nodes = sorter.get_ready() - self.assertEqual(nodes, [4, 3]) - sorter.done(nodes) - nodes = sorter.get_ready() - self.assertEqual(nodes, [5]) - sorter.done(nodes) - nodes = sorter.get_ready() - self.assertEqual(nodes, []) - - def test_topo_sort_do_not_emit_if_node_has_undone_preds(self): - sorter = retworkx.TopologicalSorter(self.graph) - nodes = sorter.get_ready() - self.assertEqual(nodes, [0, 1]) - sorter.done([0]) - nodes = sorter.get_ready() - self.assertEqual(nodes, []) - - def test_topo_sort_raises_if_node_not_ready(self): - sorter = retworkx.TopologicalSorter(self.graph) - with self.assertRaises(ValueError): - sorter.done([0]) - - def test_topo_sort_raises_if_node_already_done(self): - sorter = retworkx.TopologicalSorter(self.graph) - sorter.get_ready() - sorter.done([0]) - with self.assertRaises(ValueError): - sorter.done([0]) - - def test_topo_sort_raises_if_graph_has_cycle(self): - graph = retworkx.generators.directed_cycle_graph(5) - with self.assertRaises(retworkx.DAGHasCycle): - _ = retworkx.TopologicalSorter(graph) - - def test_topo_sort_progress_if_graph_has_cycle_and_cycle_check_disabled( - self, - ): - graph = retworkx.generators.directed_cycle_graph(5) - starting_node = graph.add_node("starting node") - graph.add_edge(starting_node, 0, "starting edge") - - sorter = retworkx.TopologicalSorter(graph, check_cycle=False) - nodes = sorter.get_ready() - self.assertEqual(nodes, [starting_node]) - sorter.done(nodes) - self.assertFalse(sorter.is_active()) diff --git a/tests/retworkx_backwards_compat/digraph/test_transitivity.py b/tests/retworkx_backwards_compat/digraph/test_transitivity.py deleted file mode 100644 index 5b95efe4c..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_transitivity.py +++ /dev/null @@ -1,43 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestTransitivity(unittest.TestCase): - def test_transitivity_directed(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(5))) - graph.add_edges_from_no_data([(0, 1), (0, 2), (0, 3), (1, 2)]) - res = retworkx.transitivity(graph) - self.assertEqual(res, 3 / 10) - - def test_transitivity_triangle_directed(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(3))) - graph.add_edges_from_no_data([(0, 1), (0, 2), (1, 2)]) - res = retworkx.transitivity(graph) - self.assertEqual(res, 0.5) - - def test_transitivity_fulltriangle_directed(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(list(range(3))) - graph.add_edges_from_no_data([(0, 1), (1, 0), (0, 2), (2, 0), (1, 2), (2, 1)]) - res = retworkx.transitivity(graph) - self.assertEqual(res, 1.0) - - def test_transitivity_empty_directed(self): - graph = retworkx.PyDiGraph() - res = retworkx.transitivity(graph) - self.assertEqual(res, 0.0) diff --git a/tests/retworkx_backwards_compat/digraph/test_union.py b/tests/retworkx_backwards_compat/digraph/test_union.py deleted file mode 100644 index d1fcaf2e9..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_union.py +++ /dev/null @@ -1,105 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest -import retworkx - - -class TestUnion(unittest.TestCase): - def test_union_merge_all(self): - dag_a = retworkx.PyDiGraph() - dag_b = retworkx.PyDiGraph() - - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "e_1") - dag_a.add_child(node_a, "a_3", "e_2") - - node_b = dag_b.add_node("a_1") - dag_b.add_child(node_b, "a_2", "e_1") - dag_b.add_child(node_b, "a_3", "e_2") - - dag_c = retworkx.digraph_union(dag_a, dag_b, True, True) - - self.assertTrue(retworkx.is_isomorphic(dag_a, dag_c)) - - def test_union_basic_merge_nodes_only(self): - dag_a = retworkx.PyDiGraph() - dag_b = retworkx.PyDiGraph() - - node_a = dag_a.add_node("a_1") - child_a = dag_a.add_child(node_a, "a_2", "e_1") - dag_a.add_child(node_a, "a_3", "e_2") - - node_b = dag_b.add_node("a_1") - dag_b.add_child(node_b, "a_2", "e_1") - dag_b.add_child(node_b, "a_3", "e_2") - - dag_c = retworkx.digraph_union(dag_a, dag_b, True, False) - - self.assertTrue(len(dag_c.edge_list()) == 4) - self.assertTrue(len(dag_c.get_all_edge_data(node_a, child_a)) == 2) - self.assertTrue(len(dag_c.nodes()) == 3) - - def test_union_basic_merge_none(self): - dag_a = retworkx.PyDiGraph() - dag_b = retworkx.PyDiGraph() - - node_a = dag_a.add_node("a_1") - dag_a.add_child(node_a, "a_2", "e_1") - dag_a.add_child(node_a, "a_3", "r_2") - - node_b = dag_b.add_node("a_1") - dag_b.add_child(node_b, "a_2", "e_1") - dag_b.add_child(node_b, "a_3", "e_2") - - dag_c = retworkx.digraph_union(dag_a, dag_b, False, False) - - self.assertTrue(len(dag_c.nodes()) == 6) - self.assertTrue(len(dag_c.edge_list()) == 4) - - def test_union_mismatch_edge_weight(self): - first = retworkx.PyDiGraph() - nodes = first.add_nodes_from([0, 1]) - first.add_edges_from([(nodes[0], nodes[1], "a")]) - - second = retworkx.PyDiGraph() - nodes = second.add_nodes_from([0, 1]) - second.add_edges_from([(nodes[0], nodes[1], "b")]) - - final = retworkx.digraph_union(first, second, merge_nodes=True, merge_edges=True) - self.assertEqual(final.weighted_edge_list(), [(0, 1, "a"), (0, 1, "b")]) - - def test_union_node_hole(self): - first = retworkx.PyDiGraph() - nodes = first.add_nodes_from([0, 1]) - first.add_edges_from([(nodes[0], nodes[1], "a")]) - - second = retworkx.PyDiGraph() - dummy = second.add_node("dummy") - nodes = second.add_nodes_from([0, 1]) - second.add_edges_from([(nodes[0], nodes[1], "a")]) - second.remove_node(dummy) - - final = retworkx.digraph_union(first, second, merge_nodes=True, merge_edges=True) - self.assertEqual(final.weighted_edge_list(), [(0, 1, "a")]) - - def test_union_edge_between_merged_and_unmerged_nodes(self): - first = retworkx.PyDiGraph() - nodes = first.add_nodes_from([0, 1]) - first.add_edges_from([(nodes[0], nodes[1], "a")]) - - second = retworkx.PyDiGraph() - nodes = second.add_nodes_from([0, 2]) - second.add_edges_from([(nodes[0], nodes[1], "b")]) - - final = retworkx.digraph_union(first, second, merge_nodes=True, merge_edges=True) - self.assertEqual(final.weighted_edge_list(), [(0, 1, "a"), (0, 2, "b")]) diff --git a/tests/retworkx_backwards_compat/digraph/test_weakly_connected.py b/tests/retworkx_backwards_compat/digraph/test_weakly_connected.py deleted file mode 100644 index 93fdcbdde..000000000 --- a/tests/retworkx_backwards_compat/digraph/test_weakly_connected.py +++ /dev/null @@ -1,81 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestWeaklyConnected(unittest.TestCase): - def test_number_weakly_connected_all_strong(self): - G = retworkx.PyDAG() - node_a = G.add_node(1) - node_b = G.add_child(node_a, 2, {}) - G.add_child(node_b, 3, {}) - self.assertEqual(retworkx.number_weakly_connected_components(G), 1) - - def test_number_weakly_connected(self): - G = retworkx.PyDAG() - node_a = G.add_node(1) - G.add_child(node_a, 2, {}) - G.add_node(3) - self.assertEqual(retworkx.number_weakly_connected_components(G), 2) - - def test_number_weakly_connected_big(self): - G = retworkx.PyDAG() - for i in range(100000): - node = G.add_node(i) - G.add_child(node, str(i), {}) - self.assertEqual(retworkx.number_weakly_connected_components(G), 100000) - - def test_number_weakly_connected_node_holes(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from([0, 1, 2]) - graph.remove_node(1) - self.assertEqual(retworkx.number_weakly_connected_components(graph), 2) - - def test_weakly_connected_components(self): - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list( - [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4)] - ) - components = retworkx.weakly_connected_components(graph) - self.assertEqual([{0, 1, 2, 3}, {4, 5, 6, 7}], components) - - def test_is_weakly_connected_false(self): - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list( - [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4)] - ) - self.assertFalse(retworkx.is_weakly_connected(graph)) - - def test_is_weakly_connected_true(self): - graph = retworkx.PyDiGraph() - graph.extend_from_edge_list( - [ - (0, 1), - (1, 2), - (2, 3), - (3, 0), - (2, 4), - (4, 5), - (5, 6), - (6, 7), - (7, 4), - ] - ) - self.assertTrue(retworkx.is_weakly_connected(graph)) - - def test_is_weakly_connected_null_graph(self): - graph = retworkx.PyDiGraph() - with self.assertRaises(retworkx.NullGraph): - retworkx.is_weakly_connected(graph) diff --git a/tests/retworkx_backwards_compat/generators/__init__.py b/tests/retworkx_backwards_compat/generators/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/retworkx_backwards_compat/generators/test_barbell.py b/tests/retworkx_backwards_compat/generators/test_barbell.py deleted file mode 100644 index 596ca95ad..000000000 --- a/tests/retworkx_backwards_compat/generators/test_barbell.py +++ /dev/null @@ -1,57 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestBarbellGraph(unittest.TestCase): - def test_barbell_graph_count(self): - graph = retworkx.generators.barbell_graph(17, 3) - self.assertEqual(len(graph), 37) - self.assertEqual(len(graph.edges()), 276) - - def test_barbell_graph_edge(self): - graph = retworkx.generators.barbell_graph(4, 3) - edge_list = graph.edge_list() - expected_edge_list = set( - [ - (0, 1), - (0, 2), - (0, 3), - (1, 2), - (1, 3), - (2, 3), - (3, 4), - (4, 5), - (5, 6), - (6, 7), - (7, 8), - (7, 9), - (7, 10), - (8, 9), - (8, 10), - (9, 10), - ] - ) - self.assertEqual(set(edge_list), set(expected_edge_list)) - - def test_barbell_graph_no_path_num(self): - graph = retworkx.generators.barbell_graph(4) - mesh = retworkx.generators.mesh_graph(4) - mesh.compose(mesh.copy(), {3: (0, None)}) - self.assertEqual(set(graph.edge_list()), set(mesh.edge_list())) - - def test_barbell_graph_no_mesh_num(self): - with self.assertRaises(IndexError): - retworkx.generators.barbell_graph() diff --git a/tests/retworkx_backwards_compat/generators/test_binomial_tree.py b/tests/retworkx_backwards_compat/generators/test_binomial_tree.py deleted file mode 100644 index f055bbbc0..000000000 --- a/tests/retworkx_backwards_compat/generators/test_binomial_tree.py +++ /dev/null @@ -1,195 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestBinomialTreeGraph(unittest.TestCase): - def test_binomial_tree_graph(self): - expected_edges = { - 0: [], - 1: [(0, 1)], - 2: [(0, 1), (2, 3), (0, 2)], - 3: [(0, 1), (2, 3), (0, 2), (4, 5), (6, 7), (4, 6), (0, 4)], - 4: [ - (0, 1), - (2, 3), - (0, 2), - (4, 5), - (6, 7), - (4, 6), - (0, 4), - (8, 9), - (10, 11), - (8, 10), - (12, 13), - (14, 15), - (12, 14), - (8, 12), - (0, 8), - ], - } - for n in range(5): - with self.subTest(n=n): - graph = retworkx.generators.binomial_tree_graph(n) - self.assertEqual(len(graph), 2**n) - self.assertEqual(len(graph.edges()), 2**n - 1) - self.assertEqual(list(graph.edge_list()), expected_edges[n]) - - def test_binomial_tree_graph_weights(self): - graph = retworkx.generators.binomial_tree_graph(2, weights=list(range(4))) - expected_edges = [(0, 1), (2, 3), (0, 2)] - self.assertEqual(len(graph), 4) - self.assertEqual([x for x in range(4)], graph.nodes()) - self.assertEqual(len(graph.edges()), 3) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_binomial_tree_graph_weight_less_nodes(self): - graph = retworkx.generators.binomial_tree_graph(2, weights=list(range(2))) - self.assertEqual(len(graph), 4) - expected_weights = [x for x in range(2)] - expected_weights.extend([None, None]) - self.assertEqual(expected_weights, graph.nodes()) - self.assertEqual(len(graph.edges()), 3) - - def test_binomial_tree_graph_weights_greater_nodes(self): - with self.assertRaises(IndexError): - retworkx.generators.binomial_tree_graph(2, weights=list(range(7))) - - def test_binomial_tree_no_order(self): - with self.assertRaises(TypeError): - retworkx.generators.binomial_tree_graph(weights=list(range(4))) - - def test_directed_binomial_tree_graph(self): - expected_edges = { - 0: [], - 1: [(0, 1)], - 2: [(0, 1), (2, 3), (0, 2)], - 3: [(0, 1), (2, 3), (0, 2), (4, 5), (6, 7), (4, 6), (0, 4)], - 4: [ - (0, 1), - (2, 3), - (0, 2), - (4, 5), - (6, 7), - (4, 6), - (0, 4), - (8, 9), - (10, 11), - (8, 10), - (12, 13), - (14, 15), - (12, 14), - (8, 12), - (0, 8), - ], - } - - for n in range(5): - with self.subTest(n=n): - graph = retworkx.generators.directed_binomial_tree_graph(n) - self.assertEqual(len(graph), 2**n) - self.assertEqual(len(graph.edges()), 2**n - 1) - self.assertEqual(list(graph.edge_list()), expected_edges[n]) - - def test_directed_binomial_tree_graph_weights(self): - graph = retworkx.generators.directed_binomial_tree_graph(2, weights=list(range(4))) - self.assertEqual(len(graph), 4) - self.assertEqual([x for x in range(4)], graph.nodes()) - self.assertEqual(len(graph.edges()), 3) - - def test_directed_binomial_tree_graph_weight_less_nodes(self): - graph = retworkx.generators.directed_binomial_tree_graph(2, weights=list(range(2))) - self.assertEqual(len(graph), 4) - expected_weights = [x for x in range(2)] - expected_weights.extend([None, None]) - self.assertEqual(expected_weights, graph.nodes()) - self.assertEqual(len(graph.edges()), 3) - - def test_directed_binomial_tree_graph_weights_greater_nodes(self): - with self.assertRaises(IndexError): - retworkx.generators.directed_binomial_tree_graph(2, weights=list(range(7))) - - def test_directed_binomial_tree_no_order(self): - with self.assertRaises(TypeError): - retworkx.generators.directed_binomial_tree_graph(weights=list(range(4))) - - def test_directed_binomial_tree_graph_bidirectional(self): - expected_edges = { - 0: [], - 1: [(0, 1), (1, 0)], - 2: [(0, 1), (1, 0), (2, 3), (3, 2), (0, 2), (2, 0)], - 3: [ - (0, 1), - (1, 0), - (2, 3), - (3, 2), - (0, 2), - (2, 0), - (4, 5), - (5, 4), - (6, 7), - (7, 6), - (4, 6), - (6, 4), - (0, 4), - (4, 0), - ], - 4: [ - (0, 1), - (1, 0), - (2, 3), - (3, 2), - (0, 2), - (2, 0), - (4, 5), - (5, 4), - (6, 7), - (7, 6), - (4, 6), - (6, 4), - (0, 4), - (4, 0), - (8, 9), - (9, 8), - (10, 11), - (11, 10), - (8, 10), - (10, 8), - (12, 13), - (13, 12), - (14, 15), - (15, 14), - (12, 14), - (14, 12), - (8, 12), - (12, 8), - (0, 8), - (8, 0), - ], - } - for n in range(5): - with self.subTest(n=n): - graph = retworkx.generators.directed_binomial_tree_graph(n, bidirectional=True) - self.assertEqual(len(graph), 2**n) - self.assertEqual(len(graph.edges()), 2 * (2**n - 1)) - self.assertEqual(list(graph.edge_list()), expected_edges[n]) - - def test_overflow_binomial_tree(self): - with self.assertRaises(OverflowError): - retworkx.generators.binomial_tree_graph(75) - - def test_overflow_directed_binomial_tree(self): - with self.assertRaises(OverflowError): - retworkx.generators.directed_binomial_tree_graph(75) diff --git a/tests/retworkx_backwards_compat/generators/test_cycle.py b/tests/retworkx_backwards_compat/generators/test_cycle.py deleted file mode 100644 index 72199776e..000000000 --- a/tests/retworkx_backwards_compat/generators/test_cycle.py +++ /dev/null @@ -1,71 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestCycleGraph(unittest.TestCase): - def test_directed_cycle_graph(self): - graph = retworkx.generators.directed_cycle_graph(20) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 20) - for i in range(19): - self.assertEqual(graph.out_edges(i), [(i, i + 1, None)]) - self.assertEqual(graph.out_edges(19), [(19, 0, None)]) - - def test_directed_cycle_graph_weights(self): - graph = retworkx.generators.directed_cycle_graph(weights=list(range(20))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 20) - for i in range(19): - self.assertEqual(graph.out_edges(i), [(i, i + 1, None)]) - self.assertEqual(graph.out_edges(19), [(19, 0, None)]) - - def test_directed_cycle_graph_bidirectional(self): - graph = retworkx.generators.directed_cycle_graph(20, bidirectional=True) - self.assertEqual(graph.out_edges(0), [(0, 19, None), (0, 1, None)]) - self.assertEqual(graph.in_edges(0), [(19, 0, None), (1, 0, None)]) - for i in range(1, 19): - self.assertEqual(graph.out_edges(i), [(i, i + 1, None), (i, i - 1, None)]) - self.assertEqual(graph.in_edges(i), [(i + 1, i, None), (i - 1, i, None)]) - self.assertEqual(graph.out_edges(19), [(19, 0, None), (19, 18, None)]) - self.assertEqual(graph.in_edges(19), [(0, 19, None), (18, 19, None)]) - - def test_cycle_directed_no_weights_or_num(self): - with self.assertRaises(IndexError): - retworkx.generators.directed_cycle_graph() - - def test_cycle_graph(self): - graph = retworkx.generators.cycle_graph(20) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 20) - - def test_cycle_graph_weights(self): - graph = retworkx.generators.cycle_graph(weights=list(range(20))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 20) - - def test_cycle_no_weights_or_num(self): - with self.assertRaises(IndexError): - retworkx.generators.cycle_graph() - - def test_zero_length_cycle_graph(self): - graph = retworkx.generators.cycle_graph(0) - self.assertEqual(0, len(graph)) - - def test_zero_length_directed_cycle_graph(self): - graph = retworkx.generators.directed_cycle_graph(0) - self.assertEqual(0, len(graph)) diff --git a/tests/retworkx_backwards_compat/generators/test_full_rary_tree.py b/tests/retworkx_backwards_compat/generators/test_full_rary_tree.py deleted file mode 100644 index 93195a99a..000000000 --- a/tests/retworkx_backwards_compat/generators/test_full_rary_tree.py +++ /dev/null @@ -1,89 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest -import retworkx - - -class TestFullRaryTreeTreeGraph(unittest.TestCase): - def test_full_rary_tree_graph(self): - b_factors = { - 0: 0, - 1: 2, - 2: 2, - 3: 5, - } - num_nodes = { - 0: 0, - 1: 4, - 2: 10, - 3: 15, - } - expected_edges = { - 0: [], - 1: [(0, 1), (0, 2), (1, 3)], - 2: [ - (0, 1), - (0, 2), - (1, 3), - (1, 4), - (2, 5), - (2, 6), - (3, 7), - (3, 8), - (4, 9), - ], - 3: [ - (0, 1), - (0, 2), - (0, 3), - (0, 4), - (0, 5), - (1, 6), - (1, 7), - (1, 8), - (1, 9), - (1, 10), - (2, 11), - (2, 12), - (2, 13), - (2, 14), - ], - } - for n in range(4): - with self.subTest(n=n): - graph = retworkx.generators.full_rary_tree(b_factors[n], num_nodes[n]) - self.assertEqual(list(graph.edge_list()), expected_edges[n]) - - def test_full_rary_tree_graph_weights(self): - graph = retworkx.generators.full_rary_tree(2, 4, weights=list(range(4))) - expected_edges = [(0, 1), (0, 2), (1, 3)] - self.assertEqual(len(graph), 4) - self.assertEqual([x for x in range(4)], graph.nodes()) - self.assertEqual(len(graph.edges()), 3) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_full_rary_tree_graph_weight_less_nodes(self): - graph = retworkx.generators.full_rary_tree(2, 6, weights=list(range(4))) - self.assertEqual(len(graph), 6) - expected_weights = [x for x in range(4)] - expected_weights.extend([None, None]) - self.assertEqual(expected_weights, graph.nodes()) - self.assertEqual(len(graph.edges()), 5) - - def test_full_rary_tree_graph_weights_greater_nodes(self): - with self.assertRaises(IndexError): - retworkx.generators.full_rary_tree(2, 4, weights=list(range(7))) - - def test_full_rary_tree_no_order(self): - with self.assertRaises(TypeError): - retworkx.generators.full_rary_tree(weights=list(range(4))) diff --git a/tests/retworkx_backwards_compat/generators/test_grid.py b/tests/retworkx_backwards_compat/generators/test_grid.py deleted file mode 100644 index a50c4653d..000000000 --- a/tests/retworkx_backwards_compat/generators/test_grid.py +++ /dev/null @@ -1,131 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestGridGraph(unittest.TestCase): - def test_directed_grid_graph_dimensions(self): - graph = retworkx.generators.directed_grid_graph(4, 5) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 31) - self.assertEqual(graph.out_edges(0), [(0, 1, None), (0, 5, None)]) - self.assertEqual(graph.out_edges(7), [(7, 8, None), (7, 12, None)]) - self.assertEqual(graph.out_edges(9), [(9, 14, None)]) - self.assertEqual(graph.out_edges(17), [(17, 18, None)]) - self.assertEqual(graph.out_edges(19), []) - self.assertEqual(graph.in_edges(0), []) - self.assertEqual(graph.in_edges(2), [(1, 2, None)]) - self.assertEqual(graph.in_edges(5), [(0, 5, None)]) - self.assertEqual(graph.in_edges(7), [(6, 7, None), (2, 7, None)]) - self.assertEqual(graph.in_edges(19), [(18, 19, None), (14, 19, None)]) - - def test_directed_grid_graph_weights(self): - graph = retworkx.generators.directed_grid_graph(weights=list(range(20))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 19) - for i in range(19): - self.assertEqual(graph.out_edges(i), [(i, i + 1, None)]) - self.assertEqual(graph.out_edges(19), []) - for i in range(1, 20): - self.assertEqual(graph.in_edges(i), [(i - 1, i, None)]) - self.assertEqual(graph.in_edges(0), []) - - def test_directed_grid_graph_dimensions_weights(self): - graph = retworkx.generators.directed_grid_graph(4, 5, weights=list(range(20))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 31) - self.assertEqual(graph.out_edges(0), [(0, 1, None), (0, 5, None)]) - self.assertEqual(graph.out_edges(7), [(7, 8, None), (7, 12, None)]) - self.assertEqual(graph.out_edges(9), [(9, 14, None)]) - self.assertEqual(graph.out_edges(17), [(17, 18, None)]) - self.assertEqual(graph.out_edges(19), []) - self.assertEqual(graph.in_edges(0), []) - self.assertEqual(graph.in_edges(2), [(1, 2, None)]) - self.assertEqual(graph.in_edges(5), [(0, 5, None)]) - self.assertEqual(graph.in_edges(7), [(6, 7, None), (2, 7, None)]) - self.assertEqual(graph.in_edges(19), [(18, 19, None), (14, 19, None)]) - - def test_directed_grid_graph_more_dimensions_weights(self): - graph = retworkx.generators.directed_grid_graph(4, 5, weights=list(range(16))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(16)] + [None] * 4, graph.nodes()) - self.assertEqual(len(graph.edges()), 31) - self.assertEqual(graph.out_edges(0), [(0, 1, None), (0, 5, None)]) - self.assertEqual(graph.out_edges(7), [(7, 8, None), (7, 12, None)]) - self.assertEqual(graph.out_edges(9), [(9, 14, None)]) - self.assertEqual(graph.out_edges(17), [(17, 18, None)]) - self.assertEqual(graph.out_edges(19), []) - self.assertEqual(graph.in_edges(0), []) - self.assertEqual(graph.in_edges(2), [(1, 2, None)]) - self.assertEqual(graph.in_edges(5), [(0, 5, None)]) - self.assertEqual(graph.in_edges(7), [(6, 7, None), (2, 7, None)]) - self.assertEqual(graph.in_edges(19), [(18, 19, None), (14, 19, None)]) - - def test_directed_grid_graph_less_dimensions_weights(self): - graph = retworkx.generators.directed_grid_graph(4, 5, weights=list(range(24))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 31) - self.assertEqual(graph.out_edges(0), [(0, 1, None), (0, 5, None)]) - self.assertEqual(graph.out_edges(7), [(7, 8, None), (7, 12, None)]) - self.assertEqual(graph.out_edges(9), [(9, 14, None)]) - self.assertEqual(graph.out_edges(17), [(17, 18, None)]) - self.assertEqual(graph.out_edges(19), []) - self.assertEqual(graph.in_edges(0), []) - self.assertEqual(graph.in_edges(2), [(1, 2, None)]) - self.assertEqual(graph.in_edges(5), [(0, 5, None)]) - self.assertEqual(graph.in_edges(7), [(6, 7, None), (2, 7, None)]) - self.assertEqual(graph.in_edges(19), [(18, 19, None), (14, 19, None)]) - - def test_grid_directed_no_weights_or_dim(self): - with self.assertRaises(IndexError): - retworkx.generators.directed_grid_graph() - retworkx.generators.directed_grid_graph(rows=5, weights=[1] * 5) - retworkx.generators.directed_grid_graph(cols=5, weights=[1] * 5) - - def test_grid_graph_dimensions(self): - graph = retworkx.generators.grid_graph(4, 5) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 31) - - def test_grid_graph_weights(self): - graph = retworkx.generators.grid_graph(weights=list(range(20))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 19) - - def test_grid_graph_dimensions_weights(self): - graph = retworkx.generators.grid_graph(4, 5, weights=list(range(20))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 31) - - graph = retworkx.generators.grid_graph(4, 5, weights=list(range(16))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(16)] + [None] * 4, graph.nodes()) - self.assertEqual(len(graph.edges()), 31) - - graph = retworkx.generators.grid_graph(4, 5, weights=list(range(24))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 31) - - def test_grid_no_weights_or_dim(self): - with self.assertRaises(IndexError): - retworkx.generators.grid_graph() - retworkx.generators.grid_graph(rows=5, weights=[1] * 5) - retworkx.generators.grid_graph(cols=5, weights=[1] * 5) diff --git a/tests/retworkx_backwards_compat/generators/test_heavy_hex.py b/tests/retworkx_backwards_compat/generators/test_heavy_hex.py deleted file mode 100644 index 09e5093fc..000000000 --- a/tests/retworkx_backwards_compat/generators/test_heavy_hex.py +++ /dev/null @@ -1,424 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestHeavyHexGraph(unittest.TestCase): - def test_directed_heavy_hex_graph_1(self): - d = 1 - graph = retworkx.generators.directed_heavy_hex_graph(d) - self.assertEqual(1, len(graph)) - self.assertEqual(graph.edge_list(), []) - - def test_heavy_hex_graph_1(self): - d = 1 - graph = retworkx.generators.heavy_hex_graph(d) - self.assertEqual(1, len(graph)) - self.assertEqual(graph.edge_list(), []) - - def test_directed_heavy_hex_graph_3(self): - d = 3 - graph = retworkx.generators.directed_heavy_hex_graph(d) - self.assertEqual(len(graph), (5 * d * d - 2 * d - 1) / 2) - self.assertEqual(len(graph.edges()), 2 * d * (d - 1) + (d + 1) * (d - 1)) - expected_edges = [ - (0, 13), - (1, 13), - (1, 14), - (2, 14), - (3, 15), - (4, 15), - (4, 16), - (5, 16), - (6, 17), - (7, 17), - (7, 18), - (8, 18), - (0, 9), - (3, 9), - (5, 12), - (8, 12), - (10, 14), - (10, 16), - (11, 15), - (11, 17), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_heavy_hex_graph_3_bidirectional(self): - d = 3 - graph = retworkx.generators.directed_heavy_hex_graph(d, bidirectional=True) - self.assertEqual(len(graph), (5 * d * d - 2 * d - 1) / 2) - self.assertEqual(len(graph.edges()), 2 * (2 * d * (d - 1) + (d + 1) * (d - 1))) - expected_edges = [ - (0, 13), - (1, 13), - (13, 0), - (13, 1), - (1, 14), - (2, 14), - (14, 1), - (14, 2), - (3, 15), - (4, 15), - (15, 3), - (15, 4), - (4, 16), - (5, 16), - (16, 4), - (16, 5), - (6, 17), - (7, 17), - (17, 6), - (17, 7), - (7, 18), - (8, 18), - (18, 7), - (18, 8), - (0, 9), - (3, 9), - (9, 0), - (9, 3), - (5, 12), - (8, 12), - (12, 5), - (12, 8), - (10, 14), - (10, 16), - (14, 10), - (16, 10), - (11, 15), - (11, 17), - (15, 11), - (17, 11), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_heavy_hex_graph_3(self): - d = 3 - graph = retworkx.generators.heavy_hex_graph(d) - self.assertEqual(len(graph), (5 * d * d - 2 * d - 1) / 2) - self.assertEqual(len(graph.edges()), 2 * d * (d - 1) + (d + 1) * (d - 1)) - expected_edges = [ - (0, 13), - (1, 13), - (1, 14), - (2, 14), - (3, 15), - (4, 15), - (4, 16), - (5, 16), - (6, 17), - (7, 17), - (7, 18), - (8, 18), - (0, 9), - (3, 9), - (5, 12), - (8, 12), - (10, 14), - (10, 16), - (11, 15), - (11, 17), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_heavy_hex_graph_5(self): - d = 5 - graph = retworkx.generators.directed_heavy_hex_graph(d) - self.assertEqual(len(graph), (5 * d * d - 2 * d - 1) / 2) - self.assertEqual(len(graph.edges()), 2 * d * (d - 1) + (d + 1) * (d - 1)) - expected_edges = [ - (0, 37), - (1, 37), - (1, 38), - (2, 38), - (2, 39), - (3, 39), - (3, 40), - (4, 40), - (5, 41), - (6, 41), - (6, 42), - (7, 42), - (7, 43), - (8, 43), - (8, 44), - (9, 44), - (10, 45), - (11, 45), - (11, 46), - (12, 46), - (12, 47), - (13, 47), - (13, 48), - (14, 48), - (15, 49), - (16, 49), - (16, 50), - (17, 50), - (17, 51), - (18, 51), - (18, 52), - (19, 52), - (20, 53), - (21, 53), - (21, 54), - (22, 54), - (22, 55), - (23, 55), - (23, 56), - (24, 56), - (0, 25), - (5, 25), - (9, 30), - (14, 30), - (10, 31), - (15, 31), - (19, 36), - (24, 36), - (26, 38), - (26, 42), - (27, 40), - (27, 44), - (28, 41), - (28, 45), - (29, 43), - (29, 47), - (32, 46), - (32, 50), - (33, 48), - (33, 52), - (34, 49), - (34, 53), - (35, 51), - (35, 55), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_heavy_hex_graph_5_bidirectional(self): - d = 5 - graph = retworkx.generators.directed_heavy_hex_graph(d, bidirectional=True) - self.assertEqual(len(graph), (5 * d * d - 2 * d - 1) / 2) - self.assertEqual(len(graph.edges()), 2 * (2 * d * (d - 1) + (d + 1) * (d - 1))) - expected_edges = [ - (0, 37), - (1, 37), - (37, 0), - (37, 1), - (1, 38), - (2, 38), - (38, 1), - (38, 2), - (2, 39), - (3, 39), - (39, 2), - (39, 3), - (3, 40), - (4, 40), - (40, 3), - (40, 4), - (5, 41), - (6, 41), - (41, 5), - (41, 6), - (6, 42), - (7, 42), - (42, 6), - (42, 7), - (7, 43), - (8, 43), - (43, 7), - (43, 8), - (8, 44), - (9, 44), - (44, 8), - (44, 9), - (10, 45), - (11, 45), - (45, 10), - (45, 11), - (11, 46), - (12, 46), - (46, 11), - (46, 12), - (12, 47), - (13, 47), - (47, 12), - (47, 13), - (13, 48), - (14, 48), - (48, 13), - (48, 14), - (15, 49), - (16, 49), - (49, 15), - (49, 16), - (16, 50), - (17, 50), - (50, 16), - (50, 17), - (17, 51), - (18, 51), - (51, 17), - (51, 18), - (18, 52), - (19, 52), - (52, 18), - (52, 19), - (20, 53), - (21, 53), - (53, 20), - (53, 21), - (21, 54), - (22, 54), - (54, 21), - (54, 22), - (22, 55), - (23, 55), - (55, 22), - (55, 23), - (23, 56), - (24, 56), - (56, 23), - (56, 24), - (0, 25), - (5, 25), - (25, 0), - (25, 5), - (9, 30), - (14, 30), - (30, 9), - (30, 14), - (10, 31), - (15, 31), - (31, 10), - (31, 15), - (19, 36), - (24, 36), - (36, 19), - (36, 24), - (26, 38), - (26, 42), - (38, 26), - (42, 26), - (27, 40), - (27, 44), - (40, 27), - (44, 27), - (28, 41), - (28, 45), - (41, 28), - (45, 28), - (29, 43), - (29, 47), - (43, 29), - (47, 29), - (32, 46), - (32, 50), - (46, 32), - (50, 32), - (33, 48), - (33, 52), - (48, 33), - (52, 33), - (34, 49), - (34, 53), - (49, 34), - (53, 34), - (35, 51), - (35, 55), - (51, 35), - (55, 35), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_heavy_hex_graph_5(self): - d = 5 - graph = retworkx.generators.heavy_hex_graph(d) - self.assertEqual(len(graph), (5 * d * d - 2 * d - 1) / 2) - self.assertEqual(len(graph.edges()), 2 * d * (d - 1) + (d + 1) * (d - 1)) - expected_edges = [ - (0, 37), - (1, 37), - (1, 38), - (2, 38), - (2, 39), - (3, 39), - (3, 40), - (4, 40), - (5, 41), - (6, 41), - (6, 42), - (7, 42), - (7, 43), - (8, 43), - (8, 44), - (9, 44), - (10, 45), - (11, 45), - (11, 46), - (12, 46), - (12, 47), - (13, 47), - (13, 48), - (14, 48), - (15, 49), - (16, 49), - (16, 50), - (17, 50), - (17, 51), - (18, 51), - (18, 52), - (19, 52), - (20, 53), - (21, 53), - (21, 54), - (22, 54), - (22, 55), - (23, 55), - (23, 56), - (24, 56), - (0, 25), - (5, 25), - (9, 30), - (14, 30), - (10, 31), - (15, 31), - (19, 36), - (24, 36), - (26, 38), - (26, 42), - (27, 40), - (27, 44), - (28, 41), - (28, 45), - (29, 43), - (29, 47), - (32, 46), - (32, 50), - (33, 48), - (33, 52), - (34, 49), - (34, 53), - (35, 51), - (35, 55), - ] - - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_heavy_hex_graph_even_d(self): - with self.assertRaises(IndexError): - retworkx.generators.heavy_hex_graph(2) diff --git a/tests/retworkx_backwards_compat/generators/test_heavy_square.py b/tests/retworkx_backwards_compat/generators/test_heavy_square.py deleted file mode 100644 index c47e7d9e7..000000000 --- a/tests/retworkx_backwards_compat/generators/test_heavy_square.py +++ /dev/null @@ -1,503 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestHeavyHexGraph(unittest.TestCase): - def test_directed_heavy_hex_graph_1(self): - d = 1 - graph = retworkx.generators.directed_heavy_square_graph(d) - self.assertEqual(1, len(graph)) - self.assertEqual(graph.edge_list(), []) - - def test_heavy_hex_graph_1(self): - d = 1 - graph = retworkx.generators.heavy_square_graph(d) - self.assertEqual(1, len(graph)) - self.assertEqual(graph.edge_list(), []) - - def test_directed_heavy_square_graph_5(self): - d = 5 - graph = retworkx.generators.directed_heavy_square_graph(d) - self.assertEqual(len(graph), 3 * d * d - 2 * d) - self.assertEqual(len(graph.edges()), 2 * d * (d - 1) + 2 * d * (d - 1)) - expected_edges = [ - (0, 45), - (45, 1), - (1, 46), - (46, 2), - (2, 47), - (47, 3), - (3, 48), - (48, 4), - (5, 49), - (49, 6), - (6, 50), - (50, 7), - (7, 51), - (51, 8), - (8, 52), - (52, 9), - (10, 53), - (53, 11), - (11, 54), - (54, 12), - (12, 55), - (55, 13), - (13, 56), - (56, 14), - (15, 57), - (57, 16), - (16, 58), - (58, 17), - (17, 59), - (59, 18), - (18, 60), - (60, 19), - (20, 61), - (61, 21), - (21, 62), - (62, 22), - (22, 63), - (63, 23), - (23, 64), - (64, 24), - (4, 29), - (9, 29), - (5, 30), - (10, 30), - (14, 39), - (19, 39), - (15, 40), - (20, 40), - (25, 45), - (25, 49), - (26, 46), - (26, 50), - (27, 47), - (27, 51), - (28, 48), - (28, 52), - (31, 49), - (31, 53), - (32, 50), - (32, 54), - (33, 51), - (33, 55), - (34, 52), - (34, 56), - (35, 53), - (35, 57), - (36, 54), - (36, 58), - (37, 55), - (37, 59), - (38, 56), - (38, 60), - (41, 57), - (41, 61), - (42, 58), - (42, 62), - (43, 59), - (43, 63), - (44, 60), - (44, 64), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_heavy_square_graph_5_bidirectional(self): - d = 5 - graph = retworkx.generators.directed_heavy_square_graph(d, bidirectional=True) - self.assertEqual(len(graph), 3 * d * d - 2 * d) - self.assertEqual(len(graph.edges()), 2 * (2 * d * (d - 1) + 2 * d * (d - 1))) - expected_edges = [ - (0, 45), - (45, 1), - (45, 0), - (1, 45), - (1, 46), - (46, 2), - (46, 1), - (2, 46), - (2, 47), - (47, 3), - (47, 2), - (3, 47), - (3, 48), - (48, 4), - (48, 3), - (4, 48), - (5, 49), - (49, 6), - (49, 5), - (6, 49), - (6, 50), - (50, 7), - (50, 6), - (7, 50), - (7, 51), - (51, 8), - (51, 7), - (8, 51), - (8, 52), - (52, 9), - (52, 8), - (9, 52), - (10, 53), - (53, 11), - (53, 10), - (11, 53), - (11, 54), - (54, 12), - (54, 11), - (12, 54), - (12, 55), - (55, 13), - (55, 12), - (13, 55), - (13, 56), - (56, 14), - (56, 13), - (14, 56), - (15, 57), - (57, 16), - (57, 15), - (16, 57), - (16, 58), - (58, 17), - (58, 16), - (17, 58), - (17, 59), - (59, 18), - (59, 17), - (18, 59), - (18, 60), - (60, 19), - (60, 18), - (19, 60), - (20, 61), - (61, 21), - (61, 20), - (21, 61), - (21, 62), - (62, 22), - (62, 21), - (22, 62), - (22, 63), - (63, 23), - (63, 22), - (23, 63), - (23, 64), - (64, 24), - (64, 23), - (24, 64), - (4, 29), - (9, 29), - (29, 4), - (29, 9), - (5, 30), - (10, 30), - (30, 5), - (30, 10), - (14, 39), - (19, 39), - (39, 14), - (39, 19), - (15, 40), - (20, 40), - (40, 15), - (40, 20), - (25, 45), - (25, 49), - (45, 25), - (49, 25), - (26, 46), - (26, 50), - (46, 26), - (50, 26), - (27, 47), - (27, 51), - (47, 27), - (51, 27), - (28, 48), - (28, 52), - (48, 28), - (52, 28), - (31, 49), - (31, 53), - (49, 31), - (53, 31), - (32, 50), - (32, 54), - (50, 32), - (54, 32), - (33, 51), - (33, 55), - (51, 33), - (55, 33), - (34, 52), - (34, 56), - (52, 34), - (56, 34), - (35, 53), - (35, 57), - (53, 35), - (57, 35), - (36, 54), - (36, 58), - (54, 36), - (58, 36), - (37, 55), - (37, 59), - (55, 37), - (59, 37), - (38, 56), - (38, 60), - (56, 38), - (60, 38), - (41, 57), - (41, 61), - (57, 41), - (61, 41), - (42, 58), - (42, 62), - (58, 42), - (62, 42), - (43, 59), - (43, 63), - (59, 43), - (63, 43), - (44, 60), - (44, 64), - (60, 44), - (64, 44), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_heavy_square_graph_5(self): - d = 5 - graph = retworkx.generators.heavy_square_graph(d) - self.assertEqual(len(graph), 3 * d * d - 2 * d) - self.assertEqual(len(graph.edges()), 2 * d * (d - 1) + 2 * d * (d - 1)) - expected_edges = [ - (0, 45), - (45, 1), - (1, 46), - (46, 2), - (2, 47), - (47, 3), - (3, 48), - (48, 4), - (5, 49), - (49, 6), - (6, 50), - (50, 7), - (7, 51), - (51, 8), - (8, 52), - (52, 9), - (10, 53), - (53, 11), - (11, 54), - (54, 12), - (12, 55), - (55, 13), - (13, 56), - (56, 14), - (15, 57), - (57, 16), - (16, 58), - (58, 17), - (17, 59), - (59, 18), - (18, 60), - (60, 19), - (20, 61), - (61, 21), - (21, 62), - (62, 22), - (22, 63), - (63, 23), - (23, 64), - (64, 24), - (4, 29), - (9, 29), - (5, 30), - (10, 30), - (14, 39), - (19, 39), - (15, 40), - (20, 40), - (25, 45), - (25, 49), - (26, 46), - (26, 50), - (27, 47), - (27, 51), - (28, 48), - (28, 52), - (31, 49), - (31, 53), - (32, 50), - (32, 54), - (33, 51), - (33, 55), - (34, 52), - (34, 56), - (35, 53), - (35, 57), - (36, 54), - (36, 58), - (37, 55), - (37, 59), - (38, 56), - (38, 60), - (41, 57), - (41, 61), - (42, 58), - (42, 62), - (43, 59), - (43, 63), - (44, 60), - (44, 64), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_heavy_square_graph_3(self): - d = 3 - graph = retworkx.generators.directed_heavy_square_graph(d) - self.assertEqual(len(graph), 3 * d * d - 2 * d) - self.assertEqual(len(graph.edges()), 2 * d * (d - 1) + 2 * d * (d - 1)) - expected_edges = [ - (0, 15), - (15, 1), - (1, 16), - (16, 2), - (3, 17), - (17, 4), - (4, 18), - (18, 5), - (6, 19), - (19, 7), - (7, 20), - (20, 8), - (2, 11), - (5, 11), - (3, 12), - (6, 12), - (9, 15), - (9, 17), - (10, 16), - (10, 18), - (13, 17), - (13, 19), - (14, 18), - (14, 20), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_heavy_square_graph_3_bidirectional(self): - d = 3 - graph = retworkx.generators.directed_heavy_square_graph(d, bidirectional=True) - self.assertEqual(len(graph), 3 * d * d - 2 * d) - self.assertEqual(len(graph.edges()), 2 * (2 * d * (d - 1) + 2 * d * (d - 1))) - expected_edges = [ - (0, 15), - (15, 1), - (15, 0), - (1, 15), - (1, 16), - (16, 2), - (16, 1), - (2, 16), - (3, 17), - (17, 4), - (17, 3), - (4, 17), - (4, 18), - (18, 5), - (18, 4), - (5, 18), - (6, 19), - (19, 7), - (19, 6), - (7, 19), - (7, 20), - (20, 8), - (20, 7), - (8, 20), - (2, 11), - (5, 11), - (11, 2), - (11, 5), - (3, 12), - (6, 12), - (12, 3), - (12, 6), - (9, 15), - (9, 17), - (15, 9), - (17, 9), - (10, 16), - (10, 18), - (16, 10), - (18, 10), - (13, 17), - (13, 19), - (17, 13), - (19, 13), - (14, 18), - (14, 20), - (18, 14), - (20, 14), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_heavy_square_graph_3(self): - d = 3 - graph = retworkx.generators.heavy_square_graph(d) - self.assertEqual(len(graph), 3 * d * d - 2 * d) - self.assertEqual(len(graph.edges()), 2 * d * (d - 1) + 2 * d * (d - 1)) - expected_edges = [ - (0, 15), - (15, 1), - (1, 16), - (16, 2), - (3, 17), - (17, 4), - (4, 18), - (18, 5), - (6, 19), - (19, 7), - (7, 20), - (20, 8), - (2, 11), - (5, 11), - (3, 12), - (6, 12), - (9, 15), - (9, 17), - (10, 16), - (10, 18), - (13, 17), - (13, 19), - (14, 18), - (14, 20), - ] - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_heavy_square_graph_no_d(self): - with self.assertRaises(TypeError): - retworkx.generators.heavy_square_graph() diff --git a/tests/retworkx_backwards_compat/generators/test_hexagonal.py b/tests/retworkx_backwards_compat/generators/test_hexagonal.py deleted file mode 100644 index 88fa25ca3..000000000 --- a/tests/retworkx_backwards_compat/generators/test_hexagonal.py +++ /dev/null @@ -1,417 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest -import retworkx - - -class TestHexagonalLatticeGraph(unittest.TestCase): - def test_directed_hexagonal_graph_2_2(self): - graph = retworkx.generators.directed_hexagonal_lattice_graph(2, 2) - expected_edges = [ - (0, 1), - (1, 2), - (2, 3), - (3, 4), - (5, 6), - (6, 7), - (7, 8), - (8, 9), - (9, 10), - (11, 12), - (12, 13), - (13, 14), - (14, 15), - (0, 5), - (2, 7), - (4, 9), - (6, 11), - (8, 13), - (10, 15), - ] - self.assertEqual(len(graph), 16) - self.assertEqual(len(graph.edges()), len(expected_edges)) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_hexagonal_graph_3_2(self): - graph = retworkx.generators.directed_hexagonal_lattice_graph(3, 2) - expected_edges = [ - (0, 1), - (1, 2), - (2, 3), - (3, 4), - (4, 5), - (5, 6), - (7, 8), - (8, 9), - (9, 10), - (10, 11), - (11, 12), - (12, 13), - (13, 14), - (15, 16), - (16, 17), - (17, 18), - (18, 19), - (19, 20), - (20, 21), - (0, 7), - (2, 9), - (4, 11), - (6, 13), - (8, 15), - (10, 17), - (12, 19), - (14, 21), - ] - self.assertEqual(len(graph), 22) - self.assertEqual(len(graph.edges()), len(expected_edges)) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_hexagonal_graph_2_4(self): - graph = retworkx.generators.directed_hexagonal_lattice_graph(2, 4) - expected_edges = [ - (0, 1), - (1, 2), - (2, 3), - (3, 4), - (5, 6), - (6, 7), - (7, 8), - (8, 9), - (9, 10), - (11, 12), - (12, 13), - (13, 14), - (14, 15), - (15, 16), - (17, 18), - (18, 19), - (19, 20), - (20, 21), - (21, 22), - (23, 24), - (24, 25), - (25, 26), - (26, 27), - (0, 5), - (2, 7), - (4, 9), - (6, 12), - (8, 14), - (10, 16), - (11, 17), - (13, 19), - (15, 21), - (18, 23), - (20, 25), - (22, 27), - ] - self.assertEqual(len(graph), 28) - self.assertEqual(len(graph.edges()), len(expected_edges)) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_hexagonal_graph_2_2_bidirectional(self): - graph = retworkx.generators.directed_hexagonal_lattice_graph(2, 2, bidirectional=True) - expected_edges = [ - (0, 1), - (1, 0), - (1, 2), - (2, 1), - (2, 3), - (3, 2), - (3, 4), - (4, 3), - (5, 6), - (6, 5), - (6, 7), - (7, 6), - (7, 8), - (8, 7), - (8, 9), - (9, 8), - (9, 10), - (10, 9), - (11, 12), - (12, 11), - (12, 13), - (13, 12), - (13, 14), - (14, 13), - (14, 15), - (15, 14), - (0, 5), - (5, 0), - (2, 7), - (7, 2), - (4, 9), - (9, 4), - (6, 11), - (11, 6), - (8, 13), - (13, 8), - (10, 15), - (15, 10), - ] - self.assertEqual(len(graph), 16) - self.assertEqual(len(graph.edges()), len(expected_edges)) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_hexagonal_graph_3_2_bidirectional(self): - graph = retworkx.generators.directed_hexagonal_lattice_graph(3, 2, bidirectional=True) - expected_edges = [ - (0, 1), - (1, 0), - (1, 2), - (2, 1), - (2, 3), - (3, 2), - (3, 4), - (4, 3), - (4, 5), - (5, 4), - (5, 6), - (6, 5), - (7, 8), - (8, 7), - (8, 9), - (9, 8), - (9, 10), - (10, 9), - (10, 11), - (11, 10), - (11, 12), - (12, 11), - (12, 13), - (13, 12), - (13, 14), - (14, 13), - (15, 16), - (16, 15), - (16, 17), - (17, 16), - (17, 18), - (18, 17), - (18, 19), - (19, 18), - (19, 20), - (20, 19), - (20, 21), - (21, 20), - (0, 7), - (7, 0), - (2, 9), - (9, 2), - (4, 11), - (11, 4), - (6, 13), - (13, 6), - (8, 15), - (15, 8), - (10, 17), - (17, 10), - (12, 19), - (19, 12), - (14, 21), - (21, 14), - ] - self.assertEqual(len(graph), 22) - self.assertEqual(len(graph.edges()), len(expected_edges)) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_directed_hexagonal_graph_2_4_bidirectional(self): - graph = retworkx.generators.directed_hexagonal_lattice_graph(2, 4, bidirectional=True) - expected_edges = [ - (0, 1), - (1, 0), - (1, 2), - (2, 1), - (2, 3), - (3, 2), - (3, 4), - (4, 3), - (5, 6), - (6, 5), - (6, 7), - (7, 6), - (7, 8), - (8, 7), - (8, 9), - (9, 8), - (9, 10), - (10, 9), - (11, 12), - (12, 11), - (12, 13), - (13, 12), - (13, 14), - (14, 13), - (14, 15), - (15, 14), - (15, 16), - (16, 15), - (17, 18), - (18, 17), - (18, 19), - (19, 18), - (19, 20), - (20, 19), - (20, 21), - (21, 20), - (21, 22), - (22, 21), - (23, 24), - (24, 23), - (24, 25), - (25, 24), - (25, 26), - (26, 25), - (26, 27), - (27, 26), - (0, 5), - (5, 0), - (2, 7), - (7, 2), - (4, 9), - (9, 4), - (6, 12), - (12, 6), - (8, 14), - (14, 8), - (10, 16), - (16, 10), - (11, 17), - (17, 11), - (13, 19), - (19, 13), - (15, 21), - (21, 15), - (18, 23), - (23, 18), - (20, 25), - (25, 20), - (22, 27), - (27, 22), - ] - self.assertEqual(len(graph), 28) - self.assertEqual(len(graph.edges()), len(expected_edges)) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_hexagonal_graph_2_2(self): - graph = retworkx.generators.hexagonal_lattice_graph(2, 2) - expected_edges = [ - (0, 1), - (1, 2), - (2, 3), - (3, 4), - (5, 6), - (6, 7), - (7, 8), - (8, 9), - (9, 10), - (11, 12), - (12, 13), - (13, 14), - (14, 15), - (0, 5), - (2, 7), - (4, 9), - (6, 11), - (8, 13), - (10, 15), - ] - self.assertEqual(len(graph), 16) - self.assertEqual(len(graph.edges()), len(expected_edges)) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_hexagonal_graph_3_2(self): - graph = retworkx.generators.hexagonal_lattice_graph(3, 2) - expected_edges = [ - (0, 1), - (1, 2), - (2, 3), - (3, 4), - (4, 5), - (5, 6), - (7, 8), - (8, 9), - (9, 10), - (10, 11), - (11, 12), - (12, 13), - (13, 14), - (15, 16), - (16, 17), - (17, 18), - (18, 19), - (19, 20), - (20, 21), - (0, 7), - (2, 9), - (4, 11), - (6, 13), - (8, 15), - (10, 17), - (12, 19), - (14, 21), - ] - self.assertEqual(len(graph), 22) - self.assertEqual(len(graph.edges()), 27) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_hexagonal_graph_2_4(self): - graph = retworkx.generators.hexagonal_lattice_graph(2, 4) - expected_edges = [ - (0, 1), - (1, 2), - (2, 3), - (3, 4), - (5, 6), - (6, 7), - (7, 8), - (8, 9), - (9, 10), - (11, 12), - (12, 13), - (13, 14), - (14, 15), - (15, 16), - (17, 18), - (18, 19), - (19, 20), - (20, 21), - (21, 22), - (23, 24), - (24, 25), - (25, 26), - (26, 27), - (0, 5), - (2, 7), - (4, 9), - (6, 12), - (8, 14), - (10, 16), - (11, 17), - (13, 19), - (15, 21), - (18, 23), - (20, 25), - (22, 27), - ] - self.assertEqual(len(graph), 28) - self.assertEqual(len(graph.edges()), len(expected_edges)) - self.assertEqual(list(graph.edge_list()), expected_edges) - - def test_hexagonal_graph_0_0(self): - graph = retworkx.generators.hexagonal_lattice_graph(0, 0) - self.assertEqual(len(graph), 0) - self.assertEqual(len(graph.edges()), 0) diff --git a/tests/retworkx_backwards_compat/generators/test_lollipop.py b/tests/retworkx_backwards_compat/generators/test_lollipop.py deleted file mode 100644 index 47f66c3e2..000000000 --- a/tests/retworkx_backwards_compat/generators/test_lollipop.py +++ /dev/null @@ -1,79 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestLollipopGraph(unittest.TestCase): - def test_lollipop_graph_count(self): - graph = retworkx.generators.lollipop_graph(17, 3) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 139) - - def test_lollipop_graph_weights_count(self): - graph = retworkx.generators.lollipop_graph( - mesh_weights=list(range(17)), path_weights=list(range(17, 20)) - ) - self.assertEqual(len(graph), 20) - self.assertEqual(list(range(20)), graph.nodes()) - self.assertEqual(len(graph.edges()), 139) - - def test_lollipop_graph_edge(self): - graph = retworkx.generators.lollipop_graph(4, 3) - edge_list = graph.edge_list() - expected_edge_list = [ - (0, 1), - (0, 2), - (0, 3), - (1, 2), - (1, 3), - (2, 3), - (3, 4), - (4, 5), - (5, 6), - ] - self.assertEqual(edge_list, expected_edge_list) - - def test_lollipop_graph_weights_edge(self): - graph = retworkx.generators.lollipop_graph( - mesh_weights=list(range(4)), path_weights=list(range(3)) - ) - weighted_edge_list = graph.weighted_edge_list() - expected_weighted_edge_list = [ - (0, 1, None), - (0, 2, None), - (0, 3, None), - (1, 2, None), - (1, 3, None), - (2, 3, None), - (3, 4, None), - (4, 5, None), - (5, 6, None), - ] - self.assertEqual(weighted_edge_list, expected_weighted_edge_list) - self.assertEqual(graph.nodes(), [0, 1, 2, 3, 0, 1, 2]) - - def test_lollipop_graph_no_path_weights_or_num(self): - graph = retworkx.generators.lollipop_graph(mesh_weights=list(range(4))) - mesh = retworkx.generators.mesh_graph(weights=list(range(4))) - self.assertEqual(graph.nodes(), mesh.nodes()) - self.assertEqual(graph.weighted_edge_list(), mesh.weighted_edge_list()) - self.assertEqual( - retworkx.generators.lollipop_graph(4).edge_list(), - retworkx.generators.mesh_graph(4).edge_list(), - ) - - def test_lollipop_graph_no_mesh_weights_or_num(self): - with self.assertRaises(IndexError): - retworkx.generators.lollipop_graph() diff --git a/tests/retworkx_backwards_compat/generators/test_mesh.py b/tests/retworkx_backwards_compat/generators/test_mesh.py deleted file mode 100644 index 02e154857..000000000 --- a/tests/retworkx_backwards_compat/generators/test_mesh.py +++ /dev/null @@ -1,67 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestMeshGraph(unittest.TestCase): - def test_directed_mesh_graph(self): - graph = retworkx.generators.directed_mesh_graph(20) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 380) - for i in range(20): - ls = [] - for j in range(19, -1, -1): - if i != j: - ls.append((i, j, None)) - self.assertEqual(graph.out_edges(i), ls) - - def test_directed_mesh_graph_weights(self): - graph = retworkx.generators.directed_mesh_graph(weights=list(range(20))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 380) - for i in range(20): - ls = [] - for j in range(19, -1, -1): - if i != j: - ls.append((i, j, None)) - self.assertEqual(graph.out_edges(i), ls) - - def test_mesh_directed_no_weights_or_num(self): - with self.assertRaises(IndexError): - retworkx.generators.directed_mesh_graph() - - def test_mesh_graph(self): - graph = retworkx.generators.mesh_graph(20) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 190) - - def test_mesh_graph_weights(self): - graph = retworkx.generators.mesh_graph(weights=list(range(20))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 190) - - def test_mesh_no_weights_or_num(self): - with self.assertRaises(IndexError): - retworkx.generators.mesh_graph() - - def test_zero_size_mesh_graph(self): - graph = retworkx.generators.mesh_graph(0) - self.assertEqual(0, len(graph)) - - def test_zero_size_directed_mesh_graph(self): - graph = retworkx.generators.directed_mesh_graph(0) - self.assertEqual(0, len(graph)) diff --git a/tests/retworkx_backwards_compat/generators/test_path.py b/tests/retworkx_backwards_compat/generators/test_path.py deleted file mode 100644 index 958851bb2..000000000 --- a/tests/retworkx_backwards_compat/generators/test_path.py +++ /dev/null @@ -1,71 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestPathGraph(unittest.TestCase): - def test_directed_path_graph(self): - graph = retworkx.generators.directed_path_graph(20) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 19) - for i in range(19): - self.assertEqual(graph.out_edges(i), [(i, i + 1, None)]) - self.assertEqual(graph.out_edges(19), []) - - def test_directed_path_graph_weights(self): - graph = retworkx.generators.directed_path_graph(weights=list(range(20))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 19) - for i in range(19): - self.assertEqual(graph.out_edges(i), [(i, i + 1, None)]) - self.assertEqual(graph.out_edges(19), []) - - def test_directed_path_graph_bidirectional(self): - graph = retworkx.generators.directed_path_graph(20, bidirectional=True) - self.assertEqual(graph.out_edges(0), [(0, 1, None)]) - self.assertEqual(graph.in_edges(0), [(1, 0, None)]) - for i in range(1, 19): - self.assertEqual(graph.out_edges(i), [(i, i + 1, None), (i, i - 1, None)]) - self.assertEqual(graph.in_edges(i), [(i + 1, i, None), (i - 1, i, None)]) - self.assertEqual(graph.out_edges(19), [(19, 18, None)]) - self.assertEqual(graph.in_edges(19), [(18, 19, None)]) - - def test_path_directed_no_weights_or_num(self): - with self.assertRaises(IndexError): - retworkx.generators.directed_path_graph() - - def test_path_graph(self): - graph = retworkx.generators.path_graph(20) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 19) - - def test_path_graph_weights(self): - graph = retworkx.generators.path_graph(weights=list(range(20))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 19) - - def test_path_no_weights_or_num(self): - with self.assertRaises(IndexError): - retworkx.generators.path_graph() - - def test_zero_length_path_graph(self): - graph = retworkx.generators.path_graph(0) - self.assertEqual(0, len(graph)) - - def test_zero_length_directed_path_graph(self): - graph = retworkx.generators.directed_path_graph(0) - self.assertEqual(0, len(graph)) diff --git a/tests/retworkx_backwards_compat/generators/test_petersen.py b/tests/retworkx_backwards_compat/generators/test_petersen.py deleted file mode 100644 index 907f52834..000000000 --- a/tests/retworkx_backwards_compat/generators/test_petersen.py +++ /dev/null @@ -1,56 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestPetersenGraph(unittest.TestCase): - def test_petersen_graph_count(self): - n = 99 - k = 23 - graph = retworkx.generators.generalized_petersen_graph(n, k) - self.assertEqual(len(graph), 2 * n) - self.assertEqual(len(graph.edges()), 3 * n) - - def test_petersen_graph_edge(self): - graph = retworkx.generators.generalized_petersen_graph(5, 2) - edge_list = graph.edge_list() - expected_edge_list = [ - (0, 2), - (1, 3), - (2, 4), - (3, 0), - (4, 1), - (5, 6), - (6, 7), - (7, 8), - (8, 9), - (9, 5), - (5, 0), - (6, 1), - (7, 2), - (8, 3), - (9, 4), - ] - self.assertEqual(edge_list, expected_edge_list) - - def test_petersen_invalid_n_k(self): - with self.assertRaises(IndexError): - retworkx.generators.generalized_petersen_graph(2, 1) - - with self.assertRaises(IndexError): - retworkx.generators.generalized_petersen_graph(5, 0) - - with self.assertRaises(IndexError): - retworkx.generators.generalized_petersen_graph(5, 4) diff --git a/tests/retworkx_backwards_compat/generators/test_star.py b/tests/retworkx_backwards_compat/generators/test_star.py deleted file mode 100644 index 698d5368d..000000000 --- a/tests/retworkx_backwards_compat/generators/test_star.py +++ /dev/null @@ -1,108 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestStarGraph(unittest.TestCase): - def test_directed_star_graph(self): - graph = retworkx.generators.directed_star_graph(20) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 19) - expected_edges = [(0, i, None) for i in range(1, 20)] - self.assertEqual(sorted(graph.out_edges(0)), sorted(expected_edges)) - - def test_star_directed_graph_inward(self): - graph = retworkx.generators.directed_star_graph(20, inward=True) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 19) - expected_edges = [(i, 0, None) for i in range(1, 20)] - self.assertEqual(sorted(graph.in_edges(0)), sorted(expected_edges)) - - def test_directed_star_graph_weights(self): - graph = retworkx.generators.directed_star_graph(weights=list(range(20))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 19) - expected_edges = sorted([(0, i, None) for i in range(1, 20)]) - self.assertEqual(sorted(graph.out_edges(0)), expected_edges) - - def test_directed_star_graph_bidirectional(self): - graph = retworkx.generators.directed_star_graph(20, bidirectional=True) - outw = [] - inw = [] - for i in range(1, 20): - outw.append((0, i, None)) - inw.append((i, 0, None)) - self.assertEqual(graph.out_edges(i), [(i, 0, None)]) - self.assertEqual(graph.in_edges(i), [(0, i, None)]) - self.assertEqual(graph.out_edges(0), outw[::-1]) - self.assertEqual(graph.in_edges(0), inw[::-1]) - - def test_directed_star_graph_bidirectional_inward(self): - graph = retworkx.generators.directed_star_graph(20, bidirectional=True, inward=True) - outw = [] - inw = [] - for i in range(1, 20): - outw.append((0, i, None)) - inw.append((i, 0, None)) - self.assertEqual(graph.out_edges(i), [(i, 0, None)]) - self.assertEqual(graph.in_edges(i), [(0, i, None)]) - self.assertEqual(graph.out_edges(0), outw[::-1]) - self.assertEqual(graph.in_edges(0), inw[::-1]) - graph = retworkx.generators.directed_star_graph(20, bidirectional=True, inward=False) - outw = [] - inw = [] - for i in range(1, 20): - outw.append((0, i, None)) - inw.append((i, 0, None)) - self.assertEqual(graph.out_edges(i), [(i, 0, None)]) - self.assertEqual(graph.in_edges(i), [(0, i, None)]) - self.assertEqual(graph.out_edges(0), outw[::-1]) - self.assertEqual(graph.in_edges(0), inw[::-1]) - - def test_star_directed_graph_weights_inward(self): - graph = retworkx.generators.directed_star_graph(weights=list(range(20)), inward=True) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 19) - expected_edges = [(i, 0, None) for i in range(1, 20)] - self.assertEqual(sorted(graph.in_edges(0)), sorted(expected_edges)) - - def test_star_directed_no_weights_or_num(self): - with self.assertRaises(IndexError): - retworkx.generators.directed_star_graph() - - def test_star_graph(self): - graph = retworkx.generators.star_graph(20) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 19) - - def test_star_graph_weights(self): - graph = retworkx.generators.star_graph(weights=list(range(20))) - self.assertEqual(len(graph), 20) - self.assertEqual([x for x in range(20)], graph.nodes()) - self.assertEqual(len(graph.edges()), 19) - - def test_star_no_weights_or_num(self): - with self.assertRaises(IndexError): - retworkx.generators.star_graph() - - def test_zero_length_star_graph(self): - graph = retworkx.generators.star_graph(0) - self.assertEqual(0, len(graph)) - - def test_zero_length_directed_star_graph(self): - graph = retworkx.generators.directed_star_graph(0) - self.assertEqual(0, len(graph)) diff --git a/tests/retworkx_backwards_compat/graph/__init__.py b/tests/retworkx_backwards_compat/graph/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/retworkx_backwards_compat/graph/test_adj.py b/tests/retworkx_backwards_compat/graph/test_adj.py deleted file mode 100644 index 43b4a6d9f..000000000 --- a/tests/retworkx_backwards_compat/graph/test_adj.py +++ /dev/null @@ -1,32 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestAdj(unittest.TestCase): - def test_single_neighbor(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, {"a": 1}) - node_c = graph.add_node("c") - graph.add_edge(node_a, node_c, {"a": 2}) - res = graph.adj(node_a) - self.assertEqual({node_b: {"a": 1}, node_c: {"a": 2}}, res) - - def test_no_neighbor(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - self.assertEqual({}, graph.adj(node_a)) diff --git a/tests/retworkx_backwards_compat/graph/test_adjencency_matrix.py b/tests/retworkx_backwards_compat/graph/test_adjencency_matrix.py deleted file mode 100644 index 32c3df44d..000000000 --- a/tests/retworkx_backwards_compat/graph/test_adjencency_matrix.py +++ /dev/null @@ -1,262 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx -import numpy as np - - -class TestGraphAdjacencyMatrix(unittest.TestCase): - def test_single_neighbor(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edge_a") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "edge_b") - res = retworkx.graph_adjacency_matrix(graph, lambda x: 1) - self.assertIsInstance(res, np.ndarray) - self.assertTrue( - np.array_equal( - np.array( - [[0.0, 1.0, 0.0], [1.0, 0.0, 1.0], [0.0, 1.0, 0.0]], - dtype=np.float64, - ), - res, - ) - ) - - def test_no_weight_fn(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edge_a") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "edge_b") - res = retworkx.graph_adjacency_matrix(graph) - self.assertIsInstance(res, np.ndarray) - self.assertTrue( - np.array_equal( - np.array( - [[0.0, 1.0, 0.0], [1.0, 0.0, 1.0], [0.0, 1.0, 0.0]], - dtype=np.float64, - ), - res, - ) - ) - - def test_default_weight(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edge_a") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "edge_b") - res = retworkx.graph_adjacency_matrix(graph, default_weight=4) - self.assertIsInstance(res, np.ndarray) - self.assertTrue( - np.array_equal( - np.array( - [[0.0, 4.0, 0.0], [4.0, 0.0, 4.0], [0.0, 4.0, 0.0]], - dtype=np.float64, - ), - res, - ) - ) - - def test_float_cast_weight_func(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, 7.0) - res = retworkx.graph_adjacency_matrix(graph, lambda x: float(x)) - self.assertIsInstance(res, np.ndarray) - self.assertTrue(np.array_equal(np.array([[0.0, 7.0], [7.0, 0.0]]), res)) - - def test_multigraph_sum_cast_weight_func(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, 7.0) - graph.add_edge(node_a, node_b, 0.5) - res = retworkx.graph_adjacency_matrix(graph, lambda x: float(x)) - self.assertIsInstance(res, np.ndarray) - self.assertTrue(np.array_equal(np.array([[0.0, 7.5], [7.5, 0.0]]), res)) - - def test_multigraph_sum_cast_weight_func_non_zero_null(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, 7.0) - graph.add_edge(node_a, node_b, 0.5) - res = retworkx.graph_adjacency_matrix(graph, lambda x: float(x), null_value=np.inf) - self.assertIsInstance(res, np.ndarray) - self.assertTrue(np.array_equal(np.array([[np.inf, 7.5], [7.5, np.inf]]), res)) - - def test_dag_to_graph_adjacency_matrix(self): - dag = retworkx.PyDAG() - self.assertRaises(TypeError, retworkx.graph_adjacency_matrix, dag) - - def test_no_edge_graph_adjacency_matrix(self): - graph = retworkx.PyGraph() - for i in range(50): - graph.add_node(i) - res = retworkx.graph_adjacency_matrix(graph, lambda x: 1) - self.assertTrue(np.array_equal(np.zeros([50, 50]), res)) - - def test_graph_with_index_holes(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, 1) - node_c = graph.add_node("c") - graph.add_edge(node_a, node_c, 1) - graph.remove_node(node_b) - res = retworkx.graph_adjacency_matrix(graph, lambda x: 1) - self.assertIsInstance(res, np.ndarray) - self.assertTrue(np.array_equal(np.array([[0, 1], [1, 0]]), res)) - - def test_from_adjacency_matrix(self): - input_array = np.array( - [[0.0, 4.0, 0.0], [4.0, 0.0, 4.0], [0.0, 4.0, 0.0]], - dtype=np.float64, - ) - graph = retworkx.PyGraph.from_adjacency_matrix(input_array) - out_array = retworkx.graph_adjacency_matrix(graph, lambda x: x) - self.assertTrue(np.array_equal(input_array, out_array)) - - def test_random_graph_full_path(self): - graph = retworkx.undirected_gnp_random_graph(100, 0.95, seed=42) - adjacency_matrix = retworkx.graph_adjacency_matrix(graph) - new_graph = retworkx.PyGraph.from_adjacency_matrix(adjacency_matrix) - new_adjacency_matrix = retworkx.graph_adjacency_matrix(new_graph) - self.assertTrue(np.array_equal(adjacency_matrix, new_adjacency_matrix)) - - def test_random_graph_different_dtype(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.int64) - with self.assertRaises(TypeError): - retworkx.PyGraph.from_adjacency_matrix(input_matrix) - - def test_random_graph_different_dtype_astype_no_copy(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.int64) - graph = retworkx.PyGraph.from_adjacency_matrix(input_matrix.astype(np.float64, copy=False)) - adj_matrix = retworkx.graph_adjacency_matrix(graph, lambda x: x) - self.assertTrue(np.array_equal(adj_matrix, input_matrix)) - - def test_random_graph_float_dtype(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=float) - graph = retworkx.PyGraph.from_adjacency_matrix(input_matrix) - adj_matrix = retworkx.graph_adjacency_matrix(graph, lambda x: x) - self.assertTrue(np.array_equal(adj_matrix, input_matrix)) - - def test_graph_to_digraph_adjacency_matrix(self): - graph = retworkx.PyGraph() - self.assertRaises(TypeError, retworkx.digraph_adjacency_matrix, graph) - - def test_non_zero_null(self): - input_matrix = np.array( - [[np.Inf, 1, np.Inf], [1, np.Inf, 1], [np.Inf, 1, np.Inf]], - dtype=np.float64, - ) - graph = retworkx.PyGraph.from_adjacency_matrix(input_matrix, null_value=np.Inf) - adj_matrix = retworkx.adjacency_matrix(graph, float) - expected_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.float64) - self.assertTrue(np.array_equal(adj_matrix, expected_matrix)) - - def test_negative_weight(self): - input_matrix = np.array([[0, -1, 0], [-1, 0, -1], [0, -1, 0]], dtype=float) - graph = retworkx.PyGraph.from_adjacency_matrix(input_matrix) - adj_matrix = retworkx.graph_adjacency_matrix(graph, lambda x: x) - self.assertTrue(np.array_equal(adj_matrix, input_matrix)) - self.assertEqual([(0, 1, -1), (1, 2, -1)], graph.weighted_edge_list()) - - def test_nan_null(self): - input_matrix = np.array( - [[np.nan, 1, np.nan], [1, np.nan, 1], [np.nan, 1, np.nan]], - dtype=np.float64, - ) - graph = retworkx.PyGraph.from_adjacency_matrix(input_matrix, null_value=np.nan) - adj_matrix = retworkx.adjacency_matrix(graph, float) - expected_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.float64) - self.assertTrue(np.array_equal(adj_matrix, expected_matrix)) - - -class TestFromComplexAdjacencyMatrix(unittest.TestCase): - def test_from_adjacency_matrix(self): - input_array = np.array( - [[0.0, 4.0, 0.0], [4.0, 0.0, 4.0], [0.0, 4.0, 0.0]], - dtype=np.complex128, - ) - graph = retworkx.PyGraph.from_complex_adjacency_matrix(input_array) - expected = [ - (0, 1, 4 + 0j), - (1, 2, 4 + 0j), - ] - self.assertEqual(graph.weighted_edge_list(), expected) - - def test_random_graph_different_dtype(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.int64) - with self.assertRaises(TypeError): - retworkx.PyGraph.from_complex_adjacency_matrix(input_matrix) - - def test_random_graph_different_dtype_astype_no_copy(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=np.int64) - graph = retworkx.PyGraph.from_complex_adjacency_matrix( - input_matrix.astype(np.complex128, copy=False) - ) - expected = [ - (0, 1, 1 + 0j), - (1, 2, 1 + 0j), - ] - self.assertEqual(graph.weighted_edge_list(), expected) - - def test_random_graph_complex_dtype(self): - input_matrix = np.array([[0, 1, 0], [1, 0, 1], [0, 1, 0]], dtype=complex) - graph = retworkx.PyGraph.from_complex_adjacency_matrix(input_matrix) - expected = [ - (0, 1, 1 + 0j), - (1, 2, 1 + 0j), - ] - self.assertEqual(graph.weighted_edge_list(), expected) - - def test_non_zero_null(self): - input_matrix = np.array( - [[np.Inf, 1, np.Inf], [1, np.Inf, 1], [np.Inf, 1, np.Inf]], - dtype=np.complex128, - ) - graph = retworkx.PyGraph.from_complex_adjacency_matrix(input_matrix, null_value=np.Inf) - expected = [ - (0, 1, 1 + 0j), - (1, 2, 1 + 0j), - ] - self.assertEqual(graph.weighted_edge_list(), expected) - - def test_negative_weight(self): - input_matrix = np.array([[0, 1, 0], [-1, 0, -1], [0, 1, 0]], dtype=complex) - graph = retworkx.PyGraph.from_complex_adjacency_matrix(input_matrix) - self.assertEqual( - [(0, 1, 1), (1, 2, -1)], - graph.weighted_edge_list(), - ) - - def test_nan_null(self): - input_matrix = np.array( - [[np.nan, 1, np.nan], [1, np.nan, 1], [np.nan, 1, np.nan]], - dtype=np.complex128, - ) - graph = retworkx.PyGraph.from_complex_adjacency_matrix(input_matrix, null_value=np.nan) - edge_list = graph.weighted_edge_list() - self.assertEqual( - edge_list, - [(0, 1, 1 + 0j), (1, 2, 1 + 0j)], - ) diff --git a/tests/retworkx_backwards_compat/graph/test_all_simple_paths.py b/tests/retworkx_backwards_compat/graph/test_all_simple_paths.py deleted file mode 100644 index 7e8d76f00..000000000 --- a/tests/retworkx_backwards_compat/graph/test_all_simple_paths.py +++ /dev/null @@ -1,245 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestGraphAllSimplePaths(unittest.TestCase): - def setUp(self): - super().setUp() - self.edges = [ - (0, 1), - (0, 2), - (0, 3), - (1, 2), - (1, 3), - (2, 3), - (2, 4), - (3, 2), - (3, 4), - (4, 2), - (4, 5), - (5, 2), - (5, 3), - ] - - def test_all_simple_paths(self): - graph = retworkx.PyGraph() - for i in range(6): - graph.add_node(i) - graph.add_edges_from_no_data(self.edges) - paths = retworkx.graph_all_simple_paths(graph, 0, 5) - expected = [ - [0, 3, 4, 5], - [0, 3, 4, 2, 5], - [0, 3, 4, 2, 5], - [0, 3, 2, 4, 5], - [0, 3, 2, 5], - [0, 3, 2, 4, 5], - [0, 3, 5], - [0, 3, 2, 4, 5], - [0, 3, 2, 5], - [0, 3, 2, 4, 5], - [0, 3, 1, 2, 4, 5], - [0, 3, 1, 2, 5], - [0, 3, 1, 2, 4, 5], - [0, 2, 4, 5], - [0, 2, 4, 3, 5], - [0, 2, 3, 4, 5], - [0, 2, 3, 5], - [0, 2, 5], - [0, 2, 4, 5], - [0, 2, 4, 3, 5], - [0, 2, 3, 4, 5], - [0, 2, 3, 5], - [0, 2, 1, 3, 4, 5], - [0, 2, 1, 3, 5], - [0, 1, 3, 4, 5], - [0, 1, 3, 4, 2, 5], - [0, 1, 3, 4, 2, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 3, 2, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 3, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 3, 2, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 2, 4, 5], - [0, 1, 2, 4, 3, 5], - [0, 1, 2, 3, 4, 5], - [0, 1, 2, 3, 5], - [0, 1, 2, 5], - [0, 1, 2, 4, 5], - [0, 1, 2, 4, 3, 5], - [0, 1, 2, 3, 4, 5], - [0, 1, 2, 3, 5], - ] - self.assertEqual(len(expected), len(paths)) - for i in expected: - self.assertIn(i, paths) - - def test_all_simple_paths_with_min_depth(self): - graph = retworkx.PyGraph() - for i in range(6): - graph.add_node(i) - graph.add_edges_from_no_data(self.edges) - paths = retworkx.graph_all_simple_paths(graph, 0, 5, min_depth=6) - expected = [ - [0, 3, 1, 2, 4, 5], - [0, 3, 1, 2, 4, 5], - [0, 2, 1, 3, 4, 5], - [0, 1, 3, 4, 2, 5], - [0, 1, 3, 4, 2, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 3, 2, 4, 5], - [0, 1, 2, 4, 3, 5], - [0, 1, 2, 3, 4, 5], - [0, 1, 2, 4, 3, 5], - [0, 1, 2, 3, 4, 5], - ] - self.assertEqual(len(expected), len(paths)) - for i in expected: - self.assertIn(i, paths) - - def test_all_simple_paths_with_cutoff(self): - graph = retworkx.PyGraph() - for i in range(6): - graph.add_node(i) - graph.add_edges_from_no_data(self.edges) - paths = retworkx.graph_all_simple_paths(graph, 0, 5, cutoff=4) - expected = [ - [0, 3, 4, 5], - [0, 3, 2, 5], - [0, 3, 5], - [0, 3, 2, 5], - [0, 2, 4, 5], - [0, 2, 3, 5], - [0, 2, 5], - [0, 2, 4, 5], - [0, 2, 3, 5], - [0, 1, 3, 5], - [0, 1, 2, 5], - ] - self.assertEqual(len(expected), len(paths)) - for i in expected: - self.assertIn(i, paths) - - def test_all_simple_paths_with_min_depth_and_cutoff(self): - graph = retworkx.PyGraph() - for i in range(6): - graph.add_node(i) - graph.add_edges_from_no_data(self.edges) - paths = retworkx.graph_all_simple_paths(graph, 0, 5, min_depth=4, cutoff=4) - expected = [ - [0, 3, 4, 5], - [0, 3, 2, 5], - [0, 3, 2, 5], - [0, 2, 4, 5], - [0, 2, 3, 5], - [0, 2, 4, 5], - [0, 2, 3, 5], - [0, 1, 3, 5], - [0, 1, 2, 5], - ] - self.assertEqual(len(expected), len(paths)) - for i in expected: - self.assertIn(i, paths) - - def test_all_simple_path_no_path(self): - dag = retworkx.PyGraph() - dag.add_node(0) - dag.add_node(1) - self.assertEqual([], retworkx.graph_all_simple_paths(dag, 0, 1)) - - def test_all_simple_path_invalid_node_index(self): - dag = retworkx.PyGraph() - dag.add_node(0) - dag.add_node(1) - with self.assertRaises(retworkx.InvalidNode): - retworkx.graph_all_simple_paths(dag, 0, 5) - - def test_digraph_graph_all_simple_paths(self): - dag = retworkx.PyDAG() - dag.add_node(0) - dag.add_node(1) - self.assertRaises(TypeError, retworkx.graph_all_simple_paths, (dag, 0, 1)) - - -class TestGraphAllSimplePathsAllPairs(unittest.TestCase): - def setUp(self): - super().setUp() - self.graph = retworkx.generators.cycle_graph(4) - - def test_all_simple_paths(self): - paths = retworkx.all_pairs_all_simple_paths(self.graph) - expected = { - 0: {1: [[0, 1], [0, 3, 2, 1]], 2: [[0, 1, 2], [0, 3, 2]], 3: [[0, 1, 2, 3], [0, 3]]}, - 1: {2: [[1, 2], [1, 0, 3, 2]], 3: [[1, 2, 3], [1, 0, 3]], 0: [[1, 2, 3, 0], [1, 0]]}, - 2: { - 3: [[2, 3], [2, 1, 0, 3]], - 0: [[2, 3, 0], [2, 1, 0]], - 1: [[2, 3, 0, 1], [2, 1]], - }, - 3: {0: [[3, 0], [3, 2, 1, 0]], 1: [[3, 0, 1], [3, 2, 1]], 2: [[3, 0, 1, 2], [3, 2]]}, - } - self.assertEqual(paths, expected) - - def test_all_simple_paths_min_depth(self): - paths = retworkx.all_pairs_all_simple_paths(self.graph, min_depth=3) - expected = { - 0: {1: [[0, 3, 2, 1]], 2: [[0, 1, 2], [0, 3, 2]], 3: [[0, 1, 2, 3]]}, - 1: {2: [[1, 0, 3, 2]], 3: [[1, 2, 3], [1, 0, 3]], 0: [[1, 2, 3, 0]]}, - 2: { - 3: [[2, 1, 0, 3]], - 0: [[2, 3, 0], [2, 1, 0]], - 1: [[2, 3, 0, 1]], - }, - 3: {0: [[3, 2, 1, 0]], 1: [[3, 0, 1], [3, 2, 1]], 2: [[3, 0, 1, 2]]}, - } - self.assertEqual(paths, expected) - - def test_all_simple_paths_with_cutoff(self): - paths = retworkx.all_pairs_all_simple_paths(self.graph, cutoff=3) - expected = { - 0: {1: [[0, 1]], 2: [[0, 1, 2], [0, 3, 2]], 3: [[0, 3]]}, - 1: {2: [[1, 2]], 3: [[1, 2, 3], [1, 0, 3]], 0: [[1, 0]]}, - 2: { - 3: [[2, 3]], - 0: [[2, 3, 0], [2, 1, 0]], - 1: [[2, 1]], - }, - 3: {0: [[3, 0]], 1: [[3, 0, 1], [3, 2, 1]], 2: [[3, 2]]}, - } - self.assertEqual(paths, expected) - - def test_all_simple_paths_with_min_depth_and_cutoff(self): - paths = retworkx.all_pairs_all_simple_paths(self.graph, min_depth=3, cutoff=3) - expected = { - 0: {2: [[0, 1, 2], [0, 3, 2]]}, - 1: {3: [[1, 2, 3], [1, 0, 3]]}, - 2: {0: [[2, 3, 0], [2, 1, 0]]}, - 3: {1: [[3, 0, 1], [3, 2, 1]]}, - } - self.assertEqual(paths, expected) - - def test_all_simple_path_no_path(self): - graph = retworkx.PyGraph() - graph.add_node(0) - graph.add_node(1) - self.assertEqual({0: {}, 1: {}}, retworkx.all_pairs_all_simple_paths(graph)) - - def test_all_simple_paths_empty(self): - self.assertEqual({}, retworkx.all_pairs_all_simple_paths(retworkx.PyGraph())) diff --git a/tests/retworkx_backwards_compat/graph/test_astar.py b/tests/retworkx_backwards_compat/graph/test_astar.py deleted file mode 100644 index 6f1525e23..000000000 --- a/tests/retworkx_backwards_compat/graph/test_astar.py +++ /dev/null @@ -1,114 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestAstarGraph(unittest.TestCase): - def test_astar_null_heuristic(self): - g = retworkx.PyGraph() - a = g.add_node("A") - b = g.add_node("B") - c = g.add_node("C") - d = g.add_node("D") - e = g.add_node("E") - f = g.add_node("F") - g.add_edge(a, b, 7) - g.add_edge(c, a, 9) - g.add_edge(a, d, 14) - g.add_edge(b, c, 10) - g.add_edge(d, c, 2) - g.add_edge(d, e, 9) - g.add_edge(b, f, 15) - g.add_edge(c, f, 11) - g.add_edge(e, f, 6) - path = retworkx.graph_astar_shortest_path( - g, a, lambda goal: goal == "E", lambda x: float(x), lambda y: 0 - ) - expected = [a, c, d, e] - self.assertEqual(expected, path) - - def test_astar_manhattan_heuristic(self): - g = retworkx.PyGraph() - a = g.add_node((0.0, 0.0)) - b = g.add_node((2.0, 0.0)) - c = g.add_node((1.0, 1.0)) - d = g.add_node((0.0, 2.0)) - e = g.add_node((3.0, 3.0)) - f = g.add_node((4.0, 2.0)) - no_path = g.add_node((5.0, 5.0)) # no path to node - g.add_edge(a, b, 2.0) - g.add_edge(a, d, 4.0) - g.add_edge(b, c, 1.0) - g.add_edge(b, f, 7.0) - g.add_edge(c, e, 5.0) - g.add_edge(e, f, 1.0) - g.add_edge(d, e, 1.0) - - def heuristic_func(f): - x1, x2 = f - return abs(x2 - x1) - - def finish_func(node, x): - return x == g.get_node_data(node) - - expected = [ - [0], - [0, 1], - [0, 1, 2], - [0, 3], - [0, 3, 4], - [0, 3, 4, 5], - ] - - for index, end in enumerate([a, b, c, d, e, f]): - path = retworkx.graph_astar_shortest_path( - g, - a, - lambda finish: finish_func(end, finish), - lambda x: float(x), - heuristic_func, - ) - self.assertEqual(expected[index], path) - - with self.assertRaises(retworkx.NoPathFound): - retworkx.graph_astar_shortest_path( - g, - a, - lambda finish: finish_func(no_path, finish), - lambda x: float(x), - heuristic_func, - ) - - def test_astar_graph_with_digraph_input(self): - g = retworkx.PyDAG() - g.add_node(0) - with self.assertRaises(TypeError): - retworkx.graph_astar_shortest_path(g, 0, lambda x: x, lambda y: 1, lambda z: 0) - - def test_astar_with_invalid_weights(self): - g = retworkx.PyGraph() - a = g.add_node("A") - b = g.add_node("B") - g.add_edge(a, b, 7) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.graph_astar_shortest_path( - g, - a, - goal_fn=lambda goal: goal == "B", - edge_cost_fn=lambda _: invalid_weight, - estimate_cost_fn=lambda _: 0, - ) diff --git a/tests/retworkx_backwards_compat/graph/test_avg_shortest_path.py b/tests/retworkx_backwards_compat/graph/test_avg_shortest_path.py deleted file mode 100644 index 18ff98ab0..000000000 --- a/tests/retworkx_backwards_compat/graph/test_avg_shortest_path.py +++ /dev/null @@ -1,89 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import math -import unittest - -import retworkx - - -class TestUnweightedAvgShortestPath(unittest.TestCase): - def test_simple_example(self): - edge_list = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (3, 6), (6, 7)] - graph = retworkx.PyGraph() - graph.extend_from_edge_list(edge_list) - res = retworkx.graph_unweighted_average_shortest_path_length(graph) - self.assertAlmostEqual(2.5714285714285716, res, delta=1e-7) - - def test_cycle_graph(self): - graph = retworkx.generators.cycle_graph(7) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertAlmostEqual(2, res, delta=1e-7) - - def test_path_graph(self): - graph = retworkx.generators.path_graph(5) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertAlmostEqual(2, res, delta=1e-7) - - def test_parallel_grid(self): - graph = retworkx.generators.grid_graph(30, 11) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertAlmostEqual(13.666666666666666, res, delta=1e-7) - - def test_empty(self): - graph = retworkx.PyGraph() - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_single_node(self): - graph = retworkx.PyGraph() - graph.add_node(0) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_single_node_self_edge(self): - graph = retworkx.PyGraph() - node = graph.add_node(0) - graph.add_edge(node, node, 0) - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_disconnected_graph(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(32))) - with self.subTest(disconnected=False): - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isinf(res), "Output is not infinity") - - with self.subTest(disconnected=True): - res = retworkx.unweighted_average_shortest_path_length(graph, disconnected=True) - self.assertTrue(math.isnan(res), "Output is not NaN") - - def test_partially_connected_graph(self): - graph = retworkx.generators.cycle_graph(32) - graph.add_nodes_from(list(range(32))) - with self.subTest(disconnected=False): - res = retworkx.unweighted_average_shortest_path_length(graph) - self.assertTrue(math.isinf(res), "Output is not infinity") - - with self.subTest(disconnected=True): - s = 8192 - den = 992 # n*(n-1), n=32 (only connected pairs considered) - res = retworkx.unweighted_average_shortest_path_length(graph, disconnected=True) - self.assertAlmostEqual(s / den, res, delta=1e-7) - - def test_connected_cycle_graph(self): - graph = retworkx.generators.cycle_graph(32) - res = retworkx.unweighted_average_shortest_path_length(graph) - s = 8192 - den = 992 # n*(n-1) - self.assertAlmostEqual(s / den, res, delta=1e-7) diff --git a/tests/retworkx_backwards_compat/graph/test_bellman_ford.py b/tests/retworkx_backwards_compat/graph/test_bellman_ford.py deleted file mode 100644 index 6511e3ea3..000000000 --- a/tests/retworkx_backwards_compat/graph/test_bellman_ford.py +++ /dev/null @@ -1,308 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestBellmanFordGraph(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - self.d = self.graph.add_node("D") - self.e = self.graph.add_node("E") - self.f = self.graph.add_node("F") - self.graph.add_edge(self.a, self.b, 7) - self.graph.add_edge(self.c, self.a, 9) - self.graph.add_edge(self.a, self.d, 14) - self.graph.add_edge(self.b, self.c, 10) - self.graph.add_edge(self.d, self.c, 2) - self.graph.add_edge(self.d, self.e, 9) - self.graph.add_edge(self.b, self.f, 15) - self.graph.add_edge(self.c, self.f, 11) - self.graph.add_edge(self.e, self.f, 6) - - def test_bellman_ford(self): - path = retworkx.graph_bellman_ford_shortest_path_lengths( - self.graph, self.a, lambda x: float(x) - ) - path_dijkstra = retworkx.graph_dijkstra_shortest_path_lengths( - self.graph, self.a, lambda x: float(x) - ) - self.assertEqual(path_dijkstra, path) - - def test_bellman_ford_path(self): - path = retworkx.graph_bellman_ford_shortest_paths( - self.graph, self.a, weight_fn=lambda x: float(x) - ) - # a -> d -> e = 23 - # a -> c -> d -> e = 20 - expected = retworkx.graph_dijkstra_shortest_paths( - self.graph, self.a, weight_fn=lambda x: float(x) - ) - self.assertEqual(expected, path) - - def test_bellman_ford_with_no_goal_set(self): - path = retworkx.graph_bellman_ford_shortest_path_lengths(self.graph, self.a, lambda x: 1) - expected = retworkx.graph_dijkstra_shortest_path_lengths(self.graph, self.a, lambda x: 1) - self.assertEqual(expected, path) - - def test_bellman_path(self): - path = retworkx.graph_bellman_ford_shortest_paths( - self.graph, self.a, weight_fn=lambda x: float(x), target=self.e - ) - expected = retworkx.graph_dijkstra_shortest_paths( - self.graph, self.a, weight_fn=lambda x: float(x), target=self.e - ) - self.assertEqual(expected, path) - - def test_bellman_path_lengths(self): - path = retworkx.graph_bellman_ford_shortest_path_lengths( - self.graph, self.a, lambda x: float(x), goal=self.e - ) - expected = retworkx.graph_dijkstra_shortest_path_lengths( - self.graph, self.a, lambda x: float(x), goal=self.e - ) - self.assertEqual(expected, path) - - def test_bellman_ford_length_with_no_path_and_goal(self): - g = retworkx.PyGraph() - a = g.add_node("A") - b = g.add_node("B") - path_lenghts = retworkx.graph_bellman_ford_shortest_path_lengths( - g, a, edge_cost_fn=float, goal=b - ) - expected = retworkx.graph_dijkstra_shortest_path_lengths(g, a, edge_cost_fn=float, goal=b) - self.assertEqual(expected, path_lenghts) - - def test_bellman_ford_length_with_no_path(self): - g = retworkx.PyGraph() - a = g.add_node("A") - g.add_node("B") - path_lenghts = retworkx.graph_bellman_ford_shortest_path_lengths(g, a, edge_cost_fn=float) - expected = {} - self.assertEqual(expected, path_lenghts) - - def test_bellman_ford_path_with_no_goal_set(self): - path = retworkx.graph_bellman_ford_shortest_paths(self.graph, self.a) - expected = { - 1: [0, 1], - 2: [0, 2], - 3: [0, 3], - 4: [0, 3, 4], - 5: [0, 1, 5], - } - self.assertEqual(expected, path) - - def test_bellman_ford_with_no_path(self): - g = retworkx.PyGraph() - a = g.add_node("A") - g.add_node("B") - path = retworkx.graph_bellman_ford_shortest_path_lengths(g, a, lambda x: float(x)) - expected = {} - self.assertEqual(expected, path) - - def test_bellman_ford_path_with_no_path(self): - g = retworkx.PyGraph() - a = g.add_node("A") - g.add_node("B") - path = retworkx.graph_bellman_ford_shortest_paths(g, a, weight_fn=lambda x: float(x)) - expected = {} - self.assertEqual(expected, path) - - def test_bellman_ford_with_disconnected_nodes(self): - g = retworkx.PyGraph() - a = g.add_node("A") - b = g.add_node("B") - g.add_edge(a, b, 1.2) - g.add_node("C") - d = g.add_node("D") - g.add_edge(b, d, 2.4) - path = retworkx.graph_bellman_ford_shortest_path_lengths(g, a, lambda x: round(x, 1)) - # Computers never work: - expected = {1: 1.2, 3: 3.5999999999999996} - self.assertEqual(expected, path) - - def test_bellman_ford_graph_with_digraph_input(self): - g = retworkx.PyDAG() - g.add_node(0) - with self.assertRaises(TypeError): - retworkx.graph_bellman_ford_shortest_path_lengths(g, 0, lambda x: x) - - def bellman_ford_with_invalid_weights(self): - graph = retworkx.generators.path_graph(2) - for as_undirected in [False, True]: - with self.subTest(as_undirected=as_undirected): - with self.assertRaises(ValueError): - retworkx.graph_bellman_ford_shortest_paths( - graph, - source=0, - weight_fn=lambda _: float("nan"), - as_undirected=as_undirected, - ) - - def bellman_ford_lengths_with_invalid_weights(self): - graph = retworkx.generators.path_graph(2) - with self.assertRaises(ValueError): - retworkx.graph_bellman_ford_shortest_path_lengths( - graph, node=0, edge_cost_fn=lambda _: float("nan") - ) - - def test_raises_negative_cycle_bellman_ford_paths(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - with self.assertRaises(retworkx.NegativeCycle): - retworkx.bellman_ford_shortest_paths(graph, 0, weight_fn=float) - - def test_raises_negative_cycle_bellman_ford_path_lenghts(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - with self.assertRaises(retworkx.NegativeCycle): - retworkx.bellman_ford_shortest_path_lengths(graph, 0, edge_cost_fn=float) - - def test_bellman_all_pair_path_lengths(self): - lengths = retworkx.all_pairs_bellman_ford_path_lengths(self.graph, float) - expected = { - 0: {1: 7.0, 2: 9.0, 3: 11.0, 4: 20.0, 5: 20.0}, - 1: {0: 7.0, 2: 10.0, 3: 12.0, 4: 21.0, 5: 15.0}, - 2: {0: 9.0, 1: 10.0, 3: 2.0, 4: 11.0, 5: 11.0}, - 3: {0: 11.0, 1: 12.0, 2: 2.0, 4: 9.0, 5: 13.0}, - 4: {0: 20.0, 1: 21.0, 2: 11.0, 3: 9.0, 5: 6.0}, - 5: {0: 20.0, 1: 15.0, 2: 11.0, 3: 13.0, 4: 6.0}, - } - self.assertEqual(expected, lengths) - - def test_bellman_ford_all_pair_paths(self): - paths = retworkx.graph_all_pairs_bellman_ford_shortest_paths(self.graph, float) - expected = { - 0: { - 1: [0, 1], - 2: [0, 2], - 3: [0, 2, 3], - 4: [0, 2, 3, 4], - 5: [0, 2, 5], - }, - 1: {0: [1, 0], 2: [1, 2], 3: [1, 2, 3], 4: [1, 5, 4], 5: [1, 5]}, - 2: {0: [2, 0], 1: [2, 1], 3: [2, 3], 4: [2, 3, 4], 5: [2, 5]}, - 3: {0: [3, 2, 0], 1: [3, 2, 1], 2: [3, 2], 4: [3, 4], 5: [3, 2, 5]}, - 4: { - 0: [4, 3, 2, 0], - 1: [4, 5, 1], - 2: [4, 3, 2], - 3: [4, 3], - 5: [4, 5], - }, - 5: {0: [5, 2, 0], 1: [5, 1], 2: [5, 2], 3: [5, 2, 3], 4: [5, 4]}, - } - - self.assertEqual(expected, paths) - - def test_bellman_ford_all_pair_path_lengths_with_node_removal(self): - self.graph.remove_node(3) - lengths = retworkx.graph_all_pairs_bellman_ford_path_lengths(self.graph, float) - expected = { - 0: {1: 7.0, 2: 9.0, 4: 26.0, 5: 20.0}, - 1: {0: 7.0, 2: 10.0, 4: 21.0, 5: 15.0}, - 2: {0: 9.0, 1: 10.0, 4: 17.0, 5: 11.0}, - 4: {0: 26.0, 1: 21.0, 2: 17.0, 5: 6.0}, - 5: {0: 20.0, 1: 15.0, 2: 11.0, 4: 6.0}, - } - self.assertEqual(expected, lengths) - - def test_bellman_ford_all_pair_paths_with_node_removal(self): - self.graph.remove_node(3) - paths = retworkx.graph_all_pairs_bellman_ford_shortest_paths(self.graph, float) - expected = { - 0: {1: [0, 1], 2: [0, 2], 4: [0, 2, 5, 4], 5: [0, 2, 5]}, - 1: {0: [1, 0], 2: [1, 2], 4: [1, 5, 4], 5: [1, 5]}, - 2: {0: [2, 0], 1: [2, 1], 4: [2, 5, 4], 5: [2, 5]}, - 4: {0: [4, 5, 2, 0], 1: [4, 5, 1], 2: [4, 5, 2], 5: [4, 5]}, - 5: {0: [5, 2, 0], 1: [5, 1], 2: [5, 2], 4: [5, 4]}, - } - self.assertEqual(expected, paths) - - def test_bellman_ford_all_pair_path_lengths_empty_graph(self): - graph = retworkx.PyGraph() - self.assertEqual({}, retworkx.graph_all_pairs_bellman_ford_path_lengths(graph, float)) - - def test_bellman_ford_all_pair_shortest_paths_empty_graph(self): - graph = retworkx.PyGraph() - self.assertEqual({}, retworkx.graph_all_pairs_bellman_ford_shortest_paths(graph, float)) - - def test_bellman_ford_all_pair_path_lengths_graph_no_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.graph_all_pairs_bellman_ford_path_lengths(graph, float), - ) - - def test_bellman_ford_all_pair_shortest_paths_no_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.graph_all_pairs_bellman_ford_shortest_paths(graph, float), - ) - - def test_raises_negative_cycle_all_pairs_bellman_ford_paths(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - with self.assertRaises(retworkx.NegativeCycle): - retworkx.all_pairs_bellman_ford_shortest_paths(graph, float) - - def test_raises_negative_cycle_all_pairs_bellman_ford_path_lenghts(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - - with self.assertRaises(retworkx.NegativeCycle): - retworkx.all_pairs_bellman_ford_path_lengths(graph, float) diff --git a/tests/retworkx_backwards_compat/graph/test_bfs_search.py b/tests/retworkx_backwards_compat/graph/test_bfs_search.py deleted file mode 100644 index 055987301..000000000 --- a/tests/retworkx_backwards_compat/graph/test_bfs_search.py +++ /dev/null @@ -1,162 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestBfsSearch(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.graph.extend_from_edge_list( - [ - (0, 1), - (0, 2), - (1, 3), - (2, 1), - (2, 5), - (2, 6), - (5, 3), - (4, 7), - ] - ) - - def test_graph_bfs_tree_edges(self): - class TreeEdgesRecorder(retworkx.visit.BFSVisitor): - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - self.edges.append((edge[0], edge[1])) - - vis = TreeEdgesRecorder() - retworkx.graph_bfs_search(self.graph, [0], vis) - self.assertEqual(vis.edges, [(0, 2), (0, 1), (2, 6), (2, 5), (1, 3)]) - - def test_graph_bfs_tree_edges_no_starting_point(self): - class TreeEdgesRecorder(retworkx.visit.BFSVisitor): - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - self.edges.append((edge[0], edge[1])) - - vis = TreeEdgesRecorder() - retworkx.graph_bfs_search(self.graph, None, vis) - self.assertEqual(vis.edges, [(0, 2), (0, 1), (2, 6), (2, 5), (1, 3), (4, 7)]) - - def test_graph_bfs_tree_edges_restricted(self): - class TreeEdgesRecorderRestricted(retworkx.visit.BFSVisitor): - - prohibited = [(0, 2), (1, 2)] - - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - edge = (edge[0], edge[1]) - if edge in self.prohibited: - raise retworkx.visit.PruneSearch - self.edges.append(edge) - - vis = TreeEdgesRecorderRestricted() - retworkx.graph_bfs_search(self.graph, [0], vis) - self.assertEqual(vis.edges, [(0, 1), (1, 3), (3, 5), (5, 2), (2, 6)]) - - def test_graph_bfs_goal_search_with_stop_search_exception(self): - class GoalSearch(retworkx.visit.BFSVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - - def tree_edge(self, edge): - u, v, _ = edge - self.parents[v] = u - - if v == self.goal: - raise retworkx.visit.StopSearch - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - retworkx.graph_bfs_search(self.graph, [0], vis) - self.assertEqual(vis.reconstruct_path(), [0, 1, 3]) - - def test_graph_bfs_goal_search_with_custom_exception(self): - class StopIfGoalFound(Exception): - pass - - class GoalSearch(retworkx.visit.BFSVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - - def tree_edge(self, edge): - u, v, _ = edge - self.parents[v] = u - - if v == self.goal: - raise StopIfGoalFound - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - try: - retworkx.graph_bfs_search(self.graph, [0], vis) - except StopIfGoalFound: - pass - self.assertEqual(vis.reconstruct_path(), [0, 1, 3]) - - def test_graph_prune_non_tree_edge(self): - class PruneNonTreeEdge(retworkx.visit.BFSVisitor): - def non_tree_edge(self, _): - raise retworkx.visit.PruneSearch - - vis = PruneNonTreeEdge() - retworkx.graph_bfs_search(self.graph, [0], vis) - - def test_graph_prune_black_target_edge(self): - class PruneBlackTargetEdge(retworkx.visit.BFSVisitor): - def black_target_edge(self, _): - raise retworkx.visit.PruneSearch - - vis = PruneBlackTargetEdge() - retworkx.graph_bfs_search(self.graph, [0], vis) - - def test_graph_prune_gray_target_edge(self): - class PruneGrayTargetEdge(retworkx.visit.BFSVisitor): - def gray_target_edge(self, _): - raise retworkx.visit.PruneSearch - - vis = PruneGrayTargetEdge() - retworkx.graph_bfs_search(self.graph, [0], vis) diff --git a/tests/retworkx_backwards_compat/graph/test_biconnected.py b/tests/retworkx_backwards_compat/graph/test_biconnected.py deleted file mode 100644 index 1ab99ae56..000000000 --- a/tests/retworkx_backwards_compat/graph/test_biconnected.py +++ /dev/null @@ -1,138 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestBiconnected(unittest.TestCase): - def setUp(self): - super().setUp() - self.graph = retworkx.PyGraph() - self.graph.extend_from_edge_list( - [ - # back edges - (0, 2), - (0, 3), - (1, 4), - (4, 9), - (5, 7), - # tree edges - (0, 1), - (1, 2), - (2, 3), - (2, 4), - (4, 5), - (4, 8), - (5, 6), - (6, 7), - (8, 9), - ] - ) - - self.barbell_graph = retworkx.PyGraph() - self.barbell_graph.extend_from_edge_list( - [ - (0, 1), - (0, 2), - (1, 2), - (3, 4), - (3, 5), - (4, 5), - (2, 3), - ] - ) - - def test_null_graph(self): - graph = retworkx.PyGraph() - self.assertEqual(retworkx.articulation_points(graph), set()) - self.assertEqual(retworkx.biconnected_components(graph), {}) - - def test_graph(self): - components = { - (4, 8): 0, - (8, 9): 0, - (9, 4): 0, - (5, 6): 1, - (6, 7): 1, - (7, 5): 1, - (4, 5): 2, - (0, 1): 3, - (1, 2): 3, - (2, 3): 3, - (2, 4): 3, - (2, 0): 3, - (3, 0): 3, - (4, 1): 3, - } - self.assertEqual(retworkx.biconnected_components(self.graph), components) - self.assertEqual(retworkx.articulation_points(self.graph), {4, 5}) - - def test_barbell_graph(self): - components = { - (0, 2): 2, - (2, 1): 2, - (1, 0): 2, - (3, 5): 0, - (5, 4): 0, - (4, 3): 0, - (2, 3): 1, - } - self.assertEqual(retworkx.biconnected_components(self.barbell_graph), components) - self.assertEqual(retworkx.articulation_points(self.barbell_graph), {2, 3}) - - def test_disconnected_graph(self): - graph = retworkx.union(self.barbell_graph, self.barbell_graph) - components = { - # first copy - (0, 2): 2, - (2, 1): 2, - (1, 0): 2, - (3, 5): 0, - (5, 4): 0, - (4, 3): 0, - (2, 3): 1, - # second copy - (6, 8): 5, - (8, 7): 5, - (7, 6): 5, - (9, 11): 3, - (11, 10): 3, - (10, 9): 3, - (8, 9): 4, - } - self.assertEqual(retworkx.biconnected_components(graph), components) - self.assertEqual(retworkx.articulation_points(graph), {2, 3, 8, 9}) - - def test_biconnected_graph(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list( - [ - (0, 1), - (0, 2), - (0, 5), - (1, 5), - (2, 3), - (2, 4), - (3, 4), - (3, 5), - (3, 6), - (4, 5), - (4, 6), - ] - ) - num_edges = graph.num_edges() - self.assertEqual(retworkx.articulation_points(graph), set()) - bicomp = retworkx.biconnected_components(graph) - self.assertEqual(len(bicomp), num_edges) - self.assertEqual(list(bicomp.values()), [0] * num_edges) diff --git a/tests/retworkx_backwards_compat/graph/test_cartesian_product.py b/tests/retworkx_backwards_compat/graph/test_cartesian_product.py deleted file mode 100644 index 5acd0f35c..000000000 --- a/tests/retworkx_backwards_compat/graph/test_cartesian_product.py +++ /dev/null @@ -1,60 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest -import retworkx - - -class TestCartesianProduct(unittest.TestCase): - def test_null_cartesian_null(self): - graph_1 = retworkx.PyGraph() - graph_2 = retworkx.PyGraph() - - graph_product, _ = retworkx.graph_cartesian_product(graph_1, graph_2) - self.assertEqual(graph_product.num_nodes(), 0) - self.assertEqual(graph_product.num_edges(), 0) - - def test_path_2_cartesian_path_2(self): - graph_1 = retworkx.generators.path_graph(2) - graph_2 = retworkx.generators.path_graph(2) - - graph_product, _ = retworkx.graph_cartesian_product(graph_1, graph_2) - self.assertEqual(graph_product.num_nodes(), 4) - self.assertEqual(graph_product.num_edges(), 4) - - def test_path_2_cartesian_path_3(self): - graph_1 = retworkx.generators.path_graph(2) - graph_2 = retworkx.generators.path_graph(3) - - graph_product, _ = retworkx.graph_cartesian_product(graph_1, graph_2) - self.assertEqual(graph_product.num_nodes(), 6) - self.assertEqual(graph_product.num_edges(), 7) - - def test_node_weights_cartesian(self): - graph_1 = retworkx.PyGraph() - graph_1.add_node("a_1") - graph_2 = retworkx.PyGraph() - graph_2.add_node(0) - - graph_product, _ = retworkx.graph_cartesian_product(graph_1, graph_2) - self.assertEqual([("a_1", 0)], graph_product.nodes()) - - def test_edge_weights_cartesian(self): - graph_1 = retworkx.PyGraph() - graph_1.add_nodes_from([0, 1]) - graph_1.add_edge(0, 1, "w_1") - graph_2 = retworkx.PyGraph() - graph_2.add_nodes_from([0, 1]) - graph_1.add_edge(0, 1, "w_2") - - graph_product, _ = retworkx.graph_cartesian_product(graph_1, graph_2) - self.assertEqual(["w_1", "w_1", "w_2", "w_2"], graph_product.edges()) diff --git a/tests/retworkx_backwards_compat/graph/test_centrality.py b/tests/retworkx_backwards_compat/graph/test_centrality.py deleted file mode 100644 index 2c0dabee8..000000000 --- a/tests/retworkx_backwards_compat/graph/test_centrality.py +++ /dev/null @@ -1,133 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import math -import unittest - -import retworkx - - -class TestCentralityGraph(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - self.d = self.graph.add_node("D") - edge_list = [ - (self.a, self.b, 1), - (self.b, self.c, 1), - (self.c, self.d, 1), - ] - self.graph.add_edges_from(edge_list) - - def test_betweenness_centrality(self): - betweenness = retworkx.graph_betweenness_centrality(self.graph) - expected = { - 0: 0.0, - 1: 0.6666666666666666, - 2: 0.6666666666666666, - 3: 0.0, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_endpoints(self): - betweenness = retworkx.graph_betweenness_centrality(self.graph, endpoints=True) - expected = { - 0: 0.5, - 1: 0.8333333333333333, - 2: 0.8333333333333333, - 3: 0.5, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_unnormalized(self): - betweenness = retworkx.graph_betweenness_centrality( - self.graph, endpoints=False, normalized=False - ) - expected = {0: 0.0, 1: 2.0, 2: 2.0, 3: 0.0} - self.assertEqual(expected, betweenness) - - def test_closeness_centrality(self): - closeness = retworkx.graph_closeness_centrality(self.graph) - expected = {0: 0.5, 1: 0.75, 2: 0.75, 3: 0.5} - self.assertEqual(expected, closeness) - - def test_closeness_centrality_wf_improved(self): - closeness = retworkx.graph_closeness_centrality(self.graph, wf_improved=False) - expected = {0: 0.5, 1: 0.75, 2: 0.75, 3: 0.5} - self.assertEqual(expected, closeness) - - -class TestCentralityGraphDeletedNode(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - c0 = self.graph.add_node("C0") - self.d = self.graph.add_node("D") - edge_list = [ - (self.a, self.b, 1), - (self.b, self.c, 1), - (self.c, self.d, 1), - ] - self.graph.add_edges_from(edge_list) - self.graph.remove_node(c0) - - def test_betweenness_centrality(self): - betweenness = retworkx.graph_betweenness_centrality(self.graph) - expected = { - 0: 0.0, - 1: 0.6666666666666666, - 2: 0.6666666666666666, - 4: 0.0, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_endpoints(self): - betweenness = retworkx.graph_betweenness_centrality(self.graph, endpoints=True) - expected = { - 0: 0.5, - 1: 0.8333333333333333, - 2: 0.8333333333333333, - 4: 0.5, - } - self.assertEqual(expected, betweenness) - - def test_betweenness_centrality_unnormalized(self): - betweenness = retworkx.graph_betweenness_centrality( - self.graph, endpoints=False, normalized=False - ) - expected = {0: 0.0, 1: 2.0, 2: 2.0, 4: 0.0} - self.assertEqual(expected, betweenness) - - -class TestEigenvectorCentrality(unittest.TestCase): - def test_complete_graph(self): - graph = retworkx.generators.mesh_graph(5) - centrality = retworkx.eigenvector_centrality(graph) - expected_value = math.sqrt(1.0 / 5.0) - for value in centrality.values(): - self.assertAlmostEqual(value, expected_value) - - def test_path_graph(self): - graph = retworkx.generators.path_graph(3) - centrality = retworkx.eigenvector_centrality(graph) - expected = [0.5, 0.7071, 0.5] - for k, v in centrality.items(): - self.assertAlmostEqual(v, expected[k], 4) - - def test_no_convergence(self): - graph = retworkx.PyGraph() - with self.assertRaises(retworkx.FailedToConverge): - retworkx.eigenvector_centrality(graph, max_iter=0) diff --git a/tests/retworkx_backwards_compat/graph/test_chain_decomposition.py b/tests/retworkx_backwards_compat/graph/test_chain_decomposition.py deleted file mode 100644 index f08916364..000000000 --- a/tests/retworkx_backwards_compat/graph/test_chain_decomposition.py +++ /dev/null @@ -1,89 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestChainDecomposition(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.graph.extend_from_edge_list( - [ - (0, 1), - (0, 2), - (1, 2), - (3, 4), - (3, 5), - (4, 5), - (2, 3), - ] - ) - return super().setUp() - - def test_graph(self): - edges = [ - # back edges - (0, 2), - (0, 3), - (1, 4), - (4, 9), - (5, 7), - # tree edges - (0, 1), - (1, 2), - (2, 3), - (2, 4), - (4, 5), - (4, 8), - (5, 6), - (6, 7), - (8, 9), - ] - - graph = retworkx.PyGraph() - graph.extend_from_edge_list(edges) - chains = retworkx.chain_decomposition(graph, source=0) - expected = [ - [(0, 3), (3, 2), (2, 1), (1, 0)], - [(0, 2)], - [(1, 4), (4, 2)], - [(4, 9), (9, 8), (8, 4)], - [(5, 7), (7, 6), (6, 5)], - ] - self.assertEqual(expected, chains) - - def test_barbell_graph(self): - chains = retworkx.chain_decomposition(self.graph, source=0) - expected = [[(0, 1), (1, 2), (2, 0)], [(3, 4), (4, 5), (5, 3)]] - self.assertEqual(expected, chains) - - def test_disconnected_graph(self): - graph = retworkx.union(self.graph, self.graph) - chains = retworkx.chain_decomposition(graph) - expected = [ - [(0, 1), (1, 2), (2, 0)], - [(3, 4), (4, 5), (5, 3)], - [(6, 7), (7, 8), (8, 6)], - [(9, 10), (10, 11), (11, 9)], - ] - self.assertEqual(expected, chains) - - def test_disconnected_graph_root_node(self): - graph = retworkx.union(self.graph, self.graph) - chains = retworkx.chain_decomposition(graph, source=0) - expected = [ - [(0, 1), (1, 2), (2, 0)], - [(3, 4), (4, 5), (5, 3)], - ] - self.assertEqual(expected, chains) diff --git a/tests/retworkx_backwards_compat/graph/test_coloring.py b/tests/retworkx_backwards_compat/graph/test_coloring.py deleted file mode 100644 index acc431f04..000000000 --- a/tests/retworkx_backwards_compat/graph/test_coloring.py +++ /dev/null @@ -1,46 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestGraphColoring(unittest.TestCase): - def test_empty_graph(self): - graph = retworkx.PyGraph() - res = retworkx.graph_greedy_color(graph) - self.assertEqual({}, res) - - def test_simple_graph(self): - graph = retworkx.PyGraph() - node_a = graph.add_node(1) - node_b = graph.add_node(2) - graph.add_edge(node_a, node_b, 1) - node_c = graph.add_node(3) - graph.add_edge(node_a, node_c, 1) - res = retworkx.graph_greedy_color(graph) - self.assertEqual({0: 0, 1: 1, 2: 1}, res) - - def test_simple_graph_large_degree(self): - graph = retworkx.PyGraph() - node_a = graph.add_node(1) - node_b = graph.add_node(2) - graph.add_edge(node_a, node_b, 1) - node_c = graph.add_node(3) - graph.add_edge(node_a, node_c, 1) - graph.add_edge(node_a, node_c, 1) - graph.add_edge(node_a, node_c, 1) - graph.add_edge(node_a, node_c, 1) - graph.add_edge(node_a, node_c, 1) - res = retworkx.graph_greedy_color(graph) - self.assertEqual({0: 0, 1: 1, 2: 1}, res) diff --git a/tests/retworkx_backwards_compat/graph/test_complement.py b/tests/retworkx_backwards_compat/graph/test_complement.py deleted file mode 100644 index 6ae796228..000000000 --- a/tests/retworkx_backwards_compat/graph/test_complement.py +++ /dev/null @@ -1,83 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestComplement(unittest.TestCase): - def test_clique(self): - N = 5 - graph = retworkx.PyGraph() - graph.extend_from_edge_list([(i, j) for i in range(N) for j in range(N) if i < j]) - - complement_graph = retworkx.complement(graph) - self.assertEqual(graph.nodes(), complement_graph.nodes()) - self.assertEqual(0, len(complement_graph.edges())) - - def test_empty(self): - N = 5 - graph = retworkx.PyGraph() - graph.add_nodes_from([i for i in range(N)]) - - expected_graph = retworkx.PyGraph() - expected_graph.extend_from_edge_list([(i, j) for i in range(N) for j in range(N) if i < j]) - - complement_graph = retworkx.complement(graph) - self.assertTrue( - retworkx.is_isomorphic( - expected_graph, - complement_graph, - ) - ) - - def test_null_graph(self): - graph = retworkx.PyGraph() - complement_graph = retworkx.complement(graph) - self.assertEqual(0, len(complement_graph.nodes())) - self.assertEqual(0, len(complement_graph.edges())) - - def test_complement(self): - N = 8 - graph = retworkx.PyGraph() - graph.extend_from_edge_list( - [(j, i) for i in range(N) for j in range(N) if i < j and (i + j) % 3 == 0] - ) - - expected_graph = retworkx.PyGraph() - expected_graph.extend_from_edge_list( - [(i, j) for i in range(N) for j in range(N) if i < j and (i + j) % 3 != 0] - ) - - complement_graph = retworkx.complement(graph) - self.assertTrue( - retworkx.is_isomorphic( - expected_graph, - complement_graph, - ) - ) - - def test_multigraph(self): - graph = retworkx.PyGraph(multigraph=True) - graph.extend_from_edge_list([(0, 0), (0, 1), (1, 1), (2, 2), (1, 0)]) - - expected_graph = retworkx.PyGraph(multigraph=True) - expected_graph.extend_from_edge_list([(0, 2), (1, 2)]) - - complement_graph = retworkx.complement(graph) - self.assertTrue( - retworkx.is_isomorphic( - expected_graph, - complement_graph, - ) - ) diff --git a/tests/retworkx_backwards_compat/graph/test_compose.py b/tests/retworkx_backwards_compat/graph/test_compose.py deleted file mode 100644 index 751309f24..000000000 --- a/tests/retworkx_backwards_compat/graph/test_compose.py +++ /dev/null @@ -1,97 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestCompose(unittest.TestCase): - def test_simple_graph_composition(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, {"a": 1}) - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, {"a": 2}) - graph_other = retworkx.PyGraph() - node_d = graph_other.add_node("d") - node_e = graph_other.add_node("e") - graph_other.add_edge(node_d, node_e, {"a": 3}) - res = graph.compose(graph_other, {node_c: (node_d, {"b": 1})}) - self.assertEqual({0: 3, 1: 4}, res) - self.assertEqual([0, 1, 2, 3, 4], graph.node_indexes()) - - def test_edge_map_and_node_map_funcs_graph_compose(self): - graph = retworkx.PyGraph() - original_input_nodes = graph.add_nodes_from(["qr[0]", "qr[1]"]) - original_op_nodes = graph.add_nodes_from(["h"]) - output_nodes = graph.add_nodes_from(["qr[0]", "qr[1]"]) - graph.add_edge(original_input_nodes[0], original_op_nodes[0], "qr[0]") - graph.add_edge(original_op_nodes[0], output_nodes[0], "qr[0]") - # Setup other graph - other_graph = retworkx.PyGraph() - input_nodes = other_graph.add_nodes_from(["qr[2]", "qr[3]"]) - op_nodes = other_graph.add_nodes_from(["cx"]) - other_output_nodes = other_graph.add_nodes_from(["qr[2]", "qr[3]"]) - other_graph.add_edges_from( - [ - (input_nodes[0], op_nodes[0], "qr[2]"), - (input_nodes[1], op_nodes[0], "qr[3]"), - ] - ) - other_graph.add_edges_from( - [ - (op_nodes[0], other_output_nodes[0], "qr[2]"), - (op_nodes[0], other_output_nodes[1], "qr[3]"), - ] - ) - - def map_fn(weight): - if weight == "qr[2]": - return "qr[0]" - elif weight == "qr[3]": - return "qr[1]" - else: - return weight - - graph.remove_nodes_from(output_nodes) - other_graph.remove_nodes_from(input_nodes) - node_map = { - original_op_nodes[0]: (op_nodes[0], "qr[0]"), - original_input_nodes[1]: (op_nodes[0], "qr[1]"), - } - res = graph.compose(other_graph, node_map, node_map_func=map_fn, edge_map_func=map_fn) - self.assertEqual({2: 4, 3: 3, 4: 5}, res) - self.assertEqual(graph[res[other_output_nodes[0]]], "qr[0]") - self.assertEqual(graph[res[other_output_nodes[1]]], "qr[1]") - # qr[0] -> h - self.assertTrue(graph.has_edge(0, 2)) - self.assertTrue(graph.get_all_edge_data(0, 2), ["qr[0]"]) - # qr[1] -> cx - self.assertTrue(graph.has_edge(1, 4)) - self.assertTrue(graph.get_all_edge_data(0, 2), ["qr[1]"]) - # h -> cx - self.assertTrue(graph.has_edge(2, 4)) - self.assertTrue(graph.get_all_edge_data(0, 2), ["qr[0]"]) - # cx -> qr[0] - self.assertTrue(graph.has_edge(4, 3)) - self.assertTrue(graph.get_all_edge_data(0, 2), ["qr[0]"]) - # cx -> qr[1] - self.assertTrue(graph.has_edge(4, 5)) - self.assertTrue(graph.get_all_edge_data(0, 2), ["qr[1]"]) - - def test_compose_digraph_onto_graph_error(self): - digraph = retworkx.PyDiGraph() - graph = retworkx.PyGraph() - with self.assertRaises(TypeError): - graph.compose(digraph, {}) diff --git a/tests/retworkx_backwards_compat/graph/test_connected_components.py b/tests/retworkx_backwards_compat/graph/test_connected_components.py deleted file mode 100644 index ecd7929be..000000000 --- a/tests/retworkx_backwards_compat/graph/test_connected_components.py +++ /dev/null @@ -1,88 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestConnectedComponents(unittest.TestCase): - def test_number_connected(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(range(3)) - graph.add_edge(0, 1, None) - self.assertEqual(retworkx.number_connected_components(graph), 2) - - def test_number_connected_direct(self): - graph = retworkx.PyDiGraph() - graph.add_nodes_from(range(4)) - graph.add_edges_from_no_data([(3, 2), (2, 1), (1, 0)]) - self.assertEqual(len(retworkx.weakly_connected_components(graph)), 1) - - def test_number_connected_node_holes(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(range(3)) - graph.remove_node(1) - self.assertEqual(retworkx.number_connected_components(graph), 2) - - def test_connected_components(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list( - [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4)] - ) - components = retworkx.connected_components(graph) - self.assertEqual([{0, 1, 2, 3}, {4, 5, 6, 7}], components) - - def test_node_connected_component(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list( - [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4)] - ) - component = retworkx.node_connected_component(graph, 0) - self.assertEqual({0, 1, 2, 3}, component) - - def test_node_connected_component_invalid_node(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list( - [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4)] - ) - with self.assertRaises(retworkx.InvalidNode): - retworkx.node_connected_component(graph, 10) - - def test_is_connected_false(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list( - [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4)] - ) - self.assertFalse(retworkx.is_connected(graph)) - - def test_is_connected_true(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list( - [ - (0, 1), - (1, 2), - (2, 3), - (3, 0), - (2, 4), - (4, 5), - (5, 6), - (6, 7), - (7, 4), - ] - ) - self.assertTrue(retworkx.is_connected(graph)) - - def test_is_connected_null_graph(self): - graph = retworkx.PyGraph() - with self.assertRaises(retworkx.NullGraph): - retworkx.is_connected(graph) diff --git a/tests/retworkx_backwards_compat/graph/test_contract_nodes.py b/tests/retworkx_backwards_compat/graph/test_contract_nodes.py deleted file mode 100644 index b43fe19c5..000000000 --- a/tests/retworkx_backwards_compat/graph/test_contract_nodes.py +++ /dev/null @@ -1,242 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class UndirectedEdge(tuple): - """An edge tuple wrapper for comparing expected edges with actual graph - edges where endpoint order doesn't matter (undirected). Supports both - edges and weighted edges. - - For example, the following become true: - ``UndirectedEdge((2, 3)) == UndirectedEdge((3, 2))`` - ``UndirectedEdge((4, 5, "a")) == UndirectedEdge((5, 4, "a"))`` - - """ - - def __eq__(self, o: object) -> bool: - return (frozenset(self[:2]), tuple(self[2:])) == ( - frozenset(o[:2]), - tuple(o[2:]), - ) - - def __hash__(self) -> int: - return hash((frozenset(self[:2]), tuple(self[2:]))) - - -class TestContractNodes(unittest.TestCase): - def test_empty_nodes(self): - """Replacing empty nodes is functionally equivalent to add_node.""" - dag = retworkx.PyGraph() - dag.contract_nodes([], "m") - - self.assertEqual(set(dag.nodes()), {"m"}) - - def test_unknown_nodes(self): - """ - Replacing all unknown nodes is functionally equivalent to add_node, - since unknown nodes should be ignored. - """ - dag = retworkx.PyGraph() - dag.contract_nodes([0, 1, 2], "m") - - self.assertEqual(set(dag.nodes()), {"m"}) - - def test_cycle_path_len_gt_1(self): - """ - ┌─┐ ┌─┐ - ┌4─┤a├─1┐ │m├──1───┐ - │ └─┘ │ └┬┘ │ - ┌┴┐ ┌┴┐ │ ┌┴┐ - │d│ │b│ ───► │ │b│ - └┬┘ └┬┘ │ └┬┘ - │ ┌─┐ 2 │ ┌─┐ 2 - └3─┤c├──┘ └3─┤c├──┘ - └─┘ └─┘ - """ - dag = retworkx.PyGraph() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - node_c = dag.add_node("c") - node_d = dag.add_node("d") - - dag.add_edge(node_a, node_b, 1) - dag.add_edge(node_b, node_c, 2) - dag.add_edge(node_c, node_d, 3) - dag.add_edge(node_a, node_d, 4) - - node_m = dag.contract_nodes([node_a, node_d], "m") - - self.assertEqual([node_b, node_c, node_m], dag.node_indexes()) - self.assertEqual( - { - UndirectedEdge((node_b, node_c)), - UndirectedEdge((node_c, node_m)), - UndirectedEdge((node_b, node_m)), - }, - set(UndirectedEdge(e) for e in dag.edge_list()), - ) - - def test_multiple_paths_would_cycle(self): - """ - ┌─┐ ┌─┐ ┌─┐ ┌─┐ - ┌3─┤c│ │e├─5┐ ┌──┤c│ │e├──┐ - │ └┬┘ └┬┘ │ │ └┬┘ └┬┘ │ - ┌┴┐ 2 ┌─┐ 4 ┌┴┐ │ 2 ┌─┐ 4 │ - │d│ └──┤b├──┘ │f│ ───► │ └──┤b├──┘ │ - └─┘ └┬┘ └─┘ 3 └┬┘ 5 - 1 │ 1 │ - ┌┴┐ │ ┌┴┐ │ - │a│ └──────┤m├──────┘ - └─┘ └─┘ - """ - dag = retworkx.PyGraph() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - node_c = dag.add_node("c") - node_d = dag.add_node("d") - node_e = dag.add_node("e") - node_f = dag.add_node("f") - - dag.add_edge(node_a, node_b, 1) - dag.add_edge(node_b, node_c, 2) - dag.add_edge(node_c, node_d, 3) - dag.add_edge(node_b, node_e, 4) - dag.add_edge(node_e, node_f, 5) - - node_m = dag.contract_nodes([node_a, node_d, node_f], "m") - - self.assertEqual([node_b, node_c, node_e, node_m], list(dag.node_indexes())) - self.assertEqual( - { - UndirectedEdge((node_b, node_c)), - UndirectedEdge((node_c, node_m)), - UndirectedEdge((node_e, node_m)), - UndirectedEdge((node_b, node_e)), - UndirectedEdge((node_b, node_m)), - }, - set(UndirectedEdge(e) for e in dag.edge_list()), - ) - - def test_replace_node_no_neighbors(self): - dag = retworkx.PyGraph() - node_a = dag.add_node("a") - node_m = dag.contract_nodes([node_a], "m") - self.assertEqual([node_m], dag.node_indexes()) - self.assertEqual(set(), set(dag.edge_list())) - - def test_keep_edges_multigraph(self): - """ - ┌─┐ ┌─┐ - ┌─┤a├─┐ ┌─┤a├─┐ - │ └─┘ │ │ └─┘ │ - 1 2 ──► 1 2 - ┌┴┐ ┌┴┐ │ ┌─┐ │ - │b│ │c│ └─┤m├─┘ - └─┘ └─┘ └─┘ - """ - dag = retworkx.PyGraph() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - node_c = dag.add_node("c") - - dag.add_edge(node_a, node_b, 1) - dag.add_edge(node_c, node_a, 2) - - node_m = dag.contract_nodes([node_b, node_c], "m") - self.assertEqual([node_a, node_m], dag.node_indexes()) - - # Note that target is *always* the new node (m). - self.assertEqual( - { - UndirectedEdge((node_a, node_m, 1)), - UndirectedEdge((node_a, node_m, 2)), - }, - set(UndirectedEdge(e) for e in dag.weighted_edge_list()), - ) - - -class TestContractNodesSimpleGraph(unittest.TestCase): - def setUp(self): - super().setUp() - self.dag = retworkx.PyGraph(multigraph=False) - self.node_a = self.dag.add_node("a") - self.node_b = self.dag.add_node("b") - self.node_c = self.dag.add_node("c") - self.node_d = self.dag.add_node("d") - self.node_e = self.dag.add_node("e") - - self.dag.add_edge(self.node_a, self.node_b, 1) - self.dag.add_edge(self.node_a, self.node_c, 2) - self.dag.add_edge(self.node_a, self.node_d, 3) - self.dag.add_edge(self.node_b, self.node_e, 4) - self.dag.add_edge(self.node_c, self.node_e, 5) - self.dag.add_edge(self.node_d, self.node_e, 6) - - def test_collapse_parallel_edges_no_combo_fn(self): - """ - Parallel edges are collapsed arbitrarily when weight_combo_fn is None. - ┌─┐ ┌─┐ - │a│ │a│ - ┌──┴┬┴──┐ └┬┘ - 1 2 3 1 or 2 or 3 - ┌┴┐ ┌┴┐ ┌┴┐ ┌┴┐ - │b│ │c│ │d│ ──► │m│ - └┬┘ └┬┘ └┬┘ └┬┘ - 4 5 6 4 or 5 or 6 - └──┬┴┬──┘ ┌┴┐ - │e│ │e│ - └─┘ └─┘ - """ - self.dag.contract_nodes([self.node_b, self.node_c, self.node_d], "m") - - self.assertEqual(set(self.dag.nodes()), {"a", "e", "m"}) - self.assertEqual(len(self.dag.edges()), 2) - - # Should have one incoming edge, one outgoing - self.assertTrue(any(e in self.dag.edges() for e in {1, 2, 3})) - self.assertTrue(any(e in self.dag.edges() for e in {4, 5, 6})) - - def test_collapse_parallel_edges(self): - """ - Parallel edges are collapsed using weight_combo_fn. - ┌─┐ ┌─┐ - │a│ │a│ - ┌──┴┬┴──┐ └┬┘ - 1 2 3 6 - ┌┴┐ ┌┴┐ ┌┴┐ ┌┴┐ - │b│ │c│ │d│ ──► │m│ - └┬┘ └┬┘ └┬┘ └┬┘ - 4 5 6 15 - └──┬┴┬──┘ ┌┴┐ - │e│ │e│ - └─┘ └─┘ - """ - self.dag.contract_nodes( - [self.node_b, self.node_c, self.node_d], - "m", - weight_combo_fn=lambda w1, w2: w1 + w2, - ) - - self.assertEqual(set(self.dag.nodes()), {"a", "e", "m"}) - self.assertEqual(len(self.dag.edges()), 2) - - # Should have one incoming edge, one outgoing - self.assertEqual(set(self.dag.edges()), {6, 15}) - - def test_replace_all_nodes(self): - self.dag.contract_nodes(self.dag.node_indexes(), "m") - self.assertEqual(set(self.dag.nodes()), {"m"}) - self.assertFalse(self.dag.edges()) diff --git a/tests/retworkx_backwards_compat/graph/test_copy.py b/tests/retworkx_backwards_compat/graph/test_copy.py deleted file mode 100644 index 1a9aa9741..000000000 --- a/tests/retworkx_backwards_compat/graph/test_copy.py +++ /dev/null @@ -1,55 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestCopy(unittest.TestCase): - def test_copy_returns_graph(self): - graph_a = retworkx.PyGraph() - node_a = graph_a.add_node("a_1") - node_b = graph_a.add_node("a_2") - graph_a.add_edge(node_a, node_b, "edge_1") - node_c = graph_a.add_node("a_3") - graph_a.add_edge(node_b, node_c, "edge_2") - graph_b = graph_a.copy() - self.assertIsInstance(graph_b, retworkx.PyGraph) - - def test_copy_with_holes_returns_graph(self): - graph_a = retworkx.PyGraph() - node_a = graph_a.add_node("a_1") - node_b = graph_a.add_node("a_2") - graph_a.add_edge(node_a, node_b, "edge_1") - node_c = graph_a.add_node("a_3") - graph_a.add_edge(node_b, node_c, "edge_2") - graph_a.remove_node(node_b) - graph_b = graph_a.copy() - self.assertIsInstance(graph_b, retworkx.PyGraph) - self.assertEqual([node_a, node_c], graph_b.node_indexes()) - - def test_copy_empty(self): - graph = retworkx.PyGraph() - empty_copy = graph.copy() - self.assertEqual(len(empty_copy), 0) - - def test_copy_shared_ref(self): - graph_a = retworkx.PyGraph() - node_a = graph_a.add_node({"a": 1}) - node_b = graph_a.add_node({"b": 2}) - graph_a.add_edge(node_a, node_b, {"edge": 1}) - graph_b = graph_a.copy() - graph_a[0]["a"] = 42 - graph_b.get_edge_data(0, 1)["edge"] = 162 - self.assertEqual(graph_b[0]["a"], 42) - self.assertEqual(graph_a.get_edge_data(0, 1), {"edge": 162}) diff --git a/tests/retworkx_backwards_compat/graph/test_core_number.py b/tests/retworkx_backwards_compat/graph/test_core_number.py deleted file mode 100644 index 0ed4907b0..000000000 --- a/tests/retworkx_backwards_compat/graph/test_core_number.py +++ /dev/null @@ -1,96 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestCoreNumber(unittest.TestCase): - def setUp(self): - # This 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 0-7, the 2-core by nodes - # 8-15, the 1-core by nodes 16-19 and node 20 is in the - # 0-core. - self.example_edges = [ - (0, 2), - (0, 3), - (0, 5), - (1, 4), - (1, 6), - (1, 7), - (2, 3), - (3, 5), - (2, 5), - (5, 6), - (4, 6), - (4, 7), - (6, 7), - (5, 8), - (6, 8), - (6, 9), - (8, 9), - (0, 10), - (1, 10), - (1, 11), - (10, 11), - (12, 13), - (13, 15), - (14, 15), - (12, 14), - (8, 19), - (11, 16), - (11, 17), - (12, 18), - ] - - example_core = {} - for i in range(8): - example_core[i] = 3 - for i in range(8, 16): - example_core[i] = 2 - for i in range(16, 20): - example_core[i] = 1 - example_core[20] = 0 - self.example_core = example_core - - def test_undirected_empty(self): - graph = retworkx.PyGraph() - res = retworkx.core_number(graph) - self.assertIsInstance(res, dict) - self.assertEqual(res, {}) - - def test_undirected_all_0(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - res = retworkx.core_number(graph) - self.assertIsInstance(res, dict) - self.assertEqual(res, {0: 0, 1: 0, 2: 0, 3: 0}) - - def test_undirected_all_3(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from_no_data([(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]) - res = retworkx.core_number(graph) - self.assertIsInstance(res, dict) - self.assertEqual(res, {0: 3, 1: 3, 2: 3, 3: 3}) - - def test_undirected_paper_example(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(21))) - graph.add_edges_from_no_data(self.example_edges) - res = retworkx.core_number(graph) - self.assertIsInstance(res, dict) - self.assertEqual(res, self.example_core) diff --git a/tests/retworkx_backwards_compat/graph/test_cycle_basis.py b/tests/retworkx_backwards_compat/graph/test_cycle_basis.py deleted file mode 100644 index 13719bb2f..000000000 --- a/tests/retworkx_backwards_compat/graph/test_cycle_basis.py +++ /dev/null @@ -1,69 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestCycleBasis(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.graph.add_nodes_from(list(range(10))) - self.graph.add_edges_from_no_data( - [ - (0, 1), - (0, 3), - (0, 5), - (0, 8), - (1, 2), - (1, 6), - (2, 3), - (3, 4), - (4, 5), - (6, 7), - (7, 8), - (8, 9), - ] - ) - - def test_cycle_basis(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(6))) - graph.add_edges_from_no_data([(0, 1), (0, 3), (0, 5), (1, 2), (2, 3), (3, 4), (4, 5)]) - res = sorted(sorted(c) for c in retworkx.cycle_basis(graph, 0)) - self.assertEqual([[0, 1, 2, 3], [0, 3, 4, 5]], res) - - def test_cycle_basis_multiple_roots_same_cycles(self): - res = sorted(sorted(x) for x in retworkx.cycle_basis(self.graph, 0)) - self.assertEqual(res, [[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5]]) - res = sorted(sorted(x) for x in retworkx.cycle_basis(self.graph, 1)) - self.assertEqual(res, [[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5]]) - res = sorted(sorted(x) for x in retworkx.cycle_basis(self.graph, 9)) - self.assertEqual(res, [[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5]]) - - def test_cycle_basis_disconnected_graphs(self): - self.graph.add_nodes_from(["A", "B", "C"]) - self.graph.add_edges_from_no_data([(10, 11), (10, 12), (11, 12)]) - cycles = retworkx.cycle_basis(self.graph, 9) - res = sorted(sorted(x) for x in cycles[:-1]) + [sorted(cycles[-1])] - self.assertEqual(res, [[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5], [10, 11, 12]]) - - def test_invalid_types(self): - digraph = retworkx.PyDiGraph() - with self.assertRaises(TypeError): - retworkx.cycle_basis(digraph) - - def test_self_loop(self): - self.graph.add_edge(1, 1, None) - res = sorted(sorted(c) for c in retworkx.cycle_basis(self.graph, 0)) - self.assertEqual([[0, 1, 2, 3], [0, 1, 6, 7, 8], [0, 3, 4, 5], [1]], res) diff --git a/tests/retworkx_backwards_compat/graph/test_deepcopy.py b/tests/retworkx_backwards_compat/graph/test_deepcopy.py deleted file mode 100644 index fcd87b1c6..000000000 --- a/tests/retworkx_backwards_compat/graph/test_deepcopy.py +++ /dev/null @@ -1,50 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import unittest - -import retworkx - - -class TestDeepcopy(unittest.TestCase): - def test_deepcopy_returns_graph(self): - dag_a = retworkx.PyGraph() - node_a = dag_a.add_node("a_1") - node_b = dag_a.add_node("a_2") - dag_a.add_edge(node_a, node_b, "edge_1") - node_c = dag_a.add_node("a_3") - dag_a.add_edge(node_b, node_c, "edge_2") - dag_b = copy.deepcopy(dag_a) - self.assertIsInstance(dag_b, retworkx.PyGraph) - - def test_deepcopy_with_holes_returns_graph(self): - dag_a = retworkx.PyGraph() - node_a = dag_a.add_node("a_1") - node_b = dag_a.add_node("a_2") - dag_a.add_edge(node_a, node_b, "edge_1") - node_c = dag_a.add_node("a_3") - dag_a.add_edge(node_b, node_c, "edge_2") - dag_a.remove_node(node_b) - dag_b = copy.deepcopy(dag_a) - self.assertIsInstance(dag_b, retworkx.PyGraph) - self.assertEqual([node_a, node_c], dag_b.node_indexes()) - - def test_deepcopy_empty(self): - dag = retworkx.PyGraph() - empty_copy = copy.deepcopy(dag) - self.assertEqual(len(empty_copy), 0) - - def test_deepcopy_attrs(self): - graph = retworkx.PyGraph(attrs="abc") - graph_copy = copy.deepcopy(graph) - self.assertEqual(graph.attrs, graph_copy.attrs) diff --git a/tests/retworkx_backwards_compat/graph/test_dfs_edges.py b/tests/retworkx_backwards_compat/graph/test_dfs_edges.py deleted file mode 100644 index 3903e45ee..000000000 --- a/tests/retworkx_backwards_compat/graph/test_dfs_edges.py +++ /dev/null @@ -1,31 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestDfsEdges(unittest.TestCase): - def test_graph_dfs_edges(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list([(0, 1), (1, 2), (1, 3), (2, 4), (3, 4)]) - edges = retworkx.graph_dfs_edges(graph, 0) - expected = [(0, 1), (1, 2), (2, 4), (4, 3)] - self.assertEqual(expected, edges) - - def test_graph_disconnected_dfs_edges(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list([(0, 1), (2, 3)]) - edges = retworkx.graph_dfs_edges(graph) - expected = [(0, 1), (2, 3)] - self.assertEqual(expected, edges) diff --git a/tests/retworkx_backwards_compat/graph/test_dfs_search.py b/tests/retworkx_backwards_compat/graph/test_dfs_search.py deleted file mode 100644 index 0b03349a5..000000000 --- a/tests/retworkx_backwards_compat/graph/test_dfs_search.py +++ /dev/null @@ -1,106 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestDfsSearch(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.graph.extend_from_edge_list( - [ - (0, 1), - (0, 2), - (1, 3), - (2, 1), - (2, 5), - (2, 6), - (5, 3), - (4, 7), - ] - ) - - def test_graph_dfs_tree_edges(self): - class TreeEdgesRecorder(retworkx.visit.DFSVisitor): - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - self.edges.append((edge[0], edge[1])) - - vis = TreeEdgesRecorder() - retworkx.graph_dfs_search(self.graph, [0], vis) - self.assertEqual(vis.edges, [(0, 2), (2, 6), (2, 5), (5, 3), (3, 1)]) - - def test_graph_dfs_tree_edges_no_starting_point(self): - class TreeEdgesRecorder(retworkx.visit.DFSVisitor): - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - self.edges.append((edge[0], edge[1])) - - vis = TreeEdgesRecorder() - retworkx.graph_dfs_search(self.graph, None, vis) - self.assertEqual(vis.edges, [(0, 2), (2, 6), (2, 5), (5, 3), (3, 1), (4, 7)]) - - def test_graph_dfs_tree_edges_restricted(self): - class TreeEdgesRecorderRestricted(retworkx.visit.DFSVisitor): - - prohibited = [(0, 2), (1, 2)] - - def __init__(self): - self.edges = [] - - def tree_edge(self, edge): - edge = (edge[0], edge[1]) - if edge in self.prohibited: - raise retworkx.visit.PruneSearch - self.edges.append(edge) - - vis = TreeEdgesRecorderRestricted() - retworkx.graph_dfs_search(self.graph, [0], vis) - self.assertEqual(vis.edges, [(0, 1), (1, 3), (3, 5), (5, 2), (2, 6)]) - - def test_graph_dfs_goal_search(self): - class GoalSearch(retworkx.visit.DFSVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - - def tree_edge(self, edge): - u, v, _ = edge - self.parents[v] = u - - if v == self.goal: - raise retworkx.visit.StopSearch - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - try: - retworkx.graph_dfs_search(self.graph, [0], vis) - except retworkx.visit.StopSearch: - pass - self.assertEqual(vis.reconstruct_path(), [0, 2, 5, 3]) diff --git a/tests/retworkx_backwards_compat/graph/test_dijkstra.py b/tests/retworkx_backwards_compat/graph/test_dijkstra.py deleted file mode 100644 index 68b9f98ee..000000000 --- a/tests/retworkx_backwards_compat/graph/test_dijkstra.py +++ /dev/null @@ -1,238 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestDijkstraGraph(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - self.d = self.graph.add_node("D") - self.e = self.graph.add_node("E") - self.f = self.graph.add_node("F") - self.graph.add_edge(self.a, self.b, 7) - self.graph.add_edge(self.c, self.a, 9) - self.graph.add_edge(self.a, self.d, 14) - self.graph.add_edge(self.b, self.c, 10) - self.graph.add_edge(self.d, self.c, 2) - self.graph.add_edge(self.d, self.e, 9) - self.graph.add_edge(self.b, self.f, 15) - self.graph.add_edge(self.c, self.f, 11) - self.graph.add_edge(self.e, self.f, 6) - - def test_dijkstra(self): - path = retworkx.graph_dijkstra_shortest_path_lengths( - self.graph, self.a, lambda x: float(x), self.e - ) - expected = {4: 20.0} - self.assertEqual(expected, path) - - def test_dijkstra_path(self): - path = retworkx.graph_dijkstra_shortest_paths( - self.graph, self.a, weight_fn=lambda x: float(x), target=self.e - ) - # a -> d -> e = 23 - # a -> c -> d -> e = 20 - expected = {4: [self.a, self.c, self.d, self.e]} - self.assertEqual(expected, path) - - def test_dijkstra_with_no_goal_set(self): - path = retworkx.graph_dijkstra_shortest_path_lengths(self.graph, self.a, lambda x: 1) - expected = {1: 1.0, 2: 1.0, 3: 1.0, 4: 2.0, 5: 2.0} - self.assertEqual(expected, path) - - def test_dijkstra_length_with_no_path(self): - g = retworkx.PyGraph() - a = g.add_node("A") - b = g.add_node("B") - path_lenghts = retworkx.graph_dijkstra_shortest_path_lengths( - g, a, edge_cost_fn=float, goal=b - ) - expected = {} - self.assertEqual(expected, path_lenghts) - - def test_dijkstra_path_with_no_goal_set(self): - path = retworkx.graph_dijkstra_shortest_paths(self.graph, self.a) - expected = { - 1: [0, 1], - 2: [0, 2], - 3: [0, 3], - 4: [0, 3, 4], - 5: [0, 1, 5], - } - self.assertEqual(expected, path) - - def test_dijkstra_with_no_path(self): - g = retworkx.PyGraph() - a = g.add_node("A") - g.add_node("B") - path = retworkx.graph_dijkstra_shortest_path_lengths(g, a, lambda x: float(x)) - expected = {} - self.assertEqual(expected, path) - - def test_dijkstra_path_with_no_path(self): - g = retworkx.PyGraph() - a = g.add_node("A") - g.add_node("B") - path = retworkx.graph_dijkstra_shortest_paths(g, a, weight_fn=lambda x: float(x)) - expected = {} - self.assertEqual(expected, path) - - def test_dijkstra_with_disconnected_nodes(self): - g = retworkx.PyGraph() - a = g.add_node("A") - b = g.add_node("B") - g.add_edge(a, b, 1.2) - g.add_node("C") - d = g.add_node("D") - g.add_edge(b, d, 2.4) - path = retworkx.graph_dijkstra_shortest_path_lengths(g, a, lambda x: round(x, 1)) - # Computers never work: - expected = {1: 1.2, 3: 3.5999999999999996} - self.assertEqual(expected, path) - - def test_dijkstra_graph_with_digraph_input(self): - g = retworkx.PyDAG() - g.add_node(0) - with self.assertRaises(TypeError): - retworkx.graph_dijkstra_shortest_path_lengths(g, 0, lambda x: x) - - def test_dijkstra_all_pair_path_lengths(self): - lengths = retworkx.graph_all_pairs_dijkstra_path_lengths(self.graph, float) - expected = { - 0: {1: 7.0, 2: 9.0, 3: 11.0, 4: 20.0, 5: 20.0}, - 1: {0: 7.0, 2: 10.0, 3: 12.0, 4: 21.0, 5: 15.0}, - 2: {0: 9.0, 1: 10.0, 3: 2.0, 4: 11.0, 5: 11.0}, - 3: {0: 11.0, 1: 12.0, 2: 2.0, 4: 9.0, 5: 13.0}, - 4: {0: 20.0, 1: 21.0, 2: 11.0, 3: 9.0, 5: 6.0}, - 5: {0: 20.0, 1: 15.0, 2: 11.0, 3: 13.0, 4: 6.0}, - } - self.assertEqual(expected, lengths) - - def test_dijkstra_all_pair_paths(self): - paths = retworkx.graph_all_pairs_dijkstra_shortest_paths(self.graph, float) - expected = { - 0: { - 1: [0, 1], - 2: [0, 2], - 3: [0, 2, 3], - 4: [0, 2, 3, 4], - 5: [0, 2, 5], - }, - 1: {0: [1, 0], 2: [1, 2], 3: [1, 2, 3], 4: [1, 2, 3, 4], 5: [1, 5]}, - 2: {0: [2, 0], 1: [2, 1], 3: [2, 3], 4: [2, 3, 4], 5: [2, 5]}, - 3: {0: [3, 2, 0], 1: [3, 2, 1], 2: [3, 2], 4: [3, 4], 5: [3, 2, 5]}, - 4: { - 0: [4, 3, 2, 0], - 1: [4, 5, 1], - 2: [4, 3, 2], - 3: [4, 3], - 5: [4, 5], - }, - 5: {0: [5, 2, 0], 1: [5, 1], 2: [5, 2], 3: [5, 2, 3], 4: [5, 4]}, - } - self.assertEqual(expected, paths) - - def test_dijkstra_all_pair_path_lengths_with_node_removal(self): - self.graph.remove_node(3) - lengths = retworkx.graph_all_pairs_dijkstra_path_lengths(self.graph, float) - expected = { - 0: {1: 7.0, 2: 9.0, 4: 26.0, 5: 20.0}, - 1: {0: 7.0, 2: 10.0, 4: 21.0, 5: 15.0}, - 2: {0: 9.0, 1: 10.0, 4: 17.0, 5: 11.0}, - 4: {0: 26.0, 1: 21.0, 2: 17.0, 5: 6.0}, - 5: {0: 20.0, 1: 15.0, 2: 11.0, 4: 6.0}, - } - self.assertEqual(expected, lengths) - - def test_dijkstra_all_pair_paths_with_node_removal(self): - self.graph.remove_node(3) - paths = retworkx.graph_all_pairs_dijkstra_shortest_paths(self.graph, float) - expected = { - 0: {1: [0, 1], 2: [0, 2], 4: [0, 2, 5, 4], 5: [0, 2, 5]}, - 1: {0: [1, 0], 2: [1, 2], 4: [1, 5, 4], 5: [1, 5]}, - 2: {0: [2, 0], 1: [2, 1], 4: [2, 5, 4], 5: [2, 5]}, - 4: {0: [4, 5, 2, 0], 1: [4, 5, 1], 2: [4, 5, 2], 5: [4, 5]}, - 5: {0: [5, 2, 0], 1: [5, 1], 2: [5, 2], 4: [5, 4]}, - } - self.assertEqual(expected, paths) - - def test_dijkstra_all_pair_path_lengths_empty_graph(self): - graph = retworkx.PyGraph() - self.assertEqual({}, retworkx.graph_all_pairs_dijkstra_path_lengths(graph, float)) - - def test_dijkstra_all_pair_shortest_paths_empty_graph(self): - graph = retworkx.PyGraph() - self.assertEqual({}, retworkx.graph_all_pairs_dijkstra_shortest_paths(graph, float)) - - def test_dijkstra_all_pair_path_lengths_graph_no_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.graph_all_pairs_dijkstra_path_lengths(graph, float), - ) - - def test_dijkstra_all_pair_shortest_paths_no_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.graph_all_pairs_dijkstra_shortest_paths(graph, float), - ) - - def dijkstra_with_invalid_weights(self): - graph = retworkx.generators.path_graph(2) - for invalid_weight in [float("nan"), -1]: - for as_undirected in [False, True]: - with self.subTest(invalid_weight=invalid_weight, as_undirected=as_undirected): - with self.assertRaises(ValueError): - retworkx.graph_dijkstra_shortest_paths( - graph, - source=0, - weight_fn=lambda _: invalid_weight, - as_undirected=as_undirected, - ) - - def dijkstra_lengths_with_invalid_weights(self): - graph = retworkx.generators.path_graph(2) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.graph_dijkstra_shortest_path_lengths( - graph, node=0, edge_cost_fn=lambda _: invalid_weight - ) - - def all_pairs_dijkstra_with_invalid_weights(self): - graph = retworkx.generators.path_graph(2) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.graph_all_pairs_dijkstra_shortest_paths( - graph, edge_cost_fn=lambda _: invalid_weight - ) - - def all_pairs_dijkstra_lenghts_with_invalid_weights(self): - graph = retworkx.generators.path_graph(2) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.graph_all_pairs_dijkstra_path_lengths( - graph, edge_cost_fn=lambda _: invalid_weight - ) diff --git a/tests/retworkx_backwards_compat/graph/test_dijkstra_search.py b/tests/retworkx_backwards_compat/graph/test_dijkstra_search.py deleted file mode 100644 index aea0dc6d7..000000000 --- a/tests/retworkx_backwards_compat/graph/test_dijkstra_search.py +++ /dev/null @@ -1,189 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestDijkstraSearch(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.graph.extend_from_weighted_edge_list( - [ - (0, 1, 1), - (0, 2, 2), - (1, 3, 10), - (2, 1, 1), - (2, 5, 1), - (2, 6, 1), - (5, 3, 1), - (4, 7, 1), - ] - ) - - def test_graph_dijkstra_tree_edges(self): - class DijkstraTreeEdgesRecorder(retworkx.visit.DijkstraVisitor): - def __init__(self): - self.edges = [] - self.parents = dict() - - def discover_vertex(self, v, _): - u = self.parents.get(v, None) - if u is not None: - self.edges.append((u, v)) - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - vis = DijkstraTreeEdgesRecorder() - retworkx.graph_dijkstra_search(self.graph, [0], float, vis) - self.assertEqual(vis.edges, [(0, 1), (0, 2), (2, 6), (2, 5), (5, 3)]) - - def test_graph_dijkstra_tree_edges_no_starting_point(self): - class DijkstraTreeEdgesRecorder(retworkx.visit.DijkstraVisitor): - def __init__(self): - self.edges = [] - self.parents = dict() - - def discover_vertex(self, v, _): - u = self.parents.get(v, None) - if u is not None: - self.edges.append((u, v)) - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - vis = DijkstraTreeEdgesRecorder() - retworkx.graph_dijkstra_search(self.graph, None, float, vis) - self.assertEqual(vis.edges, [(0, 1), (0, 2), (2, 6), (2, 5), (5, 3), (4, 7)]) - - def test_graph_dijkstra_goal_search_with_stop_search_exception(self): - class GoalSearch(retworkx.visit.DijkstraVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - self.opt_goal_cost = None - - def discover_vertex(self, v, score): - if v == self.goal: - self.opt_goal_cost = score - raise retworkx.visit.StopSearch - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - retworkx.graph_dijkstra_search(self.graph, [0], float, vis) - self.assertEqual(vis.reconstruct_path(), [0, 2, 5, 3]) - self.assertEqual(vis.opt_goal_cost, 4.0) - - def test_graph_dijkstra_goal_search_with_custom_exception(self): - class StopIfGoalFound(Exception): - pass - - class GoalSearch(retworkx.visit.DijkstraVisitor): - - goal = 3 - - def __init__(self): - self.parents = {} - self.opt_goal_cost = None - - def discover_vertex(self, v, score): - if v == self.goal: - self.opt_goal_cost = score - raise StopIfGoalFound - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - try: - retworkx.graph_dijkstra_search(self.graph, [0], float, vis) - except StopIfGoalFound: - pass - self.assertEqual(vis.reconstruct_path(), [0, 2, 5, 3]) - self.assertEqual(vis.opt_goal_cost, 4.0) - - def test_graph_dijkstra_goal_search_with_prohibited_edges(self): - class GoalSearch(retworkx.visit.DijkstraVisitor): - - goal = 3 - prohibited = [(5, 3)] - - def __init__(self): - self.parents = {} - self.opt_goal_cost = None - - def discover_vertex(self, v, score): - if v == self.goal: - self.opt_goal_cost = score - raise retworkx.visit.StopSearch - - def examine_edge(self, edge): - u, v, _ = edge - if (u, v) in self.prohibited: - raise retworkx.visit.PruneSearch - - def edge_relaxed(self, edge): - u, v, _ = edge - self.parents[v] = u - - def reconstruct_path(self): - v = self.goal - path = [v] - while v in self.parents: - v = self.parents[v] - path.append(v) - - path.reverse() - return path - - vis = GoalSearch() - retworkx.graph_dijkstra_search(self.graph, [0], float, vis) - self.assertEqual(vis.reconstruct_path(), [0, 1, 3]) - self.assertEqual(vis.opt_goal_cost, 11.0) - - def test_graph_prune_edge_not_relaxed(self): - class PruneEdgeNotRelaxed(retworkx.visit.DijkstraVisitor): - def edge_not_relaxed(self, _): - raise retworkx.visit.PruneSearch - - vis = PruneEdgeNotRelaxed() - retworkx.graph_dijkstra_search(self.graph, [0], float, vis) diff --git a/tests/retworkx_backwards_compat/graph/test_dist_matrix.py b/tests/retworkx_backwards_compat/graph/test_dist_matrix.py deleted file mode 100644 index 166312575..000000000 --- a/tests/retworkx_backwards_compat/graph/test_dist_matrix.py +++ /dev/null @@ -1,102 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import numpy as np - -import retworkx - - -class TestDistanceMatrix(unittest.TestCase): - def test_graph_distance_matrix(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.graph_distance_matrix(graph) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0], - ] - ) - self.assertTrue(np.array_equal(dist, expected)) - - def test_graph_distance_matrix_parallel(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.graph_distance_matrix(graph, parallel_threshold=5) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0], - ] - ) - self.assertTrue(np.array_equal(dist, expected)) - - def test_graph_distance_matrix_non_zero_null(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - graph.add_node(7) - dist = retworkx.graph_distance_matrix(graph, null_value=np.nan) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0, np.nan], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0, np.nan], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0, np.nan], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0, np.nan], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0, np.nan], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0, np.nan], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0, np.nan], - [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, 0.0], - ] - ) - self.assertTrue(np.array_equal(dist, expected, equal_nan=True)) - - def test_graph_distance_matrix_parallel_non_zero_null(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - graph.add_node(7) - dist = retworkx.graph_distance_matrix(graph, parallel_threshold=5, null_value=np.nan) - expected = np.array( - [ - [0.0, 1.0, 2.0, 3.0, 3.0, 2.0, 1.0, np.nan], - [1.0, 0.0, 1.0, 2.0, 3.0, 3.0, 2.0, np.nan], - [2.0, 1.0, 0.0, 1.0, 2.0, 3.0, 3.0, np.nan], - [3.0, 2.0, 1.0, 0.0, 1.0, 2.0, 3.0, np.nan], - [3.0, 3.0, 2.0, 1.0, 0.0, 1.0, 2.0, np.nan], - [2.0, 3.0, 3.0, 2.0, 1.0, 0.0, 1.0, np.nan], - [1.0, 2.0, 3.0, 3.0, 2.0, 1.0, 0.0, np.nan], - [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, 0.0], - ], - ) - self.assertTrue(np.array_equal(dist, expected, equal_nan=True)) - - def test_graph_distance_matrix_node_hole(self): - graph = retworkx.generators.path_graph(4) - graph.remove_node(0) - dist = retworkx.graph_distance_matrix(graph) - expected = np.array([[0.0, 1.0, 2.0], [1.0, 0.0, 1.0], [2.0, 1.0, 0.0]]) - self.assertTrue(np.array_equal(dist, expected)) diff --git a/tests/retworkx_backwards_compat/graph/test_dot.py b/tests/retworkx_backwards_compat/graph/test_dot.py deleted file mode 100644 index fafbbcd87..000000000 --- a/tests/retworkx_backwards_compat/graph/test_dot.py +++ /dev/null @@ -1,130 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import tempfile -import unittest - -import retworkx - - -class TestDot(unittest.TestCase): - def setUp(self): - fd, self.path = tempfile.mkstemp() - os.close(fd) - os.remove(self.path) - - def test_graph_to_dot(self): - graph = retworkx.PyGraph() - graph.add_node( - { - "color": "black", - "fillcolor": "green", - "label": "a", - "style": "filled", - } - ) - graph.add_node( - { - "color": "black", - "fillcolor": "red", - "label": "a", - "style": "filled", - } - ) - graph.add_edge(0, 1, dict(label="1", name="1")) - expected = ( - 'graph {\n0 [color=black, fillcolor=green, label="a", style=filled' - '];\n1 [color=black, fillcolor=red, label="a", style=filled];' - '\n0 -- 1 [label="1", name=1];\n}\n' - ) - res = graph.to_dot(lambda node: node, lambda edge: edge) - self.assertEqual(expected, res) - - def test_digraph_to_dot(self): - graph = retworkx.PyDiGraph() - graph.add_node( - { - "color": "black", - "fillcolor": "green", - "label": "a", - "style": "filled", - } - ) - graph.add_node( - { - "color": "black", - "fillcolor": "red", - "label": "a", - "style": "filled", - } - ) - graph.add_edge(0, 1, dict(label="1", name="1")) - expected = ( - 'digraph {\n0 [color=black, fillcolor=green, label="a", ' - 'style=filled];\n1 [color=black, fillcolor=red, label="a", ' - 'style=filled];\n0 -> 1 [label="1", name=1];\n}\n' - ) - res = graph.to_dot(lambda node: node, lambda edge: edge) - self.assertEqual(expected, res) - - def test_graph_to_dot_to_file(self): - graph = retworkx.PyGraph() - graph.add_node( - { - "color": "black", - "fillcolor": "green", - "label": "a", - "style": "filled", - } - ) - graph.add_node( - { - "color": "black", - "fillcolor": "red", - "label": "a", - "style": "filled", - } - ) - graph.add_edge(0, 1, dict(label="1", name="1")) - expected = ( - 'graph {\n0 [color=black, fillcolor=green, label="a", ' - 'style=filled];\n1 [color=black, fillcolor=red, label="a", ' - 'style=filled];\n0 -- 1 [label="1", name=1];\n}\n' - ) - res = graph.to_dot(lambda node: node, lambda edge: edge, filename=self.path) - self.addCleanup(os.remove, self.path) - self.assertIsNone(res) - with open(self.path, "r") as fd: - res = fd.read() - self.assertEqual(expected, res) - - def test_graph_empty_dicts(self): - graph = retworkx.undirected_gnp_random_graph(3, 0.9, seed=42) - dot_str = graph.to_dot(lambda _: {}, lambda _: {}) - self.assertEqual( - "graph {\n0 ;\n1 ;\n2 ;\n1 -- 0 ;\n2 -- 0 ;\n" "2 -- 1 ;\n}\n", - dot_str, - ) - - def test_graph_graph_attrs(self): - graph = retworkx.undirected_gnp_random_graph(3, 0.9, seed=42) - dot_str = graph.to_dot(lambda _: {}, lambda _: {}, {"bgcolor": "red"}) - self.assertEqual( - "graph {\nbgcolor=red ;\n0 ;\n1 ;\n2 ;\n1 -- 0 ;\n" "2 -- 0 ;\n2 -- 1 ;\n}\n", - dot_str, - ) - - def test_graph_no_args(self): - graph = retworkx.undirected_gnp_random_graph(3, 0.95, seed=24) - dot_str = graph.to_dot() - self.assertEqual("graph {\n0 ;\n1 ;\n2 ;\n2 -- 0 ;\n2 -- 1 ;\n}\n", dot_str) diff --git a/tests/retworkx_backwards_compat/graph/test_edgelist.py b/tests/retworkx_backwards_compat/graph/test_edgelist.py deleted file mode 100644 index c6092a173..000000000 --- a/tests/retworkx_backwards_compat/graph/test_edgelist.py +++ /dev/null @@ -1,209 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import tempfile -import unittest - -import retworkx - - -class TestEdgeList(unittest.TestCase): - def test_empty_edge_list_graph(self): - with tempfile.NamedTemporaryFile() as fd: - graph = retworkx.PyGraph.read_edge_list(fd.name) - self.assertEqual(graph.nodes(), []) - - def test_invalid_path_graph(self): - path = os.path.join(tempfile.gettempdir(), "fake_file_name.txt") - with self.assertRaises(FileNotFoundError): - retworkx.PyGraph.read_edge_list(path) - - def test_simple_example_graph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1\n") - fd.write("1 2\n") - fd.flush() - graph = retworkx.PyGraph.read_edge_list(fd.name) - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertTrue(graph.has_edge(1, 0)) - self.assertTrue(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - - def test_blank_line_graph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1\n") - fd.write("\n") - fd.write("1 2\n") - fd.flush() - graph = retworkx.PyGraph.read_edge_list(fd.name) - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertTrue(graph.has_edge(1, 0)) - self.assertTrue(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - - def test_comment_graph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1\n") - fd.write("1 2 # test comments\n") - fd.write("#2 3\n") - fd.flush() - graph = retworkx.PyGraph.read_edge_list(fd.name, comment="#") - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertTrue(graph.has_edge(1, 0)) - self.assertTrue(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - - def test_comment_leading_space_graph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1\n") - fd.write("1 2 # test comments\n") - fd.write(" #2 3\n") - fd.flush() - graph = retworkx.PyGraph.read_edge_list(fd.name, comment="#") - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertTrue(graph.has_edge(1, 0)) - self.assertTrue(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - - def test_weight_graph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0 1 0\n") - fd.write("1 2 1# test comments\n") - fd.write("#2 3\n") - fd.flush() - graph = retworkx.PyGraph.read_edge_list(fd.name, comment="#") - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertTrue(graph.has_edge(1, 0)) - self.assertTrue(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - self.assertEqual(graph.edges(), ["0", "1"]) - - def test_delim_graph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("0,1,0\n") - fd.write("1,2,1# test comments\n") - fd.write("#2,3\n") - fd.flush() - graph = retworkx.PyGraph.read_edge_list(fd.name, comment="#", deliminator=",") - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertTrue(graph.has_edge(1, 0)) - self.assertTrue(graph.has_edge(2, 1)) - self.assertFalse(graph.has_edge(0, 2)) - self.assertEqual(graph.edges(), ["0", "1"]) - - def test_labels_graph(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("a|b|0// test a comment\n") - fd.write("b|c|1\n") - fd.write("//c|d\n") - fd.flush() - graph = retworkx.PyGraph.read_edge_list( - fd.name, comment="//", deliminator="|", labels=True - ) - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertFalse(graph.has_edge(0, 2)) - self.assertEqual(graph.edges(), ["0", "1"]) - - def test_labels_graph_target_existing(self): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write("a|b|0// test a comment\n") - fd.write("b|c|1\n") - fd.write("a|c\n") - fd.flush() - graph = retworkx.PyGraph.read_edge_list( - fd.name, comment="//", deliminator="|", labels=True - ) - self.assertEqual(graph.node_indexes(), [0, 1, 2]) - self.assertTrue(graph.has_edge(0, 1)) - self.assertTrue(graph.has_edge(1, 2)) - self.assertTrue(graph.has_edge(0, 2)) - self.assertEqual(graph.edges(), ["0", "1", None]) - - def test_write_edge_list_empty_digraph(self): - path = os.path.join(tempfile.gettempdir(), "empty.txt") - graph = retworkx.PyGraph() - graph.write_edge_list(path) - self.addCleanup(os.remove, path) - with open(path, "rt") as edge_file: - self.assertEqual("", edge_file.read()) - - def test_write_edge_list_round_trip(self): - path = os.path.join(tempfile.gettempdir(), "round_trip.txt") - graph = retworkx.generators.star_graph(5) - count = iter(range(5)) - - def weight_fn(edge): - return str(next(count)) - - graph.write_edge_list(path, weight_fn=weight_fn) - self.addCleanup(os.remove, path) - new_graph = retworkx.PyGraph.read_edge_list(path) - expected = [ - (0, 1, "0"), - (0, 2, "1"), - (0, 3, "2"), - (0, 4, "3"), - ] - self.assertEqual(expected, new_graph.weighted_edge_list()) - - def test_custom_delim(self): - path = os.path.join(tempfile.gettempdir(), "custom_delim.txt") - graph = retworkx.generators.path_graph(5) - graph.write_edge_list(path, deliminator=",") - self.addCleanup(os.remove, path) - expected = """0,1 -1,2 -2,3 -3,4 -""" - with open(path, "rt") as edge_file: - self.assertEqual(edge_file.read(), expected) - - def test_invalid_return_type_weight_fn(self): - path = os.path.join(tempfile.gettempdir(), "fail.txt") - graph = retworkx.undirected_gnm_random_graph(5, 4) - self.addCleanup(cleanup_file, path) - with self.assertRaises(TypeError): - graph.write_edge_list(path, weight_fn=lambda _: 4.5) - - def test_weight_fn_raises(self): - path = os.path.join(tempfile.gettempdir(), "fail.txt") - graph = retworkx.undirected_gnm_random_graph(5, 4) - - def weight_fn(edge): - raise KeyError - - self.addCleanup(cleanup_file, path) - with self.assertRaises(KeyError): - graph.write_edge_list(path, weight_fn=weight_fn) - - -def cleanup_file(path): - try: - os.remove(path) - except Exception: - pass diff --git a/tests/retworkx_backwards_compat/graph/test_edges.py b/tests/retworkx_backwards_compat/graph/test_edges.py deleted file mode 100644 index bcb7fd252..000000000 --- a/tests/retworkx_backwards_compat/graph/test_edges.py +++ /dev/null @@ -1,819 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestEdges(unittest.TestCase): - def test_get_edge_data(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - res = graph.get_edge_data(node_a, node_b) - self.assertEqual("Edgy", res) - - def test_get_all_edge_data(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - graph.add_edge(node_a, node_b, "b") - res = graph.get_all_edge_data(node_a, node_b) - self.assertIn("b", res) - self.assertIn("Edgy", res) - - def test_no_edge(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.get_edge_data, node_a, node_b) - - def test_num_edges(self): - graph = retworkx.PyGraph() - graph.add_node(1) - graph.add_node(42) - graph.add_node(146) - graph.add_edges_from_no_data([(0, 1), (1, 2)]) - self.assertEqual(2, graph.num_edges()) - - def test_num_edges_no_edges(self): - graph = retworkx.PyGraph() - graph.add_node(1) - graph.add_node(42) - self.assertEqual(0, graph.num_edges()) - - def test_update_edge(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "not edgy") - graph.update_edge(node_a, node_b, "Edgy") - self.assertEqual([(0, 1, "Edgy")], graph.weighted_edge_list()) - - def test_update_edge_no_edge(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.update_edge, node_a, node_b, None) - - def test_update_edge_by_index(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - edge_index = graph.add_edge(node_a, node_b, "not edgy") - graph.update_edge_by_index(edge_index, "Edgy") - self.assertEqual([(0, 1, "Edgy")], graph.weighted_edge_list()) - - def test_update_edge_invalid_index(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - self.assertRaises(IndexError, graph.update_edge_by_index, 0, None) - - def test_update_edge_parallel_edges(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "not edgy") - edge_index = graph.add_edge(node_a, node_b, "not edgy") - graph.update_edge_by_index(edge_index, "Edgy") - self.assertEqual( - [(0, 1, "not edgy"), (0, 1, "Edgy")], - list(graph.weighted_edge_list()), - ) - - def test_no_edge_get_all_edge_data(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.get_all_edge_data, node_a, node_b) - - def test_has_edge(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, {}) - self.assertTrue(graph.has_edge(node_a, node_b)) - self.assertTrue(graph.has_edge(node_b, node_a)) - - def test_has_edge_no_edge(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertFalse(graph.has_edge(node_a, node_b)) - - def test_edges(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Super edgy") - self.assertEqual(["Edgy", "Super edgy"], graph.edges()) - - def test_edges_empty(self): - graph = retworkx.PyGraph() - graph.add_node("a") - self.assertEqual([], graph.edges()) - - def test_edge_indices(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Super edgy") - self.assertEqual([0, 1], graph.edge_indices()) - - def test_get_edge_indices_empty(self): - graph = retworkx.PyGraph() - graph.add_node("a") - self.assertEqual([], graph.edge_indices()) - - def test_add_duplicates(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("a") - graph.add_edge(node_a, node_b, "a") - graph.add_edge(node_a, node_b, "b") - self.assertEqual(["a", "b"], graph.edges()) - - def test_remove_no_edge(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.remove_edge, node_a, node_b) - - def test_remove_edge_single(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.remove_edge(node_a, node_b) - self.assertEqual([], graph.edges()) - - def test_remove_multiple(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.add_edge(node_a, node_b, "super_edgy") - graph.remove_edge_from_index(0) - self.assertEqual(["super_edgy"], graph.edges()) - - def test_remove_edge_from_index(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.remove_edge_from_index(0) - self.assertEqual([], graph.edges()) - - def test_remove_edge_no_edge(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.remove_edge_from_index(0) - self.assertEqual([], graph.edges()) - - def test_remove_edges_from(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - node_c = graph.add_node("c") - graph.add_edge(node_a, node_b, "edgy") - graph.add_edge(node_a, node_c, "super_edgy") - graph.remove_edges_from([(node_a, node_b), (node_a, node_c)]) - self.assertEqual([], graph.edges()) - - def test_remove_edges_from_invalid(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - node_c = graph.add_node("c") - graph.add_edge(node_a, node_b, "edgy") - graph.add_edge(node_a, node_c, "super_edgy") - with self.assertRaises(retworkx.NoEdgeBetweenNodes): - graph.remove_edges_from([(node_b, node_c), (node_a, node_c)]) - - def test_degree(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Super edgy") - self.assertEqual(2, graph.degree(node_b)) - - def test_degree_with_self_loops(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list([(0, 0), (0, 1), (0, 0)]) - self.assertEqual(5, graph.degree(0)) - - def test_add_edge_from(self): - graph = retworkx.PyGraph() - nodes = list(range(4)) - graph.add_nodes_from(nodes) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - res = graph.add_edges_from(edge_list) - self.assertEqual(len(res), 5) - self.assertEqual(["a", "b", "c", "d", "e"], graph.edges()) - self.assertEqual(3, graph.degree(0)) - self.assertEqual(2, graph.degree(1)) - self.assertEqual(3, graph.degree(2)) - self.assertEqual(2, graph.degree(3)) - - def test_add_edge_from_empty(self): - graph = retworkx.PyGraph() - res = graph.add_edges_from([]) - self.assertEqual([], res) - - def test_add_edge_from_no_data(self): - graph = retworkx.PyGraph() - nodes = list(range(4)) - graph.add_nodes_from(nodes) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - res = graph.add_edges_from_no_data(edge_list) - self.assertEqual(len(res), 5) - self.assertEqual([None, None, None, None, None], graph.edges()) - self.assertEqual(3, graph.degree(0)) - self.assertEqual(2, graph.degree(1)) - self.assertEqual(3, graph.degree(2)) - self.assertEqual(2, graph.degree(3)) - - def test_add_edge_from_empty_no_data(self): - graph = retworkx.PyGraph() - res = graph.add_edges_from_no_data([]) - self.assertEqual([], res) - - def test_extend_from_weighted_edge_list_empty(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list([]) - self.assertEqual(0, len(graph)) - - def test_extend_from_weighted_edge_list_nodes_exist(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual(["a", "b", "c", "d", "e"], graph.edges()) - - def test_extend_from_weighted_edge_list_edges_exist(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - (0, 1, "not_a"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual(["a", "b", "c", "d", "e", "not_a"], graph.edges()) - - def test_edge_list(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.add_edges_from(edge_list) - self.assertEqual([(x[0], x[1]) for x in edge_list], graph.edge_list()) - - def test_edge_list_empty(self): - graph = retworkx.PyGraph() - self.assertEqual([], graph.edge_list()) - - def test_weighted_edge_list(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.add_edges_from(edge_list) - self.assertEqual(edge_list, graph.weighted_edge_list()) - - def test_weighted_edge_list_empty(self): - graph = retworkx.PyGraph() - self.assertEqual([], graph.weighted_edge_list()) - - def test_extend_from_edge_list(self): - graph = retworkx.PyGraph() - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - graph.extend_from_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual([None] * 5, graph.edges()) - self.assertEqual(3, graph.degree(0)) - self.assertEqual(2, graph.degree(1)) - self.assertEqual(3, graph.degree(2)) - self.assertEqual(2, graph.degree(3)) - - def test_extend_from_edge_list_empty(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list([]) - self.assertEqual(0, len(graph)) - - def test_extend_from_edge_list_nodes_exist(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - graph.extend_from_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual([None] * 5, graph.edges()) - self.assertEqual(3, graph.degree(0)) - self.assertEqual(2, graph.degree(1)) - self.assertEqual(3, graph.degree(2)) - self.assertEqual(2, graph.degree(3)) - - def test_extend_from_edge_list_existing_edge(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3), (0, 1)] - graph.extend_from_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual([None] * 6, graph.edges()) - - def test_extend_from_weighted_edge_list(self): - graph = retworkx.PyGraph() - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - - def test_add_edges_from_parallel_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from([0, 1]) - res = graph.add_edges_from([(0, 1, False), (1, 0, True)]) - self.assertEqual([0, 1], res) - self.assertEqual([False, True], graph.edges()) - - def test_add_edges_from_no_data_parallel_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from([0, 1]) - res = graph.add_edges_from_no_data([(0, 1), (1, 0)]) - self.assertEqual([0, 1], res) - self.assertEqual([None, None], graph.edges()) - - def test_multigraph_attr(self): - graph = retworkx.PyGraph() - self.assertTrue(graph.multigraph) - - def test_has_parallel_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from([0, 1]) - graph.add_edge(0, 1, None) - graph.add_edge(1, 0, 0) - self.assertTrue(graph.has_parallel_edges()) - - def test_has_parallel_edges_no_parallel_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from([0, 1]) - graph.add_edge(0, 1, None) - self.assertFalse(graph.has_parallel_edges()) - - def test_has_parallel_edges_empty(self): - graph = retworkx.PyGraph() - self.assertFalse(graph.has_parallel_edges()) - - def test_edge_index_map(self): - graph = retworkx.PyGraph() - node_a = graph.add_node(0) - node_b = graph.add_node(1) - node_c = graph.add_node("c") - node_d = graph.add_node("d") - graph.add_edge(node_a, node_c, "edge a") - graph.add_edge(node_b, node_d, "edge_b") - graph.add_edge(node_c, node_d, "edge c") - self.assertEqual( - { - 0: (node_a, node_c, "edge a"), - 1: (node_b, node_d, "edge_b"), - 2: (node_c, node_d, "edge c"), - }, - graph.edge_index_map(), - ) - - def test_incident_edges(self): - graph = retworkx.PyGraph() - node_a = graph.add_node(0) - node_b = graph.add_node(1) - node_c = graph.add_node("c") - node_d = graph.add_node("d") - graph.add_edge(node_a, node_c, "edge a") - graph.add_edge(node_b, node_d, "edge_b") - graph.add_edge(node_c, node_d, "edge c") - res = graph.incident_edges(node_d) - self.assertEqual({1, 2}, set(res)) - - def test_incident_edges_invalid_node(self): - graph = retworkx.PyGraph() - res = graph.incident_edges(42) - self.assertEqual([], res) - - def test_incident_edge_index_map(self): - graph = retworkx.PyGraph() - node_a = graph.add_node(0) - node_b = graph.add_node(1) - node_c = graph.add_node("c") - node_d = graph.add_node("d") - graph.add_edge(node_a, node_c, "edge a") - graph.add_edge(node_b, node_d, "edge_b") - graph.add_edge(node_c, node_d, "edge c") - res = graph.incident_edge_index_map(node_d) - self.assertEqual({2: (3, 2, "edge c"), 1: (3, 1, "edge_b")}, res) - - def test_incident_edge_index_map_invalid_node(self): - graph = retworkx.PyGraph() - res = graph.incident_edge_index_map(42) - self.assertEqual({}, res) - - def test_single_neighbor_out_edges(self): - g = retworkx.PyGraph() - node_a = g.add_node("a") - node_b = g.add_node("b") - g.add_edge(node_a, node_b, {"a": 1}) - node_c = g.add_node("c") - g.add_edge(node_a, node_c, {"a": 2}) - res = g.out_edges(node_a) - self.assertEqual([(node_a, node_c, {"a": 2}), (node_a, node_b, {"a": 1})], res) - - def test_neighbor_surrounded_in_out_edges(self): - g = retworkx.PyGraph() - node_a = g.add_node("a") - node_b = g.add_node("b") - node_c = g.add_node("c") - g.add_edge(node_a, node_b, {"a": 1}) - g.add_edge(node_b, node_c, {"a": 2}) - res = g.out_edges(node_b) - self.assertEqual([(node_b, node_c, {"a": 2}), (node_b, node_a, {"a": 1})], res) - res = g.in_edges(node_b) - self.assertEqual([(node_c, node_b, {"a": 2}), (node_a, node_b, {"a": 1})], res) - - def test_edge_index_map_empty(self): - graph = retworkx.PyGraph() - self.assertEqual({}, graph.edge_index_map()) - - def test_get_edge_data_by_index(self): - graph = retworkx.PyGraph() - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - res = graph.get_edge_data_by_index(2) - self.assertEqual("c", res) - - def test_get_edge_data_by_index_invalid_index(self): - graph = retworkx.PyGraph() - with self.assertRaisesRegex( - IndexError, "Provided edge index 2 is not present in the graph" - ): - graph.get_edge_data_by_index(2) - - def test_get_edge_endpoints_by_index(self): - graph = retworkx.PyGraph() - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - res = graph.get_edge_endpoints_by_index(2) - self.assertEqual((0, 2), res) - - def test_get_edge_endpoints_by_index_invalid_index(self): - graph = retworkx.PyGraph() - with self.assertRaisesRegex( - IndexError, "Provided edge index 2 is not present in the graph" - ): - graph.get_edge_endpoints_by_index(2) - - -class TestEdgesMultigraphFalse(unittest.TestCase): - def test_multigraph_attr(self): - graph = retworkx.PyGraph(multigraph=False) - self.assertFalse(graph.multigraph) - - def test_has_parallel_edges(self): - graph = retworkx.PyGraph(multigraph=False) - graph.add_nodes_from([0, 1]) - graph.add_edge(0, 1, None) - graph.add_edge(1, 0, 0) - self.assertFalse(graph.has_parallel_edges()) - - def test_parallel_edges_not_in_edge_list(self): - graph = retworkx.PyGraph(multigraph=False) - edge_list = [ - (8, 6), - (6, 5), - (6, 5), - (4, 5), - (5, 4), - (4, 5), - (3, 4), - (4, 3), - (3, 4), - (2, 3), - (0, 2), - (2, 0), - (0, 2), - (2, 3), - ] - graph.extend_from_edge_list(edge_list) - graph_edge_list = graph.edge_list() - expected_edges = [(6, 8), (5, 6), (4, 5), (3, 4), (2, 3), (0, 2)] - self.assertEqual(len(graph_edge_list), len(expected_edges)) - for edge in expected_edges: - if edge not in graph_edge_list and (edge[1], edge[0]) not in graph_edge_list: - self.fail(f"{edge} not found in graph edge list {graph_edge_list}") - - def test_get_edge_data(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - res = graph.get_edge_data(node_a, node_b) - self.assertEqual("Edgy", res) - - def test_get_all_edge_data(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - graph.add_edge(node_a, node_b, "b") - res = graph.get_all_edge_data(node_a, node_b) - self.assertIn("b", res) - self.assertNotIn("Edgy", res) - - def test_no_edge(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.get_edge_data, node_a, node_b) - - def test_no_edge_get_all_edge_data(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.get_all_edge_data, node_a, node_b) - - def test_has_edge(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, {}) - self.assertTrue(graph.has_edge(node_a, node_b)) - self.assertTrue(graph.has_edge(node_b, node_a)) - - def test_has_edge_no_edge(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertFalse(graph.has_edge(node_a, node_b)) - - def test_edges(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Super edgy") - self.assertEqual(["Edgy", "Super edgy"], graph.edges()) - - def test_edges_empty(self): - graph = retworkx.PyGraph(False) - graph.add_node("a") - self.assertEqual([], graph.edges()) - - def test_add_duplicates(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("a") - graph.add_edge(node_a, node_b, "a") - graph.add_edge(node_a, node_b, "b") - self.assertEqual(["b"], graph.edges()) - - def test_remove_no_edge(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - self.assertRaises(retworkx.NoEdgeBetweenNodes, graph.remove_edge, node_a, node_b) - - def test_remove_edge_single(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.remove_edge(node_a, node_b) - self.assertEqual([], graph.edges()) - - def test_remove_multiple(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.add_edge(node_a, node_b, "super_edgy") - graph.remove_edge_from_index(0) - self.assertEqual([], graph.edges()) - - def test_remove_edge_from_index(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "edgy") - graph.remove_edge_from_index(0) - self.assertEqual([], graph.edges()) - - def test_remove_edge_no_edge(self): - graph = retworkx.PyGraph(False) - graph.add_node("a") - graph.remove_edge_from_index(0) - self.assertEqual([], graph.edges()) - - def test_degree(self): - graph = retworkx.PyGraph(False) - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Super edgy") - self.assertEqual(2, graph.degree(node_b)) - - def test_add_edge_from(self): - graph = retworkx.PyGraph(False) - nodes = list(range(4)) - graph.add_nodes_from(nodes) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - res = graph.add_edges_from(edge_list) - self.assertEqual(len(res), 5) - self.assertEqual(["a", "b", "c", "d", "e"], graph.edges()) - self.assertEqual(3, graph.degree(0)) - self.assertEqual(2, graph.degree(1)) - self.assertEqual(3, graph.degree(2)) - self.assertEqual(2, graph.degree(3)) - - def test_add_edge_from_empty(self): - graph = retworkx.PyGraph(False) - res = graph.add_edges_from([]) - self.assertEqual([], res) - - def test_add_edge_from_no_data(self): - graph = retworkx.PyGraph(False) - nodes = list(range(4)) - graph.add_nodes_from(nodes) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - res = graph.add_edges_from_no_data(edge_list) - self.assertEqual(len(res), 5) - self.assertEqual([None, None, None, None, None], graph.edges()) - self.assertEqual(3, graph.degree(0)) - self.assertEqual(2, graph.degree(1)) - self.assertEqual(3, graph.degree(2)) - self.assertEqual(2, graph.degree(3)) - - def test_add_edge_from_empty_no_data(self): - graph = retworkx.PyGraph(False) - res = graph.add_edges_from_no_data([]) - self.assertEqual([], res) - - def test_add_edges_from_parallel_edges(self): - graph = retworkx.PyGraph(False) - graph.add_nodes_from([0, 1]) - res = graph.add_edges_from([(0, 1, False), (1, 0, True)]) - self.assertEqual([0, 0], res) - self.assertEqual([True], graph.edges()) - - def test_add_edges_from_no_data_parallel_edges(self): - graph = retworkx.PyGraph(False) - graph.add_nodes_from([0, 1]) - res = graph.add_edges_from_no_data([(0, 1), (1, 0)]) - self.assertEqual([0, 0], res) - self.assertEqual([None], graph.edges()) - - def test_extend_from_weighted_edge_list_empty(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list([]) - self.assertEqual(0, len(graph)) - - def test_extend_from_weighted_edge_list_nodes_exist(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual(["a", "b", "c", "d", "e"], graph.edges()) - - def test_extend_from_weighted_edge_list_edges_exist(self): - graph = retworkx.PyGraph(False) - graph.add_nodes_from(list(range(4))) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - (0, 1, "not_a"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual(["not_a", "b", "c", "d", "e"], graph.edges()) - - def test_extend_from_edge_list(self): - graph = retworkx.PyGraph(False) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - graph.extend_from_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual([None] * 5, graph.edges()) - - def test_extend_from_edge_list_empty(self): - graph = retworkx.PyGraph(False) - graph.extend_from_edge_list([]) - self.assertEqual(0, len(graph)) - - def test_extend_from_edge_list_nodes_exist(self): - graph = retworkx.PyGraph(False) - graph.add_nodes_from(list(range(4))) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3)] - graph.extend_from_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual([None] * 5, graph.edges()) - self.assertEqual(3, graph.degree(0)) - self.assertEqual(2, graph.degree(1)) - self.assertEqual(3, graph.degree(2)) - self.assertEqual(2, graph.degree(3)) - - def test_extend_from_edge_list_existing_edge(self): - graph = retworkx.PyGraph(False) - graph.add_nodes_from(list(range(4))) - edge_list = [(0, 1), (1, 2), (0, 2), (2, 3), (0, 3), (0, 1)] - graph.extend_from_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual([None] * 5, graph.edges()) - - def test_extend_from_weighted_edge_list(self): - graph = retworkx.PyGraph(False) - edge_list = [ - (0, 1, "a"), - (1, 2, "b"), - (0, 2, "c"), - (2, 3, "d"), - (0, 3, "e"), - ] - graph.extend_from_weighted_edge_list(edge_list) - self.assertEqual(len(graph), 4) - self.assertEqual(["a", "b", "c", "d", "e"], graph.edges()) diff --git a/tests/retworkx_backwards_compat/graph/test_floyd_warshall.py b/tests/retworkx_backwards_compat/graph/test_floyd_warshall.py deleted file mode 100644 index a7fc4452e..000000000 --- a/tests/retworkx_backwards_compat/graph/test_floyd_warshall.py +++ /dev/null @@ -1,201 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import numpy - -import retworkx - - -class TestFloydWarshall(unittest.TestCase): - parallel_threshold = 300 - - def test_vs_dijkstra_all_pairs(self): - graph = retworkx.PyGraph() - a = graph.add_node("A") - b = graph.add_node("B") - c = graph.add_node("C") - d = graph.add_node("D") - e = graph.add_node("E") - f = graph.add_node("F") - edge_list = [ - (a, b, 7), - (c, a, 9), - (a, d, 14), - (b, c, 10), - (d, c, 2), - (d, e, 9), - (b, f, 15), - (c, f, 11), - (e, f, 6), - ] - graph.add_edges_from(edge_list) - - dijkstra_lengths = retworkx.graph_all_pairs_dijkstra_path_lengths(graph, float) - - expected = {k: {**v, k: 0.0} for k, v in dijkstra_lengths.items()} - - result = retworkx.graph_floyd_warshall( - graph, float, parallel_threshold=self.parallel_threshold - ) - - self.assertEqual(result, expected) - - def test_vs_dijkstra_all_pairs_with_node_removal(self): - graph = retworkx.PyGraph() - a = graph.add_node("A") - b = graph.add_node("B") - c = graph.add_node("C") - d = graph.add_node("D") - e = graph.add_node("E") - f = graph.add_node("F") - edge_list = [ - (a, b, 7), - (c, a, 9), - (a, d, 14), - (b, c, 10), - (d, c, 2), - (d, e, 9), - (b, f, 15), - (c, f, 11), - (e, f, 6), - ] - graph.add_edges_from(edge_list) - graph.remove_node(d) - - dijkstra_lengths = retworkx.graph_all_pairs_dijkstra_path_lengths(graph, float) - - expected = {k: {**v, k: 0.0} for k, v in dijkstra_lengths.items()} - - result = retworkx.graph_floyd_warshall( - graph, float, parallel_threshold=self.parallel_threshold - ) - - self.assertEqual(result, expected) - - def test_floyd_warshall_empty_graph(self): - graph = retworkx.PyGraph() - self.assertEqual({}, retworkx.graph_floyd_warshall(graph, float)) - - def test_floyd_warshall_graph_no_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(1000))) - expected = {x: {} for x in range(1000)} - self.assertEqual( - expected, - retworkx.graph_floyd_warshall(graph, float), - ) - - def test_floyd_warshall_numpy_three_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(6))) - weights = [2, 12, 1, 5, 1] - graph.add_edges_from([(i, i + 1, weights[i]) for i in range(5)]) - graph.add_edge(5, 0, 10) - dist = retworkx.graph_floyd_warshall_numpy( - graph, lambda x: x, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 3], 15) - self.assertEqual(dist[3, 0], 15) - - def test_weighted_numpy_two_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(8))) - graph.add_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 = retworkx.graph_floyd_warshall_numpy( - graph, lambda x: x, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 2], 4) - self.assertEqual(dist[2, 0], 4) - - def test_weighted_numpy_negative_cycle(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.add_edges_from( - [ - (0, 1, 1), - (1, 2, -1), - (2, 3, -1), - (3, 0, -1), - ] - ) - dist = retworkx.graph_floyd_warshall_numpy( - graph, lambda x: x, parallel_threshold=self.parallel_threshold - ) - self.assertTrue(numpy.all(numpy.diag(dist) < 0)) - - def test_floyd_warshall_numpy_cycle(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - dist = retworkx.graph_floyd_warshall_numpy( - graph, lambda x: 1, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 3], 3) - self.assertEqual(dist[0, 4], 3) - - def test_numpy_no_edges(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - dist = retworkx.graph_floyd_warshall_numpy( - graph, lambda x: x, parallel_threshold=self.parallel_threshold - ) - expected = numpy.full((4, 4), numpy.inf) - numpy.fill_diagonal(expected, 0) - self.assertTrue(numpy.array_equal(dist, expected)) - - def test_floyd_warshall_numpy_graph_cycle_with_removals(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(8))) - graph.remove_node(0) - graph.add_edges_from_no_data([(1, 2), (1, 7), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]) - dist = retworkx.graph_floyd_warshall_numpy( - graph, lambda x: 1, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 3], 3) - self.assertEqual(dist[0, 4], 3) - - def test_floyd_warshall_numpy_graph_cycle_no_weight_fn(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(8))) - graph.remove_node(0) - graph.add_edges_from_no_data([(1, 2), (1, 7), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]) - dist = retworkx.graph_floyd_warshall_numpy(graph) - self.assertEqual(dist[0, 3], 3) - self.assertEqual(dist[0, 4], 3) - - def test_floyd_warshall_numpy_graph_cycle_default_weight(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(8))) - graph.remove_node(0) - graph.add_edges_from_no_data([(1, 2), (1, 7), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7)]) - dist = retworkx.graph_floyd_warshall_numpy( - graph, default_weight=2, parallel_threshold=self.parallel_threshold - ) - self.assertEqual(dist[0, 3], 6) - self.assertEqual(dist[0, 4], 6) - - -class TestParallelFloydWarshall(TestFloydWarshall): - parallel_threshold = 0 diff --git a/tests/retworkx_backwards_compat/graph/test_graph_attrs.py b/tests/retworkx_backwards_compat/graph/test_graph_attrs.py deleted file mode 100644 index d91ab1666..000000000 --- a/tests/retworkx_backwards_compat/graph/test_graph_attrs.py +++ /dev/null @@ -1,31 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestAttributes(unittest.TestCase): - def test_no_attrs(self): - graph = retworkx.PyGraph() - self.assertIsNone(graph.attrs) - - def test_attrs_set_at_init(self): - graph = retworkx.PyGraph(attrs=dict(foo="bar")) - self.assertEqual({"foo": "bar"}, graph.attrs) - - def test_attrs_set_at_init_override(self): - graph = retworkx.PyGraph(attrs=dict(foo="bar")) - self.assertEqual({"foo": "bar"}, graph.attrs) - graph.attrs = "ABC" - self.assertEqual("ABC", graph.attrs) diff --git a/tests/retworkx_backwards_compat/graph/test_isomorphic.py b/tests/retworkx_backwards_compat/graph/test_isomorphic.py deleted file mode 100644 index e034b6751..000000000 --- a/tests/retworkx_backwards_compat/graph/test_isomorphic.py +++ /dev/null @@ -1,313 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestIsomorphic(unittest.TestCase): - def test_empty_isomorphic_identical(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_isomorphic(g_a, g_b, id_order=id_order)) - - def test_empty_isomorphic(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_isomorphic(g_a, g_b, id_order=id_order)) - - def test_empty_isomorphic_compare_nodes(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic(g_a, g_b, lambda x, y: x == y, id_order=id_order) - ) - - def test_isomorphic_identical(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_isomorphic(g_a, g_b, id_order=id_order)) - - def test_isomorphic_mismatch_node_data(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - nodes = g_b.add_nodes_from(["b_1", "b_2", "b_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "b_1"), (nodes[1], nodes[2], "b_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_isomorphic(g_a, g_b, id_order=id_order)) - - def test_isomorphic_compare_nodes_mismatch_node_data(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - nodes = g_b.add_nodes_from(["b_1", "b_2", "b_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "b_1"), (nodes[1], nodes[2], "b_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertFalse( - retworkx.is_isomorphic(g_a, g_b, lambda x, y: x == y, id_order=id_order) - ) - - def test_is_isomorphic_nodes_compare_raises(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - nodes = g_b.add_nodes_from(["b_1", "b_2", "b_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "b_1"), (nodes[1], nodes[2], "b_2")]) - - def compare_nodes(a, b): - raise TypeError("Failure") - - self.assertRaises(TypeError, retworkx.is_isomorphic, (g_a, g_b, compare_nodes)) - - def test_isomorphic_compare_nodes_identical(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic(g_a, g_b, lambda x, y: x == y, id_order=id_order) - ) - - def test_isomorphic_compare_edges_identical(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic( - g_a, - g_b, - edge_matcher=lambda x, y: x == y, - id_order=id_order, - ) - ) - - def test_isomorphic_removed_nodes_in_second_graph(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - nodes = g_b.add_nodes_from(["a_0", "a_2", "a_1", "a_3"]) - g_b.add_edges_from( - [ - (nodes[0], nodes[1], "e_01"), - (nodes[0], nodes[3], "e_03"), - (nodes[2], nodes[1], "a_1"), - (nodes[1], nodes[3], "a_2"), - ] - ) - g_b.remove_node(nodes[0]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_isomorphic(g_a, g_b, lambda x, y: x == y, id_order=id_order) - ) - - def test_isomorphic_node_count_not_equal(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1")]) - - nodes = g_b.add_nodes_from(["a_0", "a_1"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1")]) - g_b.remove_node(nodes[0]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertFalse(retworkx.is_isomorphic(g_a, g_b, id_order=id_order)) - - def test_same_degrees_non_isomorphic(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4", "b_1", "b_2", "b_3", "b_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[2], nodes[3], "a_3"), - (nodes[3], nodes[0], "a_4"), - (nodes[4], nodes[5], "b_1"), - (nodes[5], nodes[6], "b_2"), - (nodes[6], nodes[7], "b_3"), - (nodes[7], nodes[4], "b_4"), - (nodes[0], nodes[4], "e_1"), - (nodes[1], nodes[5], "e_2"), - ] - ) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3", "a_4", "b_1", "b_2", "b_3", "b_4"]) - g_b.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[2], nodes[3], "a_3"), - (nodes[3], nodes[0], "a_4"), - (nodes[4], nodes[5], "b_1"), - (nodes[5], nodes[6], "b_2"), - (nodes[6], nodes[7], "b_3"), - (nodes[7], nodes[4], "b_4"), - (nodes[0], nodes[4], "e_1"), - (nodes[2], nodes[6], "e_2"), - ] - ) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertFalse(retworkx.is_isomorphic(g_a, g_b, id_order=id_order)) - - def test_graph_isomorphic_self_loop(self): - graph = retworkx.PyGraph() - graph.add_nodes_from([0, 1]) - graph.add_edges_from_no_data([(0, 0), (0, 1)]) - self.assertTrue(retworkx.is_isomorphic(graph, graph)) - - def test_graph_isomorphic_petersen(self): - """Based on 'The isomorphism classes of the generalized Petersen graphs' - by Steimle and Staton: https://doi.org/10.1016/j.disc.2007.12.074 - - For 2 <= k <= n- 2 with gcd(n, k) = 1, - G(n, k) is isomorphic to G(n, l) if and only if: - k ≡ -l (mod n) or kl ≡ ±1 (mod n) - """ - n = 23 - upper_bound_k = (n - 1) // 2 - for k in range(1, upper_bound_k + 1): - for t in range(k, upper_bound_k + 1): - with self.subTest(k=k, t=t): - self.assertEqual( - retworkx.is_isomorphic( - retworkx.generators.generalized_petersen_graph(n, k), - retworkx.generators.generalized_petersen_graph(n, t), - ), - (k == t) or (k == n - t) or (k * t % n == 1) or (k * t % n == n - 1), - ) - - def test_isomorphic_parallel_edges(self): - first = retworkx.PyGraph() - first.extend_from_edge_list([(0, 1), (0, 1), (1, 2), (2, 3)]) - second = retworkx.PyGraph() - second.extend_from_edge_list([(0, 1), (1, 2), (1, 2), (2, 3)]) - self.assertFalse(retworkx.is_isomorphic(first, second)) - - def test_isomorphic_parallel_edges_with_edge_matcher(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list([(0, 1, "a"), (0, 1, "b"), (1, 2, "c")]) - self.assertTrue(retworkx.is_isomorphic(graph, graph, edge_matcher=lambda x, y: x == y)) - - def test_graph_isomorphic_insufficient_call_limit(self): - graph = retworkx.generators.path_graph(5) - self.assertFalse(retworkx.is_isomorphic(graph, graph, call_limit=2)) - - def test_graph_vf2_mapping_identical(self): - graph = retworkx.generators.grid_graph(2, 2) - second_graph = retworkx.generators.grid_graph(2, 2) - mapping = retworkx.graph_vf2_mapping(graph, second_graph) - self.assertEqual(next(mapping), {0: 0, 1: 1, 2: 2, 3: 3}) - - def test_graph_vf2_mapping_identical_removals(self): - graph = retworkx.generators.path_graph(2) - second_graph = retworkx.generators.path_graph(4) - second_graph.remove_nodes_from([1, 2]) - second_graph.add_edge(0, 3, None) - mapping = retworkx.graph_vf2_mapping(graph, second_graph) - self.assertEqual({0: 0, 1: 3}, next(mapping)) - - def test_graph_vf2_mapping_identical_removals_first(self): - second_graph = retworkx.generators.path_graph(2) - graph = retworkx.generators.path_graph(4) - graph.remove_nodes_from([1, 2]) - graph.add_edge(0, 3, None) - mapping = retworkx.graph_vf2_mapping( - graph, - second_graph, - ) - self.assertEqual({0: 0, 3: 1}, next(mapping)) - - def test_graph_vf2_mapping_identical_vf2pp(self): - graph = retworkx.generators.grid_graph(2, 2) - second_graph = retworkx.generators.grid_graph(2, 2) - mapping = retworkx.graph_vf2_mapping(graph, second_graph, id_order=False) - self.assertEqual(next(mapping), {0: 0, 1: 1, 2: 2, 3: 3}) - - def test_graph_vf2_mapping_identical_removals_vf2pp(self): - graph = retworkx.generators.path_graph(2) - second_graph = retworkx.generators.path_graph(4) - second_graph.remove_nodes_from([1, 2]) - second_graph.add_edge(0, 3, None) - mapping = retworkx.graph_vf2_mapping(graph, second_graph, id_order=False) - self.assertEqual({0: 0, 1: 3}, next(mapping)) - - def test_graph_vf2_mapping_identical_removals_first_vf2pp(self): - second_graph = retworkx.generators.path_graph(2) - graph = retworkx.generators.path_graph(4) - graph.remove_nodes_from([1, 2]) - graph.add_edge(0, 3, None) - mapping = retworkx.graph_vf2_mapping(graph, second_graph, id_order=False) - self.assertEqual({0: 0, 3: 1}, next(mapping)) - - def test_graph_vf2_number_of_valid_mappings(self): - graph = retworkx.generators.mesh_graph(3) - mapping = retworkx.graph_vf2_mapping(graph, graph, id_order=True) - total = 0 - for _ in mapping: - total += 1 - self.assertEqual(total, 6) - - def test_empty_graph_vf2_mapping(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - mapping = retworkx.graph_vf2_mapping(g_a, g_b, id_order=id_order, subgraph=False) - self.assertEqual({}, next(mapping)) diff --git a/tests/retworkx_backwards_compat/graph/test_k_shortest_path.py b/tests/retworkx_backwards_compat/graph/test_k_shortest_path.py deleted file mode 100644 index 8c01b6497..000000000 --- a/tests/retworkx_backwards_compat/graph/test_k_shortest_path.py +++ /dev/null @@ -1,75 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestKShortestpath(unittest.TestCase): - def test_graph_k_shortest_path_lengths(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(8))) - graph.add_edges_from_no_data( - [ - (0, 1), - (1, 2), - (2, 3), - (3, 0), - (4, 5), - (1, 4), - (5, 6), - (6, 7), - (7, 5), - ] - ) - res = retworkx.graph_k_shortest_path_lengths(graph, 1, 2, lambda _: 1) - expected = {0: 3, 1: 2, 2: 3, 3: 2, 4: 3, 5: 4, 6: 4, 7: 4} - self.assertEqual(res, expected) - - def test_k_graph_shortest_path_with_goal(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(7))) - graph.add_edges_from_no_data([(0, 1), (0, 6), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - res = retworkx.graph_k_shortest_path_lengths(graph, 0, 2, lambda _: 1, 3) - self.assertEqual({3: 4}, res) - - def test_k_graph_shortest_path_with_goal_node_hole(self): - graph = retworkx.generators.path_graph(4) - graph.remove_node(0) - res = retworkx.graph_k_shortest_path_lengths( - graph, start=1, k=1, edge_cost=lambda _: 1, goal=3 - ) - self.assertEqual({3: 2}, res) - - def test_graph_k_shortest_path_with_invalid_weight(self): - graph = retworkx.generators.path_graph(4) - for invalid_weight in [float("nan"), -1]: - with self.subTest(invalid_weight=invalid_weight): - with self.assertRaises(ValueError): - retworkx.graph_k_shortest_path_lengths( - graph, - start=1, - k=1, - edge_cost=lambda _: invalid_weight, - goal=3, - ) - - def test_k_shortest_path_with_no_path(self): - g = retworkx.PyGraph() - a = g.add_node("A") - b = g.add_node("B") - path_lenghts = retworkx.graph_k_shortest_path_lengths( - g, start=a, k=1, edge_cost=float, goal=b - ) - expected = {} - self.assertEqual(expected, path_lenghts) diff --git a/tests/retworkx_backwards_compat/graph/test_layout.py b/tests/retworkx_backwards_compat/graph/test_layout.py deleted file mode 100644 index 38e56737d..000000000 --- a/tests/retworkx_backwards_compat/graph/test_layout.py +++ /dev/null @@ -1,477 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class LayoutTest(unittest.TestCase): - thres = 1e-6 - - def assertLayoutEquiv(self, exp, res): - for k in exp: - ev = exp[k] - rv = res[k] - if abs(ev[0] - rv[0]) > self.thres or abs(ev[1] - rv[1]) > self.thres: - self.fail( - "The position for node %s, %s, differs from the expected " - "position, %s by more than the allowed threshold of %s" - % (k, rv, ev, self.thres) - ) - - -class TestRandomLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.path_graph(10) - - def test_random_layout(self): - res = retworkx.graph_random_layout(self.graph, seed=42) - expected = { - 0: (0.2265125179283135, 0.23910669031859955), - 4: (0.8025885957751138, 0.37085692752109345), - 5: (0.23635127852185123, 0.9286365888207462), - 1: (0.760833410686741, 0.5278396573581516), - 3: (0.1879083014236631, 0.524657662927804), - 2: (0.9704763177409157, 0.37546268141451944), - 6: (0.462700947802672, 0.44025745918644743), - 7: (0.3125895420208278, 0.0893209773065271), - 8: (0.5567725240957387, 0.21079648777222115), - 9: (0.7586719404939911, 0.43090704138697045), - } - self.assertEqual(expected, res) - - def test_random_layout_center(self): - res = retworkx.graph_random_layout(self.graph, center=(0.5, 0.5), seed=42) - expected = { - 1: [1.260833410686741, 1.0278396573581516], - 5: [0.7363512785218512, 1.4286365888207462], - 7: [0.8125895420208278, 0.5893209773065271], - 4: [1.3025885957751138, 0.8708569275210934], - 8: [1.0567725240957389, 0.7107964877722212], - 9: [1.2586719404939912, 0.9309070413869704], - 0: [0.7265125179283135, 0.7391066903185995], - 2: [1.4704763177409157, 0.8754626814145194], - 6: [0.962700947802672, 0.9402574591864474], - 3: [0.6879083014236631, 1.0246576629278041], - } - self.assertEqual(expected, res) - - def test_random_layout_no_seed(self): - res = retworkx.graph_random_layout(self.graph) - # Random output, just assert structurally correct - self.assertIsInstance(res, retworkx.Pos2DMapping) - self.assertEqual(len(res), 10) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - -class TestBipartiteLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.path_graph(10) - - def test_bipartite_layout_empty(self): - res = retworkx.bipartite_layout(retworkx.PyGraph(), set()) - self.assertEqual({}, res) - - def test_bipartite_layout_hole(self): - g = retworkx.generators.path_graph(5) - g.remove_nodes_from([1]) - res = retworkx.bipartite_layout(g, set()) - expected = { - 0: (0.0, -1.0), - 2: (0.0, -0.3333333333333333), - 3: (0.0, 0.3333333333333333), - 4: (0.0, 1.0), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout(self): - res = retworkx.bipartite_layout(self.graph, {0, 1, 2, 3, 4}) - expected = { - 0: (-1.0, -0.75), - 1: (-1.0, -0.375), - 2: (-1.0, 0.0), - 3: (-1.0, 0.375), - 4: (-1.0, 0.75), - 5: (1.0, -0.75), - 6: (1.0, -0.375), - 7: (1.0, 0.0), - 8: (1.0, 0.375), - 9: (1.0, 0.75), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout_horizontal(self): - res = retworkx.bipartite_layout(self.graph, {0, 1, 2, 3}, horizontal=True) - expected = { - 0: (1.0, -0.9), - 1: (0.3333333333333333, -0.9), - 2: (-0.333333333333333, -0.9), - 3: (-1.0, -0.9), - 4: (1.0, 0.6), - 5: (0.6, 0.6), - 6: (0.2, 0.6), - 7: (-0.2, 0.6), - 8: (-0.6, 0.6), - 9: (-1.0, 0.6), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout_scale(self): - res = retworkx.bipartite_layout(self.graph, {0, 1, 2}, scale=2) - expected = { - 0: (-2.0, -1.0714285714285714), - 1: (-2.0, 2.3790493384824785e-17), - 2: (-2.0, 1.0714285714285714), - 3: (0.8571428571428571, -1.0714285714285714), - 4: (0.8571428571428571, -0.7142857142857143), - 5: (0.8571428571428571, -0.35714285714285715), - 6: (0.8571428571428571, 2.3790493384824785e-17), - 7: (0.8571428571428571, 0.35714285714285704), - 8: (0.8571428571428571, 0.7142857142857141), - 9: (0.8571428571428571, 1.0714285714285714), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout_center(self): - res = retworkx.bipartite_layout(self.graph, {4, 5, 6}, center=(0.5, 0.5)) - expected = { - 4: (-0.5, -0.0357142857142857), - 5: (-0.5, 0.5), - 6: (-0.5, 1.0357142857142856), - 0: (0.9285714285714286, -0.0357142857142857), - 1: (0.9285714285714286, 0.14285714285714285), - 2: (0.9285714285714286, 0.3214285714285714), - 3: (0.9285714285714286, 0.5), - 7: (0.9285714285714286, 0.6785714285714285), - 8: (0.9285714285714286, 0.857142857142857), - 9: (0.9285714285714286, 1.0357142857142856), - } - self.assertLayoutEquiv(expected, res) - - def test_bipartite_layout_ratio(self): - res = retworkx.bipartite_layout(self.graph, {2, 4, 8}, aspect_ratio=4) - expected = { - 8: [-1.0, 0.17857142857142858], - 2: [-1.0, -0.17857142857142858], - 4: [-1.0, 0], - 0: [0.42857142857142855, -0.17857142857142858], - 1: [0.42857142857142855, -0.11904761904761907], - 3: [0.42857142857142855, -0.05952380952380952], - 5: [0.42857142857142855, 0], - 6: [0.42857142857142855, 0.05952380952380952], - 7: [0.42857142857142855, 0.11904761904761903], - 9: [0.42857142857142855, 0.17857142857142858], - } - self.assertLayoutEquiv(expected, res) - - -class TestCircularLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.path_graph(10) - - def test_circular_layout_empty(self): - res = retworkx.circular_layout(retworkx.PyGraph()) - self.assertEqual({}, res) - - def test_circular_layout_one_node(self): - res = retworkx.circular_layout(retworkx.generators.path_graph(1)) - self.assertEqual({0: (0.0, 0.0)}, res) - - def test_circular_layout_hole(self): - g = retworkx.generators.path_graph(5) - g.remove_nodes_from([1]) - res = retworkx.circular_layout(g) - expected = { - 0: (0.999999986090933, 2.1855693665697608e-08), - 2: (-3.576476059301554e-08, 1.0), - 3: (-0.9999999701976796, -6.556708099709282e-08), - 4: (1.987150711625619e-08, -0.9999999562886126), - } - self.assertLayoutEquiv(expected, res) - - def test_circular_layout(self): - res = retworkx.circular_layout(self.graph) - expected = { - 0: (1.0, 2.662367085193061e-08), - 1: (0.8090170042900712, 0.5877852653564984), - 2: (0.3090169789580973, 0.9510565581329226), - 3: (-0.3090170206813483, 0.9510564985282783), - 4: (-0.8090170460133221, 0.5877852057518542), - 5: (-0.9999999821186069, -6.079910493992474e-08), - 6: (-0.8090169268040337, -0.5877853313184453), - 7: (-0.3090170802859925, -0.9510564452809367), - 8: (0.3090171279697079, -0.9510564452809367), - 9: (0.809016944685427, -0.587785271713801), - } - self.assertLayoutEquiv(expected, res) - - def test_circular_layout_scale(self): - res = retworkx.circular_layout(self.graph, scale=2) - expected = { - 0: (2.0, 5.324734170386122e-08), - 1: (1.6180340085801423, 1.1755705307129969), - 2: (0.6180339579161946, 1.9021131162658451), - 3: (-0.6180340413626966, 1.9021129970565567), - 4: (-1.6180340920266443, 1.1755704115037084), - 5: (-1.9999999642372137, -1.2159820987984948e-07), - 6: (-1.6180338536080674, -1.1755706626368907), - 7: (-0.618034160571985, -1.9021128905618734), - 8: (0.6180342559394159, -1.9021128905618734), - 9: (1.618033889370854, -1.175570543427602), - } - self.assertLayoutEquiv(expected, res) - - def test_circular_layout_center(self): - res = retworkx.circular_layout(self.graph, center=(0.5, 0.5)) - expected = { - 0: (1.5, 0.5000000266236708), - 1: (1.3090170042900713, 1.0877852653564983), - 2: (0.8090169789580973, 1.4510565581329224), - 3: (0.1909829793186517, 1.4510564985282783), - 4: (-0.30901704601332214, 1.0877852057518542), - 5: (-0.49999998211860686, 0.4999999392008951), - 6: (-0.3090169268040337, -0.08778533131844535), - 7: (0.1909829197140075, -0.4510564452809367), - 8: (0.8090171279697079, -0.4510564452809367), - 9: (1.309016944685427, -0.08778527171380102), - } - self.assertLayoutEquiv(expected, res) - - -class TestShellLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.path_graph(10) - - def test_shell_layout_empty(self): - res = retworkx.circular_layout(retworkx.PyGraph()) - self.assertEqual({}, res) - - def test_shell_layout_one_node(self): - res = retworkx.shell_layout(retworkx.generators.path_graph(1)) - self.assertEqual({0: (0.0, 0.0)}, res) - - def test_shell_layout_hole(self): - g = retworkx.generators.path_graph(5) - g.remove_nodes_from([1]) - res = retworkx.shell_layout(g) - expected = { - 0: (-1.0, -8.742277657347586e-08), - 2: (1.1924880638503055e-08, -1.0), - 3: (1.0, 1.7484555314695172e-07), - 4: (-3.3776623808989825e-07, 1.0), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_hole_two_shells(self): - g = retworkx.generators.path_graph(5) - g.remove_nodes_from([2]) - res = retworkx.shell_layout(g, [[0, 1], [3, 4]]) - expected = { - 0: (-2.1855694143368964e-08, 0.5), - 1: (5.962440319251527e-09, -0.5), - 3: (-1.0, -8.742277657347586e-08), - 4: (1.0, 1.7484555314695172e-07), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout(self): - res = retworkx.shell_layout(self.graph) - expected = { - 0: (-1.0, -8.742277657347586e-08), - 1: (-0.8090169429779053, -0.5877853631973267), - 2: (-0.3090170919895172, -0.9510564804077148), - 3: (0.3090171217918396, -0.9510564804077148), - 4: (0.8090172410011292, -0.5877849459648132), - 5: (1.0, 1.7484555314695172e-07), - 6: (0.80901700258255, 0.5877852439880371), - 7: (0.30901679396629333, 0.9510565996170044), - 8: (-0.30901744961738586, 0.9510563611984253), - 9: (-0.8090168833732605, 0.5877854228019714), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_nlist(self): - res = retworkx.shell_layout(self.graph, nlist=[[0, 2], [1, 3], [4, 9], [8, 7], [6, 5]]) - expected = { - 0: (0.16180340945720673, 0.11755704879760742), - 2: (-0.16180339455604553, -0.11755707114934921), - 1: (0.12360679358243942, 0.3804226219654083), - 3: (-0.123606838285923, -0.38042259216308594), - 4: (-0.18541023135185242, 0.5706338882446289), - 9: (0.185410276055336, -0.5706338882446289), - 8: (-0.6472136378288269, 0.4702281653881073), - 7: (0.6472138166427612, -0.4702279567718506), - 6: (-1.0, -8.742277657347586e-08), - 5: (1.0, 1.7484555314695172e-07), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_rotate(self): - res = retworkx.shell_layout( - self.graph, nlist=[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]], rotate=0.5 - ) - expected = { - 0: (0.21939563751220703, 0.11985638737678528), - 1: (-0.21349650621414185, 0.13007399439811707), - 2: (-0.005899117328226566, -0.24993039667606354), - 3: (0.27015113830566406, 0.4207354784011841), - 4: (-0.4994432032108307, 0.023589985445141792), - 5: (0.229292094707489, -0.4443254768848419), - 6: (0.05305289849638939, 0.7481212615966797), - 7: (-0.6744184494018555, -0.3281154930591583), - 8: (0.6213656067848206, -0.420005738735199), - 9: (-0.416146844625473, 0.9092974066734314), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_scale(self): - res = retworkx.shell_layout(self.graph, nlist=[[0, 1, 2, 3, 4], [9, 8, 7, 6, 5]], scale=2) - expected = { - 0: (-4.371138828673793e-08, 1.0), - 1: (-0.9510565996170044, 0.30901679396629333), - 2: (-0.5877850651741028, -0.8090171217918396), - 3: (0.5877854824066162, -0.8090168237686157), - 4: (0.9510564208030701, 0.30901727080345154), - 9: (-2.0, -1.7484555314695172e-07), - 8: (-0.6180341839790344, -1.9021129608154297), - 7: (1.6180344820022583, -1.1755698919296265), - 6: (1.6180340051651, 1.1755704879760742), - 5: (-0.6180348992347717, 1.9021127223968506), - } - self.assertLayoutEquiv(expected, res) - - def test_shell_layout_center(self): - res = retworkx.shell_layout( - self.graph, - nlist=[[0, 1, 2, 3, 4], [9, 8, 7, 6, 5]], - center=(0.5, 0.5), - ) - expected = { - 0: (0.49999997814430586, 1.0), - 1: (0.024471700191497803, 0.6545083969831467), - 2: (0.2061074674129486, 0.0954914391040802), - 3: (0.7938927412033081, 0.09549158811569214), - 4: (0.975528210401535, 0.6545086354017258), - 9: (-0.5, 0.4999999125772234), - 8: (0.1909829080104828, -0.45105648040771484), - 7: (1.3090172410011292, -0.08778494596481323), - 6: (1.30901700258255, 1.087785243988037), - 5: (0.19098255038261414, 1.4510563611984253), - } - self.assertLayoutEquiv(expected, res) - - -class TestSpiralLayout(LayoutTest): - def setUp(self): - self.graph = retworkx.generators.path_graph(10) - - def test_spiral_layout_empty(self): - res = retworkx.spiral_layout(retworkx.PyGraph()) - self.assertEqual({}, res) - - def test_spiral_layout_one_node(self): - res = retworkx.spiral_layout(retworkx.generators.path_graph(1)) - self.assertEqual({0: (0.0, 0.0)}, res) - - def test_spiral_layout_hole(self): - g = retworkx.generators.path_graph(5) - g.remove_nodes_from([1]) - res = retworkx.spiral_layout(g) - expected = { - 0: (-0.6415327868391166, -0.6855508729419231), - 2: (-0.03307913182988828, -0.463447951079834), - 3: (0.34927952438480797, 0.1489988240217569), - 4: (0.32533239428419697, 1.0), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout(self): - res = retworkx.spiral_layout(self.graph) - expected = { - 0: (0.3083011152777303, -0.36841870322845377), - 1: (0.4448595378922136, -0.3185709877650719), - 2: (0.5306742824266687, -0.18111636841212878), - 3: (0.5252997033017661, 0.009878257518578544), - 4: (0.40713492048969163, 0.20460820654918466), - 5: (0.17874125121181098, 0.3468009691240852), - 6: (-0.1320415949011884, 0.3844997574641717), - 7: (-0.4754889029311045, 0.28057288841663486), - 8: (-0.7874803127675889, 0.021164283410983312), - 9: (-0.9999999999999999, -0.3794183030779839), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout_scale(self): - res = retworkx.spiral_layout(self.graph, scale=2) - expected = { - 0: (0.6166022305554606, -0.7368374064569075), - 1: (0.8897190757844272, -0.6371419755301438), - 2: (1.0613485648533374, -0.36223273682425755), - 3: (1.0505994066035322, 0.01975651503715709), - 4: (0.8142698409793833, 0.4092164130983693), - 5: (0.35748250242362195, 0.6936019382481704), - 6: (-0.2640831898023768, 0.7689995149283434), - 7: (-0.950977805862209, 0.5611457768332697), - 8: (-1.5749606255351778, 0.042328566821966625), - 9: (-1.9999999999999998, -0.7588366061559678), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout_center(self): - res = retworkx.spiral_layout(self.graph, center=(1, 1)) - expected = { - 0: (1.3083011152777302, 0.6315812967715462), - 1: (1.4448595378922136, 0.681429012234928), - 2: (1.5306742824266686, 0.8188836315878713), - 3: (1.5252997033017661, 1.0098782575185785), - 4: (1.4071349204896917, 1.2046082065491848), - 5: (1.178741251211811, 1.3468009691240852), - 6: (0.8679584050988116, 1.3844997574641718), - 7: (0.5245110970688955, 1.2805728884166347), - 8: (0.2125196872324111, 1.0211642834109833), - 9: (1.1102230246251565e-16, 0.6205816969220161), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout_resolution(self): - res = retworkx.spiral_layout(self.graph, resolution=0.6) - expected = { - 0: (0.14170895375949058, 0.22421978768273812), - 1: (0.2657196183870804, 0.30906004798138936), - 2: (0.2506009612140119, 0.5043065412934762), - 3: (0.039294315670400995, 0.6631957258449066), - 4: (-0.3014789232909145, 0.6301862160709318), - 5: (-0.602046830323471, 0.3302396035952633), - 6: (-0.66674476042188, -0.17472522299849289), - 7: (-0.3739394496041176, -0.6924895145748617), - 8: (0.2468861146093996, -0.9732085843739783), - 9: (1.0, -0.8207846005213728), - } - self.assertLayoutEquiv(expected, res) - - def test_spiral_layout_equidistant(self): - res = retworkx.spiral_layout(self.graph, equidistant=True) - expected = { - 0: (-0.13161882865656718, -0.7449342807652114), - 1: (0.7160560542246066, -0.6335352483233974), - 2: (0.6864868274284994, -0.34165899654603915), - 3: (0.5679822628330004, -0.07281296883784087), - 4: (0.375237081214659, 0.14941210155952697), - 5: (0.12730720268992277, 0.30830226777240866), - 6: (-0.15470865936858091, 0.3939608192236113), - 7: (-0.4495426197217269, 0.4027809258196645), - 8: (-0.7371993206438128, 0.33662707199446507), - 9: (-1.0, 0.2018583081028111), - } - self.assertLayoutEquiv(expected, res) diff --git a/tests/retworkx_backwards_compat/graph/test_matching.py b/tests/retworkx_backwards_compat/graph/test_matching.py deleted file mode 100644 index 820a6a38a..000000000 --- a/tests/retworkx_backwards_compat/graph/test_matching.py +++ /dev/null @@ -1,56 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest -import retworkx - - -class TestMatching(unittest.TestCase): - def test_valid(self): - graph = retworkx.generators.path_graph(4) - matching = {(0, 1), (2, 3)} - self.assertTrue(retworkx.is_maximal_matching(graph, matching)) - - def test_not_matching(self): - graph = retworkx.generators.path_graph(4) - matching = {(0, 1), (1, 2), (2, 3)} - self.assertFalse(retworkx.is_maximal_matching(graph, matching)) - - def test_not_maximal(self): - graph = retworkx.generators.path_graph(4) - matching = {(0, 1)} - self.assertFalse(retworkx.is_maximal_matching(graph, matching)) - - def test_is_matching_empty(self): - graph = retworkx.generators.path_graph(4) - matching = set() - self.assertTrue(retworkx.is_matching(graph, matching)) - - def test_is_matching_single_edge(self): - graph = retworkx.generators.path_graph(4) - matching = {(1, 2)} - self.assertTrue(retworkx.is_matching(graph, matching)) - - def test_is_matching_valid(self): - graph = retworkx.generators.path_graph(4) - matching = {(0, 1), (2, 3)} - self.assertTrue(retworkx.is_matching(graph, matching)) - - def test_is_matching_invalid(self): - graph = retworkx.generators.path_graph(4) - matching = {(0, 1), (1, 2), (2, 3)} - self.assertFalse(retworkx.is_matching(graph, matching)) - - def test_is_matching_invalid_edge(self): - graph = retworkx.generators.path_graph(4) - matching = {(0, 3), (1, 2)} - self.assertFalse(retworkx.is_matching(graph, matching)) diff --git a/tests/retworkx_backwards_compat/graph/test_max_weight_matching.py b/tests/retworkx_backwards_compat/graph/test_max_weight_matching.py deleted file mode 100644 index 79e4d7041..000000000 --- a/tests/retworkx_backwards_compat/graph/test_max_weight_matching.py +++ /dev/null @@ -1,577 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -# These tests are adapated from the networkx test cases: -# https://github.com/networkx/networkx/blob/3351206a3ce5b3a39bb2fc451e93ef545b96c95b/networkx/algorithms/tests/test_matching.py - -import random - -import fixtures -import networkx -import testtools - -import retworkx - - -def match_dict_to_set(match): - return {(u, v) for (u, v) in set(map(frozenset, match.items()))} - - -class TestMaxWeightMatching(testtools.TestCase): - def setUp(self): - super().setUp() - stdout = self.useFixture(fixtures.StringStream("stdout")).stream - self.useFixture(fixtures.MonkeyPatch("sys.stdout", stdout)) - stderr = self.useFixture(fixtures.StringStream("stderr")).stream - self.useFixture(fixtures.MonkeyPatch("sys.stderr", stderr)) - - def compare_match_sets(self, rx_match, expected_match): - for (u, v) in rx_match: - if (u, v) not in expected_match and (v, u) not in expected_match: - self.fail( - "Element %s and it's reverse %s not found in " - "expected output.\nretworkx output: %s\nexpected " - "output: %s" % ((u, v), (v, u), rx_match, expected_match) - ) - - def compare_rx_nx_sets(self, rx_graph, rx_matches, nx_matches, seed, nx_graph): - def get_rx_weight(edge): - weight = rx_graph.get_edge_data(*edge) - if weight is None: - return 1 - return weight - - def get_nx_weight(edge): - weight = nx_graph.get_edge_data(*edge) - if not weight: - return 1 - return weight["weight"] - - not_match = False - for (u, v) in rx_matches: - if (u, v) not in nx_matches: - if (v, u) not in nx_matches: - print( - "seed %s failed. Element %s and it's " - "reverse %s not found in networkx output.\nretworkx" - " output: %s\nnetworkx output: %s\nedge list: %s\n" - "falling back to checking for a valid solution" - % ( - seed, - (u, v), - (v, u), - rx_matches, - nx_matches, - list(rx_graph.weighted_edge_list()), - ) - ) - not_match = True - break - if not_match: - self.assertTrue( - retworkx.is_matching(rx_graph, rx_matches), - "%s is not a valid matching" % rx_matches, - ) - self.assertTrue( - retworkx.is_maximal_matching(rx_graph, rx_matches), - "%s is not a maximal matching" % rx_matches, - ) - self.assertEqual( - sum(map(get_rx_weight, rx_matches)), - sum(map(get_nx_weight, nx_matches)), - ) - - def test_empty_graph(self): - graph = retworkx.PyGraph() - self.assertEqual(retworkx.max_weight_matching(graph), set()) - - def test_single_edge(self): - graph = retworkx.PyGraph() - graph.add_nodes_from([0, 1]) - graph.add_edges_from([(0, 1, 1)]) - self.compare_match_sets( - retworkx.max_weight_matching(graph, verify_optimum=True), - { - (0, 1), - }, - ) - - def test_single_edge_no_verification(self): - graph = retworkx.PyGraph() - graph.add_nodes_from([0, 1]) - graph.add_edges_from([(0, 1, 1)]) - self.compare_match_sets( - retworkx.max_weight_matching(graph, verify_optimum=False), - { - (0, 1), - }, - ) - - def test_single_self_edge(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list([(0, 0, 100)]) - self.assertEqual(retworkx.max_weight_matching(graph), set()) - - def test_small_graph(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list([(1, 2, 10), (2, 3, 11)]) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - { - (2, 3), - }, - ) - - def test_path_graph(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list([(1, 2, 5), (2, 3, 11), (3, 4, 5)]) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - { - (2, 3), - }, - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, True, weight_fn=lambda x: x, verify_optimum=True), - {(1, 2), (3, 4)}, - ) - - def test_negative_weights(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 2), - (1, 3, -2), - (2, 3, 1), - (2, 4, -1), - (3, 4, -6), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - { - (1, 2), - }, - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, True, weight_fn=lambda x: x, verify_optimum=True), - {(1, 3), (2, 4)}, - ) - - def test_s_blossom(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (0, 1, 8), - (0, 2, 9), - (1, 2, 10), - (2, 3, 7), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(0, 1), (2, 3)}, - ) - graph.extend_from_weighted_edge_list([(0, 5, 5), (3, 4, 6)]) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(0, 5), (1, 2), (3, 4)}, - ) - - def test_s_t_blossom(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 9), - (1, 3, 8), - (2, 3, 10), - (1, 4, 5), - (4, 5, 4), - (1, 6, 3), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 6), (2, 3), (4, 5)}, - ) - graph.remove_edge(1, 6) - graph.remove_edge(4, 5) - graph.extend_from_weighted_edge_list([(4, 5, 3), (1, 6, 4)]) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 6), (2, 3), (4, 5)}, - ) - graph.remove_edge(1, 6) - graph.add_edge(3, 6, 4) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 2), (3, 6), (4, 5)}, - ) - - def test_s_t_blossom_with_removed_nodes(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 9), - (1, 3, 8), - (2, 3, 10), - (1, 4, 5), - (4, 5, 4), - (1, 6, 3), - ] - ) - node_id = graph.add_node(None) - graph.remove_node(5) - graph.add_edge(4, node_id, 4) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 6), (2, 3), (4, 7)}, - ) - graph.remove_edge(1, 6) - graph.remove_edge(4, 7) - graph.extend_from_weighted_edge_list([(4, node_id, 3), (1, 6, 4)]) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 6), (2, 3), (4, 7)}, - ) - graph.remove_edge(1, 6) - graph.add_edge(3, 6, 4) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 2), (3, 6), (4, 7)}, - ) - - def test_nested_s_blossom(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 9), - (1, 3, 9), - (2, 3, 10), - (2, 4, 8), - (3, 5, 8), - (4, 5, 10), - (5, 6, 6), - ] - ) - expected = {(1, 3), (2, 4), (5, 6)} - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - expected, - ) - - def test_nested_s_blossom_relabel(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (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), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 2), (3, 4), (5, 6), (7, 8)}, - ) - - def test_nested_s_blossom_expand(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (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), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 2), (3, 5), (4, 6), (7, 8)}, - ) - - def test_s_blossom_relabel_expand(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (1, 2, 23), - (1, 5, 22), - (1, 6, 15), - (2, 3, 25), - (3, 4, 22), - (4, 5, 25), - (4, 8, 14), - (5, 7, 13), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - {(1, 6), (2, 3), (4, 8), (5, 7)}, - ) - - def test_nested_s_blossom_relabel_expand(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (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), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - match_dict_to_set({1: 8, 2: 3, 3: 2, 4: 7, 5: 6, 6: 5, 7: 4, 8: 1}), - ) - - def test_blossom_relabel_multiple_paths(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (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), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - match_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_blossom_relabel_multiple_path_alternate(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (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), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - match_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_blossom_relabel_multiple_paths_least_slack(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (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), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - match_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_nested_blossom_expand_recursively(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (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), - ] - ) - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - match_dict_to_set({1: 2, 2: 1, 3: 5, 4: 9, 5: 3, 6: 7, 7: 6, 8: 10, 9: 4, 10: 8}), - ) - - def test_nested_blossom_augmented(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (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), - ] - ) - expected = { - 1: 8, - 2: 3, - 3: 2, - 4: 6, - 5: 9, - 6: 4, - 7: 10, - 8: 1, - 9: 5, - 10: 7, - 11: 12, - 12: 11, - } - self.compare_match_sets( - retworkx.max_weight_matching(graph, weight_fn=lambda x: x, verify_optimum=True), - match_dict_to_set(expected), - ) - - def test_gnp_random_against_networkx(self): - for i in range(1024): - with self.subTest(i=i): - rx_graph = retworkx.undirected_gnp_random_graph(10, 0.75, seed=42 + i) - nx_graph = networkx.Graph(list(rx_graph.edge_list())) - nx_matches = networkx.max_weight_matching(nx_graph) - rx_matches = retworkx.max_weight_matching(rx_graph, verify_optimum=True) - self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 42 + i, nx_graph) - - def test_gnp_random_against_networkx_with_weight(self): - for i in range(1024): - with self.subTest(i=i): - random.seed(i) - rx_graph = retworkx.undirected_gnp_random_graph(10, 0.75, seed=42 + i) - for edge in rx_graph.edge_list(): - rx_graph.update_edge(*edge, random.randint(0, 5000)) - nx_graph = networkx.Graph( - [(x[0], x[1], {"weight": x[2]}) for x in rx_graph.weighted_edge_list()] - ) - nx_matches = networkx.max_weight_matching(nx_graph) - rx_matches = retworkx.max_weight_matching( - rx_graph, weight_fn=lambda x: x, verify_optimum=True - ) - self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 42 + i, nx_graph) - - def test_gnp_random_against_networkx_with_negative_weight(self): - for i in range(1024): - with self.subTest(i=i): - random.seed(i) - rx_graph = retworkx.undirected_gnp_random_graph(10, 0.75, seed=42 + i) - for edge in rx_graph.edge_list(): - rx_graph.update_edge(*edge, random.randint(-5000, 5000)) - nx_graph = networkx.Graph( - [(x[0], x[1], {"weight": x[2]}) for x in rx_graph.weighted_edge_list()] - ) - nx_matches = networkx.max_weight_matching(nx_graph) - rx_matches = retworkx.max_weight_matching( - rx_graph, weight_fn=lambda x: x, verify_optimum=True - ) - self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 42 + i, nx_graph) - - def test_gnp_random_against_networkx_max_cardinality(self): - rx_graph = retworkx.undirected_gnp_random_graph(10, 0.78, seed=428) - nx_graph = networkx.Graph(list(rx_graph.edge_list())) - nx_matches = networkx.max_weight_matching(nx_graph, maxcardinality=True) - rx_matches = retworkx.max_weight_matching( - rx_graph, max_cardinality=True, verify_optimum=True - ) - self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 428, nx_graph) - - def test_gnp_random_against_networkx_with_weight_max_cardinality(self): - for i in range(1024): - with self.subTest(i=i): - random.seed(i) - rx_graph = retworkx.undirected_gnp_random_graph(10, 0.75, seed=42 + i) - for edge in rx_graph.edge_list(): - rx_graph.update_edge(*edge, random.randint(0, 5000)) - nx_graph = networkx.Graph( - [(x[0], x[1], {"weight": x[2]}) for x in rx_graph.weighted_edge_list()] - ) - nx_matches = networkx.max_weight_matching(nx_graph, maxcardinality=True) - rx_matches = retworkx.max_weight_matching( - rx_graph, - weight_fn=lambda x: x, - max_cardinality=True, - verify_optimum=True, - ) - self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 42 + i, nx_graph) - - def test_gnp_random__networkx_with_negative_weight_max_cardinality(self): - for i in range(1024): - with self.subTest(i=i): - random.seed(i) - rx_graph = retworkx.undirected_gnp_random_graph(10, 0.75, seed=42 + i) - for edge in rx_graph.edge_list(): - rx_graph.update_edge(*edge, random.randint(-5000, 5000)) - nx_graph = networkx.Graph( - [(x[0], x[1], {"weight": x[2]}) for x in rx_graph.weighted_edge_list()] - ) - nx_matches = networkx.max_weight_matching(nx_graph, maxcardinality=True) - rx_matches = retworkx.max_weight_matching( - rx_graph, - weight_fn=lambda x: x, - max_cardinality=True, - verify_optimum=True, - ) - self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 42 + i, nx_graph) - - def test_gnm_random_against_networkx(self): - rx_graph = retworkx.undirected_gnm_random_graph(10, 13, seed=42) - nx_graph = networkx.Graph(list(rx_graph.edge_list())) - nx_matches = networkx.max_weight_matching(nx_graph) - rx_matches = retworkx.max_weight_matching(rx_graph, verify_optimum=True) - self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 42, nx_graph) - - def test_gnm_random_against_networkx_max_cardinality(self): - rx_graph = retworkx.undirected_gnm_random_graph(10, 12, seed=42) - nx_graph = networkx.Graph(list(rx_graph.edge_list())) - nx_matches = networkx.max_weight_matching(nx_graph, maxcardinality=True) - rx_matches = retworkx.max_weight_matching( - rx_graph, max_cardinality=True, verify_optimum=True - ) - self.compare_rx_nx_sets(rx_graph, rx_matches, nx_matches, 42, nx_graph) diff --git a/tests/retworkx_backwards_compat/graph/test_mst.py b/tests/retworkx_backwards_compat/graph/test_mst.py deleted file mode 100644 index 895d2328b..000000000 --- a/tests/retworkx_backwards_compat/graph/test_mst.py +++ /dev/null @@ -1,122 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestMinimumSpanningTree(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.a = self.graph.add_node("A") - self.b = self.graph.add_node("B") - self.c = self.graph.add_node("C") - self.d = self.graph.add_node("D") - self.e = self.graph.add_node("E") - self.f = self.graph.add_node("F") - - edge_list = [ - (self.a, self.b, 3), - (self.a, self.d, 2), - (self.b, self.c, 4), - (self.c, self.d, 1), - (self.a, self.f, 1), - (self.b, self.f, 6), - (self.d, self.e, 5), - (self.c, self.e, 7), - ] - self.graph.add_edges_from(edge_list) - - self.expected_edges = [ - (self.a, self.b, 3), - (self.a, self.d, 2), - (self.c, self.d, 1), - (self.a, self.f, 1), - (self.d, self.e, 5), - ] - - def assertEqualEdgeList(self, expected, actual): - self.assertEqual(len(expected), len(actual)) - for edge in actual: - self.assertTrue(edge in expected) - - def test_edges(self): - mst_edges = retworkx.minimum_spanning_edges(self.graph, weight_fn=lambda x: x) - self.assertEqual(len(self.graph.nodes()) - 1, len(mst_edges)) - for edge in mst_edges: - self.assertTrue(edge in self.expected_edges) - - def test_tree(self): - mst_graph = retworkx.minimum_spanning_tree(self.graph, weight_fn=lambda x: x) - self.assertEqual(self.graph.nodes(), mst_graph.nodes()) - self.assertEqual(len(self.graph.nodes()) - 1, len(mst_graph.edge_list())) - self.assertEqualEdgeList(self.expected_edges, mst_graph.weighted_edge_list()) - - def test_forest(self): - s = self.graph.add_node("S") - t = self.graph.add_node("T") - u = self.graph.add_node("U") - self.graph.add_edges_from([(s, t, 10), (t, u, 9), (s, u, 8)]) - forest_expected_edges = self.expected_edges + [(s, u, 8), (t, u, 9)] - - msf_graph = retworkx.minimum_spanning_tree(self.graph, weight_fn=lambda x: x) - self.assertEqual(self.graph.nodes(), msf_graph.nodes()) - self.assertEqual(len(self.graph.nodes()) - 2, len(msf_graph.edge_list())) - self.assertEqualEdgeList(forest_expected_edges, msf_graph.weighted_edge_list()) - - def test_isolated(self): - s = self.graph.add_node("S") - - msf_graph = retworkx.minimum_spanning_tree(self.graph, weight_fn=lambda x: x) - self.assertEqual("S", msf_graph.nodes()[s]) - self.assertEqual(self.graph.nodes(), msf_graph.nodes()) - self.assertEqual(len(self.graph.nodes()) - 2, len(msf_graph.edge_list())) - self.assertEqualEdgeList(self.expected_edges, msf_graph.weighted_edge_list()) - - def test_multigraph(self): - mutligraph = retworkx.PyGraph(multigraph=True) - mutligraph.extend_from_weighted_edge_list( - [(0, 1, 1), (0, 2, 3), (1, 2, 2), (0, 0, -10), (1, 2, 1)] - ) - - mst_graph = retworkx.minimum_spanning_tree(mutligraph, weight_fn=lambda x: x) - self.assertEqualEdgeList([(0, 1, 1), (1, 2, 1)], mst_graph.weighted_edge_list()) - - def test_default_weight(self): - weightless_graph = retworkx.PyGraph() - weightless_graph.extend_from_edge_list( - [(0, 1), (0, 2), (0, 3), (0, 4), (1, 5), (2, 6), (3, 7), (4, 8)] - ) # MST of the graph is itself - - mst_graph_default_weight = retworkx.minimum_spanning_tree(weightless_graph) - mst_graph_weight_2 = retworkx.minimum_spanning_tree(weightless_graph, default_weight=2.0) - - self.assertTrue( - retworkx.is_isomorphic( - weightless_graph, - mst_graph_default_weight, - ) - ) - self.assertTrue( - retworkx.is_isomorphic( - weightless_graph, - mst_graph_weight_2, - ) - ) - - def test_nan_weight(self): - invalid_graph = retworkx.PyGraph() - invalid_graph.extend_from_weighted_edge_list([(0, 1, 0.5), (0, 2, float("nan"))]) - - with self.assertRaises(ValueError): - retworkx.minimum_spanning_tree(invalid_graph, lambda x: x) diff --git a/tests/retworkx_backwards_compat/graph/test_neighbors.py b/tests/retworkx_backwards_compat/graph/test_neighbors.py deleted file mode 100644 index 25ec06258..000000000 --- a/tests/retworkx_backwards_compat/graph/test_neighbors.py +++ /dev/null @@ -1,43 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestNeighbors(unittest.TestCase): - def test_single_neighbor(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, {"a": 1}) - node_c = graph.add_node("c") - graph.add_edge(node_a, node_c, {"a": 2}) - res = graph.neighbors(node_a) - self.assertCountEqual([node_c, node_b], res) - - def test_unique_neighbors_on_graphs(self): - dag = retworkx.PyGraph() - node_a = dag.add_node("a") - node_b = dag.add_node("b") - node_c = dag.add_node("c") - dag.add_edge(node_a, node_b, ["edge a->b"]) - dag.add_edge(node_a, node_b, ["edge a->b bis"]) - dag.add_edge(node_a, node_c, ["edge a->c"]) - res = dag.neighbors(node_a) - self.assertCountEqual([node_c, node_b], res) - - def test_no_neighbor(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - self.assertEqual([], graph.neighbors(node_a)) diff --git a/tests/retworkx_backwards_compat/graph/test_nodes.py b/tests/retworkx_backwards_compat/graph/test_nodes.py deleted file mode 100644 index c9bfe053e..000000000 --- a/tests/retworkx_backwards_compat/graph/test_nodes.py +++ /dev/null @@ -1,181 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestNodes(unittest.TestCase): - def test_nodes(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - res = graph.nodes() - self.assertEqual(["a", "b"], res) - self.assertEqual([0, 1], graph.node_indexes()) - - def test_node_indices(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - self.assertEqual([0, 1], graph.node_indices()) - - def test_no_nodes(self): - graph = retworkx.PyGraph() - self.assertEqual([], graph.nodes()) - self.assertEqual([], graph.node_indexes()) - self.assertEqual([], graph.node_indices()) - - def test_remove_node(self): - graph = retworkx.PyGraph() - graph.add_node("a") - node_b = graph.add_node("b") - graph.add_node("c") - graph.remove_node(node_b) - res = graph.nodes() - self.assertEqual(["a", "c"], res) - self.assertEqual([0, 2], graph.node_indexes()) - - def test_remove_node_invalid_index(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.remove_node(76) - res = graph.nodes() - self.assertEqual(["a", "b", "c"], res) - self.assertEqual([0, 1, 2], graph.node_indexes()) - - def test_remove_nodes_from(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Edgy_mk2") - graph.remove_nodes_from([node_b, node_c]) - res = graph.nodes() - self.assertEqual(["a"], res) - self.assertEqual([0], graph.node_indexes()) - - def test_remove_nodes_from_with_invalid_index(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Edgy_mk2") - graph.remove_nodes_from([node_b, node_c, 76]) - res = graph.nodes() - self.assertEqual(["a"], res) - self.assertEqual([0], graph.node_indexes()) - - def test_get_node_data(self): - graph = retworkx.PyGraph() - graph.add_node("a") - node_b = graph.add_node("b") - self.assertEqual("b", graph.get_node_data(node_b)) - - def test_get_node_data_bad_index(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - self.assertRaises(IndexError, graph.get_node_data, 42) - - def test_pygraph_length(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "An_edge") - self.assertEqual(2, len(graph)) - - def test_pygraph_num_nodes(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "An_edge") - self.assertEqual(2, graph.num_nodes()) - - def test_pygraph_length_empty(self): - graph = retworkx.PyGraph() - self.assertEqual(0, len(graph)) - - def test_pygraph_num_nodes_empty(self): - graph = retworkx.PyGraph() - self.assertEqual(0, graph.num_nodes()) - - def test_add_nodes_from(self): - graph = retworkx.PyGraph() - nodes = list(range(100)) - res = graph.add_nodes_from(nodes) - self.assertEqual(len(res), 100) - self.assertEqual(res, nodes) - - def test_add_node_from_empty(self): - graph = retworkx.PyGraph() - res = graph.add_nodes_from([]) - self.assertEqual(len(res), 0) - - def test_get_node_data_getitem(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - self.assertEqual("b", graph[node_b]) - - def test_get_node_data_getitem_bad_index(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - with self.assertRaises(IndexError): - graph[42] - - def test_set_node_data_setitem(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - graph[node_b] = "Oh so cool" - self.assertEqual("Oh so cool", graph[node_b]) - - def test_set_node_data_setitem_bad_index(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - with self.assertRaises(IndexError): - graph[42] = "Oh so cool" - - def test_remove_node_delitem(self): - graph = retworkx.PyGraph() - node_a = graph.add_node("a") - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, "Edgy") - node_c = graph.add_node("c") - graph.add_edge(node_b, node_c, "Edgy_mk2") - del graph[node_b] - res = graph.nodes() - self.assertEqual(["a", "c"], res) - self.assertEqual([0, 2], graph.node_indexes()) - - def test_remove_node_delitem_invalid_index(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - with self.assertRaises(IndexError): - del graph[76] - res = graph.nodes() - self.assertEqual(["a", "b", "c"], res) - self.assertEqual([0, 1, 2], graph.node_indexes()) diff --git a/tests/retworkx_backwards_compat/graph/test_num_shortest_path.py b/tests/retworkx_backwards_compat/graph/test_num_shortest_path.py deleted file mode 100644 index c1182eb8f..000000000 --- a/tests/retworkx_backwards_compat/graph/test_num_shortest_path.py +++ /dev/null @@ -1,138 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestNumShortestpath(unittest.TestCase): - def test_num_shortest_path_unweighted(self): - graph = retworkx.PyGraph() - node_a = graph.add_node(0) - node_b = graph.add_node("end") - for i in range(3): - node = graph.add_node(i) - graph.add_edge(node_a, node, None) - graph.add_edge(node, node_b, None) - res = retworkx.graph_num_shortest_paths_unweighted(graph, node_a) - expected = {2: 1, 4: 1, 3: 1, 1: 3} - self.assertEqual(expected, res) - - def test_parallel_paths(self): - graph = retworkx.PyGraph() - graph.extend_from_edge_list( - [ - (0, 1), - (1, 2), - (2, 3), - (0, 4), - (4, 5), - (5, 3), - ] - ) - res = retworkx.num_shortest_paths_unweighted(graph, 0) - expected = { - 1: 1, - 2: 1, - 3: 2, - 4: 1, - 5: 1, - } - self.assertEqual(expected, res) - - def test_grid_graph(self): - """Test num shortest paths for a 5x5 grid graph - 0 - 1 - 2 - 3 - 4 - | | | | | - 5 - 6 - 7 - 8 - 9 - | | | | | - 10- 11- 12- 13- 14 - | | | | | - 15- 16- 17- 18- 19 - | | | | | - 20- 21- 22- 23- 24 - """ - graph = retworkx.generators.grid_graph(5, 5) - res = retworkx.num_shortest_paths_unweighted(graph, 0) - expected = { - 1: 1, - 2: 1, - 3: 1, - 4: 1, - 5: 1, - 6: 2, - 7: 3, - 8: 4, - 9: 5, - 10: 1, - 11: 3, - 12: 6, - 13: 10, - 14: 15, - 15: 1, - 16: 4, - 17: 10, - 18: 20, - 19: 35, - 20: 1, - 21: 5, - 22: 15, - 23: 35, - 24: 70, - } - self.assertEqual(expected, res) - - def test_node_with_no_path(self): - graph = retworkx.generators.path_graph(5) - graph.extend_from_edge_list([(6, 7), (7, 8), (8, 9), (9, 10), (10, 11)]) - expected = {1: 1, 2: 1, 3: 1, 4: 1} - res = retworkx.num_shortest_paths_unweighted(graph, 0) - self.assertEqual(expected, res) - res = retworkx.num_shortest_paths_unweighted(graph, 6) - expected = {7: 1, 8: 1, 9: 1, 10: 1, 11: 1} - self.assertEqual(expected, res) - - def test_node_indices_with_holes(self): - graph = retworkx.generators.path_graph(5) - graph.extend_from_edge_list([(6, 7), (7, 8), (8, 9), (9, 10), (10, 11)]) - graph.add_edge(4, 6, None) - graph.remove_node(5) - expected = { - 1: 1, - 2: 1, - 3: 1, - 4: 1, - 6: 1, - 7: 1, - 8: 1, - 9: 1, - 10: 1, - 11: 1, - } - res = retworkx.num_shortest_paths_unweighted(graph, 0) - self.assertEqual(expected, res) - - def test_no_edges(self): - graph = retworkx.PyGraph() - graph.add_node(0) - graph.add_node(1) - res = retworkx.num_shortest_paths_unweighted(graph, 0) - self.assertEqual({}, res) - - def test_invalid_source_index(self): - graph = retworkx.PyGraph() - graph.add_node(0) - graph.add_node(1) - graph.add_edge(0, 1, None) - with self.assertRaises(IndexError): - retworkx.num_shortest_paths_unweighted(graph, 4) diff --git a/tests/retworkx_backwards_compat/graph/test_spring_layout.py b/tests/retworkx_backwards_compat/graph/test_spring_layout.py deleted file mode 100644 index 48a51fe38..000000000 --- a/tests/retworkx_backwards_compat/graph/test_spring_layout.py +++ /dev/null @@ -1,73 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestSpringLayout(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - node_a = self.graph.add_node(1) - node_b = self.graph.add_node(2) - self.graph.add_edge(node_a, node_b, 1) - node_c = self.graph.add_node(3) - self.graph.add_edge(node_a, node_c, 2) - - def test_empty_graph(self): - graph = retworkx.PyGraph() - res = retworkx.spring_layout(graph) - self.assertEqual({}, res) - - def test_simple_graph(self): - res = retworkx.spring_layout(self.graph, seed=42) - self.assertEqual(len(res), 3) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - def test_simple_graph_with_edge_weights(self): - res = retworkx.spring_layout(self.graph, weight_fn=lambda e: e) - self.assertEqual(len(res), 3) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - def test_simple_graph_center(self): - res = retworkx.spring_layout(self.graph, center=[0.5, 0.5]) - self.assertEqual(len(res), 3) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - def test_simple_graph_fixed(self): - pos = {0: [0.1, 0.1]} - res = retworkx.spring_layout(self.graph, pos=pos, fixed={0}) - self.assertEqual(res[0], pos[0]) - - def test_simple_graph_fixed_not_pos(self): - with self.assertRaises(ValueError): - retworkx.spring_layout(self.graph, fixed={0}) - - def test_simple_graph_linear_cooling(self): - res = retworkx.spring_layout(self.graph, adaptive_cooling=False) - self.assertEqual(len(res), 3) - self.assertEqual(len(res[0]), 2) - self.assertIsInstance(res[0][0], float) - - def test_graph_with_removed_nodes(self): - graph = retworkx.PyGraph() - nodes = graph.add_nodes_from([0, 1, 2]) - graph.remove_node(nodes[1]) - res = retworkx.spring_layout(graph) - self.assertEqual(len(res), 2) - self.assertTrue(nodes[0] in res) - self.assertTrue(nodes[2] in res) - self.assertFalse(nodes[1] in res) diff --git a/tests/retworkx_backwards_compat/graph/test_steiner_tree.py b/tests/retworkx_backwards_compat/graph/test_steiner_tree.py deleted file mode 100644 index 703caf499..000000000 --- a/tests/retworkx_backwards_compat/graph/test_steiner_tree.py +++ /dev/null @@ -1,188 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import pprint -import unittest - -import retworkx - - -class TestSteinerTree(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph(multigraph=False) - self.graph.add_node(None) - self.graph.extend_from_weighted_edge_list( - [ - (1, 2, 10), - (2, 3, 10), - (3, 4, 10), - (4, 5, 10), - (5, 6, 10), - (2, 7, 1), - (7, 5, 1), - ] - ) - self.graph.remove_node(0) - - def test_metric_closure(self): - closure_graph = retworkx.metric_closure(self.graph, weight_fn=float) - expected_edges = [ - (1, 2, (10.0, [1, 2])), - (1, 3, (20.0, [1, 2, 3])), - (1, 4, (22.0, [1, 2, 7, 5, 4])), - (1, 5, (12.0, [1, 2, 7, 5])), - (1, 6, (22.0, [1, 2, 7, 5, 6])), - (1, 7, (11.0, [1, 2, 7])), - (2, 3, (10.0, [2, 3])), - (2, 4, (12.0, [2, 7, 5, 4])), - (2, 5, (2.0, [2, 7, 5])), - (2, 6, (12, [2, 7, 5, 6])), - (2, 7, (1.0, [2, 7])), - (3, 4, (10.0, [3, 4])), - (3, 5, (12.0, [3, 2, 7, 5])), - (3, 6, (22.0, [3, 2, 7, 5, 6])), - (3, 7, (11.0, [3, 2, 7])), - (4, 5, (10.0, [4, 5])), - (4, 6, (20.0, [4, 5, 6])), - (4, 7, (11.0, [4, 5, 7])), - (5, 6, (10.0, [5, 6])), - (5, 7, (1.0, [5, 7])), - (6, 7, (11.0, [6, 5, 7])), - ] - edges = list(closure_graph.weighted_edge_list()) - for edge in expected_edges: - found = False - if edge in edges: - found = True - if not found: - - if ( - edge[1], - edge[0], - (edge[2][0], list(reversed(edge[2][1]))), - ) in edges: - found = True - if not found: - self.fail( - f"edge: {edge} nor it's reverse not found in metric " - f"closure output:\n{pprint.pformat(edges)}" - ) - - def test_not_connected_metric_closure(self): - self.graph.add_node(None) - with self.assertRaises(ValueError): - retworkx.metric_closure(self.graph, weight_fn=float) - - def test_partially_connected_metric_closure(self): - graph = retworkx.PyGraph() - graph.add_node(None) - graph.extend_from_weighted_edge_list( - [ - (1, 2, 10), - (2, 3, 10), - (3, 4, 10), - (4, 5, 10), - (5, 6, 10), - (2, 7, 1), - (7, 5, 1), - ] - ) - graph.extend_from_weighted_edge_list( - [ - (0, 8, 20), - (0, 9, 20), - (0, 10, 20), - (8, 10, 10), - (9, 10, 5), - ] - ) - with self.assertRaises(ValueError): - retworkx.metric_closure(graph, weight_fn=float) - - def test_metric_closure_empty_graph(self): - graph = retworkx.PyGraph() - closure = retworkx.metric_closure(graph, weight_fn=float) - self.assertEqual([], closure.weighted_edge_list()) - - def test_steiner_graph(self): - steiner_tree = retworkx.steiner_tree(self.graph, [1, 2, 3, 4, 5], weight_fn=float) - expected_steiner_tree = [ - (1, 2, 10), - (2, 3, 10), - (2, 7, 1), - (3, 4, 10), - (7, 5, 1), - ] - steiner_tree_edge_list = steiner_tree.weighted_edge_list() - for edge in expected_steiner_tree: - self.assertIn(edge, steiner_tree_edge_list) - - def test_steiner_graph_multigraph(self): - edge_list = [ - (1, 2, 1), - (2, 3, 999), - (2, 3, 1), - (3, 4, 1), - (3, 5, 1), - ] - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list(edge_list) - graph.remove_node(0) - terminal_nodes = [2, 4, 5] - tree = retworkx.steiner_tree(graph, terminal_nodes, weight_fn=float) - expected_edges = [ - (2, 3, 1), - (3, 4, 1), - (3, 5, 1), - ] - steiner_tree_edge_list = tree.weighted_edge_list() - for edge in expected_edges: - self.assertIn(edge, steiner_tree_edge_list) - - def test_not_connected_steiner_tree(self): - self.graph.add_node(None) - with self.assertRaises(ValueError): - retworkx.steiner_tree(self.graph, [1, 2, 8], weight_fn=float) - - def test_steiner_tree_empty_graph(self): - graph = retworkx.PyGraph() - tree = retworkx.steiner_tree(graph, [], weight_fn=float) - self.assertEqual([], tree.weighted_edge_list()) - - def test_equal_distance_graph(self): - n = 3 - graph = retworkx.PyGraph() - graph.add_nodes_from(range(n + 5)) - graph.add_edges_from( - [ - (n, n + 1, 0.5), - (n, n + 2, 0.5), - (n + 1, n + 2, 0.5), - (n, n + 3, 0.5), - (n + 1, n + 4, 0.5), - ] - ) - graph.add_edges_from([(i, n + 2, 2) for i in range(n)]) - terminals = list(range(5)) + [n + 3, n + 4] - tree = retworkx.steiner_tree(graph, terminals, weight_fn=float) - # Assert no cycle - self.assertEqual(retworkx.cycle_basis(tree), []) - expected_edges = [ - (3, 4, 0.5), - (4, 5, 0.5), - (3, 6, 0.5), - (4, 7, 0.5), - (0, 5, 2), - (1, 5, 2), - (2, 5, 2), - ] - self.assertEqual(tree.weighted_edge_list(), expected_edges) diff --git a/tests/retworkx_backwards_compat/graph/test_subgraph.py b/tests/retworkx_backwards_compat/graph/test_subgraph.py deleted file mode 100644 index 2f0259640..000000000 --- a/tests/retworkx_backwards_compat/graph/test_subgraph.py +++ /dev/null @@ -1,150 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestSubgraph(unittest.TestCase): - def test_subgraph(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([1, 3]) - self.assertEqual([(0, 1, 4)], subgraph.weighted_edge_list()) - self.assertEqual(["b", "d"], subgraph.nodes()) - - def test_subgraph_empty_list(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([]) - self.assertEqual([], subgraph.weighted_edge_list()) - self.assertEqual(0, len(subgraph)) - - def test_subgraph_invalid_entry(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([42]) - self.assertEqual([], subgraph.weighted_edge_list()) - self.assertEqual(0, len(subgraph)) - - def test_subgraph_pass_by_reference(self): - graph = retworkx.PyGraph() - graph.add_node({"a": 0}) - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([0, 1, 3]) - self.assertEqual([(0, 1, 1), (0, 2, 3), (1, 2, 4)], subgraph.weighted_edge_list()) - self.assertEqual([{"a": 0}, "b", "d"], subgraph.nodes()) - graph[0]["a"] = 4 - self.assertEqual(subgraph[0]["a"], 4) - - def test_subgraph_replace_weight_no_reference(self): - graph = retworkx.PyGraph() - graph.add_node({"a": 0}) - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([0, 1, 3]) - self.assertEqual([(0, 1, 1), (0, 2, 3), (1, 2, 4)], subgraph.weighted_edge_list()) - self.assertEqual([{"a": 0}, "b", "d"], subgraph.nodes()) - graph[0] = 4 - self.assertEqual(subgraph[0]["a"], 0) - - def test_edge_subgraph(self): - graph = retworkx.PyGraph() - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.edge_subgraph([(0, 1), (1, 3)]) - self.assertEqual(["a", "b", "d"], subgraph.nodes()) - self.assertEqual([(0, 1, 1), (1, 3, 4)], subgraph.weighted_edge_list()) - - def test_edge_subgraph_parallel_edge(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.extend_from_weighted_edge_list( - [ - (0, 1, 2), - (0, 1, 3), - (0, 2, 2), - (1, 2, 4), - (0, 3, 5), - (2, 3, 6), - ] - ) - subgraph = graph.edge_subgraph([(0, 1), (1, 2)]) - self.assertEqual([0, 1, 2], subgraph.nodes()) - self.assertEqual([(0, 1, 2), (0, 1, 3), (1, 2, 4)], subgraph.weighted_edge_list()) - - def test_edge_subgraph_empty_list(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.extend_from_weighted_edge_list( - [ - (0, 1, 2), - (0, 1, 3), - (0, 2, 2), - (1, 2, 4), - (0, 3, 5), - (2, 3, 6), - ] - ) - subgraph = graph.edge_subgraph([]) - self.assertEqual([], subgraph.nodes()) - - def test_edge_subgraph_non_edge(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(4))) - graph.extend_from_weighted_edge_list( - [ - (0, 1, 2), - (0, 1, 3), - (0, 2, 2), - (1, 2, 4), - (0, 3, 5), - (2, 3, 6), - ] - ) - # 1->3 isn't an edge in graph - subgraph = graph.edge_subgraph([(0, 1), (1, 2), (1, 3)]) - self.assertEqual([0, 1, 2], subgraph.nodes()) - self.assertEqual([(0, 1, 2), (0, 1, 3), (1, 2, 4)], subgraph.weighted_edge_list()) - - def test_preserve_attrs(self): - graph = retworkx.PyGraph(attrs="My attribute") - graph.add_node("a") - graph.add_node("b") - graph.add_node("c") - graph.add_node("d") - graph.add_edges_from([(0, 1, 1), (0, 2, 2), (0, 3, 3), (1, 3, 4)]) - subgraph = graph.subgraph([1, 3], preserve_attrs=True) - self.assertEqual([(0, 1, 4)], subgraph.weighted_edge_list()) - self.assertEqual(["b", "d"], subgraph.nodes()) - self.assertEqual(graph.attrs, subgraph.attrs) diff --git a/tests/retworkx_backwards_compat/graph/test_subgraph_isomorphic.py b/tests/retworkx_backwards_compat/graph/test_subgraph_isomorphic.py deleted file mode 100644 index 3fa842443..000000000 --- a/tests/retworkx_backwards_compat/graph/test_subgraph_isomorphic.py +++ /dev/null @@ -1,296 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestSubgraphIsomorphic(unittest.TestCase): - def test_empty_subgraph_isomorphic_identical(self): - g_a = retworkx.PyGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_a, id_order=id_order)) - - def test_empty_subgraph_isomorphic(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order)) - - def test_empty_subgraph_isomorphic_compare_nodes(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_subgraph_isomorphic( - g_a, g_b, lambda x, y: x == y, id_order=id_order - ) - ) - - def test_subgraph_isomorphic_identical(self): - g_a = retworkx.PyGraph() - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_a, id_order=id_order)) - - def test_subgraph_isomorphic_mismatch_node_data(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[0], nodes[3], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["b_1", "b_2", "b_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "b_1"), (nodes[1], nodes[2], "b_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order)) - - def test_subgraph_isomorphic_compare_nodes_mismatch_node_data(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[0], nodes[3], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["b_1", "b_2", "b_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "b_1"), (nodes[1], nodes[2], "b_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertFalse( - retworkx.is_subgraph_isomorphic( - g_a, g_b, lambda x, y: x == y, id_order=id_order - ) - ) - - def test_subgraph_isomorphic_compare_nodes_identical(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[0], nodes[3], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_subgraph_isomorphic( - g_a, g_b, lambda x, y: x == y, id_order=id_order - ) - ) - - def test_is_subgraph_isomorphic_nodes_compare_raises(self): - g_a = retworkx.PyGraph() - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - - def compare_nodes(a, b): - raise TypeError("Failure") - - self.assertRaises( - TypeError, - retworkx.is_subgraph_isomorphic, - (g_a, g_a, compare_nodes), - ) - - def test_subgraph_isomorphic_compare_edges_identical(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3", "a_4"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[0], nodes[3], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertTrue( - retworkx.is_subgraph_isomorphic( - g_a, - g_b, - edge_matcher=lambda x, y: x == y, - id_order=id_order, - ) - ) - - def test_subgraph_isomorphic_node_count_not_ge(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2"]) - g_a.add_edges_from([(nodes[0], nodes[1], "a_1")]) - - nodes = g_b.add_nodes_from(["a_0", "a_1", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order): - self.assertFalse(retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order)) - - def test_non_induced_subgraph_isomorphic(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - - nodes = g_a.add_nodes_from(["a_1", "a_2", "a_3"]) - g_a.add_edges_from( - [ - (nodes[0], nodes[1], "a_1"), - (nodes[1], nodes[2], "a_2"), - (nodes[2], nodes[0], "a_3"), - ] - ) - - nodes = g_b.add_nodes_from(["a_1", "a_2", "a_3"]) - g_b.add_edges_from([(nodes[0], nodes[1], "a_1"), (nodes[1], nodes[2], "a_2")]) - for id_order in [False, True]: - with self.subTest(id_order=id_order, induced=True): - self.assertFalse( - retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order, induced=True) - ) - with self.subTest(id_order=id_order, induced=False): - self.assertTrue( - retworkx.is_subgraph_isomorphic(g_a, g_b, id_order=id_order, induced=False) - ) - - def test_subgraph_isomorphic_edge_matcher(self): - first = retworkx.PyGraph() - first.extend_from_weighted_edge_list([(0, 1, "a"), (1, 2, "b"), (2, 0, "c")]) - second = retworkx.PyGraph() - second.extend_from_weighted_edge_list([(0, 1, "a"), (1, 2, "b")]) - - self.assertTrue( - retworkx.is_subgraph_isomorphic( - first, second, induced=False, edge_matcher=lambda x, y: x == y - ) - ) - - def test_subgraph_isomorphic_mismatch_edge_data_parallel_edges(self): - first = retworkx.PyGraph() - first.extend_from_weighted_edge_list([(0, 1, "a"), (0, 1, "f"), (1, 2, "b"), (2, 0, "c")]) - second = retworkx.PyGraph() - second.extend_from_weighted_edge_list([(0, 1, "a"), (0, 1, "a"), (1, 2, "b")]) - - self.assertFalse( - retworkx.is_subgraph_isomorphic( - first, second, id_order=True, edge_matcher=lambda x, y: x == y - ) - ) - - def test_subgraph_isomorphic_parallel_edges(self): - first = retworkx.PyGraph() - first.extend_from_edge_list([(0, 1), (1, 2), (2, 3)]) - second = retworkx.PyGraph() - second.extend_from_edge_list([(0, 1), (0, 1)]) - self.assertFalse(retworkx.is_subgraph_isomorphic(first, second, induced=True)) - self.assertFalse(retworkx.is_subgraph_isomorphic(first, second, induced=False)) - - def test_non_induced_grid_subgraph_isomorphic(self): - g_a = retworkx.generators.grid_graph(2, 2) - g_b = retworkx.PyGraph() - g_b.add_nodes_from([0, 1, 2, 3]) - g_b.add_edges_from_no_data([(0, 1), (2, 3)]) - - self.assertFalse(retworkx.is_subgraph_isomorphic(g_a, g_b, induced=True)) - - self.assertTrue(retworkx.is_subgraph_isomorphic(g_a, g_b, induced=False)) - - def test_non_induced_subgraph_isomorphic_parallel_edges(self): - first = retworkx.PyGraph() - first.extend_from_edge_list([(0, 1), (0, 1), (1, 2), (1, 2)]) - second = retworkx.PyGraph() - second.extend_from_edge_list([(0, 1), (1, 2), (1, 2)]) - self.assertFalse(retworkx.is_subgraph_isomorphic(first, second, induced=True)) - self.assertTrue(retworkx.is_subgraph_isomorphic(first, second, induced=False)) - - def test_subgraph_vf2_mapping(self): - graph = retworkx.generators.grid_graph(10, 10) - second_graph = retworkx.generators.grid_graph(2, 2) - mapping = retworkx.graph_vf2_mapping(graph, second_graph, subgraph=True) - self.assertEqual(next(mapping), {0: 0, 1: 1, 10: 2, 11: 3}) - - def test_subgraph_vf2_all_mappings(self): - graph = retworkx.generators.path_graph(3) - second_graph = retworkx.generators.path_graph(2) - mapping = retworkx.graph_vf2_mapping(graph, second_graph, subgraph=True, id_order=True) - self.assertEqual(next(mapping), {0: 0, 1: 1}) - self.assertEqual(next(mapping), {0: 1, 1: 0}) - self.assertEqual(next(mapping), {2: 1, 1: 0}) - self.assertEqual(next(mapping), {1: 1, 2: 0}) - - def test_subgraph_vf2_mapping_vf2pp(self): - graph = retworkx.generators.grid_graph(3, 3) - second_graph = retworkx.generators.grid_graph(2, 2) - mapping = retworkx.graph_vf2_mapping(graph, second_graph, subgraph=True, id_order=False) - self.assertEqual(next(mapping), {4: 0, 3: 2, 0: 3, 1: 1}) - - def test_vf2pp_remapping(self): - temp = retworkx.generators.grid_graph(3, 3) - - graph = retworkx.PyGraph() - dummy = graph.add_node(0) - - graph.compose(temp, dict()) - graph.remove_node(dummy) - - second_graph = retworkx.generators.grid_graph(2, 2) - mapping = retworkx.graph_vf2_mapping(graph, second_graph, subgraph=True, id_order=False) - self.assertEqual(next(mapping), {5: 0, 4: 2, 1: 3, 2: 1}) - - def test_empty_subgraph_vf2_mapping(self): - g_a = retworkx.PyGraph() - g_b = retworkx.PyGraph() - for id_order in [False, True]: - with self.subTest(id_order=id_order): - mapping = retworkx.graph_vf2_mapping(g_a, g_b, id_order=id_order, subgraph=True) - self.assertEqual({}, next(mapping)) - - def test_subgraph_vf2_mapping_out_size(self): - first = retworkx.PyGraph() - first.add_nodes_from([0, 1, 2, 3]) - first.add_edges_from_no_data([(0, 1), (0, 2), (1, 2), (2, 3)]) - second = retworkx.PyGraph() - second.add_nodes_from([0, 1, 2, 3]) - second.add_edges_from_no_data([(0, 1), (0, 2), (1, 3)]) - mapping = retworkx.graph_vf2_mapping( - first, second, subgraph=True, id_order=True, induced=False - ) - self.assertEqual(next(mapping), {0: 0, 1: 2, 2: 1, 3: 3}) diff --git a/tests/retworkx_backwards_compat/graph/test_tensor_product.py b/tests/retworkx_backwards_compat/graph/test_tensor_product.py deleted file mode 100644 index 9d282b0bb..000000000 --- a/tests/retworkx_backwards_compat/graph/test_tensor_product.py +++ /dev/null @@ -1,112 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest -import retworkx - - -class TestTensorProduct(unittest.TestCase): - def test_null_tensor_null(self): - graph_1 = retworkx.PyGraph() - graph_2 = retworkx.PyGraph() - - graph_product, _ = retworkx.graph_tensor_product(graph_1, graph_2) - self.assertEqual(graph_product.num_nodes(), 0) - self.assertEqual(graph_product.num_edges(), 0) - - def test_path_2_tensor_path_2(self): - graph_1 = retworkx.generators.path_graph(2) - graph_2 = retworkx.generators.path_graph(2) - - graph_product, node_map = retworkx.graph_tensor_product(graph_1, graph_2) - - expected_node_map = {(0, 0): 0, (0, 1): 1, (1, 0): 2, (1, 1): 3} - self.assertEqual(node_map, expected_node_map) - - expected_edges = [(0, 3), (1, 2)] - self.assertEqual(graph_product.num_nodes(), 4) - self.assertEqual(graph_product.num_edges(), 2) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_path_2_tensor_path_3(self): - graph_1 = retworkx.generators.path_graph(2) - graph_2 = retworkx.generators.path_graph(3) - - graph_product, node_map = retworkx.graph_tensor_product(graph_1, graph_2) - expected_node_map = {(0, 1): 1, (1, 0): 3, (0, 0): 0, (1, 2): 5, (0, 2): 2, (1, 1): 4} - self.assertEqual(dict(node_map), expected_node_map) - - expected_edges = [(0, 4), (1, 5), (1, 3), (2, 4)] - self.assertEqual(graph_product.num_nodes(), 6) - self.assertEqual(graph_product.num_edges(), 4) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_node_weights_tensor(self): - graph_1 = retworkx.PyGraph() - graph_1.add_node("a_1") - graph_2 = retworkx.PyGraph() - graph_2.add_node(0) - - graph_product, _ = retworkx.graph_tensor_product(graph_1, graph_2) - self.assertEqual([("a_1", 0)], graph_product.nodes()) - - def test_edge_weights_tensor(self): - graph_1 = retworkx.PyGraph() - graph_1.add_nodes_from([0, 1]) - graph_1.add_edge(0, 1, "w_1") - - graph_2 = retworkx.PyGraph() - graph_2.add_nodes_from([0, 1]) - graph_2.add_edge(0, 1, "w_2") - - graph_product, _ = retworkx.graph_tensor_product(graph_1, graph_2) - self.assertEqual([("w_1", "w_2"), ("w_1", "w_2")], graph_product.edges()) - - def test_multi_graph_1(self): - graph_1 = retworkx.generators.path_graph(2) - graph_1.add_edge(0, 1, None) - graph_2 = retworkx.generators.path_graph(2) - - graph_product, _ = retworkx.graph_tensor_product(graph_1, graph_2) - expected_edges = [(0, 3), (0, 3), (1, 2), (1, 2)] - self.assertEqual(graph_product.num_edges(), 4) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_multi_graph_2(self): - graph_1 = retworkx.generators.path_graph(2) - graph_1.add_edge(0, 0, None) - graph_2 = retworkx.generators.path_graph(2) - - graph_product, _ = retworkx.graph_tensor_product(graph_1, graph_2) - expected_edges = [(0, 3), (0, 1), (1, 2)] - self.assertEqual(graph_product.num_edges(), 3) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_multi_graph_3(self): - graph_1 = retworkx.generators.path_graph(2) - graph_2 = retworkx.generators.path_graph(2) - graph_2.add_edge(0, 1, None) - - graph_product, _ = retworkx.graph_tensor_product(graph_1, graph_2) - expected_edges = [(0, 3), (0, 3), (1, 2), (1, 2)] - self.assertEqual(graph_product.num_edges(), 4) - self.assertEqual(graph_product.edge_list(), expected_edges) - - def test_multi_graph_4(self): - graph_1 = retworkx.generators.path_graph(2) - graph_2 = retworkx.generators.path_graph(2) - graph_2.add_edge(0, 0, None) - - graph_product, _ = retworkx.graph_tensor_product(graph_1, graph_2) - expected_edges = [(0, 3), (0, 2), (1, 2)] - self.assertEqual(graph_product.num_edges(), 3) - self.assertEqual(graph_product.edge_list(), expected_edges) diff --git a/tests/retworkx_backwards_compat/graph/test_to_directed.py b/tests/retworkx_backwards_compat/graph/test_to_directed.py deleted file mode 100644 index 16b97b866..000000000 --- a/tests/retworkx_backwards_compat/graph/test_to_directed.py +++ /dev/null @@ -1,79 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestToDirected(unittest.TestCase): - def test_to_undirected_empty_graph(self): - graph = retworkx.PyGraph() - digraph = graph.to_directed() - self.assertEqual(0, len(digraph)) - - def test_path_graph(self): - graph = retworkx.generators.path_graph(5) - digraph = graph.to_directed() - expected = [ - (0, 1, None), - (1, 0, None), - (1, 2, None), - (2, 1, None), - (2, 3, None), - (3, 2, None), - (3, 4, None), - (4, 3, None), - ] - self.assertEqual(digraph.weighted_edge_list(), expected) - - def test_parallel_edge_graph(self): - graph = retworkx.PyGraph() - graph.extend_from_weighted_edge_list( - [ - (0, 1, "A"), - (0, 1, "B"), - (0, 2, "C"), - (0, 3, "D"), - ] - ) - digraph = graph.to_directed() - expected = [ - (0, 1, "A"), - (1, 0, "A"), - (0, 1, "B"), - (1, 0, "B"), - (0, 2, "C"), - (2, 0, "C"), - (0, 3, "D"), - (3, 0, "D"), - ] - self.assertEqual(digraph.weighted_edge_list(), expected) - - def test_shared_ref(self): - graph = retworkx.PyGraph() - node_weight = {"a": 1} - node_a = graph.add_node(node_weight) - edge_weight = {"a": 1} - node_b = graph.add_node("b") - graph.add_edge(node_a, node_b, edge_weight) - digraph = graph.to_directed() - self.assertEqual(digraph[node_a], {"a": 1}) - self.assertEqual(graph[node_a], {"a": 1}) - node_weight["b"] = 2 - self.assertEqual(digraph[node_a], {"a": 1, "b": 2}) - self.assertEqual(graph[node_a], {"a": 1, "b": 2}) - self.assertEqual(digraph.get_edge_data(0, 1), {"a": 1}) - self.assertEqual(graph.get_edge_data(0, 1), {"a": 1}) - edge_weight["b"] = 2 - self.assertEqual(digraph.get_edge_data(0, 1), {"a": 1, "b": 2}) - self.assertEqual(graph.get_edge_data(0, 1), {"a": 1, "b": 2}) diff --git a/tests/retworkx_backwards_compat/graph/test_transitivity.py b/tests/retworkx_backwards_compat/graph/test_transitivity.py deleted file mode 100644 index 5d7d8fed8..000000000 --- a/tests/retworkx_backwards_compat/graph/test_transitivity.py +++ /dev/null @@ -1,49 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest - -import retworkx - - -class TestTransitivity(unittest.TestCase): - def test_transitivity(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(5))) - graph.add_edges_from_no_data([(0, 1), (0, 2), (0, 3), (0, 4), (1, 2)]) - res = retworkx.transitivity(graph) - self.assertEqual(res, 3 / 8) - - def test_transitivity_triangle(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(3))) - graph.add_edges_from_no_data([(0, 1), (0, 2), (1, 2)]) - res = retworkx.transitivity(graph) - self.assertEqual(res, 1.0) - - def test_transitivity_star(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(5))) - graph.add_edges_from_no_data([(0, 1), (0, 2), (0, 3), (0, 4)]) - res = retworkx.transitivity(graph) - self.assertEqual(res, 0.0) - - def test_transitivity_empty(self): - graph = retworkx.PyGraph() - res = retworkx.transitivity(graph) - self.assertEqual(res, 0.0) - - def test_transitivity_disconnected(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(3))) - res = retworkx.transitivity(graph) - self.assertEqual(res, 0.0) diff --git a/tests/retworkx_backwards_compat/graph/test_union.py b/tests/retworkx_backwards_compat/graph/test_union.py deleted file mode 100644 index 6ada9c331..000000000 --- a/tests/retworkx_backwards_compat/graph/test_union.py +++ /dev/null @@ -1,74 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest -import retworkx - - -class TestUnion(unittest.TestCase): - def setUp(self): - self.graph = retworkx.PyGraph() - self.graph.add_nodes_from(["a_1", "a_2", "a_3"]) - self.graph.extend_from_weighted_edge_list([(0, 1, "e_1"), (1, 2, "e_2")]) - - def test_union_basic_merge_none(self): - final = retworkx.graph_union(self.graph, self.graph, merge_nodes=False, merge_edges=False) - self.assertTrue(len(final.nodes()) == 6) - self.assertTrue(len(final.edge_list()) == 4) - - def test_union_merge_all(self): - final = retworkx.graph_union(self.graph, self.graph, merge_nodes=True, merge_edges=True) - self.assertTrue(retworkx.is_isomorphic(final, self.graph)) - - def test_union_basic_merge_nodes_only(self): - final = retworkx.graph_union(self.graph, self.graph, merge_nodes=True, merge_edges=False) - self.assertTrue(len(final.edge_list()) == 4) - self.assertTrue(len(final.get_all_edge_data(0, 1)) == 2) - self.assertTrue(len(final.nodes()) == 3) - - def test_union_mismatch_edge_weight(self): - first = retworkx.PyGraph() - nodes = first.add_nodes_from([0, 1]) - first.add_edges_from([(nodes[0], nodes[1], "a")]) - - second = retworkx.PyGraph() - nodes = second.add_nodes_from([0, 1]) - second.add_edges_from([(nodes[0], nodes[1], "b")]) - - final = retworkx.graph_union(first, second, merge_nodes=True, merge_edges=True) - self.assertEqual(final.weighted_edge_list(), [(0, 1, "a"), (0, 1, "b")]) - - def test_union_node_hole(self): - first = retworkx.PyGraph() - nodes = first.add_nodes_from([0, 1]) - first.add_edges_from([(nodes[0], nodes[1], "a")]) - - second = retworkx.PyGraph() - dummy = second.add_node("dummy") - nodes = second.add_nodes_from([0, 1]) - second.add_edges_from([(nodes[0], nodes[1], "a")]) - second.remove_node(dummy) - - final = retworkx.graph_union(first, second, merge_nodes=True, merge_edges=True) - self.assertEqual(final.weighted_edge_list(), [(0, 1, "a")]) - - def test_union_edge_between_merged_and_unmerged_nodes(self): - first = retworkx.PyGraph() - nodes = first.add_nodes_from([0, 1]) - first.add_edges_from([(nodes[0], nodes[1], "a")]) - - second = retworkx.PyGraph() - nodes = second.add_nodes_from([0, 2]) - second.add_edges_from([(nodes[0], nodes[1], "b")]) - - final = retworkx.graph_union(first, second, merge_nodes=True, merge_edges=True) - self.assertEqual(final.weighted_edge_list(), [(0, 1, "a"), (0, 2, "b")]) diff --git a/tests/retworkx_backwards_compat/test_converters.py b/tests/retworkx_backwards_compat/test_converters.py deleted file mode 100644 index df753b72c..000000000 --- a/tests/retworkx_backwards_compat/test_converters.py +++ /dev/null @@ -1,117 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest -import retworkx -import networkx - - -class TestNetworkxConverter(unittest.TestCase): - def test_undirected_gnm_graph(self): - g = networkx.gnm_random_graph(10, 10, seed=42) - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_directed_gnm_graph(self): - g = networkx.gnm_random_graph(10, 10, seed=42, directed=True) - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyDiGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_empty_graph(self): - g = networkx.Graph() - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_empty_multigraph(self): - g = networkx.MultiGraph() - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_empty_directed_graph(self): - g = networkx.DiGraph() - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyDiGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_empty_directed_multigraph(self): - g = networkx.MultiDiGraph() - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyDiGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_cubical_graph(self): - g = networkx.cubical_graph(networkx.Graph) - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_cubical_multigraph(self): - g = networkx.cubical_graph(networkx.MultiGraph) - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_random_k_out_graph(self): - g = networkx.random_k_out_graph(100, 50, 3.14159, True, 42) - for keep_attributes in [True, False]: - with self.subTest(keep_attributes=keep_attributes): - out_graph = retworkx.networkx_converter(g, keep_attributes=keep_attributes) - self.assertIsInstance(out_graph, retworkx.PyDiGraph) - self.assertEqual(list(out_graph.node_indexes()), list(g.nodes)) - self.assertEqual(out_graph.weighted_edge_list(), list(g.edges(data=True))) - self.assertEqual(out_graph.multigraph, g.is_multigraph()) - - def test_networkx_graph_attributes_are_converted(self): - g = networkx.Graph() - for node in range(100): - g.add_node(str(node), test=True) - - out_graph = retworkx.networkx_converter(g, keep_attributes=True) - for node in out_graph.node_indexes(): - self.assertEqual(out_graph[node]["test"], True) - self.assertEqual(out_graph[node]["__networkx_node__"], str(node)) diff --git a/tests/retworkx_backwards_compat/test_custom_return_types.py b/tests/retworkx_backwards_compat/test_custom_return_types.py deleted file mode 100644 index a3bb14260..000000000 --- a/tests/retworkx_backwards_compat/test_custom_return_types.py +++ /dev/null @@ -1,1561 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import pickle -import unittest - -import retworkx -import numpy as np - - -class TestBFSSuccessorsComparisons(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - self.node_a = self.dag.add_node("a") - self.node_b = self.dag.add_child(self.node_a, "b", "Edgy") - - def test__eq__match(self): - self.assertTrue(retworkx.bfs_successors(self.dag, 0) == [("a", ["b"])]) - - def test__eq__not_match(self): - self.assertFalse(retworkx.bfs_successors(self.dag, 0) == [("b", ["c"])]) - - def test_eq_not_match_inner(self): - self.assertFalse(retworkx.bfs_successors(self.dag, 0) == [("a", ["c"])]) - - def test__eq__different_length(self): - self.assertFalse(retworkx.bfs_successors(self.dag, 0) == [("a", ["b"]), ("b", ["c"])]) - - def test__eq__invalid_type(self): - with self.assertRaises(TypeError): - retworkx.bfs_successors(self.dag, 0) == ["a"] - - def test__ne__match(self): - self.assertFalse(retworkx.bfs_successors(self.dag, 0) != [("a", ["b"])]) - - def test__ne__not_match(self): - self.assertTrue(retworkx.bfs_successors(self.dag, 0) != [("b", ["c"])]) - - def test_ne_not_match_inner(self): - self.assertTrue(retworkx.bfs_successors(self.dag, 0) != [("a", ["c"])]) - - def test__ne__different_length(self): - self.assertTrue(retworkx.bfs_successors(self.dag, 0) != [("a", ["b"]), ("b", ["c"])]) - - def test__ne__invalid_type(self): - with self.assertRaises(TypeError): - retworkx.bfs_successors(self.dag, 0) != ["a"] - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - retworkx.bfs_successors(self.dag, 0) > [("b", ["c"])] - - def test_deepcopy(self): - bfs = retworkx.bfs_successors(self.dag, 0) - bfs_copy = copy.deepcopy(bfs) - self.assertEqual(bfs, bfs_copy) - - def test_pickle(self): - bfs = retworkx.bfs_successors(self.dag, 0) - bfs_pickle = pickle.dumps(bfs) - bfs_copy = pickle.loads(bfs_pickle) - self.assertEqual(bfs, bfs_copy) - - def test_str(self): - res = retworkx.bfs_successors(self.dag, 0) - self.assertEqual("BFSSuccessors[(a, [b])]", str(res)) - - def test_hash(self): - res = retworkx.bfs_successors(self.dag, 0) - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_hash_invalid_type(self): - self.dag.add_child(0, [1, 2, 3], "edgy") - res = retworkx.bfs_successors(self.dag, 0) - with self.assertRaises(TypeError): - hash(res) - - def test_slices(self): - self.dag.add_child(self.node_a, "c", "New edge") - self.dag.add_child(self.node_b, "d", "New edge to d") - successors = retworkx.bfs_successors(self.dag, 0) - slice_return = successors[0:3:2] - self.assertEqual([("a", ["c", "b"])], slice_return) - - -class TestNodeIndicesComparisons(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - node_a = self.dag.add_node("a") - self.dag.add_child(node_a, "b", "Edgy") - - def test__eq__match(self): - self.assertTrue(self.dag.node_indexes() == [0, 1]) - - def test__eq__not_match(self): - self.assertFalse(self.dag.node_indexes() == [1, 2]) - - def test__eq__different_length(self): - self.assertFalse(self.dag.node_indexes() == [0, 1, 2, 3]) - - def test__eq__invalid_type(self): - with self.assertRaises(TypeError): - self.dag.node_indexes() == ["a", None] - - def test__ne__match(self): - self.assertFalse(self.dag.node_indexes() != [0, 1]) - - def test__ne__not_match(self): - self.assertTrue(self.dag.node_indexes() != [1, 2]) - - def test__ne__different_length(self): - self.assertTrue(self.dag.node_indexes() != [0, 1, 2, 3]) - - def test__ne__invalid_type(self): - with self.assertRaises(TypeError): - self.dag.node_indexes() != ["a", None] - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.dag.node_indexes() > [2, 1] - - def test_deepcopy(self): - nodes = self.dag.node_indexes() - nodes_copy = copy.deepcopy(nodes) - self.assertEqual(nodes, nodes_copy) - - def test_pickle(self): - nodes = self.dag.node_indexes() - nodes_pickle = pickle.dumps(nodes) - nodes_copy = pickle.loads(nodes_pickle) - self.assertEqual(nodes, nodes_copy) - - def test_str(self): - res = self.dag.node_indexes() - self.assertEqual("NodeIndices[0, 1]", str(res)) - - def test_hash(self): - res = self.dag.node_indexes() - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_slices(self): - self.dag.add_node("new") - self.dag.add_node("fun") - nodes = self.dag.node_indices() - slice_return = nodes[0:3:2] - self.assertEqual([0, 2], slice_return) - self.assertEqual(nodes[0:-1], [0, 1, 2]) - - def test_slices_negatives(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(range(5)) - indices = graph.node_indices() - slice_return = indices[-1:-3:-1] - self.assertEqual([4, 3], slice_return) - slice_return = indices[3:1:-2] - self.assertEqual([3], slice_return) - slice_return = indices[-3:-1] - self.assertEqual([2, 3], slice_return) - self.assertEqual([], indices[-1:-2]) - - def test_numpy_conversion(self): - res = self.dag.node_indexes() - np.testing.assert_array_equal(np.asarray(res, dtype=np.uintp), np.array([0, 1])) - - -class TestNodesCountMapping(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - node_a = self.dag.add_node("a") - self.dag.add_child(node_a, "b", "Edgy") - - def test__eq__match(self): - self.assertTrue(retworkx.num_shortest_paths_unweighted(self.dag, 0) == {1: 1}) - - def test__eq__not_match_keys(self): - self.assertFalse(retworkx.num_shortest_paths_unweighted(self.dag, 0) == {2: 1}) - - def test__eq__not_match_values(self): - self.assertFalse(retworkx.num_shortest_paths_unweighted(self.dag, 0) == {1: 2}) - - def test__eq__different_length(self): - self.assertFalse(retworkx.num_shortest_paths_unweighted(self.dag, 0) == {1: 1, 2: 2}) - - def test_eq__same_type(self): - self.assertEqual( - retworkx.num_shortest_paths_unweighted(self.dag, 0), - retworkx.num_shortest_paths_unweighted(self.dag, 0), - ) - - def test__eq__invalid_type(self): - self.assertFalse(retworkx.num_shortest_paths_unweighted(self.dag, 0) == ["a", None]) - - def test__eq__invalid_inner_type(self): - self.assertFalse(retworkx.num_shortest_paths_unweighted(self.dag, 0) == {0: "a"}) - - def test__ne__match(self): - self.assertFalse(retworkx.num_shortest_paths_unweighted(self.dag, 0) != {1: 1}) - - def test__ne__not_match(self): - self.assertTrue(retworkx.num_shortest_paths_unweighted(self.dag, 0) != {2: 1}) - - def test__ne__not_match_values(self): - self.assertTrue(retworkx.num_shortest_paths_unweighted(self.dag, 0) != {1: 2}) - - def test__ne__different_length(self): - self.assertTrue(retworkx.num_shortest_paths_unweighted(self.dag, 0) != {1: 1, 2: 2}) - - def test__ne__invalid_type(self): - self.assertTrue(retworkx.num_shortest_paths_unweighted(self.dag, 0) != ["a", None]) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - retworkx.num_shortest_paths_unweighted(self.dag, 0) > {1: 1} - - def test_deepcopy(self): - paths = retworkx.num_shortest_paths_unweighted(self.dag, 0) - paths_copy = copy.deepcopy(paths) - self.assertEqual(paths, paths_copy) - - def test_pickle(self): - paths = retworkx.num_shortest_paths_unweighted(self.dag, 0) - paths_pickle = pickle.dumps(paths) - paths_copy = pickle.loads(paths_pickle) - self.assertEqual(paths, paths_copy) - - def test_str(self): - res = retworkx.num_shortest_paths_unweighted(self.dag, 0) - self.assertEqual("NodesCountMapping{1: 1}", str(res)) - - def test_hash(self): - res = retworkx.num_shortest_paths_unweighted(self.dag, 0) - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_index_error(self): - res = retworkx.num_shortest_paths_unweighted(self.dag, 0) - with self.assertRaises(IndexError): - res[42] - - def test_keys(self): - keys = retworkx.num_shortest_paths_unweighted(self.dag, 0).keys() - self.assertEqual([1], list(keys)) - - def test_values(self): - values = retworkx.num_shortest_paths_unweighted(self.dag, 0).values() - self.assertEqual([1], list(values)) - - def test_items(self): - items = retworkx.num_shortest_paths_unweighted(self.dag, 0).items() - self.assertEqual([(1, 1)], list(items)) - - def test_iter(self): - mapping_iter = iter(retworkx.num_shortest_paths_unweighted(self.dag, 0)) - output = list(mapping_iter) - self.assertEqual(output, [1]) - - def test_contains(self): - res = retworkx.num_shortest_paths_unweighted(self.dag, 0) - self.assertIn(1, res) - - def test_not_contains(self): - res = retworkx.num_shortest_paths_unweighted(self.dag, 0) - self.assertNotIn(0, res) - - -class TestEdgeIndicesComparisons(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDiGraph() - node_a = self.dag.add_node("a") - node_b = self.dag.add_child(node_a, "b", "Edgy") - self.dag.add_child(node_b, "c", "Super Edgy") - - def test__eq__match(self): - self.assertTrue(self.dag.edge_indices() == [0, 1]) - - def test__eq__not_match(self): - self.assertFalse(self.dag.edge_indices() == [1, 2]) - - def test__eq__different_length(self): - self.assertFalse(self.dag.edge_indices() == [0, 1, 2, 3]) - - def test__eq__invalid_type(self): - with self.assertRaises(TypeError): - self.dag.edge_indices() == ["a", None] - - def test__ne__match(self): - self.assertFalse(self.dag.edge_indices() != [0, 1]) - - def test__ne__not_match(self): - self.assertTrue(self.dag.edge_indices() != [1, 2]) - - def test__ne__different_length(self): - self.assertTrue(self.dag.edge_indices() != [0, 1, 2, 3]) - - def test__ne__invalid_type(self): - with self.assertRaises(TypeError): - self.dag.edge_indices() != ["a", None] - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.dag.edge_indices() > [2, 1] - - def test_deepcopy(self): - edges = self.dag.edge_indices() - edges_copy = copy.deepcopy(edges) - self.assertEqual(edges, edges_copy) - - def test_pickle(self): - edges = self.dag.edge_indices() - edges_pickle = pickle.dumps(edges) - edges_copy = pickle.loads(edges_pickle) - self.assertEqual(edges, edges_copy) - - def test_str(self): - res = self.dag.edge_indices() - self.assertEqual("EdgeIndices[0, 1]", str(res)) - - def test_hash(self): - res = self.dag.edge_indices() - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_slices(self): - self.dag.add_edge(0, 1, None) - edges = self.dag.edge_indices() - slice_return = edges[0:-1] - self.assertEqual([0, 1], slice_return) - - -class TestEdgeListComparisons(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - node_a = self.dag.add_node("a") - self.dag.add_child(node_a, "b", "Edgy") - - def test__eq__match(self): - self.assertTrue(self.dag.edge_list() == [(0, 1)]) - - def test__eq__not_match(self): - self.assertFalse(self.dag.edge_list() == [(1, 2)]) - - def test__eq__different_length(self): - self.assertFalse(self.dag.edge_list() == [(0, 1), (2, 3)]) - - def test__eq__invalid_type(self): - self.assertFalse(self.dag.edge_list() == ["a", None]) - - def test__ne__match(self): - self.assertFalse(self.dag.edge_list() != [(0, 1)]) - - def test__ne__not_match(self): - self.assertTrue(self.dag.edge_list() != [(1, 2)]) - - def test__ne__different_length(self): - self.assertTrue(self.dag.edge_list() != [(0, 1), (2, 3)]) - - def test__ne__invalid_type(self): - self.assertTrue(self.dag.edge_list() != ["a", None]) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.dag.edge_list() > [(2, 1)] - - def test_deepcopy(self): - edges = self.dag.edge_list() - edges_copy = copy.deepcopy(edges) - self.assertEqual(edges, edges_copy) - - def test_pickle(self): - edges = self.dag.edge_list() - edges_pickle = pickle.dumps(edges) - edges_copy = pickle.loads(edges_pickle) - self.assertEqual(edges, edges_copy) - - def test_str(self): - res = self.dag.edge_list() - self.assertEqual("EdgeList[(0, 1)]", str(res)) - - def test_hash(self): - res = self.dag.edge_list() - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_slice(self): - self.dag.add_edge(0, 1, None) - self.dag.add_edge(0, 1, None) - edges = self.dag.edge_list() - slice_return = edges[0:3:2] - self.assertEqual([(0, 1), (0, 1)], slice_return) - - @staticmethod - def test_numpy_conversion(): - g = retworkx.generators.directed_star_graph(5) - res = g.edge_list() - - np.testing.assert_array_equal( - np.asarray(res, dtype=np.uintp), np.array([[0, 1], [0, 2], [0, 3], [0, 4]]) - ) - - -class TestWeightedEdgeListComparisons(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - node_a = self.dag.add_node("a") - self.dag.add_child(node_a, "b", "Edgy") - - def test__eq__match(self): - self.assertTrue(self.dag.weighted_edge_list() == [(0, 1, "Edgy")]) - - def test__eq__not_match(self): - self.assertFalse(self.dag.weighted_edge_list() == [(1, 2, None)]) - - def test__eq__different_length(self): - self.assertFalse(self.dag.weighted_edge_list() == [(0, 1, "Edgy"), (2, 3, "Not Edgy")]) - - def test__eq__invalid_type(self): - self.assertFalse(self.dag.weighted_edge_list() == ["a", None]) - - def test__ne__match(self): - self.assertFalse(self.dag.weighted_edge_list() != [(0, 1, "Edgy")]) - - def test__ne__not_match(self): - self.assertTrue(self.dag.weighted_edge_list() != [(1, 2, "Not Edgy")]) - - def test__ne__different_length(self): - self.assertTrue(self.dag.node_indexes() != [0, 1, 2, 3]) - - def test__ne__invalid_type(self): - self.assertTrue(self.dag.weighted_edge_list() != ["a", None]) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.dag.weighted_edge_list() > [(2, 1, "Not Edgy")] - - def test_deepcopy(self): - edges = self.dag.weighted_edge_list() - edges_copy = copy.deepcopy(edges) - self.assertEqual(edges, edges_copy) - - def test_pickle(self): - edges = self.dag.weighted_edge_list() - edges_pickle = pickle.dumps(edges) - edges_copy = pickle.loads(edges_pickle) - self.assertEqual(edges, edges_copy) - - def test_str(self): - res = self.dag.weighted_edge_list() - self.assertEqual("WeightedEdgeList[(0, 1, Edgy)]", str(res)) - - def test_hash(self): - res = self.dag.weighted_edge_list() - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_hash_invalid_type(self): - self.dag.add_child(0, "c", ["edgy", "not_edgy"]) - res = self.dag.weighted_edge_list() - with self.assertRaises(TypeError): - hash(res) - - def test_slice(self): - self.dag.add_edge(0, 1, None) - self.dag.add_edge(0, 1, None) - edges = self.dag.weighted_edge_list() - slice_return = edges[0:3:2] - self.assertEqual([(0, 1, "Edgy"), (0, 1, None)], slice_return) - - def test_numpy_conversion(self): - np.testing.assert_array_equal( - np.asarray(self.dag.weighted_edge_list()), np.array([(0, 1, "Edgy")], dtype=object) - ) - - -class TestPathMapping(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - node_a = self.dag.add_node("a") - self.dag.add_child(node_a, "b", "Edgy") - - def test__eq__match(self): - self.assertTrue(retworkx.dijkstra_shortest_paths(self.dag, 0) == {1: [0, 1]}) - - def test__eq__not_match_keys(self): - self.assertFalse(retworkx.dijkstra_shortest_paths(self.dag, 0) == {2: [0, 1]}) - - def test__eq__not_match_values(self): - self.assertFalse(retworkx.dijkstra_shortest_paths(self.dag, 0) == {1: [0, 2]}) - - def test__eq__different_length(self): - self.assertFalse(retworkx.dijkstra_shortest_paths(self.dag, 0) == {1: [0, 1], 2: [0, 2]}) - - def test_eq__same_type(self): - self.assertEqual( - retworkx.dijkstra_shortest_paths(self.dag, 0), - retworkx.dijkstra_shortest_paths(self.dag, 0), - ) - - def test__eq__invalid_type(self): - self.assertFalse(retworkx.dijkstra_shortest_paths(self.dag, 0) == ["a", None]) - - def test__eq__invalid_inner_type(self): - self.assertFalse(retworkx.dijkstra_shortest_paths(self.dag, 0) == {0: {"a": None}}) - - def test__ne__match(self): - self.assertFalse(retworkx.dijkstra_shortest_paths(self.dag, 0) != {1: [0, 1]}) - - def test__ne__not_match(self): - self.assertTrue(retworkx.dijkstra_shortest_paths(self.dag, 0) != {2: [0, 1]}) - - def test__ne__not_match_values(self): - self.assertTrue(retworkx.dijkstra_shortest_paths(self.dag, 0) != {1: [0, 2]}) - - def test__ne__different_length(self): - self.assertTrue(retworkx.dijkstra_shortest_paths(self.dag, 0) != {1: [0, 1], 2: [0, 2]}) - - def test__ne__invalid_type(self): - self.assertTrue(retworkx.dijkstra_shortest_paths(self.dag, 0) != ["a", None]) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - retworkx.dijkstra_shortest_paths(self.dag, 0) > {1: [0, 2]} - - def test_deepcopy(self): - paths = retworkx.dijkstra_shortest_paths(self.dag, 0) - paths_copy = copy.deepcopy(paths) - self.assertEqual(paths, paths_copy) - - def test_pickle(self): - paths = retworkx.dijkstra_shortest_paths(self.dag, 0) - paths_pickle = pickle.dumps(paths) - paths_copy = pickle.loads(paths_pickle) - self.assertEqual(paths, paths_copy) - - def test_str(self): - res = retworkx.dijkstra_shortest_paths(self.dag, 0) - self.assertEqual("PathMapping{1: [0, 1]}", str(res)) - - def test_hash(self): - res = retworkx.dijkstra_shortest_paths(self.dag, 0) - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_index_error(self): - res = retworkx.dijkstra_shortest_paths(self.dag, 0) - with self.assertRaises(IndexError): - res[42] - - def test_keys(self): - keys = retworkx.dijkstra_shortest_paths(self.dag, 0).keys() - self.assertEqual([1], list(keys)) - - def test_values(self): - values = retworkx.dijkstra_shortest_paths(self.dag, 0).values() - self.assertEqual([[0, 1]], list(values)) - - def test_items(self): - items = retworkx.dijkstra_shortest_paths(self.dag, 0).items() - self.assertEqual([(1, [0, 1])], list(items)) - - def test_iter(self): - mapping_iter = iter(retworkx.dijkstra_shortest_paths(self.dag, 0)) - output = list(mapping_iter) - self.assertEqual(output, [1]) - - def test_contains(self): - res = retworkx.dijkstra_shortest_paths(self.dag, 0) - self.assertIn(1, res) - - def test_not_contains(self): - res = retworkx.dijkstra_shortest_paths(self.dag, 0) - self.assertNotIn(0, res) - - -class TestPathLengthMapping(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - node_a = self.dag.add_node("a") - self.dag.add_child(node_a, "b", "Edgy") - self.fn = lambda _: 1.0 - - def test__eq__match(self): - self.assertTrue(retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) == {1: 1.0}) - - def test__eq__not_match_keys(self): - self.assertFalse(retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) == {2: 1.0}) - - def test__eq__not_match_values(self): - self.assertFalse(retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) == {1: 2.0}) - - def test__eq__different_length(self): - self.assertFalse( - retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) == {1: 1.0, 2: 2.0} - ) - - def test_eq__same_type(self): - self.assertEqual( - retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn), - retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn), - ) - - def test__eq__invalid_type(self): - self.assertFalse( - retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) == ["a", None] - ) - - def test__eq__invalid_inner_type(self): - self.assertFalse(retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) == {0: "a"}) - - def test__ne__match(self): - self.assertFalse(retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) != {1: 1.0}) - - def test__ne__not_match(self): - self.assertTrue(retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) != {2: 1.0}) - - def test__ne__not_match_values(self): - self.assertTrue(retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) != {1: 2.0}) - - def test__ne__different_length(self): - self.assertTrue( - retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) != {1: 1.0, 2: 2.0} - ) - - def test__ne__invalid_type(self): - self.assertTrue( - retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) != ["a", None] - ) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) > {1: 1.0} - - def test_deepcopy(self): - paths = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) - paths_copy = copy.deepcopy(paths) - self.assertEqual(paths, paths_copy) - - def test_pickle(self): - paths = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) - paths_pickle = pickle.dumps(paths) - paths_copy = pickle.loads(paths_pickle) - self.assertEqual(paths, paths_copy) - - def test_str(self): - res = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, lambda _: 3.14) - self.assertEqual("PathLengthMapping{1: 3.14}", str(res)) - - def test_hash(self): - res = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_index_error(self): - res = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) - with self.assertRaises(IndexError): - res[42] - - def test_keys(self): - keys = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn).keys() - self.assertEqual([1], list(keys)) - - def test_values(self): - values = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn).values() - self.assertEqual([1.0], list(values)) - - def test_items(self): - items = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn).items() - self.assertEqual([(1, 1.0)], list(items)) - - def test_iter(self): - mapping_iter = iter(retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn)) - output = list(mapping_iter) - self.assertEqual(output, [1]) - - def test_contains(self): - res = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) - self.assertIn(1, res) - - def test_not_contains(self): - res = retworkx.dijkstra_shortest_path_lengths(self.dag, 0, self.fn) - self.assertNotIn(0, res) - - -class TestPos2DMapping(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDiGraph() - self.dag.add_node("a") - - def test__eq__match(self): - res = retworkx.random_layout(self.dag, seed=10244242) - self.assertTrue(res == {0: (0.4883489113112722, 0.6545867364101975)}) - - def test__eq__not_match_keys(self): - self.assertFalse(retworkx.random_layout(self.dag, seed=10244242) == {2: 1.0}) - - def test__eq__not_match_values(self): - self.assertFalse(retworkx.random_layout(self.dag, seed=10244242) == {1: 2.0}) - - def test__eq__different_length(self): - res = retworkx.random_layout(self.dag, seed=10244242) - self.assertFalse(res == {1: 1.0, 2: 2.0}) - - def test_eq__same_type(self): - self.assertEqual( - retworkx.random_layout(self.dag, seed=10244242), - retworkx.random_layout(self.dag, seed=10244242), - ) - - def test__eq__invalid_type(self): - self.assertFalse(retworkx.random_layout(self.dag, seed=10244242) == {"a": None}) - - def test__ne__match(self): - res = retworkx.random_layout(self.dag, seed=10244242) - self.assertFalse(res != {0: (0.4883489113112722, 0.6545867364101975)}) - - def test__ne__not_match(self): - self.assertTrue(retworkx.random_layout(self.dag, seed=10244242) != {2: 1.0}) - - def test__ne__not_match_values(self): - self.assertTrue(retworkx.random_layout(self.dag, seed=10244242) != {1: 2.0}) - - def test__ne__different_length(self): - res = retworkx.random_layout(self.dag, seed=10244242) - - self.assertTrue(res != {1: 1.0, 2: 2.0}) - - def test__ne__invalid_type(self): - self.assertTrue(retworkx.random_layout(self.dag, seed=10244242) != ["a", None]) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - retworkx.random_layout(self.dag, seed=10244242) > {1: 1.0} - - def test_deepcopy(self): - positions = retworkx.random_layout(self.dag) - positions_copy = copy.deepcopy(positions) - self.assertEqual(positions_copy, positions) - - def test_pickle(self): - pos = retworkx.random_layout(self.dag) - pos_pickle = pickle.dumps(pos) - pos_copy = pickle.loads(pos_pickle) - self.assertEqual(pos, pos_copy) - - def test_str(self): - res = retworkx.random_layout(self.dag, seed=10244242) - self.assertEqual( - "Pos2DMapping{0: [0.4883489113112722, 0.6545867364101975]}", - str(res), - ) - - def test_hash(self): - res = retworkx.random_layout(self.dag, seed=10244242) - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_index_error(self): - res = retworkx.random_layout(self.dag, seed=10244242) - with self.assertRaises(IndexError): - res[42] - - def test_keys(self): - keys = retworkx.random_layout(self.dag, seed=10244242).keys() - self.assertEqual([0], list(keys)) - - def test_values(self): - values = retworkx.random_layout(self.dag, seed=10244242).values() - expected = [[0.4883489113112722, 0.6545867364101975]] - self.assertEqual(expected, list(values)) - - def test_items(self): - items = retworkx.random_layout(self.dag, seed=10244242).items() - self.assertEqual([(0, [0.4883489113112722, 0.6545867364101975])], list(items)) - - def test_iter(self): - mapping_iter = iter(retworkx.random_layout(self.dag, seed=10244242)) - output = list(mapping_iter) - self.assertEqual(output, [0]) - - def test_contains(self): - res = retworkx.random_layout(self.dag, seed=10244242) - self.assertIn(0, res) - - def test_not_contains(self): - res = retworkx.random_layout(self.dag, seed=10244242) - self.assertNotIn(1, res) - - -class TestEdgeIndices(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDiGraph() - self.dag.add_node("a") - self.dag.add_child(0, "b", "edge") - - def test__eq__match(self): - res = self.dag.edge_index_map() - self.assertTrue(res == {0: (0, 1, "edge")}) - - def test__eq__not_match_keys(self): - res = self.dag.edge_index_map() - self.assertFalse(res == {2: (0, 1, "edge")}) - - def test__eq__not_match_values(self): - res = self.dag.edge_index_map() - self.assertFalse(res == {0: (1, 2, "edge")}) - self.assertFalse(res == {0: (0, 1, "not edge")}) - - def test__eq__different_length(self): - res = self.dag.edge_index_map() - self.assertFalse(res == {1: (0, 1, "edge"), 0: (0, 1, "double edge")}) - - def test_eq__same_type(self): - self.assertEqual(self.dag.edge_index_map(), self.dag.edge_index_map()) - - def test__eq__invalid_type(self): - res = self.dag.edge_index_map() - self.assertFalse(res == {"a": ("a", "b", "c")}) - - def test__ne__match(self): - res = self.dag.edge_index_map() - self.assertFalse(res != {0: (0, 1, "edge")}) - - def test__ne__not_match(self): - res = self.dag.edge_index_map() - self.assertTrue(res, {2: (0, 1, "edge")}) - - def test__ne__not_match_values(self): - res = self.dag.edge_index_map() - self.assertTrue(res, {0: (0, 2, "edge")}) - - def test__ne__different_length(self): - res = self.dag.edge_index_map() - self.assertTrue(res != {1: (0, 1, "double edge"), 0: (0, 1, "edge")}) - - def test__ne__invalid_type(self): - res = self.dag.edge_index_map() - self.assertTrue(res != {"a": ("a", "b", "c")}) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.dag.edge_index_map() > {0: (0, 1, "edge")} - - def test_deepcopy(self): - edge_map = self.dag.edge_index_map() - edge_map_copy = copy.deepcopy(edge_map) - self.assertEqual(edge_map_copy, edge_map) - - def test_pickle(self): - edge_map = self.dag.edge_index_map() - edge_map_pickle = pickle.dumps(edge_map) - edge_map_copy = pickle.loads(edge_map_pickle) - self.assertEqual(edge_map, edge_map_copy) - - def test_str(self): - res = self.dag.edge_index_map() - self.assertEqual( - "EdgeIndexMap{0: (0, 1, edge)}", - str(res), - ) - - def test_hash(self): - res = self.dag.edge_index_map() - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_index_error(self): - res = self.dag.edge_index_map() - with self.assertRaises(IndexError): - res[42] - - def test_keys(self): - keys = self.dag.edge_index_map().keys() - self.assertEqual([0], list(keys)) - - def test_values(self): - values = self.dag.edge_index_map().values() - expected = [(0, 1, "edge")] - self.assertEqual(expected, list(values)) - - def test_items(self): - items = self.dag.edge_index_map().items() - self.assertEqual([(0, (0, 1, "edge"))], list(items)) - - def test_iter(self): - mapping_iter = iter(self.dag.edge_index_map()) - output = list(mapping_iter) - self.assertEqual(output, [0]) - - def test_contains(self): - res = self.dag.edge_index_map() - self.assertIn(0, res) - - def test_not_contains(self): - res = self.dag.edge_index_map() - self.assertNotIn(1, res) - - -class TestAllPairsPathMapping(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - node_a = self.dag.add_node("a") - self.dag.add_child(node_a, "b", "Edgy") - self.fn = lambda _: 1.0 - - def test__eq__match(self): - self.assertTrue( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) == {0: {1: [0, 1]}, 1: {}} - ) - - def test__eq__not_match_keys(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) == {2: {2: [0, 1]}, 1: {}} - ) - - def test__eq__not_match_values(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) == {0: {1: [0, 2]}, 1: {}} - ) - - def test__eq__different_length(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) == {1: [0, 1], 2: [0, 2]} - ) - - def test_eq__same_type(self): - self.assertEqual( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn), - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn), - ) - - def test__eq__invalid_type(self): - self.assertFalse(retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) == {"a": []}) - - def test__eq__invalid_inner_type(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) == {0: {1: None}} - ) - - def test__ne__match(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) != {0: {1: [0, 1]}, 1: {}} - ) - - def test__ne__not_match(self): - self.assertTrue( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) != {2: [0, 1]} - ) - - def test__ne__not_match_values(self): - self.assertTrue( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) != {1: [0, 2]} - ) - - def test__ne__different_length(self): - self.assertTrue( - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) != {1: [0, 1], 2: [0, 2]} - ) - - def test__ne__invalid_type(self): - self.assertTrue(retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) != {"a": {}}) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) > {1: [0, 2]} - - def test_deepcopy(self): - paths = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) - paths_copy = copy.deepcopy(paths) - self.assertEqual(paths, paths_copy) - - def test_pickle(self): - paths = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) - paths_pickle = pickle.dumps(paths) - paths_copy = pickle.loads(paths_pickle) - self.assertEqual(paths, paths_copy) - - def test_str(self): - res = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) - # Since run in parallel the order is not deterministic - expected_valid = [ - "AllPairsPathMapping{1: PathMapping{}, 0: PathMapping{1: [0, 1]}}", - "AllPairsPathMapping{0: PathMapping{1: [0, 1]}, 1: PathMapping{}}", - ] - self.assertIn(str(res), expected_valid) - - def test_hash(self): - res = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_index_error(self): - res = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) - with self.assertRaises(IndexError): - res[42] - - def test_keys(self): - keys = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn).keys() - self.assertEqual([0, 1], list(sorted(keys))) - - def test_values(self): - values = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn).values() - # Since run in parallel the order is not deterministic - expected_valid = [[{1: [0, 1]}, {}], [{}, {1: [0, 1]}]] - self.assertIn(list(values), expected_valid) - - def test_items(self): - items = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn).items() - # Since run in parallel the order is not deterministic - expected_valid = [ - [(0, {1: [0, 1]}), (1, {})], - [(1, {}), (0, {1: [0, 1]})], - ] - self.assertIn(list(items), expected_valid) - - def test_iter(self): - mapping_iter = iter(retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn)) - output = list(sorted(mapping_iter)) - self.assertEqual(output, [0, 1]) - - def test_contains(self): - res = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) - self.assertIn(1, res) - - def test_not_contains(self): - res = retworkx.all_pairs_dijkstra_shortest_paths(self.dag, self.fn) - self.assertNotIn(2, res) - - -class TestAllPairsPathLengthMapping(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - node_a = self.dag.add_node("a") - self.dag.add_child(node_a, "b", "Edgy") - self.fn = lambda _: 1.0 - - def test__eq__match(self): - self.assertTrue( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) == {0: {1: 1.0}, 1: {}} - ) - - def test__eq__not_match_keys(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) == {1: {2: 1.0}} - ) - - def test__eq__not_match_values(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) == {0: {2: 2.0}} - ) - - def test__eq__different_length(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) == {0: {1: 1.0, 2: 2.0}} - ) - - def test_eq__same_type(self): - self.assertEqual( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn), - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn), - ) - - def test__eq__invalid_type(self): - self.assertFalse(retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) == {"a": 2}) - - def test__eq__invalid_inner_type(self): - self.assertFalse(retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) == {0: "a"}) - - def test__ne__match(self): - self.assertFalse( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) != {0: {1: 1.0}, 1: {}} - ) - - def test__ne__not_match(self): - self.assertTrue( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) != {0: {2: 1.0}} - ) - - def test__ne__not_match_values(self): - self.assertTrue( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) != {0: {1: 2.0}} - ) - - def test__ne__different_length(self): - self.assertTrue( - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) - != {0: {1: 1.0}, 2: {1: 2.0}} - ) - - def test__ne__invalid_type(self): - self.assertTrue(retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) != {1: []}) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) > {1: 1.0} - - def test_deepcopy(self): - paths = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) - paths_copy = copy.deepcopy(paths) - self.assertEqual(paths, paths_copy) - - def test_pickle(self): - paths = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) - paths_pickle = pickle.dumps(paths) - paths_copy = pickle.loads(paths_pickle) - self.assertEqual(paths, paths_copy) - - def test_str(self): - res = retworkx.all_pairs_dijkstra_path_lengths(self.dag, lambda _: 3.14) - # Since all_pairs_dijkstra_path_lengths() is parallel the order of the - # output is non-determinisitic - valid_values = [ - "AllPairsPathLengthMapping{1: PathLengthMapping{}, " "0: PathLengthMapping{1: 3.14}}", - "AllPairsPathLengthMapping{" - "0: PathLengthMapping{1: 3.14}, " - "1: PathLengthMapping{}}", - ] - self.assertIn(str(res), valid_values) - - def test_hash(self): - res = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_index_error(self): - res = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) - with self.assertRaises(IndexError): - res[42] - - def test_keys(self): - keys = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn).keys() - self.assertEqual([0, 1], list(sorted((keys)))) - - def test_values(self): - values = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn).values() - # Since run in parallel the order is not deterministic - valid_expected = [[{}, {1: 1.0}], [{1: 1.0}, {}]] - self.assertIn(list(values), valid_expected) - - def test_items(self): - items = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn).items() - # Since run in parallel the order is not deterministic - valid_expected = [[(0, {1: 1.0}), (1, {})], [(1, {}), (0, {1: 1.0})]] - self.assertIn(list(items), valid_expected) - - def test_iter(self): - mapping_iter = iter(retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn)) - output = list(sorted(mapping_iter)) - self.assertEqual(output, [0, 1]) - - def test_contains(self): - res = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) - self.assertIn(0, res) - - def test_not_contains(self): - res = retworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn) - self.assertNotIn(2, res) - - -class TestNodeMap(unittest.TestCase): - def setUp(self): - self.dag = retworkx.PyDAG() - self.dag.add_node("a") - self.in_dag = retworkx.generators.directed_path_graph(1) - - def test__eq__match(self): - self.assertTrue( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) == {0: 1} - ) - - def test__eq__not_match_keys(self): - self.assertFalse( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) == {2: 1} - ) - - def test__eq__not_match_values(self): - self.assertFalse( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) == {0: 2} - ) - - def test__eq__different_length(self): - self.assertFalse( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - == {0: 1, 1: 2} - ) - - def test_eq__same_type(self): - res = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - self.assertEqual(res, res) - - def test__ne__match(self): - self.assertFalse( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) != {0: 1} - ) - - def test__ne__not_match(self): - self.assertTrue( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) != {2: 2} - ) - - def test__ne__not_match_values(self): - self.assertTrue( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) != {0: 2} - ) - - def test__ne__different_length(self): - self.assertTrue( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - != {0: 1, 1: 2} - ) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) > {1: 2} - - def test__len__(self): - in_dag = retworkx.generators.directed_grid_graph(5, 5) - node_map = self.dag.substitute_node_with_subgraph(0, in_dag, lambda *args: None) - self.assertEqual(25, len(node_map)) - - def test_deepcopy(self): - node_map = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - node_map_copy = copy.deepcopy(node_map) - self.assertEqual(node_map, node_map_copy) - - def test_pickle(self): - node_map = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - node_map_pickle = pickle.dumps(node_map) - node_map_copy = pickle.loads(node_map_pickle) - self.assertEqual(node_map, node_map_copy) - - def test_str(self): - res = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - self.assertEqual("NodeMap{0: 1}", str(res)) - - def test_hash(self): - res = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - hash_res = hash(res) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(res)) - - def test_index_error(self): - res = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - with self.assertRaises(IndexError): - res[42] - - def test_keys(self): - keys = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None).keys() - self.assertEqual([0], list(keys)) - - def test_values(self): - values = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None).values() - self.assertEqual([1], list(values)) - - def test_items(self): - items = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None).items() - self.assertEqual([(0, 1)], list(items)) - - def test_iter(self): - mapping_iter = iter( - self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - ) - output = list(mapping_iter) - self.assertEqual(output, [0]) - - def test_contains(self): - res = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - self.assertIn(0, res) - - def test_not_contains(self): - res = self.dag.substitute_node_with_subgraph(0, self.in_dag, lambda *args: None) - self.assertNotIn(2, res) - - def test_iter_stable_for_same_obj(self): - graph = retworkx.PyDiGraph() - graph.add_node(0) - in_graph = retworkx.generators.directed_path_graph(5) - res = self.dag.substitute_node_with_subgraph(0, in_graph, lambda *args: None) - first_iter = list(iter(res)) - second_iter = list(iter(res)) - third_iter = list(iter(res)) - self.assertEqual(first_iter, second_iter) - self.assertEqual(first_iter, third_iter) - - -class TestChainsComparisons(unittest.TestCase): - def setUp(self): - self.graph = retworkx.generators.cycle_graph(3) - self.chains = retworkx.chain_decomposition(self.graph) - - def test__eq__match(self): - self.assertTrue(self.chains == [[(0, 2), (2, 1), (1, 0)]]) - - def test__eq__not_match(self): - self.assertFalse(self.chains == [[(0, 2), (2, 1), (2, 0)]]) - - def test__eq__different_length(self): - self.assertFalse(self.chains == [[(0, 2)]]) - - def test__eq__invalid_type(self): - with self.assertRaises(TypeError): - self.chains == [0] - - def test__ne__match(self): - self.assertFalse(self.chains != [[(0, 2), (2, 1), (1, 0)]]) - - def test__ne__not_match(self): - self.assertTrue(self.chains != [[(0, 2), (2, 1), (2, 0)]]) - - def test__ne__different_length(self): - self.assertTrue(self.chains != [[(0, 2)]]) - - def test__ne__invalid_type(self): - with self.assertRaises(TypeError): - self.chains != [0] - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.chains > [[(0, 2)]] - - def test_deepcopy(self): - chains_copy = copy.deepcopy(self.chains) - self.assertEqual(self.chains, chains_copy) - - def test_pickle(self): - chains_pickle = pickle.dumps(self.chains) - chains_copy = pickle.loads(chains_pickle) - self.assertEqual(self.chains, chains_copy) - - def test_str(self): - self.assertEqual("Chains[EdgeList[(0, 2), (2, 1), (1, 0)]]", str(self.chains)) - - def test_hash(self): - hash_res = hash(self.chains) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(self.chains)) - - def test_numpy_conversion(self): - # this test assumes the array is 1-dimensional which avoids issues with jagged arrays - self.assertTrue(np.asarray(self.chains).shape, (1,)) - - -class TestProductNodeMap(unittest.TestCase): - def setUp(self): - self.first = retworkx.PyGraph() - self.first.add_node("a0") - self.first.add_node("a1") - - self.second = retworkx.PyGraph() - self.second.add_node("b") - _, self.node_map = retworkx.graph_cartesian_product(self.first, self.second) - - def test__eq__match(self): - self.assertTrue(self.node_map == {(0, 0): 0, (1, 0): 1}) - - def test__eq__not_match_keys(self): - self.assertFalse(self.node_map == {(0, 0): 0, (2, 0): 1}) - - def test__eq__not_match_values(self): - self.assertFalse(self.node_map == {(0, 0): 0, (1, 0): 2}) - - def test__eq__different_length(self): - self.assertFalse(self.node_map == {(0, 0): 0}) - - def test_eq__same_type(self): - _, res = retworkx.graph_cartesian_product(self.first, self.second) - self.assertEqual(self.node_map, res) - - def test__ne__match(self): - self.assertFalse(self.node_map != {(0, 0): 0, (1, 0): 1}) - - def test__ne__not_match(self): - self.assertTrue(self.node_map != {(0, 0): 0, (2, 0): 1}) - - def test__ne__not_match_values(self): - self.assertTrue(self.node_map != {(0, 0): 0, (1, 0): 2}) - - def test__ne__different_length(self): - self.assertTrue(self.node_map != {(0, 0): 0}) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.node_map > {1: 2} - - def test__len__(self): - self.assertEqual(2, len(self.node_map)) - - def test_deepcopy(self): - node_map_copy = copy.deepcopy(self.node_map) - self.assertEqual(self.node_map, node_map_copy) - - def test_pickle(self): - node_map_pickle = pickle.dumps(self.node_map) - node_map_copy = pickle.loads(node_map_pickle) - self.assertEqual(self.node_map, node_map_copy) - - def test_str(self): - valid_str_output = [ - "ProductNodeMap{(0, 0): 0, (1, 0): 1}", - "ProductNodeMap{(1, 0): 1, (0, 0): 0}", - ] - self.assertTrue(str(self.node_map) in valid_str_output) - - def test_hash(self): - hash_res = hash(self.node_map) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(self.node_map)) - - def test_index_error(self): - with self.assertRaises(IndexError): - self.node_map[(1, 1)] - - def test_keys(self): - keys = self.node_map.keys() - self.assertEqual(set([(0, 0), (1, 0)]), set(keys)) - - def test_values(self): - values = self.node_map.values() - self.assertEqual(set([0, 1]), set(values)) - - def test_items(self): - items = self.node_map.items() - self.assertEqual(set([((0, 0), 0), ((1, 0), 1)]), set(items)) - - def test_iter(self): - mapping_iter = iter(self.node_map) - output = set(mapping_iter) - self.assertEqual(output, set([(0, 0), (1, 0)])) - - def test_contains(self): - self.assertIn((0, 0), self.node_map) - - def test_not_contains(self): - self.assertNotIn((1, 1), self.node_map) - - -class TestBiconnectedComponentsMap(unittest.TestCase): - def setUp(self): - self.graph = retworkx.generators.path_graph(3) - self.bicon_map = retworkx.biconnected_components(self.graph) - - def test__eq__match(self): - self.assertTrue(self.bicon_map == {(0, 1): 1, (1, 2): 0}) - - def test__eq__not_match_keys(self): - self.assertFalse(self.bicon_map == {(0, 0): 1, (2, 0): 0}) - - def test__eq__not_match_values(self): - self.assertFalse(self.bicon_map == {(0, 1): 2, (1, 2): 0}) - - def test__eq__different_length(self): - self.assertFalse(self.bicon_map == {(0, 1): 1}) - - def test_eq__same_type(self): - res = retworkx.biconnected_components(self.graph) - self.assertEqual(self.bicon_map, res) - - def test__ne__match(self): - self.assertFalse(self.bicon_map != {(0, 1): 1, (1, 2): 0}) - - def test__ne__not_match(self): - self.assertTrue(self.bicon_map != {(0, 2): 1, (1, 2): 0}) - - def test__ne__not_match_values(self): - self.assertTrue(self.bicon_map != {(0, 1): 0, (1, 2): 0}) - - def test__ne__different_length(self): - self.assertTrue(self.bicon_map != {(0, 1): 1}) - - def test__gt__not_implemented(self): - with self.assertRaises(NotImplementedError): - self.bicon_map > {1: 2} - - def test__len__(self): - self.assertEqual(2, len(self.bicon_map)) - - def test_deepcopy(self): - bicon_map_copy = copy.deepcopy(self.bicon_map) - self.assertEqual(self.bicon_map, bicon_map_copy) - - def test_pickle(self): - bicon_map_pickle = pickle.dumps(self.bicon_map) - bicon_map_copy = pickle.loads(bicon_map_pickle) - self.assertEqual(self.bicon_map, bicon_map_copy) - - def test_str(self): - valid_str_output = [ - "BiconnectedComponents{(0, 1): 1, (1, 2): 0}", - "BiconnectedComponents{(1, 2): 0, (0, 1): 1}", - ] - self.assertTrue(str(self.bicon_map) in valid_str_output) - - def test_hash(self): - hash_res = hash(self.bicon_map) - self.assertIsInstance(hash_res, int) - # Assert hash is stable - self.assertEqual(hash_res, hash(self.bicon_map)) - - def test_index_error(self): - with self.assertRaises(IndexError): - self.bicon_map[(1, 1)] - - def test_keys(self): - keys = self.bicon_map.keys() - self.assertEqual(set([(0, 1), (1, 2)]), set(keys)) - - def test_values(self): - values = self.bicon_map.values() - self.assertEqual(set([0, 1]), set(values)) - - def test_items(self): - items = self.bicon_map.items() - self.assertEqual(set([((0, 1), 1), ((1, 2), 0)]), set(items)) - - def test_iter(self): - mapping_iter = iter(self.bicon_map) - output = set(mapping_iter) - self.assertEqual(output, set([(0, 1), (1, 2)])) - - def test_contains(self): - self.assertIn((0, 1), self.bicon_map) - - def test_not_contains(self): - self.assertNotIn((0, 2), self.bicon_map) diff --git a/tests/retworkx_backwards_compat/test_dispatch.py b/tests/retworkx_backwards_compat/test_dispatch.py deleted file mode 100644 index 5bdc83e55..000000000 --- a/tests/retworkx_backwards_compat/test_dispatch.py +++ /dev/null @@ -1,111 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest -import retworkx - -import numpy - - -class TestDispatchPyGraph(unittest.TestCase): - - class_type = "PyGraph" - - def setUp(self): - super().setUp() - if self.class_type == "PyGraph": - self.graph = retworkx.undirected_gnp_random_graph(10, 0.5, seed=42) - else: - self.graph = retworkx.directed_gnp_random_graph(10, 0.5, seed=42) - - def test_distance_matrix(self): - res = retworkx.distance_matrix(self.graph) - self.assertIsInstance(res, numpy.ndarray) - - def test_distance_matrix_as_undirected(self): - if self.class_type == "PyGraph": - with self.assertRaises(TypeError): - retworkx.distance_matrix(self.graph, as_undirected=True) - else: - res = retworkx.distance_matrix(self.graph, as_undirected=True) - self.assertIsInstance(res, numpy.ndarray) - - def test_adjacency_matrix(self): - res = retworkx.adjacency_matrix(self.graph) - self.assertIsInstance(res, numpy.ndarray) - - def test_all_simple_paths(self): - res = retworkx.all_simple_paths(self.graph, 0, 1) - self.assertIsInstance(res, list) - - def test_floyd_warshall(self): - res = retworkx.floyd_warshall(self.graph) - self.assertIsInstance(res, retworkx.AllPairsPathLengthMapping) - - def test_floyd_warshall_numpy(self): - res = retworkx.floyd_warshall_numpy(self.graph) - self.assertIsInstance(res, numpy.ndarray) - - if self.class_type == "PyGraph": - expected_res = retworkx.graph_floyd_warshall_numpy(self.graph) - else: - expected_res = retworkx.digraph_floyd_warshall_numpy(self.graph) - - self.assertTrue(numpy.array_equal(expected_res, res)) - - def test_astar_shortest_path(self): - res = retworkx.astar_shortest_path(self.graph, 0, lambda _: True, lambda _: 1, lambda _: 1) - self.assertIsInstance(list(res), list) - - def test_dijkstra_shortest_paths(self): - res = retworkx.dijkstra_shortest_paths(self.graph, 0) - self.assertIsInstance(res, retworkx.PathMapping) - - def test_dijkstra_shortest_path_lengths(self): - res = retworkx.dijkstra_shortest_path_lengths(self.graph, 0, lambda _: 1) - self.assertIsInstance(res, retworkx.PathLengthMapping) - - def test_k_shortest_path_lengths(self): - res = retworkx.k_shortest_path_lengths(self.graph, 0, 2, lambda _: 1) - self.assertIsInstance(res, retworkx.PathLengthMapping) - - def test_dfs_edges(self): - res = retworkx.dfs_edges(self.graph, 0) - self.assertIsInstance(list(res), list) - - def test_all_pairs_dijkstra_shortest_paths(self): - res = retworkx.all_pairs_dijkstra_shortest_paths(self.graph, lambda _: 1) - self.assertIsInstance(res, retworkx.AllPairsPathMapping) - - def test_all_pairs_dijkstra_path_lengthss(self): - res = retworkx.all_pairs_dijkstra_path_lengths(self.graph, lambda _: 1) - self.assertIsInstance(res, retworkx.AllPairsPathLengthMapping) - - def test_is_isomorphic_nodes_incompatible_raises(self): - with self.assertRaises(TypeError): - if self.class_type == "PyGraph": - retworkx.is_isomorphic(self.graph, retworkx.PyDiGraph()) - else: - retworkx.is_isomorphic(self.graph, retworkx.PyGraph()) - - def test_betweenness_centrality(self): - res = retworkx.betweenness_centrality(self.graph) - self.assertIsInstance(res, retworkx.CentralityMapping) - - def test_closeness_centrality(self): - res = retworkx.closeness_centrality(self.graph) - self.assertIsInstance(res, retworkx.CentralityMapping) - - -class TestDispatchPyDiGraph(TestDispatchPyGraph): - - class_type = "PyDiGraph" diff --git a/tests/retworkx_backwards_compat/test_graphml.py b/tests/retworkx_backwards_compat/test_graphml.py deleted file mode 100644 index 1750d68c7..000000000 --- a/tests/retworkx_backwards_compat/test_graphml.py +++ /dev/null @@ -1,512 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest -import tempfile -import numpy - -import retworkx - - -class TestGraphML(unittest.TestCase): - HEADER = """ - - - {} - - """ - - def assertDictPayloadEqual(self, xs, ys): - self.assertEqual(len(xs), len(ys)) - for key, va in xs.items(): - vb = ys.get(key, None) - self.assertTrue( - (isinstance(va, float) and isinstance(vb, float) and numpy.allclose(va, vb)) - or (va == vb) - ) - - def assertGraphEqual(self, graph, nodes, edges, directed=True, attrs={}): - self.assertTrue(isinstance(graph, retworkx.PyDiGraph if directed else retworkx.PyGraph)) - self.assertEqual(len(graph), len(nodes)) - self.assertEqual(graph.attrs, attrs) - for node_a, node_b in zip(graph.nodes(), nodes): - self.assertDictPayloadEqual(node_a, node_b) - - for ((s, t, data), edge) in zip(graph.weighted_edge_list(), edges): - self.assertEqual((graph[s]["id"], graph[t]["id"]), (edge[0], edge[1])) - self.assertDictPayloadEqual(data, edge[2]) - - def assertGraphMLRaises(self, graph_xml): - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - with self.assertRaises(Exception): - retworkx.read_graphml(fd.name) - - def test_simple(self): - graph_xml = self.HEADER.format( - """ - - yellow - - - 0.95 - - - - blue - - - - green - - - 0.98 - - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [ - {"id": "n0", "color": "blue"}, - {"id": "n1", "color": "yellow"}, - {"id": "n2", "color": "green"}, - ] - edges = [ - ("n0", "n1", {"fidelity": 0.98}), - ("n0", "n2", {"fidelity": 0.95}), - ] - self.assertGraphEqual(graph, nodes, edges, directed=False) - - def test_multiple_graphs_in_single_file(self): - graph_xml = self.HEADER.format( - """ - - yellow - - - 0.95 - - - - blue - - - - 0.98 - - - - - red - - - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - self.assertEqual(len(graphml), 2) - graph = graphml[0] - nodes = [ - {"id": "n0", "color": "blue"}, - {"id": "n1", "color": "yellow"}, - ] - edges = [ - ("n0", "n1", {"id": "e01", "fidelity": 0.98}), - ] - self.assertGraphEqual(graph, nodes, edges, directed=False) - graph = graphml[1] - nodes = [ - {"id": "n0", "color": "red"}, - {"id": "n1", "color": "yellow"}, - ] - edges = [ - ("n0", "n1", {"id": "e01", "fidelity": 0.95}), - ] - self.assertGraphEqual(graph, nodes, edges, directed=True) - - def test_key_for_graph(self): - graph_xml = self.HEADER.format( - """ - - - true - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [{"id": "n0"}] - edges = [] - self.assertGraphEqual(graph, nodes, edges, directed=True, attrs={"test": True}) - - def test_key_for_all(self): - graph_xml = self.HEADER.format( - """ - - - I'm a graph. - - I'm a node. - - - I'm a node. - - - I'm an edge. - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [ - {"id": "n0", "test": "I'm a node."}, - {"id": "n1", "test": "I'm a node."}, - ] - edges = [("n0", "n1", {"test": "I'm an edge."})] - self.assertGraphEqual( - graph, nodes, edges, directed=True, attrs={"test": "I'm a graph."} - ) - - def test_key_default_undefined(self): - graph_xml = self.HEADER.format( - """ - - - - true - - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [ - {"id": "n0", "test": True}, - {"id": "n1", "test": None}, - ] - edges = [] - self.assertGraphEqual(graph, nodes, edges, directed=True) - - def test_bool(self): - graph_xml = self.HEADER.format( - """ - - false - - - - true - - - - false - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [ - {"id": "n0", "test": True}, - {"id": "n1", "test": False}, - {"id": "n2", "test": False}, - ] - edges = [] - self.assertGraphEqual(graph, nodes, edges, directed=True) - - def test_int(self): - graph_xml = self.HEADER.format( - """ - - 42 - - - - 8 - - - - 42 - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [ - {"id": "n0", "test": 8}, - {"id": "n1", "test": 42}, - {"id": "n2", "test": 42}, - ] - edges = [] - self.assertGraphEqual(graph, nodes, edges, directed=True) - - def test_float(self): - graph_xml = self.HEADER.format( - """ - - 4.2 - - - - 1.8 - - - - 4.2 - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [ - {"id": "n0", "test": 1.8}, - {"id": "n1", "test": 4.2}, - {"id": "n2", "test": 4.2}, - ] - edges = [] - self.assertGraphEqual(graph, nodes, edges, directed=True) - - def test_double(self): - graph_xml = self.HEADER.format( - """ - - 4.2 - - - - 1.8 - - - - 4.2 - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [ - {"id": "n0", "test": 1.8}, - {"id": "n1", "test": 4.2}, - {"id": "n2", "test": 4.2}, - ] - edges = [] - self.assertGraphEqual(graph, nodes, edges, directed=True) - - def test_string(self): - graph_xml = self.HEADER.format( - """ - - yellow - - - - blue - - - - yellow - - - """ - ) - - with tempfile.NamedTemporaryFile("wt") as fd: - fd.write(graph_xml) - fd.flush() - graphml = retworkx.read_graphml(fd.name) - graph = graphml[0] - nodes = [ - {"id": "n0", "test": "blue"}, - {"id": "n1", "test": "yellow"}, - {"id": "n2", "test": "yellow"}, - ] - edges = [] - self.assertGraphEqual(graph, nodes, edges, directed=True) - - def test_convert_error(self): - graph_xml = self.HEADER.format( - """ - - blah - - """ - ) - - for type in ["boolean", "int", "float", "double"]: - self.assertGraphMLRaises(graph_xml=graph_xml.format(type)) - - def test_invalid_xml(self): - graph_xml = self.HEADER.format( - """ - - - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_invalid_edgedefault(self): - graph_xml = self.HEADER.format( - """ - - - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_missing_node_id(self): - graph_xml = self.HEADER.format( - """ - - - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_missing_key_for_node(self): - graph_xml = self.HEADER.format( - """ - - - - blue - - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_invalid_key_type(self): - graph_xml = self.HEADER.format( - """ - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_unsupported_key_domain(self): - graph_xml = self.HEADER.format( - """ - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_unsupported_nested_graphs(self): - graph_xml = self.HEADER.format( - """ - - - - - - - - - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_unsupported_hyperedges(self): - graph_xml = self.HEADER.format( - """ - - - - - - - - - - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_unsupported_ports(self): - graph_xml = self.HEADER.format( - """ - - - - - - """ - ) - self.assertGraphMLRaises(graph_xml) - - def test_unsupported_nested_ports(self): - graph_xml = self.HEADER.format( - """ - - - - - - - - """ - ) - self.assertGraphMLRaises(graph_xml) diff --git a/tests/retworkx_backwards_compat/test_random.py b/tests/retworkx_backwards_compat/test_random.py deleted file mode 100644 index 67a60760c..000000000 --- a/tests/retworkx_backwards_compat/test_random.py +++ /dev/null @@ -1,222 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import unittest -import random - -import retworkx - - -class TestGNPRandomGraph(unittest.TestCase): - def test_random_gnp_directed(self): - graph = retworkx.directed_gnp_random_graph(20, 0.5, seed=10) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 104) - - def test_random_gnp_directed_empty_graph(self): - graph = retworkx.directed_gnp_random_graph(20, 0) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 0) - - def test_random_gnp_directed_complete_graph(self): - graph = retworkx.directed_gnp_random_graph(20, 1) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 20 * (20 - 1)) - - def test_random_gnp_directed_invalid_num_nodes(self): - with self.assertRaises(ValueError): - retworkx.directed_gnp_random_graph(0, 0.5) - - def test_random_gnp_directed_invalid_probability(self): - with self.assertRaises(ValueError): - retworkx.directed_gnp_random_graph(23, 123.5) - - def test_random_gnp_undirected(self): - graph = retworkx.undirected_gnp_random_graph(20, 0.5, seed=10) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 105) - - def test_random_gnp_undirected_empty_graph(self): - graph = retworkx.undirected_gnp_random_graph(20, 0) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 0) - - def test_random_gnp_undirected_complete_graph(self): - graph = retworkx.undirected_gnp_random_graph(20, 1) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 20 * (20 - 1) / 2) - - def test_random_gnp_undirected_invalid_num_nodes(self): - with self.assertRaises(ValueError): - retworkx.undirected_gnp_random_graph(0, 0.5) - - def test_random_gnp_undirected_invalid_probability(self): - with self.assertRaises(ValueError): - retworkx.undirected_gnp_random_graph(23, 123.5) - - -class TestGNMRandomGraph(unittest.TestCase): - def test_random_gnm_directed(self): - graph = retworkx.directed_gnm_random_graph(20, 100) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 100) - # with other arguments equal, same seed results in same graph - graph_s1 = retworkx.directed_gnm_random_graph(20, 100, seed=10) - graph_s2 = retworkx.directed_gnm_random_graph(20, 100, seed=10) - self.assertEqual(graph_s1.edge_list(), graph_s2.edge_list()) - - def test_random_gnm_directed_empty_graph(self): - graph = retworkx.directed_gnm_random_graph(20, 0) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 0) - # passing a seed when passing zero edges has no effect - graph = retworkx.directed_gnm_random_graph(20, 0, 44) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 0) - - def test_random_gnm_directed_complete_graph(self): - n = 20 - max_m = n * (n - 1) - # passing the max edges for the passed number of nodes - graph = retworkx.directed_gnm_random_graph(n, max_m) - self.assertEqual(len(graph), n) - self.assertEqual(len(graph.edges()), max_m) - # passing m > the max edges n(n-1) still returns the max edges - graph = retworkx.directed_gnm_random_graph(n, max_m + 1) - self.assertEqual(len(graph), n) - self.assertEqual(len(graph.edges()), max_m) - # passing a seed when passing max edges has no effect - graph = retworkx.directed_gnm_random_graph(n, max_m, 55) - self.assertEqual(len(graph), n) - self.assertEqual(len(graph.edges()), max_m) - - def test_random_gnm_directed_invalid_num_nodes(self): - with self.assertRaises(ValueError): - retworkx.directed_gnm_random_graph(0, 5) - - def test_random_gnm_directed_invalid_num_edges(self): - with self.assertRaises(OverflowError): - retworkx.directed_gnm_random_graph(23, -5) - - def test_random_gnm_undirected(self): - graph = retworkx.undirected_gnm_random_graph(20, 100) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 100) - # with other arguments equal, same seed results in same graph - graph_s1 = retworkx.undirected_gnm_random_graph(20, 100, seed=10) - graph_s2 = retworkx.undirected_gnm_random_graph(20, 100, seed=10) - self.assertEqual(graph_s1.edge_list(), graph_s2.edge_list()) - - def test_random_gnm_undirected_empty_graph(self): - graph = retworkx.undirected_gnm_random_graph(20, 0) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 0) - # passing a seed when passing zero edges has no effect - graph = retworkx.undirected_gnm_random_graph(20, 0, 44) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 0) - - def test_random_gnm_undirected_complete_graph(self): - n = 20 - max_m = n * (n - 1) // 2 - # passing the max edges for the passed number of nodes - graph = retworkx.undirected_gnm_random_graph(n, max_m) - self.assertEqual(len(graph), n) - self.assertEqual(len(graph.edges()), max_m) - # passing m > the max edges n(n-1)/2 still returns the max edges - graph = retworkx.undirected_gnm_random_graph(n, max_m + 1) - self.assertEqual(len(graph), n) - self.assertEqual(len(graph.edges()), max_m) - # passing a seed when passing max edges has no effect - graph = retworkx.undirected_gnm_random_graph(n, max_m, 55) - self.assertEqual(len(graph), n) - self.assertEqual(len(graph.edges()), max_m) - - def test_random_gnm_undirected_invalid_num_nodes(self): - with self.assertRaises(ValueError): - retworkx.undirected_gnm_random_graph(0, 5) - - def test_random_gnm_undirected_invalid_num_edges(self): - with self.assertRaises(OverflowError): - retworkx.undirected_gnm_random_graph(23, -5) - - -class TestGeometricRandomGraph(unittest.TestCase): - def test_random_geometric_empty(self): - graph = retworkx.random_geometric_graph(20, 0) - self.assertEqual(len(graph), 20) - self.assertEqual(len(graph.edges()), 0) - - def test_random_geometric_complete(self): - r = 1.42 # > sqrt(2) - graph = retworkx.random_geometric_graph(10, r) - self.assertEqual(len(graph), 10) - self.assertEqual(len(graph.edges()), 45) - - def test_random_geometric_same_seed(self): - # with other arguments equal, same seed results in same graph - graph_s1 = retworkx.random_geometric_graph(20, 0.5, seed=10) - graph_s2 = retworkx.random_geometric_graph(20, 0.5, seed=10) - self.assertEqual(graph_s1.edge_list(), graph_s2.edge_list()) - - def test_random_geometric_dim(self): - graph = retworkx.random_geometric_graph(10, 0.5, dim=3) - self.assertEqual(len(graph[0]["pos"]), 3) - - def test_random_geometric_pos(self): - pos = [[0.1, 0.1], [0.2, 0.2], [0.3, 0.3]] - graph = retworkx.random_geometric_graph(3, 0.15, pos=pos) - self.assertEqual(set(graph.edge_list()), {(0, 1), (1, 2)}) - for i in range(3): - self.assertEqual(graph[i]["pos"], pos[i]) - - def test_random_geometric_pos_1norm(self): - pos = [[0.1, 0.1], [0.2, 0.2], [0.3, 0.3]] - graph = retworkx.random_geometric_graph(3, 0.21, pos=pos, p=1.0) - self.assertEqual(set(graph.edge_list()), {(0, 1), (1, 2)}) - - def test_random_geometric_pos_inf_norm(self): - pos = [[0.1, 0.1], [0.2, 0.2], [0.3, 0.3]] - graph = retworkx.random_geometric_graph(3, 0.11, pos=pos, p=float("inf")) - self.assertEqual(set(graph.edge_list()), {(0, 1), (1, 2)}) - - def test_random_geometric_num_nodes_invalid(self): - with self.assertRaises(ValueError): - retworkx.random_geometric_graph(0, 1.0) - - def test_random_geometric_pos_num_nodes_incomp(self): - with self.assertRaises(ValueError): - retworkx.random_geometric_graph(3, 0.15, pos=[[0.5, 0.5]]) - - -class TestRandomSubGraphIsomorphism(unittest.TestCase): - def test_random_gnm_induced_subgraph_isomorphism(self): - graph = retworkx.undirected_gnm_random_graph(50, 150) - nodes = random.sample(range(50), 25) - subgraph = graph.subgraph(nodes) - - self.assertTrue( - retworkx.is_subgraph_isomorphic(graph, subgraph, id_order=True, induced=True) - ) - - def test_random_gnm_non_induced_subgraph_isomorphism(self): - graph = retworkx.undirected_gnm_random_graph(50, 150) - nodes = random.sample(range(50), 25) - subgraph = graph.subgraph(nodes) - - indexes = list(subgraph.edge_indices()) - for idx in random.sample(indexes, len(indexes) // 2): - subgraph.remove_edge_from_index(idx) - - self.assertTrue( - retworkx.is_subgraph_isomorphic(graph, subgraph, id_order=True, induced=False) - ) diff --git a/tests/retworkx_backwards_compat/visualization/__init__.py b/tests/retworkx_backwards_compat/visualization/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/retworkx_backwards_compat/visualization/test_graphviz.py b/tests/retworkx_backwards_compat/visualization/test_graphviz.py deleted file mode 100644 index 5d9039537..000000000 --- a/tests/retworkx_backwards_compat/visualization/test_graphviz.py +++ /dev/null @@ -1,152 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import subprocess -import tempfile -import unittest - -import retworkx -from retworkx.visualization import graphviz_draw - -try: - import PIL - - subprocess.run( - ["dot", "-V"], - cwd=tempfile.gettempdir(), - check=True, - capture_output=True, - ) - HAS_PILLOW = True -except Exception: - HAS_PILLOW = False - -SAVE_IMAGES = os.getenv("RUSTWORKX_TEST_PRESERVE_IMAGES", None) - - -def _save_image(image, path): - if SAVE_IMAGES: - image.save(path) - - -@unittest.skipUnless(HAS_PILLOW, "pillow and graphviz are required for running these tests") -class TestGraphvizDraw(unittest.TestCase): - def test_draw_no_args(self): - graph = retworkx.generators.star_graph(24) - image = graphviz_draw(graph) - self.assertIsInstance(image, PIL.Image.Image) - _save_image(image, "test_graphviz_draw.png") - - def test_draw_node_attr_fn(self): - graph = retworkx.PyGraph() - graph.add_node( - { - "color": "black", - "fillcolor": "green", - "label": "a", - "style": "filled", - } - ) - graph.add_node( - { - "color": "black", - "fillcolor": "red", - "label": "a", - "style": "filled", - } - ) - graph.add_edge(0, 1, dict(label="1", name="1")) - image = graphviz_draw(graph, lambda node: node) - self.assertIsInstance(image, PIL.Image.Image) - _save_image(image, "test_graphviz_draw_node_attr.png") - - def test_draw_edge_attr_fn(self): - graph = retworkx.PyGraph() - graph.add_node( - { - "color": "black", - "fillcolor": "green", - "label": "a", - "style": "filled", - } - ) - graph.add_node( - { - "color": "black", - "fillcolor": "red", - "label": "a", - "style": "filled", - } - ) - graph.add_edge(0, 1, dict(label="1", name="1")) - image = graphviz_draw(graph, lambda node: node, lambda edge: edge) - self.assertIsInstance(image, PIL.Image.Image) - _save_image(image, "test_graphviz_draw_edge_attr.png") - - def test_draw_graph_attr(self): - graph = retworkx.PyGraph() - graph.add_node( - { - "color": "black", - "fillcolor": "green", - "label": "a", - "style": "filled", - } - ) - graph.add_node( - { - "color": "black", - "fillcolor": "red", - "label": "a", - "style": "filled", - } - ) - graph.add_edge(0, 1, dict(label="1", name="1")) - graph_attr = {"bgcolor": "red"} - image = graphviz_draw(graph, lambda node: node, lambda edge: edge, graph_attr) - self.assertIsInstance(image, PIL.Image.Image) - _save_image(image, "test_graphviz_draw_graph_attr.png") - - def test_image_type(self): - graph = retworkx.directed_gnp_random_graph(50, 0.8) - image = graphviz_draw(graph, image_type="jpg") - self.assertIsInstance(image, PIL.Image.Image) - _save_image(image, "test_graphviz_draw_image_type.jpg") - - def test_image_type_invalid_type(self): - graph = retworkx.directed_gnp_random_graph(50, 0.8) - with self.assertRaises(ValueError): - graphviz_draw(graph, image_type="raw") - - def test_method(self): - graph = retworkx.directed_gnp_random_graph(50, 0.8) - image = graphviz_draw(graph, method="sfdp") - self.assertIsInstance(image, PIL.Image.Image) - _save_image(image, "test_graphviz_method.png") - - def test_method_invalid_method(self): - graph = retworkx.directed_gnp_random_graph(50, 0.8) - with self.assertRaises(ValueError): - graphviz_draw(graph, method="special") - - def test_filename(self): - graph = retworkx.generators.grid_graph(20, 20) - graphviz_draw( - graph, - filename="test_graphviz_filename.svg", - image_type="svg", - method="neato", - ) - self.assertTrue(os.path.isfile("test_graphviz_filename.svg")) - if not SAVE_IMAGES: - self.addCleanup(os.remove, "test_graphviz_filename.svg") diff --git a/tests/retworkx_backwards_compat/visualization/test_mpl.py b/tests/retworkx_backwards_compat/visualization/test_mpl.py deleted file mode 100644 index 4d600c19b..000000000 --- a/tests/retworkx_backwards_compat/visualization/test_mpl.py +++ /dev/null @@ -1,194 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -# Based on the equivalent tests for the networkx matplotlib drawer: -# https://github.com/networkx/networkx/blob/ead0e65bda59862e329f2e6f1da47919c6b07ca9/networkx/drawing/tests/test_pylab.py - -import os -import unittest - -import retworkx -from retworkx.visualization import mpl_draw - -try: - import matplotlib as mpl - import matplotlib.pyplot as plt - - mpl.use("PS") - plt.rcParams["text.usetex"] = False - HAS_MPL = True -except ImportError: - HAS_MPL = False - -SAVE_IMAGES = os.getenv("RUSTWORKX_TEST_PRESERVE_IMAGES", None) - - -def _save_images(fig, path): - fig.savefig(path, dpi=400) - if not SAVE_IMAGES: - try: - os.unlink(path) - except OSError: - pass - - -@unittest.skipUnless(HAS_MPL, "matplotlib is required for running these tests") -class TestMPLDraw(unittest.TestCase): - def test_draw(self): - graph = retworkx.generators.star_graph(24) - options = {"node_color": "black", "node_size": 100, "width": 3} - fig = mpl_draw(graph, **options) - _save_images(fig, "test.png") - - def test_node_list(self): - graph = retworkx.generators.star_graph(24) - node_list = list(range(4)) + list(range(4, 10)) + list(range(10, 14)) - fig = mpl_draw(graph, node_list=node_list) - _save_images(fig, "test_node_list.png") - - def test_edge_colormap(self): - graph = retworkx.generators.star_graph(24) - colors = range(len(graph.edge_list())) - fig = mpl_draw( - graph, - edge_color=colors, - width=4, - edge_cmap=plt.cm.Blues, - with_labels=True, - ) - _save_images(fig, "test_edge_colors.png") - - def test_arrows(self): - graph = retworkx.generators.directed_star_graph(24) - fig = mpl_draw(graph) - _save_images(fig, "test_arrows.png") - - def test_empty_graph(self): - graph = retworkx.PyGraph() - fig = mpl_draw(graph) - _save_images(fig, "test_empty.png") - - def test_axes(self): - fig, ax = plt.subplots() - graph = retworkx.directed_gnp_random_graph(50, 0.75) - mpl_draw(graph, ax=ax) - _save_images(fig, "test_axes.png") - - def test_selfloop_with_single_edge_in_edge_list(self): - fig, ax = plt.subplots() - # Graph with selfloop - graph = retworkx.generators.path_graph(2) - graph.add_edge(1, 1, None) - pos = {n: (n, n) for n in graph.node_indexes()} - mpl_draw(graph, pos, ax=ax, edge_list=[(1, 1)]) - _save_images(fig, "test_self_loop.png") - - def test_draw_edges_min_source_target_margins(self): - """Test that there is a wider gap between the node and the start of an - incident edge when min_source_margin is specified. - - This test checks that the use of min_{source/target}_margin kwargs - result in shorter (more padding) between the edges and source and - target nodes. As a crude visual example, let 's' and 't' represent - source and target nodes, respectively: - Default: - s-----------------------------t - With margins: - s ----------------------- t - """ - node_shapes = ["o", "s"] - graph = retworkx.PyGraph() - graph.extend_from_edge_list([(0, 1)]) - pos = {0: (0, 0), 1: (1, 0)} # horizontal layout - - for node_shape in node_shapes: - with self.subTest(shape=node_shape): - fig, ax = plt.subplots() - mpl_draw( - graph, - pos=pos, - ax=ax, - node_shape=node_shape, - min_source_margin=100, - min_target_margin=100, - ) - _save_images(fig, "test_node_shape_%s.png" % node_shape) - - def test_alpha_iter(self): - graph = retworkx.generators.grid_graph(4, 6) - # with fewer alpha elements than nodes - plt.subplot(131) - mpl_draw(graph, alpha=[0.1, 0.2]) - # with equal alpha elements and nodes - num_nodes = len(graph) - alpha = [x / num_nodes for x in range(num_nodes)] - colors = range(num_nodes) - plt.subplot(132) - mpl_draw(graph, node_color=colors, alpha=alpha) - # with more alpha elements than nodes - alpha.append(1) - plt.subplot(133) - mpl_draw(graph, alpha=alpha) - fig = plt.gcf() - _save_images(fig, "test_alpha_iter.png") - - def test_labels_and_colors(self): - graph = retworkx.PyGraph() - graph.add_nodes_from(list(range(8))) - edge_list = [ - (0, 1, 5), - (1, 2, 2), - (2, 3, 7), - (3, 0, 6), - (5, 6, 1), - (4, 5, 7), - (6, 7, 3), - (7, 4, 7), - ] - 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$" - graph.add_edges_from(edge_list) - pos = retworkx.random_layout(graph) - mpl_draw( - graph, - pos=pos, - node_list=[0, 1, 2, 3], - node_color="r", - edge_list=[(0, 1), (1, 2), (2, 3), (3, 0)], - node_size=500, - alpha=0.75, - width=1.0, - labels=lambda x: labels[x], - font_size=16, - ) - mpl_draw( - graph, - pos=pos, - node_list=[4, 5, 6, 7], - node_color="b", - node_size=500, - alpha=0.5, - edge_list=[(4, 5), (5, 6), (6, 7), (7, 4)], - width=8, - edge_color="r", - rotate=False, - edge_labels=lambda edge: labels[edge], - ) - fig = plt.gcf() - _save_images(fig, "test_labels_and_colors.png") diff --git a/tests/rustworkx_tests/digraph/test_bipartite.py b/tests/rustworkx_tests/digraph/test_bipartite.py new file mode 100644 index 000000000..f3e29bdde --- /dev/null +++ b/tests/rustworkx_tests/digraph/test_bipartite.py @@ -0,0 +1,76 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import unittest + +import rustworkx + + +class TestBipartite(unittest.TestCase): + def test_is_bipartite(self): + graph = rustworkx.generators.directed_heavy_square_graph(5) + self.assertTrue(rustworkx.is_bipartite(graph)) + + def test_two_colors(self): + graph = rustworkx.generators.directed_star_graph(5) + self.assertEqual(rustworkx.two_color(graph), {0: 1, 1: 0, 2: 0, 3: 0, 4: 0}) + + def test_two_colors_reverse_direction(self): + graph = rustworkx.generators.directed_star_graph(5, inward=True) + self.assertEqual(rustworkx.two_color(graph), {0: 1, 1: 0, 2: 0, 3: 0, 4: 0}) + + def test_two_colors_with_isolates(self): + graph = rustworkx.generators.directed_star_graph(5) + graph.add_nodes_from(range(3)) + self.assertEqual( + rustworkx.two_color(graph), {0: 1, 1: 0, 2: 0, 3: 0, 4: 0, 5: 1, 6: 1, 7: 1} + ) + + def test_is_bipartite_with_isolates(self): + graph = rustworkx.generators.directed_star_graph(5) + graph.add_nodes_from(range(3)) + self.assertTrue(rustworkx.is_bipartite(graph)) + + def test_two_colors_not_biparite_with_isolates(self): + graph = rustworkx.generators.directed_complete_graph(5) + graph.add_nodes_from(range(3)) + self.assertIsNone(rustworkx.two_color(graph)) + + def test_not_biparite_with_isolates(self): + graph = rustworkx.generators.directed_complete_graph(5) + graph.add_nodes_from(range(3)) + self.assertFalse(rustworkx.is_bipartite(graph)) + + def test_not_biparite(self): + graph = rustworkx.generators.directed_complete_graph(5) + self.assertFalse(rustworkx.is_bipartite(graph)) + + def test_two_color_not_biparite(self): + graph = rustworkx.generators.directed_complete_graph(5) + self.assertIsNone(rustworkx.two_color(graph)) + + def test_grid_graph(self): + for i in range(10): + for j in range(10): + with self.subTest((i, j)): + graph = rustworkx.generators.directed_grid_graph(i, j) + self.assertTrue(rustworkx.is_bipartite(graph)) + + def test_cycle_graph(self): + for i in range(20): + with self.subTest(i): + graph = rustworkx.generators.directed_cycle_graph(i) + res = rustworkx.is_bipartite(graph) + if i % 2: + self.assertFalse(res) + else: + self.assertTrue(res) diff --git a/tests/rustworkx_tests/digraph/test_clear.py b/tests/rustworkx_tests/digraph/test_clear.py new file mode 100644 index 000000000..043ae43e6 --- /dev/null +++ b/tests/rustworkx_tests/digraph/test_clear.py @@ -0,0 +1,66 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import unittest + +import rustworkx + + +class TestClear(unittest.TestCase): + def test_clear(self): + dag = rustworkx.PyDAG() + node_a = dag.add_node("a") + dag.add_child(node_a, "b", {"a": 1}) + dag.add_child(node_a, "c", {"a": 2}) + dag.clear() + self.assertEqual(dag.num_nodes(), 0) + self.assertEqual(dag.num_edges(), 0) + self.assertEqual(dag.nodes(), []) + self.assertEqual(dag.edges(), []) + + def test_clear_reuse(self): + dag = rustworkx.PyDAG() + node_a = dag.add_node("a") + dag.add_child(node_a, "b", {"a": 1}) + dag.add_child(node_a, "c", {"a": 2}) + dag.clear() + node_a = dag.add_node("a") + dag.add_child(node_a, "b", {"a": 1}) + dag.add_child(node_a, "c", {"a": 2}) + self.assertEqual(dag.num_nodes(), 3) + self.assertEqual(dag.num_edges(), 2) + self.assertEqual(dag.nodes(), ["a", "b", "c"]) + self.assertEqual(dag.edges(), [{"a": 1}, {"a": 2}]) + + def test_clear_edges(self): + dag = rustworkx.PyDAG() + node_a = dag.add_node("a") + dag.add_child(node_a, "b", {"a": 1}) + dag.add_child(node_a, "c", {"a": 2}) + dag.clear_edges() + self.assertEqual(dag.num_nodes(), 3) + self.assertEqual(dag.num_edges(), 0) + self.assertEqual(dag.nodes(), ["a", "b", "c"]) + self.assertEqual(dag.edges(), []) + + def test_clear_edges_reuse(self): + dag = rustworkx.PyDAG() + node_a = dag.add_node("a") + node_b = dag.add_child(node_a, "b", {"a": 1}) + node_c = dag.add_child(node_a, "c", {"a": 2}) + dag.clear_edges() + dag.add_edge(node_a, node_b, {"a": 1}) + dag.add_edge(node_a, node_c, {"a": 2}) + self.assertEqual(dag.num_nodes(), 3) + self.assertEqual(dag.num_edges(), 2) + self.assertEqual(dag.nodes(), ["a", "b", "c"]) + self.assertEqual(dag.edges(), [{"a": 1}, {"a": 2}]) diff --git a/tests/rustworkx_tests/digraph/test_dot.py b/tests/rustworkx_tests/digraph/test_dot.py index 64957ef04..f2dc98428 100644 --- a/tests/rustworkx_tests/digraph/test_dot.py +++ b/tests/rustworkx_tests/digraph/test_dot.py @@ -50,7 +50,7 @@ def test_digraph_to_dot_to_file(self): res = graph.to_dot(lambda node: node, lambda edge: edge, filename=self.path) self.addCleanup(os.remove, self.path) self.assertIsNone(res) - with open(self.path, "r") as fd: + with open(self.path) as fd: res = fd.read() self.assertEqual(expected, res) diff --git a/tests/rustworkx_tests/digraph/test_edgelist.py b/tests/rustworkx_tests/digraph/test_edgelist.py index d47d9f781..d51a08c29 100644 --- a/tests/rustworkx_tests/digraph/test_edgelist.py +++ b/tests/rustworkx_tests/digraph/test_edgelist.py @@ -152,7 +152,7 @@ def test_write_edge_list_empty_digraph(self): graph = rustworkx.PyDiGraph() graph.write_edge_list(path) self.addCleanup(os.remove, path) - with open(path, "rt") as edge_file: + with open(path) as edge_file: self.assertEqual("", edge_file.read()) def test_write_edge_list_round_trip(self): @@ -184,7 +184,7 @@ def test_custom_delim(self): 2,3 3,4 """ - with open(path, "rt") as edge_file: + with open(path) as edge_file: self.assertEqual(edge_file.read(), expected) def test_invalid_return_type_weight_fn(self): diff --git a/tests/rustworkx_tests/digraph/test_isolates.py b/tests/rustworkx_tests/digraph/test_isolates.py new file mode 100644 index 000000000..bb1993bb8 --- /dev/null +++ b/tests/rustworkx_tests/digraph/test_isolates.py @@ -0,0 +1,47 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import unittest + +import rustworkx + + +class TestIsolates(unittest.TestCase): + def test_isolates(self): + graph = rustworkx.PyDiGraph() + graph.add_nodes_from(range(4)) + graph.add_edge(0, 1, None) + res = rustworkx.isolates(graph) + self.assertEqual(res, [2, 3]) + + def test_isolates_with_holes(self): + graph = rustworkx.PyDiGraph() + graph.add_nodes_from(range(4)) + graph.add_edge(0, 1, None) + graph.remove_node(2) + res = rustworkx.isolates(graph) + self.assertEqual(res, [3]) + + def test_isolates_empty_graph(self): + graph = rustworkx.PyDiGraph() + res = rustworkx.isolates(graph) + self.assertEqual(res, []) + + def test_isolates_outgoing_star(self): + graph = rustworkx.generators.directed_star_graph(5) + res = rustworkx.isolates(graph) + self.assertEqual(res, []) + + def test_isolates_incoming_star(self): + graph = rustworkx.generators.directed_star_graph(5, inward=True) + res = rustworkx.isolates(graph) + self.assertEqual(res, []) diff --git a/tests/rustworkx_tests/digraph/test_layout.py b/tests/rustworkx_tests/digraph/test_layout.py index 792557556..5d5b1a0b0 100644 --- a/tests/rustworkx_tests/digraph/test_layout.py +++ b/tests/rustworkx_tests/digraph/test_layout.py @@ -24,9 +24,8 @@ def assertLayoutEquiv(self, exp, res): rv = res[k] if abs(ev[0] - rv[0]) > self.thres or abs(ev[1] - rv[1]) > self.thres: self.fail( - "The position for node %s, %s, differs from the expected " - "position, %s by more than the allowed threshold of %s" - % (k, rv, ev, self.thres) + f"The position for node {k}, {rv}, differs from the expected " + f"position, {ev} by more than the allowed threshold of {self.thres}" ) diff --git a/tests/rustworkx_tests/graph/test_bipartite.py b/tests/rustworkx_tests/graph/test_bipartite.py new file mode 100644 index 000000000..59c2eb9da --- /dev/null +++ b/tests/rustworkx_tests/graph/test_bipartite.py @@ -0,0 +1,89 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import unittest + +import rustworkx + + +class TestBipartite(unittest.TestCase): + def test_is_bipartite(self): + graph = rustworkx.generators.heavy_square_graph(5) + self.assertTrue(rustworkx.is_bipartite(graph)) + + def test_two_colors(self): + graph = rustworkx.generators.star_graph(5) + self.assertEqual(rustworkx.two_color(graph), {0: 1, 1: 0, 2: 0, 3: 0, 4: 0}) + + def test_two_colors_with_isolates(self): + graph = rustworkx.generators.star_graph(5) + graph.add_nodes_from(range(3)) + self.assertEqual( + rustworkx.two_color(graph), {0: 1, 1: 0, 2: 0, 3: 0, 4: 0, 5: 1, 6: 1, 7: 1} + ) + + def test_is_bipartite_with_isolates(self): + graph = rustworkx.generators.star_graph(5) + graph.add_nodes_from(range(3)) + self.assertTrue(rustworkx.is_bipartite(graph)) + + def test_two_colors_not_biparite_with_isolates(self): + graph = rustworkx.generators.complete_graph(5) + graph.add_nodes_from(range(3)) + self.assertIsNone(rustworkx.two_color(graph)) + + def test_not_biparite_with_isolates(self): + graph = rustworkx.generators.complete_graph(5) + graph.add_nodes_from(range(3)) + self.assertFalse(rustworkx.is_bipartite(graph)) + + def test_not_biparite(self): + graph = rustworkx.generators.complete_graph(5) + self.assertFalse(rustworkx.is_bipartite(graph)) + + def test_two_color_not_biparite(self): + graph = rustworkx.generators.complete_graph(5) + self.assertIsNone(rustworkx.two_color(graph)) + + def test_bipartite_petersen_graph(self): + # Per Lemma 3 of https://arxiv.org/pdf/1008.3208.pdf A petersen graph is bipartite + # for any even value of n and odd value of k + for i in range(3, 30): + for j in range(30): + n = 2 * i + k = 2 * j + 1 + if n <= k * 2: + continue + + with self.subTest((n, k)): + graph = rustworkx.generators.generalized_petersen_graph(n, k) + self.assertTrue(rustworkx.is_bipartite(graph)) + + def test_not_bipartite_petersen_graph(self): + # Per Lemma 3 of https://arxiv.org/pdf/1008.3208.pdf A petersen graph is bipartite + # for any even value of n and odd value of k + for n in range(3, 30): + for k in range(1, 31): + with self.subTest((2 * n, 2 * k)): + if 2 * n > k * 4: + graph = rustworkx.generators.generalized_petersen_graph(2 * n, 2 * k) + self.assertFalse(rustworkx.is_bipartite(graph)) + with self.subTest((2 * n + 1, 2 * k)): + if 2 * n + 1 > k * 4: + graph = rustworkx.generators.generalized_petersen_graph(2 * n + 1, 2 * k) + self.assertFalse(rustworkx.is_bipartite(graph)) + with self.subTest((2 * n + 1, 2 * k + 1)): + if 2 * n + 1 > k * 4 + 2: + graph = rustworkx.generators.generalized_petersen_graph( + 2 * n + 1, 2 * k + 1 + ) + self.assertFalse(rustworkx.is_bipartite(graph)) diff --git a/tests/rustworkx_tests/graph/test_clear.py b/tests/rustworkx_tests/graph/test_clear.py new file mode 100644 index 000000000..3672564fb --- /dev/null +++ b/tests/rustworkx_tests/graph/test_clear.py @@ -0,0 +1,76 @@ +# Licensed under the Apache License, Version 3.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import unittest + +import rustworkx + + +class TestClear(unittest.TestCase): + def test_clear(self): + graph = rustworkx.PyGraph() + node_a = graph.add_node("a") + node_b = graph.add_node("b") + graph.add_edge(node_a, node_b, {"a": 1}) + node_c = graph.add_node("c") + graph.add_edge(node_a, node_c, {"a": 2}) + graph.clear() + self.assertEqual(graph.num_nodes(), 0) + self.assertEqual(graph.num_edges(), 0) + self.assertEqual(graph.nodes(), []) + self.assertEqual(graph.edges(), []) + + def test_clear_reuse(self): + graph = rustworkx.PyGraph() + node_a = graph.add_node("a") + node_b = graph.add_node("b") + graph.add_edge(node_a, node_b, {"a": 1}) + node_c = graph.add_node("c") + graph.add_edge(node_a, node_c, {"a": 2}) + graph.clear() + node_a = graph.add_node("a") + node_b = graph.add_node("b") + graph.add_edge(node_a, node_b, {"a": 1}) + node_c = graph.add_node("c") + graph.add_edge(node_a, node_c, {"a": 2}) + self.assertEqual(graph.num_nodes(), 3) + self.assertEqual(graph.num_edges(), 2) + self.assertEqual(graph.nodes(), ["a", "b", "c"]) + self.assertEqual(graph.edges(), [{"a": 1}, {"a": 2}]) + + def test_clear_edges(self): + graph = rustworkx.PyGraph() + node_a = graph.add_node("a") + node_b = graph.add_node("b") + graph.add_edge(node_a, node_b, {"e1", 1}) + node_c = graph.add_node("c") + graph.add_edge(node_a, node_c, {"e2", 2}) + graph.clear_edges() + self.assertEqual(graph.num_edges(), 0) + self.assertEqual(graph.edges(), []) + self.assertEqual(graph.num_nodes(), 3) + self.assertEqual(graph.nodes(), ["a", "b", "c"]) + + def test_clear_edges_reuse(self): + graph = rustworkx.PyGraph() + node_a = graph.add_node("a") + node_b = graph.add_node("b") + graph.add_edge(node_a, node_b, {"e1", 1}) + node_c = graph.add_node("c") + graph.add_edge(node_a, node_c, {"e2", 2}) + graph.clear_edges() + graph.add_edge(node_a, node_b, {"e1", 1}) + graph.add_edge(node_a, node_c, {"e2", 2}) + self.assertEqual(graph.num_nodes(), 3) + self.assertEqual(graph.num_edges(), 2) + self.assertEqual(graph.nodes(), ["a", "b", "c"]) + self.assertEqual(graph.edges(), [{"e1", 1}, {"e2", 2}]) diff --git a/tests/rustworkx_tests/graph/test_dot.py b/tests/rustworkx_tests/graph/test_dot.py index 5ab04d656..63c98804e 100644 --- a/tests/rustworkx_tests/graph/test_dot.py +++ b/tests/rustworkx_tests/graph/test_dot.py @@ -104,7 +104,7 @@ def test_graph_to_dot_to_file(self): res = graph.to_dot(lambda node: node, lambda edge: edge, filename=self.path) self.addCleanup(os.remove, self.path) self.assertIsNone(res) - with open(self.path, "r") as fd: + with open(self.path) as fd: res = fd.read() self.assertEqual(expected, res) diff --git a/tests/rustworkx_tests/graph/test_edgelist.py b/tests/rustworkx_tests/graph/test_edgelist.py index 95063e54f..6b4165e44 100644 --- a/tests/rustworkx_tests/graph/test_edgelist.py +++ b/tests/rustworkx_tests/graph/test_edgelist.py @@ -148,7 +148,7 @@ def test_write_edge_list_empty_digraph(self): graph = rustworkx.PyGraph() graph.write_edge_list(path) self.addCleanup(os.remove, path) - with open(path, "rt") as edge_file: + with open(path) as edge_file: self.assertEqual("", edge_file.read()) def test_write_edge_list_round_trip(self): @@ -180,7 +180,7 @@ def test_custom_delim(self): 2,3 3,4 """ - with open(path, "rt") as edge_file: + with open(path) as edge_file: self.assertEqual(edge_file.read(), expected) def test_invalid_return_type_weight_fn(self): diff --git a/tests/rustworkx_tests/graph/test_isolates.py b/tests/rustworkx_tests/graph/test_isolates.py new file mode 100644 index 000000000..fc21911cc --- /dev/null +++ b/tests/rustworkx_tests/graph/test_isolates.py @@ -0,0 +1,37 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import unittest + +import rustworkx + + +class TestIsolates(unittest.TestCase): + def test_isolates(self): + graph = rustworkx.PyGraph() + graph.add_nodes_from(range(4)) + graph.add_edge(0, 1, None) + res = rustworkx.isolates(graph) + self.assertEqual(res, [2, 3]) + + def test_isolates_with_holes(self): + graph = rustworkx.PyGraph() + graph.add_nodes_from(range(4)) + graph.add_edge(0, 1, None) + graph.remove_node(2) + res = rustworkx.isolates(graph) + self.assertEqual(res, [3]) + + def test_isolates_empty_graph(self): + graph = rustworkx.PyGraph() + res = rustworkx.isolates(graph) + self.assertEqual(res, []) diff --git a/tests/rustworkx_tests/graph/test_layout.py b/tests/rustworkx_tests/graph/test_layout.py index 032857899..c656b7fe5 100644 --- a/tests/rustworkx_tests/graph/test_layout.py +++ b/tests/rustworkx_tests/graph/test_layout.py @@ -24,9 +24,8 @@ def assertLayoutEquiv(self, exp, res): rv = res[k] if abs(ev[0] - rv[0]) > self.thres or abs(ev[1] - rv[1]) > self.thres: self.fail( - "The position for node %s, %s, differs from the expected " - "position, %s by more than the allowed threshold of %s" - % (k, rv, ev, self.thres) + f"The position for node {k}, {rv}, differs from the expected " + f"position, {ev} by more than the allowed threshold of {self.thres}" ) diff --git a/tests/rustworkx_tests/graph/test_max_weight_matching.py b/tests/rustworkx_tests/graph/test_max_weight_matching.py index 89bc468f0..429036649 100644 --- a/tests/rustworkx_tests/graph/test_max_weight_matching.py +++ b/tests/rustworkx_tests/graph/test_max_weight_matching.py @@ -14,10 +14,9 @@ # https://github.com/networkx/networkx/blob/3351206a3ce5b3a39bb2fc451e93ef545b96c95b/networkx/algorithms/tests/test_matching.py import random +import unittest -import fixtures import networkx -import testtools import rustworkx @@ -26,21 +25,14 @@ def match_dict_to_set(match): return {(u, v) for (u, v) in set(map(frozenset, match.items()))} -class TestMaxWeightMatching(testtools.TestCase): - def setUp(self): - super().setUp() - stdout = self.useFixture(fixtures.StringStream("stdout")).stream - self.useFixture(fixtures.MonkeyPatch("sys.stdout", stdout)) - stderr = self.useFixture(fixtures.StringStream("stderr")).stream - self.useFixture(fixtures.MonkeyPatch("sys.stderr", stderr)) - +class TestMaxWeightMatching(unittest.TestCase): def compare_match_sets(self, rx_match, expected_match): for (u, v) in rx_match: if (u, v) not in expected_match and (v, u) not in expected_match: self.fail( - "Element %s and it's reverse %s not found in " - "expected output.\nrustworkx output: %s\nexpected " - "output: %s" % ((u, v), (v, u), rx_match, expected_match) + f"Element {(u, v)} and it's reverse {(v, u)} not found in " + f"expected output.\nrustworkx output: {rx_match}\nexpected " + f"output: {expected_match}" ) def compare_rx_nx_sets(self, rx_graph, rx_matches, nx_matches, seed, nx_graph): @@ -61,11 +53,10 @@ def get_nx_weight(edge): if (u, v) not in nx_matches: if (v, u) not in nx_matches: print( - "seed %s failed. Element %s and it's " - "reverse %s not found in networkx output.\nrustworkx" - " output: %s\nnetworkx output: %s\nedge list: %s\n" - "falling back to checking for a valid solution" - % ( + "seed {} failed. Element {} and it's " + "reverse {} not found in networkx output.\nrustworkx" + " output: {}\nnetworkx output: {}\nedge list: {}\n" + "falling back to checking for a valid solution".format( seed, (u, v), (v, u), diff --git a/tests/rustworkx_tests/graph/test_substitute_node_with_subgraph.py b/tests/rustworkx_tests/graph/test_substitute_node_with_subgraph.py index 2ddd8bf3e..e76f1f56c 100644 --- a/tests/rustworkx_tests/graph/test_substitute_node_with_subgraph.py +++ b/tests/rustworkx_tests/graph/test_substitute_node_with_subgraph.py @@ -34,7 +34,7 @@ def test_single_node(self): def test_node_filter(self): in_graph = rustworkx.generators.complete_graph(5) res = self.graph.substitute_node_with_subgraph( - 0, in_graph, lambda _, __, ___: 2, node_filter=lambda node: node == None + 0, in_graph, lambda _, __, ___: 2, node_filter=lambda node: node is None ) self.assertEqual(res, {i: i + 5 for i in range(5)}) self.assertEqual( diff --git a/tests/rustworkx_tests/test_custom_return_types.py b/tests/rustworkx_tests/test_custom_return_types.py index 2362f125b..48aeb7c0a 100644 --- a/tests/rustworkx_tests/test_custom_return_types.py +++ b/tests/rustworkx_tests/test_custom_return_types.py @@ -1175,7 +1175,7 @@ def test_index_error(self): def test_keys(self): keys = rustworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn).keys() - self.assertEqual([0, 1], list(sorted((keys)))) + self.assertEqual([0, 1], list(sorted(keys))) def test_values(self): values = rustworkx.all_pairs_dijkstra_path_lengths(self.dag, self.fn).values() diff --git a/tox.ini b/tox.ini index 12f6d1ec8..82ee34eaa 100644 --- a/tox.ini +++ b/tox.ini @@ -33,12 +33,12 @@ commands = basepython = python3 deps = black~=22.0 - flake8 + ruff setuptools-rust whitelist_externals=cargo commands = black --check --diff {posargs} '../rustworkx' '../tests' '../retworkx' - flake8 --per-file-ignores='../rustworkx/__init__.py:F405,F403' ../setup.py ../rustworkx ../retworkx . + ruff check ../rustworkx ../retworkx . ../setup.py cargo fmt --all -- --check python {toxinidir}/tools/find_stray_release_notes.py @@ -77,14 +77,3 @@ basepython = python3 deps = mypy==1.0.1 commands = python -m mypy.stubtest --concise --ignore-missing-stub rustworkx.rustworkx - -[flake8] -# E125 is deliberately excluded. See https://github.com/jcrocholl/pep8/issues/126 -# E123 skipped because it is ignored by default in the default pep8 -# E129 skipped because it is too limiting when combined with other rules -# E711 skipped because sqlalchemy filter() requires using == instead of is -# max-line-length, E203, W503 are added for black compatibility -max-line-length = 110 -ignore = E125,E123,E129,E711 -extend-ignore = E203, W503 -exclude = .venv,.git,.tox,dist,doc,*egg,build