Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

1
vendor/petgraph/.cargo-checksum.json vendored Normal file

File diff suppressed because one or more lines are too long

129
vendor/petgraph/CONTRIBUTING.rst vendored Normal file
View File

@@ -0,0 +1,129 @@
Contributing to ``petgraph``
============================
Hi! We'd love to have your contributions! If you want help or mentorship, reach
out to us in a GitHub issue, or ping ``bluss`` in `#rust on irc.mozilla.org`_
and introduce yourself.
.. _`\#rust on irc.mozilla.org`: irc://irc.mozilla.org#rust
* `Building`_
* `Testing`_
* `Pull Requests`_
* `Bug Fixes`_
* `Performance Improvements`_
* `Implementing New Algorithms`_
* `Where We Need Help`_
* `Team`_
Building
--------
::
$ cargo build
Testing
-------
::
$ cargo test --features all
Pull Requests
-------------
All pull requests are reviewed by a team_ member before merging.
Additionally, different kinds of pull requests have different requirements.
Bug Fixes
.........
We love getting bug fixes!
Make sure to include a regression test, so that we can be sure that we never
accidentally re-introduce the bug again.
Performance Improvements
........................
You made an algorithm faster? Awesome.
When submitting performance improvement, include the following:
* A new ``#[bench]`` function that exercises this code path, if one doesn't
already exist
* Before and after ``cargo bench`` scores, optionally formatted using
`cargo-benchcmp`_
.. _`cargo-benchcmp`: https://github.com/BurntSushi/cargo-benchcmp
Implementing New Algorithms
...........................
Implementing new graph algorithms is encouraged!
If you're going to implement a new algorithm, make sure that you do the
following:
* Add a ``quickcheck`` property test for the new algorithm
* Add a ``benchmark`` test for measuring performance of the new algorithm
* Document what the algorithm does and in what situations it should be used
* Document the big-O running time of the algorithm
* Include links to relevant reading materials, such as a paper or Wikipedia
* Make the algorithm work with generic graphs, constraining the generic graph
type parameter with our existing graph traits, like ``Visitable``, or with new
graph traits
Any team_ member can review a pull request implementing a new algorithm, but the
final decision whether or not the algorithm is appropriate for inclusion in the
``petgraph`` crate is left to ``@bluss``.
Additionally, assuming that the new algorithm is merged into ``petgraph``, you
are *strongly* encouraged to join the ``petgraph`` team_! *You* are the best
person to review any future bug fixes, performance improvements, and whatever
other changes that affect this new algorithm.
Where We Need Help
------------------
* Issues labeled `"help wanted"`_ are issues where we could use a little help
from you.
* Issues Labeled `"mentored"`_ are issues that don't really involve any more
investigation, just implementation. We've outlined what needs to be done, and
a team_ member has volunteered to help whoever claims the issue implement it,
and get the implementation merged.
.. _`"help wanted"`:
https://github.com/bluss/petgraph/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22
.. _`"mentored"`:
https://github.com/bluss/petgraph/issues?q=is%3Aopen+is%3Aissue+label%3A%22mentored%22
Team
----
The ``petgraph`` team consists of:
* ``@bluss``
* ``@fitzgen``
We need more team members to help spread out reviewing and maintenance
responsibilities — want to join us? `Drop a comment in this issue!`_
.. _`Drop a comment in this issue!`: https://github.com/bluss/petgraph/issues/TODO

280
vendor/petgraph/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,280 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2018"
rust-version = "1.64"
name = "petgraph"
version = "0.7.1"
authors = [
"bluss",
"mitchmindtree",
]
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "Graph data structure library. Provides graph types and graph algorithms."
documentation = "https://docs.rs/petgraph/"
readme = "README.md"
keywords = [
"data-structure",
"graph",
"unionfind",
"graph-algorithms",
]
categories = ["data-structures"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/petgraph/petgraph"
[package.metadata.docs.rs]
features = [
"rayon",
"serde-1",
"quickcheck",
]
[package.metadata.release]
no-dev-version = true
[profile.bench]
debug = 2
[profile.release]
[lib]
name = "petgraph"
path = "src/lib.rs"
bench = false
[[test]]
name = "adjacency_matrix"
path = "tests/adjacency_matrix.rs"
[[test]]
name = "coloring"
path = "tests/coloring.rs"
[[test]]
name = "floyd_warshall"
path = "tests/floyd_warshall.rs"
[[test]]
name = "ford_fulkerson"
path = "tests/ford_fulkerson.rs"
[[test]]
name = "graph"
path = "tests/graph.rs"
[[test]]
name = "graph6"
path = "tests/graph6.rs"
[[test]]
name = "graphmap"
path = "tests/graphmap.rs"
[[test]]
name = "iso"
path = "tests/iso.rs"
[[test]]
name = "k_shortest_path"
path = "tests/k_shortest_path.rs"
[[test]]
name = "list"
path = "tests/list.rs"
[[test]]
name = "matching"
path = "tests/matching.rs"
[[test]]
name = "min_spanning_tree"
path = "tests/min_spanning_tree.rs"
[[test]]
name = "operator"
path = "tests/operator.rs"
[[test]]
name = "page_rank"
path = "tests/page_rank.rs"
[[test]]
name = "quickcheck"
path = "tests/quickcheck.rs"
[[test]]
name = "stable_graph"
path = "tests/stable_graph.rs"
[[test]]
name = "unionfind"
path = "tests/unionfind.rs"
[[bench]]
name = "acyclic"
path = "benches/acyclic.rs"
[[bench]]
name = "bellman_ford"
path = "benches/bellman_ford.rs"
[[bench]]
name = "coloring"
path = "benches/coloring.rs"
[[bench]]
name = "dijkstra"
path = "benches/dijkstra.rs"
[[bench]]
name = "feedback_arc_set"
path = "benches/feedback_arc_set.rs"
[[bench]]
name = "floyd_warshall"
path = "benches/floyd_warshall.rs"
[[bench]]
name = "ford_fulkerson"
path = "benches/ford_fulkerson.rs"
[[bench]]
name = "graph6_decoder"
path = "benches/graph6_decoder.rs"
[[bench]]
name = "graph6_encoder"
path = "benches/graph6_encoder.rs"
[[bench]]
name = "graphmap"
path = "benches/graphmap.rs"
[[bench]]
name = "iso"
path = "benches/iso.rs"
[[bench]]
name = "k_shortest_path"
path = "benches/k_shortest_path.rs"
[[bench]]
name = "matching"
path = "benches/matching.rs"
[[bench]]
name = "matrix_graph"
path = "benches/matrix_graph.rs"
[[bench]]
name = "min_spanning_tree"
path = "benches/min_spanning_tree.rs"
[[bench]]
name = "ograph"
path = "benches/ograph.rs"
[[bench]]
name = "page_rank"
path = "benches/page_rank.rs"
[[bench]]
name = "serialize"
path = "benches/serialize.rs"
[[bench]]
name = "stable_graph"
path = "benches/stable_graph.rs"
[[bench]]
name = "unionfind"
path = "benches/unionfind.rs"
[dependencies.fixedbitset]
version = "0.5.7"
default-features = false
[dependencies.indexmap]
version = "2.5.0"
[dependencies.quickcheck]
version = "0.8"
optional = true
default-features = false
[dependencies.rayon]
version = "1.5.3"
optional = true
[dependencies.serde]
version = "1.0"
optional = true
[dependencies.serde_derive]
version = "1.0"
optional = true
[dev-dependencies.ahash]
version = "0.7.2"
[dev-dependencies.bincode]
version = "1.3.3"
[dev-dependencies.defmac]
version = "0.2.1"
[dev-dependencies.fxhash]
version = "0.2.1"
[dev-dependencies.itertools]
version = "0.12.1"
default-features = false
[dev-dependencies.odds]
version = "0.4.0"
[dev-dependencies.rand]
version = "0.5.5"
[features]
all = [
"unstable",
"quickcheck",
"matrix_graph",
"stable_graph",
"graphmap",
"rayon",
]
default = [
"graphmap",
"stable_graph",
"matrix_graph",
]
generate = []
graphmap = []
matrix_graph = []
rayon = [
"dep:rayon",
"indexmap/rayon",
]
serde-1 = [
"serde",
"serde_derive",
]
stable_graph = []
unstable = ["generate"]

201
vendor/petgraph/LICENSE-APACHE vendored Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

25
vendor/petgraph/LICENSE-MIT vendored Normal file
View File

@@ -0,0 +1,25 @@
Copyright (c) 2015
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

38
vendor/petgraph/Makefile vendored Normal file
View File

@@ -0,0 +1,38 @@
DOCCRATES = petgraph fixedbitset
# deps to delete the generated docs
RMDOCS =
FEATURES = unstable
VERSIONS = $(patsubst %,target/VERS/%,$(DOCCRATES))
docs: mkdocs mksvgs subst $(RMDOCS)
# https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html
$(VERSIONS): Cargo.toml
mkdir -p $(@D)
cargo pkgid $(@F) | sed -e "s/.*#\(\|.*:\)//" > "$@"
$(DOCCRATES): %: target/VERS/%
# Put in the crate version into the docs
find ./doc/$@ -name "*.html" -exec sed -i -e "s/<title>\(.*\) - Rust/<title>$@ $(shell cat $<) - \1 - Rust/g" {} \;
subst: $(DOCCRATES)
mkdocs: Cargo.toml
cargo doc --features=$(FEATURES)
rm -rf ./doc
cp -r ./target/doc ./doc
- cat ./custom.css >> doc/main.css
$(RMDOCS): mkdocs
rm -r ./doc/$@
sed -i "/searchIndex\['$@'\]/d" doc/search-index.js
mksvgs: mkdocs graph-example.dot
dot -Tsvg < ./graph-example.dot > graph-example.svg
mv graph-example.svg ./doc/petgraph/graph/
.PHONY: docs mkdocs mksvgs subst $(DOCCRATES) $(RMDOCS)

52
vendor/petgraph/README.md vendored Normal file
View File

@@ -0,0 +1,52 @@
![](assets/graphosaurus-512.png)
# petgraph
Graph data structure library. Please read the [API documentation here][].
Supports Rust 1.64 and later.
[![Crates.io][crates-badge]][crates-url]
[![docs.rs][docsrs-badge]][docsrs-url]
![MSRV][msrv-badge]
[![Discord chat][discord-badge]][discord-url]
[![build_status][]](https://github.com/petgraph/petgraph/actions)
Crate feature flags:
- `graphmap` (default) enable `GraphMap`.
- `stable_graph` (default) enable `StableGraph`.
- `matrix_graph` (default) enable `MatrixGraph`.
- `serde-1` (optional) enable serialization for `Graph, StableGraph, GraphMap`
using serde 1.0. Requires Rust version as required by serde.
- `rayon` (optional) enable parallel iterators for the underlying data in `GraphMap`. Requires Rust version as required by Rayon.
## Recent Changes
See [RELEASES][] for a list of changes. The minimum supported rust
version will only change on major releases.
## Logo
The mascot is named "Sir Paul Rustory Graphosaurus" (close friends call him Paul).
The logo has been created by the talented Aren.
## License
Dual-licensed to be compatible with the Rust project.
Licensed under the Apache License, Version 2.0
<http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
<http://opensource.org/licenses/MIT>, at your option. This file may not
be copied, modified, or distributed except according to those terms.
[API documentation here]: https://docs.rs/petgraph/
[build_status]: https://github.com/petgraph/petgraph/workflows/Continuous%20integration/badge.svg?branch=master
[docsrs-badge]: https://img.shields.io/docsrs/petgraph
[docsrs-url]: https://docs.rs/petgraph/latest/petgraph/
[crates-badge]: https://img.shields.io/crates/v/petgraph.svg
[crates-url]: https://crates.io/crates/petgraph
[discord-badge]: https://img.shields.io/discord/1166289348384280616?logo=discord&style=flat
[discord-url]: https://discord.gg/n2tc79tJ4e
[msrv-badge]: https://img.shields.io/badge/rustc-1.64+-blue.svg
[RELEASES]: RELEASES.rst

637
vendor/petgraph/RELEASES.rst vendored Normal file
View File

@@ -0,0 +1,637 @@
Version 0.7.1 (2025-01-08)
==========================
- Do not unnecessarily restrict ``indexmap`` version (`#714`_)
- Export ``UndirectedAdaptor`` (`#717`_)
.. _`#714`: https://github.com/petgraph/petgraph/pull/714
.. _`#717`: https://github.com/petgraph/petgraph/pull/717
Version 0.7.0 (2024-12-31)
==========================
- Re-released version 0.6.6 with the correct version number, as it included a major update to an exposed crate (`#664`_).
Version 0.6.6 (2024-12-31 - yanked)
===================================
- Add graph6 format encoder and decoder (`#658`_)
- Dynamic Topological Sort algorithm support (`#675`_)
- Add ``UndirectedAdaptor`` (`#695`_)
- Add ``LowerHex`` and ``UpperHex`` implementations for ``Dot`` (`#687`_)
- Make ``serde`` support more complete (`#550`_)
- Process multiple edges in the Floyd-Warshall implementation (`#685`_)
- Update ``fixedbitset`` to 0.5.7 (`#664`_)
- Fix ``immediately_dominated_by`` function called on root of graph returns root itself (`#670`_)
- Fix adjacency matrix for ``Csr`` and ``List`` (`#648`_)
- Fix clippy warnings (`#701`_)
- Add performance note to the ``all_simple_paths`` function documentation (`#693`_)
.. _`#658`: https://github.com/petgraph/petgraph/pull/658
.. _`#675`: https://github.com/petgraph/petgraph/pull/675
.. _`#695`: https://github.com/petgraph/petgraph/pull/695
.. _`#687`: https://github.com/petgraph/petgraph/pull/687
.. _`#550`: https://github.com/petgraph/petgraph/pull/550
.. _`#685`: https://github.com/petgraph/petgraph/pull/685
.. _`#664`: https://github.com/petgraph/petgraph/pull/664
.. _`#670`: https://github.com/petgraph/petgraph/pull/670
.. _`#648`: https://github.com/petgraph/petgraph/pull/648
.. _`#701`: https://github.com/petgraph/petgraph/pull/701
.. _`#693`: https://github.com/petgraph/petgraph/pull/693
Version 0.6.5 (2024-05-06)
==========================
- Add rayon support for ``GraphMap`` (`#573`_, `#615`_)
- Add ``Topo::with_initials`` method (`#585`_)
- Add logo to the project (`#598`_)
- Add Ford-Fulkerson algorithm (`#640`_)
- Update ``itertools`` to 0.12.1 (`#628`_)
- Update ``GraphMap`` to allow custom hash functions (`#622`_)
- Fix documentation (`#630`_)
- Fix clippy warnings (`#627`_)
- (internal) Fix remove old ``copyclone`` macro (`#601`_)
- (internal) Move minimum spanning tree into own module (`#624`_)
.. _`#573`: https://github.com/petgraph/petgraph/pull/573
.. _`#615`: https://github.com/petgraph/petgraph/pull/615
.. _`#585`: https://github.com/petgraph/petgraph/pull/585
.. _`#598`: https://github.com/petgraph/petgraph/pull/598
.. _`#640`: https://github.com/petgraph/petgraph/pull/640
.. _`#628`: https://github.com/petgraph/petgraph/pull/628
.. _`#622`: https://github.com/petgraph/petgraph/pull/622
.. _`#630`: https://github.com/petgraph/petgraph/pull/630
.. _`#627`: https://github.com/petgraph/petgraph/pull/627
.. _`#601`: https://github.com/petgraph/petgraph/pull/601
.. _`#624`: https://github.com/petgraph/petgraph/pull/624
Version 0.6.4 (2023-08-21)
==========================
- Update ``indexmap`` to 2.0.0 (`#568`_)
- Fix typos (`#544`_)
.. _`#544`: https://github.com/petgraph/petgraph/pull/544
.. _`#568`: https://github.com/petgraph/petgraph/pull/568
Version 0.6.3 (2023-02-07)
==========================
- Added an iterator over subgraph isomorphisms (`#500`_)
- Added serde support on ``GraphMap`` (`#496`_)
- Added ``reverse`` method for ``StableGraph`` (`#533`_)
- Added ``edges_connecting`` iterator for ``StableGraph`` (`#521`_)
- Fix Floyd-Warshall algorithm behaviour on undirected graphs (`487`_)
- Fix IntoEdgesDirected implementation for NodeFiltered when direction is Incoming (`476`_)
- Fix cardinality check in subgraph isomorphism (`472`_)
- Fix UB in ``MatrixGraph`` (`#505`_)
.. _`#472`: https://github.com/petgraph/petgraph/issues/472
.. _`#476`: https://github.com/petgraph/petgraph/issues/476
.. _`#487`: https://github.com/petgraph/petgraph/issues/487
.. _`#496`: https://github.com/petgraph/petgraph/issues/496
.. _`#500`: https://github.com/petgraph/petgraph/issues/500
.. _`#505`: https://github.com/petgraph/petgraph/issues/505
.. _`#521`: https://github.com/petgraph/petgraph/issues/521
.. _`#533`: https://github.com/petgraph/petgraph/issues/533
Version 0.6.2 (2022-05-28)
==========================
- Loosed the strict version dependency set in `493`_, to allow users to use newer versions of indexmap (`495`_).
.. _`#495`: https://github.com/petgraph/petgraph/issues/493
Version 0.6.1 (2022-05-22)
==========================
- Added clarifications on Graph docs (`491`_).
- Fix build errors on rust 1.41 (`493`_).
.. _`#491`: https://github.com/petgraph/petgraph/issues/491
.. _`#493`: https://github.com/petgraph/petgraph/issues/493
Version 0.6.0 (2021-07-04)
==========================
Breaking changes
----------------
- MSRV is now 1.41 (`#444`_).
- Removed the ``NodeCompactIndexable`` trait impl for ``MatrixGraph`` (`#429`_).
- The ``IntoEdges::edges`` implementations are now required return edges with the passed node as source (`#433`_).
New features
------------
- Multiple documentation improvements (`#360`_, `#383`_, `#426`_, `#433`_, `#437`_, `#443`_, `#450`_).
- Added an ``immediately_dominated_by`` method to the dominators result (`#337`_).
- Added ``adj::List``, a new append-only graph type using a simple adjacency list with no node-weights (`#263`_).
- Added ``dag_to_toposorted_adjacency_list`` and ``dag_transitive_reduction_closure`` algorithms to transitively reduce an acyclic graph (`#263`_).
- Made the ``is_isomorphic`` algorithm generic on both graph types (`#369`_).
- Implement Debug and Clone for all the iterators (`#418`_).
- Implement multiple mising traits on graph implementations and adapters (`#405`_, `#429`_).
- Add an EdgeIndexable public trait (`#402`_).
- Added immutable ``node_weights`` and ``edge_weights`` methods for ``Graph`` and ``StableGraph`` (`#363`_).
New algorithms
--------------
- Added a k-shortest-path implementation (`#328`_).
- Added a generic graph complement implementation (`#371`_).
- Added a maximum matching implementation (`#400`_).
- Added a Floyd-Warshall shortest path algorithm (`#377`_).
- Added a greedy feedback arc set algorithm (`#386`_).
- Added a `find_negative_cycle` algorithm (`#434`_).
Performance
-----------
- Reuse the internal state in ``tarjan_scc`` (`#313`_)
- Reduce memory usage in ``tarjan_scc`` (`#413`_).
- Added tighter size hints to all iterators (`#380`_).
- Optimized ``petgraph::dot`` a bit (`#424`_).
- Optimized StableGraph de-serialization with holes (`#395`_).
Bug fixes
---------
- Fixed A* not producing optimal solutions with inconsistent heuristics (`#379`_).
- Fixed a stacked borrow violation (`#404`_).
- Fixed a panic in ``StableGraph::extend_with_edges`` (`#415`_).
- Fixed multiple bugs in the matrix graph implementation (`#427`_).
- Fixed ``GraphMap::remove_node`` not removing some edges (`#432`_).
- Fixed all clippy warnings (`#440`_, `#449`_).
Other changes
-------------
- Now using github actions as CI (`#391`_).
- Replace matchs on `Option<T>` with `map` (`#381`_).
- Added benchmarks for ``tarjan_scc`` (`#421`_).
.. _`#263`: https://github.com/petgraph/petgraph/issues/263
.. _`#313`: https://github.com/petgraph/petgraph/issues/313
.. _`#328`: https://github.com/petgraph/petgraph/issues/328
.. _`#337`: https://github.com/petgraph/petgraph/issues/337
.. _`#360`: https://github.com/petgraph/petgraph/issues/360
.. _`#363`: https://github.com/petgraph/petgraph/issues/363
.. _`#369`: https://github.com/petgraph/petgraph/issues/369
.. _`#371`: https://github.com/petgraph/petgraph/issues/371
.. _`#377`: https://github.com/petgraph/petgraph/issues/377
.. _`#379`: https://github.com/petgraph/petgraph/issues/378
.. _`#380`: https://github.com/petgraph/petgraph/issues/380
.. _`#381`: https://github.com/petgraph/petgraph/issues/381
.. _`#383`: https://github.com/petgraph/petgraph/issues/383
.. _`#386`: https://github.com/petgraph/petgraph/issues/386
.. _`#391`: https://github.com/petgraph/petgraph/issues/391
.. _`#395`: https://github.com/petgraph/petgraph/issues/395
.. _`#400`: https://github.com/petgraph/petgraph/issues/400
.. _`#402`: https://github.com/petgraph/petgraph/issues/402
.. _`#404`: https://github.com/petgraph/petgraph/issues/404
.. _`#405`: https://github.com/petgraph/petgraph/issues/405
.. _`#413`: https://github.com/petgraph/petgraph/issues/413
.. _`#415`: https://github.com/petgraph/petgraph/issues/415
.. _`#418`: https://github.com/petgraph/petgraph/issues/418
.. _`#421`: https://github.com/petgraph/petgraph/issues/421
.. _`#424`: https://github.com/petgraph/petgraph/issues/424
.. _`#426`: https://github.com/petgraph/petgraph/issues/426
.. _`#427`: https://github.com/petgraph/petgraph/issues/427
.. _`#429`: https://github.com/petgraph/petgraph/issues/429
.. _`#432`: https://github.com/petgraph/petgraph/issues/432
.. _`#433`: https://github.com/petgraph/petgraph/issues/433
.. _`#434`: https://github.com/petgraph/petgraph/issues/434
.. _`#437`: https://github.com/petgraph/petgraph/issues/437
.. _`#440`: https://github.com/petgraph/petgraph/issues/440
.. _`#443`: https://github.com/petgraph/petgraph/issues/443
.. _`#444`: https://github.com/petgraph/petgraph/issues/444
.. _`#449`: https://github.com/petgraph/petgraph/issues/449
.. _`#450`: https://github.com/petgraph/petgraph/issues/450
Version 0.5.1 (2020-05-23)
==========================
- Implement ``Default`` for traversals.
- Export ``EdgesConnecting`` publicly.
- Implement ``is_bipartite_graph``.
- Add ``FilterNode`` implementation for ``FixedBitSet`` and ``HashSet``.
- Implement ``node_weights_mut`` and ``edge_weights_mut`` for ``StableGraph``.
- Add configurable functions for adding attributes to dotfile features.
Version 0.5.0 (2019-12-25)
==========================
Breaking changes
----------------
- The iterative DFS implementation, ``Dfs``, now marks nodes visited when
they are pushed onto the stack, not when they're popped off. This may
require changes to callers that use ``Dfs::from_parts`` or manipulate
its internals.
- The ``IntoEdgesDirected`` trait now has a stricter contract for
undirected graphs. Custom implementations of this trait may have to be
updated. See the `trait documentation`__ for more.
Other changes
-------------
- Upgrade to Rust 2018 edition
- Fix clippy warnings and unify code formatting
- Improved and enhanced documentation
- Update dependencies including modern quickcheck
- Numerous bugfixes and refactorings
- Added ``MatrixGraph`` implementation
__ https://docs.rs/petgraph/0.5/petgraph/visit/trait.IntoEdgesDirected.html
Version 0.4.13 (2018-08-26)
===========================
- Fix clippy warnings by @jonasbb
- Add docs for ``Csr`` by @ksadorf
- Fix conflict with new stable method ``find_map`` in new Rust
Version 0.4.12 (2018-03-26)
===========================
- Newtype ``Time`` now also implements ``Hash``
- Documentation updates for ``Frozen``.
Version 0.4.11 (2018-01-07)
===========================
- Fix ``petgraph::graph::NodeReferences`` to be publicly visible
- Small doc typo and code style files by @shepmaster and @waywardmonkeys
- Fix a future compat warning with pointer casts
Version 0.4.10 (2017-08-15)
===========================
- Add graph trait ``IntoEdgesDirected``
- Update dependencies
Version 0.4.9 (2017-10-02)
==========================
- Fix ``bellman_ford`` to work correctly with undirected graphs (#152) by
@carrutstick
- Performance improvements for ``Graph, Stablegraph``'s ``.map()``.
Version 0.4.8 (2017-09-20)
==========================
- ``StableGraph`` learned new methods nearing parity with ``Graph``. Note
that the ``StableGraph`` methods preserve index stability even in the batch
removal methods like ``filter_map`` and ``retain_edges``.
+ Added ``.filter_map()``, which maps associated node and edge data
+ Added ``.retain_edges()``, ``.edge_indices()`` and ``.clear_edges()``
- Existing ``Graph`` iterators gained some trait impls:
+ ``.node_indices(), .edge_indices()`` are ``ExactSizeIterator``
+ ``.node_references()`` is now
``DoubleEndedIterator + ExactSizeIterator``.
+ ``.edge_references()`` is now ``ExactSizeIterator``.
- Implemented ``From<StableGraph>`` for ``Graph``.
Version 0.4.7 (2017-09-16)
==========================
- New algorithm by @jmcomets: A* search algorithm in ``petgraph::algo::astar``
- One ``StableGraph`` bug fix whose patch was supposed to be in the previous
version:
+ ``add_edge(m, n, _)`` now properly always panics if nodes m or n don't
exist in the graph.
Version 0.4.6 (2017-09-12)
==========================
- New optional crate feature: ``"serde-1"``, which enables serialization
for ``Graph`` and ``StableGraph`` using serde.
- Add methods ``new``, ``add_node`` to ``Csr`` by @jmcomets
- Add indexing with ``[]`` by node index, ``NodeCompactIndexable`` for
``Csr`` by @jmcomets
- Amend doc for ``GraphMap::into_graph`` (it has a case where it can panic)
- Add implementation of ``From<Graph>`` for ``StableGraph``.
- Add implementation of ``IntoNodeReferences`` for ``&StableGraph``.
- Add method ``StableGraph::map`` that maps associated data
- Add method ``StableGraph::find_edge_undirected``
- Many ``StableGraph`` bug fixes involving node vacancies (holes left by
deletions):
+ ``neighbors(n)`` and similar neighbor and edge iterator methods now
handle n being a vacancy properly. (This produces an empty iterator.)
+ ``find_edge(m, n)`` now handles m being a vacancy correctly too
+ ``StableGraph::node_bound`` was fixed for empty graphs and returns 0
- Add implementation of ``DoubleEndedIterator`` to ``Graph, StableGraph``'s
edge references iterators.
- Debug output for ``Graph`` now shows node and edge count. ``Graph, StableGraph``
show nothing for the edges list if it's empty (no label).
- ``Arbitrary`` implementation for ``StableGraph`` now can produce graphs with
vacancies (used by quickcheck)
Version 0.4.5 (2017-06-16)
==========================
- Fix ``max`` ambiguity error with current rust nightly by @daboross (#153)
Version 0.4.4 (2017-03-14)
==========================
- Add ``GraphMap::all_edges_mut()`` iterator by @Binero
- Add ``StableGraph::retain_nodes`` by @Rupsbant
- Add ``StableGraph::index_twice_mut`` by @christolliday
Version 0.4.3 (2017-01-21)
==========================
- Add crate categories
Version 0.4.2 (2017-01-06)
==========================
- Move the ``visit.rs`` file due to changed rules for a modules directory
ownership in Rust, resolving a future compat warning.
- The error types ``Cycle, NegativeCycle`` now implement ``PartialEq``.
Version 0.4.1 (2016-10-26)
==========================
- Add new algorithm ``simple_fast`` for computing dominators in a control-flow
graph.
Version 0.4.0 (2016-10-17)
==========================
Breaking changes in ``Graph``
-----------------------------
- ``Graph::edges`` and the other edges methods now return an iterator of
edge references
Other breaking changes
----------------------
- ``toposort`` now returns an error if the graph had a cycle.
- ``is_cyclic_directed`` no longer takes a dfs space argument. It is
now recursive.
- ``scc`` was renamed to ``kosaraju_scc``.
- ``min_spanning_tree`` now returns an iterator that needs to be
made into a specific graph type deliberately.
- ``dijkstra`` now uses the ``IntoEdges`` trait.
- ``NodeIndexable`` changed its method signatures.
- ``IntoExternals`` was removed, and many other smaller adjustments
in graph traits. ``NodeId`` must now implement ``PartialEq``, for example.
- ``DfsIter, BfsIter`` were removed in favour of a more general approach
with the ``Walker`` trait and its iterator conversion.
New features
------------
- New graph traits, for example ``IntoEdges`` which returns
an iterator of edge references. Everything implements the graph traits
much more consistently.
- Traits for associated data access and building graphs: ``DataMap``,
``Build, Create, FromElements``.
- Graph adaptors: ``EdgeFiltered``. ``Filtered`` was renamed to ``NodeFiltered``.
- New algorithms: bellman-ford
- New graph: compressed sparse row (``Csr``).
- ``GraphMap`` implements ``NodeIndexable``.
- ``Dot`` was generalized
Version 0.3.2 (2016-10-11)
==========================
- Add ``depth_first_search``, a recursive dfs visitor that emits discovery,
finishing and edge classification events.
- Add graph adaptor ``Filtered``.
- impl ``Debug, NodeIndexable`` for ``Reversed``.
Version 0.3.1 (2016-10-05)
==========================
- Add ``.edges(), .edges_directed()`` to ``StableGraph``. Note that these
differ from ``Graph``, because this is the signature they will all use
in the future.
- Add ``.update_edge()`` to ``StableGraph``.
- Add reexports of common items in ``stable_graph`` module (for example
``NodeIndex``).
- Minor performance improvements to graph iteration
- Improved docs for ``visit`` module.
Version 0.3.0 (2016-10-03)
==========================
- Overhaul all graph visitor traits so that they use the ``IntoIterator``
style. This makes them composable.
- Multiple graph algorithms use new visitor traits.
- **Help is welcome to port more algorithms (and create new graph traits in
the process)!**
- ``GraphMap`` can now have directed edges. ``GraphMap::new`` is now generic
in the edge type. ``DiGraphMap`` and ``UnGraphMap`` are new type aliases.
- Add type aliases ``DiGraph, UnGraph, StableDiGraph, StableUnGraph``
- ``GraphMap`` is based on the indexmap crate. Deterministic iteration
order, faster iteration, no side tables needed to convert to ``Graph``.
- Improved docs for a lot of types and functions.
- Add graph visitor ``DfsPostOrder``
- ``Dfs`` gained new methods ``from_parts`` and ``reset``.
- New algo ``has_path_connecting``.
- New algo ``tarjan_scc``, a second scc implementation.
- Document traversal order in ``Dfs, DfsPostOrder, scc, tarjan_scc``.
- Optional graph visitor workspace reuse in ``has_path_connecting``,
``is_cyclic_directed, toposort``.
- Improved ``Debug`` formatting for ``Graph, StableGraph``.
- Add a prelude module
- ``GraphMap`` now has a method ``.into_graph()`` that makes a ``Graph``.
- ``Graph::retain_nodes, retain_edges`` now expose the self graph only
as wrapped in ``Frozen``, so that weights can be mutated but the
graph structure not.
- Enable ``StableGraph`` by default
- Add method ``Graph::contains_edge``.
- Renamed ``EdgeDirection````Direction``.
- Remove ``SubTopo``.
- Require Rust 1.12 or later
Version 0.2.10 (2016-07-27)
===========================
- Fix compilation with rust nightly
Version 0.2.9 (2016-10-01)
==========================
- Fix a bug in SubTopo (#81)
Version 0.2.8 (2016-09-12)
==========================
- Add Graph methods reserve_nodes, reserve_edges, reserve_exact_nodes,
reserve_exact_edges, shrink_to_fit_edges, shrink_to_fit_nodes, shrink_to_fit
Version 0.2.7 (2016-04-22)
==========================
- Update URLs
Version 0.2.6 (2016-04-20)
==========================
- Fix warning about type parameter defaults (no functional change)
Version 0.2.5 (2016-04-10)
==========================
- Add SubTopo, a topo walker for the subgraph reachable from a starting point.
- Add condensation, which forms the graph of a graphs strongly connected
components.
Version 0.2.4 (2016-04-05)
==========================
- Fix an algorithm error in scc (#61). This time we have a test that
crosschecks the result of the algorithm vs another implementation, for
greater confidence in its correctness.
Version 0.2.3 (2016-02-22)
==========================
- Require Rust 1.6: Due to changes in how rust uses type parameter defaults.
- Implement Graph::clone_from.
Version 0.2.2 (2015-12-14)
==========================
- Require Rust 1.5
- ``Dot`` passes on the alternate flag to node and edge label formatting
- Add ``Clone`` impl for some iterators
- Document edge iteration order for ``Graph::neighbors``
- Add *experimental feature* ``StableGraph``, using feature flag ``stable_graph``
Version 0.2.1 (2015-12-06)
==========================
- Add algorithm ``is_isomorphic_matching``
Version 0.2.0 (2015-12-03)
==========================
New Features
------------
- Add Graph::neighbors().detach() to step edges without borrowing.
This is more general than, and replaces now deprecated
walk_edges_directed. (#39)
- Implement Default for Graph, GraphMap
- Add method EdgeDirection::opposite()
Breaking changes
----------------
- Graph::neighbors() for undirected graphs and Graph::neighbors_undirected
for any graph now visit self loop edges once, not twice. (#31)
- Renamed Graph::without_edges to Graph::externals
- Removed Graph::edges_both
- GraphMap::add_edge now returns ``Option<E>``
- Element type of ``GraphMap<N, E>::all_edges()`` changed to ``(N, N, &E)``
Minor breaking changes
----------------------
- IntoWeightedEdge changed a type parameter to associated type
- IndexType is now an unsafe trait
- Removed IndexType::{one, zero}, use method new instead.
- Removed MinScored
- Ptr moved to the graphmap module.
- Directed, Undirected are now void enums.
- Fields of graphmap::Edges are now private (#19)
Version 0.1.18 (2015-11-30)
===========================
- Fix bug on calling GraphMap::add_edge with existing edge (#35)
Version 0.1.17 (2015-11-25)
===========================
- Add Graph::capacity(), GraphMap::capacity()
- Fix bug in Graph::reverse()
- Graph and GraphMap have `quickcheck::Arbitrary` implementations,
if optional feature `check` is enabled.
Version 0.1.16 (2015-11-25)
===========================
- Add Graph::node_indices(), Graph::edge_indices()
- Add Graph::retain_nodes(), Graph::retain_edges()
- Add Graph::extend_with_edges(), Graph::from_edges()
- Add functions petgraph::graph::{edge_index, node_index};
- Add GraphMap::extend(), GraphMap::from_edges()
- Add petgraph::dot::Dot for simple graphviz dot output
Version 0.1.15 (2015-11-20)
===========================
- Add Graph::clear_edges()
- Add Graph::edge_endpoints()
- Add Graph::map() and Graph::filter_map()
Version 0.1.14 (2015-11-19)
===========================
- Add new topological order visitor Topo
- New graph traits NeighborsDirected, Externals, Revisitable
Version 0.1.13 (2015-11-11)
===========================
- Add iterator GraphMap::all_edges
Version 0.1.12 (2015-11-07)
===========================
- Fix an algorithm error in scc (#14)
Version 0.1.11 (2015-08-16)
===========================
- Update for well-formedness warnings (Rust RFC 1214), adding
new lifetime bounds on NeighborIter and Dfs, impact should be minimal.
Version 0.1.10 (2015-06-22)
===========================
- Fix bug in WalkEdges::next_neighbor()
Version 0.1.9 (2015-06-17)
==========================
- Fix Dfs/Bfs for a rustc bugfix that disallowed them
- Add method next_neighbor() to WalkEdges
Version 0.1.8 (2015-06-08)
==========================
- Add Graph::walk_edges_directed()
- Add Graph::index_twice_mut()
Version 0.1.7 (2015-06-08)
==========================
- Add Graph::edges_directed()
Version 0.1.6 (2015-06-04)
==========================
- Add Graph::node_weights_mut and Graph::edge_weights_mut
Version 0.1.4 (2015-05-20)
==========================
- Add back DfsIter, BfsIter

7
vendor/petgraph/assets/LICENSE.md vendored Normal file
View File

@@ -0,0 +1,7 @@
Graphosaurus (c) by the petgraph project.
Graphosaurus is licensed under a
Creative Commons Attribution-ShareAlike 4.0 International License.
You should have received a copy of the license along with this
work. If not, see <http://creativecommons.org/licenses/by-sa/4.0/>.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

79
vendor/petgraph/assets/graphosaurus.svg vendored Normal file
View File

@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 1080 1080" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.4939;">
<g id="BG" transform="matrix(1.45617,0,0,1.45617,-177.479,-316.846)">
<circle cx="492.717" cy="588.424" r="370.836" style="fill:url(#_Linear1);"/>
</g>
<g id="Dino" transform="matrix(1.31121,0,0,1.31121,-168.053,-160.872)">
<g id="Spine">
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M344.381,624.427C352.952,630.783 291.743,593.515 305.989,554.967C309.656,545.043 327.367,538.101 337.698,539.727C352.535,542.061 361.823,550.315 361.823,550.315C361.823,550.315 301.592,487.382 337.387,455.659C372.587,424.463 414.052,469.675 414.052,469.675C414.052,469.675 396.39,446.84 390.528,422.13C386.016,403.11 390.364,381.847 410.371,371.779C455.802,348.915 489.35,420.373 489.35,420.373C489.35,420.373 483.894,389.2 497.626,355.227C506.318,333.724 523.567,310.411 551.363,310.953C585.811,311.625 600.113,340.976 605.598,366.84C611.701,395.623 604.834,416.791 604.834,416.791C603.86,419.188 615.694,390.81 638.086,373.982C653.254,362.583 675.954,358.705 692.466,364.739C727.903,377.689 726.41,418.417 721.78,435.169C714.039,463.173 701.392,476.439 701.392,476.439C701.392,476.439 717.331,461.164 737.597,458.735C753.393,456.842 772.367,458.317 783.095,477.345C803.737,513.954 746.279,563.679 746.279,563.679C746.279,563.679 763.19,551.794 778.493,549.443C786.068,548.279 795.042,551.478 799.829,555.673C819.262,572.702 791.394,611.758 791.394,611.758C791.394,611.758 801.439,598.091 816.261,592.639C821.478,590.72 828.538,591.133 834.232,591.703C851.62,593.443 850.95,622.319 850.95,622.319C850.95,622.319 856.174,602.696 870.25,602.561C880.629,602.461 885.607,611.627 885.607,611.627C885.607,611.627 887.33,601.757 895.307,601.875C901.361,601.964 902.461,606.953 902.461,606.953C902.456,608.485 855.54,629.12 822.806,625.673C789.183,622.133 748.842,610.936 720.089,512.441C715.874,498.002 707.012,488.3 699.635,478.234C658.548,422.172 583.878,423.491 543.985,417.099C498.457,409.803 368.81,497.877 355.151,589.488L344.381,624.427Z" style="fill:rgb(26,187,157);stroke:rgb(12,85,71);stroke-width:8.37px;"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M829.04,622.594C829.111,620.298 829.167,618.137 829.438,615.906C829.62,614.411 829.804,613.009 830.151,611.568C830.603,610.571 830.16,609.393 829.163,608.941C828.165,608.489 826.988,608.931 826.535,609.929C825.575,611.288 824.794,612.671 823.983,614.154C822.808,616.303 821.871,618.465 820.872,620.761C820.367,623.015 821.786,625.256 824.04,625.761C826.294,626.267 828.534,624.848 829.04,622.594Z" style="fill:rgb(21,150,126);"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M730.423,520.994C733.375,516.956 736.371,513.363 739.528,510.215C743.065,506.689 746.674,503.717 750.471,501.32C751.438,500.806 751.806,499.603 751.293,498.636C750.779,497.668 749.576,497.3 748.609,497.814C744.176,499.758 739.849,502.343 735.511,505.532C731.635,508.382 727.856,511.729 724.055,515.561C722.556,517.318 722.765,519.962 724.523,521.461C726.28,522.96 728.924,522.751 730.423,520.994Z" style="fill:rgb(21,150,126);"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M662.299,439.844C665.211,432.962 668.352,426.402 671.929,420.301C675.697,413.871 679.874,407.973 684.7,402.784C685.484,402.02 685.501,400.763 684.737,399.978C683.972,399.193 682.715,399.176 681.93,399.941C676.349,404.862 671.37,410.593 666.766,416.922C662.428,422.884 658.49,429.365 654.761,436.205C653.757,438.285 654.63,440.789 656.711,441.793C658.791,442.798 661.295,441.924 662.299,439.844Z" style="fill:rgb(21,150,126);"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M551.438,410.493C550.328,400.074 549.541,389.985 549.413,380.444C549.319,373.436 549.56,366.759 550.291,360.488C550.465,359.407 549.728,358.387 548.646,358.213C547.565,358.04 546.545,358.776 546.372,359.858C545.061,366.232 544.215,373.067 543.685,380.272C542.971,389.989 542.876,400.321 543.084,411.018C543.229,413.323 545.218,415.077 547.523,414.932C549.829,414.787 551.583,412.798 551.438,410.493Z" style="fill:rgb(21,150,126);"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M451.391,437.895C447.116,433.573 442.991,428.935 439.178,423.548C435.751,418.708 432.564,413.341 429.733,407.126C429.336,406.105 428.185,405.599 427.164,405.996C426.143,406.393 425.636,407.544 426.033,408.565C428.251,415.387 430.946,421.364 433.948,426.823C437.327,432.967 441.122,438.36 445.117,443.435C446.646,445.167 449.293,445.331 451.024,443.802C452.755,442.273 452.92,439.626 451.391,437.895Z" style="fill:rgb(21,150,126);"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M389.282,499.105C384.076,497.303 378.951,495.119 373.948,492.065C369.388,489.282 364.942,485.876 360.645,481.479C359.929,480.65 358.675,480.557 357.845,481.273C357.016,481.988 356.923,483.242 357.639,484.072C361.632,489.332 365.923,493.547 370.411,497.122C375.414,501.107 380.664,504.172 386.057,506.829C388.189,507.719 390.642,506.711 391.532,504.579C392.422,502.448 391.414,499.995 389.282,499.105Z" style="fill:rgb(21,150,126);"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M350.324,579.188C347.175,578.532 344.109,577.81 341.095,576.712C338.153,575.64 335.323,574.359 332.607,572.548C331.768,571.844 330.515,571.954 329.811,572.793C329.108,573.633 329.218,574.886 330.057,575.589C332.598,578.244 335.392,580.347 338.363,582.244C341.355,584.154 344.488,585.682 347.732,587.147C349.928,587.862 352.292,586.66 353.007,584.464C353.723,582.267 352.52,579.903 350.324,579.188Z" style="fill:rgb(21,150,126);"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M762.355,592.909C765.432,589.398 768.512,585.961 772.094,582.864C774.381,580.887 776.79,579.046 779.522,577.434C780.512,576.966 780.936,575.781 780.467,574.791C779.999,573.801 778.815,573.377 777.825,573.845C774.567,575.036 771.61,576.535 768.758,578.206C764.402,580.759 760.497,583.755 756.59,586.84C754.915,588.431 754.847,591.082 756.438,592.757C758.028,594.431 760.68,594.5 762.355,592.909Z" style="fill:rgb(21,150,126);"/>
</g>
</g>
<g id="Body" transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M338.634,620.121C342.3,604.078 384.038,411.662 548.588,410.744C608.922,410.407 659.271,430.309 690.072,463.237C740.152,516.776 743.248,578.944 765.584,596.255C787.919,613.566 816.363,623.423 843.686,622.893C871.175,622.359 897.605,602.106 906.153,608.041C915.712,614.68 898.348,634.112 894.237,641.08C890.125,648.049 829.318,709.148 735.453,731.686C735.088,739.273 737.911,779.304 707.467,779.154C677.023,779.004 679.842,741.328 679.826,731.938C679.826,731.938 602.452,736.145 565.23,735.794C527.688,735.439 451.631,731.938 451.631,731.938C451.631,731.938 456.748,779.154 423.99,779.154C391.231,779.154 397.686,733.898 396.004,731.686C392.109,731.235 383.289,730.094 371.553,731.615C333.414,736.558 273.886,753.504 244.862,740.618C219.677,729.437 213.02,718.784 210.942,696.892C209.148,677.996 227.065,641.931 253.045,627.718C279.128,613.45 315.372,619.822 338.634,620.121Z" style="fill:rgb(255,196,70);stroke:rgb(68,51,14);stroke-width:8.37px;"/>
</g>
<g id="Graph-Pattern" serif:id="Graph Pattern">
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M700.432,581.919L674.794,511.529L636.404,558.23L619.068,510.05L559.588,553.092" style="fill:none;stroke:rgb(150,103,46);stroke-width:8.37px;"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M601.785,596.577L700.432,581.919L663.929,637.373L700.432,581.919L736.6,626.852L700.432,581.919L636.404,558.23L559.588,553.092L619.068,510.05L674.794,511.529L619.068,510.05" style="fill:none;stroke:rgb(150,103,46);stroke-width:8.37px;"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M676.726,588.454C675.828,586.355 668.228,561.104 676.667,549.971C685.573,538.223 716.288,578.617 715.01,587.942C714.208,593.793 706.164,599.058 698.929,598.673C694.138,598.419 679.477,594.885 676.726,588.454Z" style="fill:rgb(255,144,8);stroke:rgb(77,47,10);stroke-width:8.37px;"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M732.943,641.686C729.307,639.169 718.604,623.417 728.11,616.323C739.315,607.962 747.221,625.727 743.344,632.664C740.495,637.761 736.314,644.019 732.943,641.686Z" style="fill:rgb(255,144,8);stroke:rgb(77,47,10);stroke-width:8.37px;"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M585.689,608.455C581.52,603.031 592.753,577.973 596.473,574.228C601.566,569.101 622.85,599.263 621.489,606.773C620.612,611.608 589.858,613.879 585.689,608.455Z" style="fill:rgb(255,144,8);stroke:rgb(77,47,10);stroke-width:8.37px;"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M556.812,537.246C562.629,536.033 578.739,557.291 576.127,560.606C573.515,563.922 564.016,564.735 557.847,561.571C552.582,558.872 546.114,555.025 546.564,550.146C547.014,545.267 554.137,537.803 556.812,537.246Z" style="fill:rgb(255,144,8);stroke:rgb(77,47,10);stroke-width:8.37px;"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M623.545,565.917C619.162,558.48 620.21,550.615 630.296,547.563C639.174,544.876 644.977,538.675 647.806,551.585C650.635,564.495 650.511,574.753 646.509,579.203C642.507,583.653 626.602,571.105 623.545,565.917Z" style="fill:rgb(255,144,8);stroke:rgb(77,47,10);stroke-width:8.37px;"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M611.474,524.301C602.774,515.729 607.242,497.654 611.814,495.014C616.714,492.184 623.795,498.523 631.415,504.419C639.673,510.81 646.482,518.434 641.52,524.166C636.557,529.898 612.235,525.051 611.474,524.301Z" style="fill:rgb(255,144,8);stroke:rgb(77,47,10);stroke-width:8.37px;"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M661.515,524.417C658.661,521.165 658.698,515.164 660.993,503.893C662.709,495.464 673.107,488.38 687.905,504.808C701.044,519.394 705.301,526.544 700.571,530.366C695.841,534.188 664.688,528.033 661.515,524.417Z" style="fill:rgb(255,144,8);stroke:rgb(77,47,10);stroke-width:8.37px;"/>
</g>
<g transform="matrix(1,0,0,1,-19.9019,-42.4382)">
<path d="M656.306,647.582C654.429,646.446 644.397,636.963 653.58,629.001C663.296,620.576 673.542,630.844 671.782,639.692C670.351,646.891 660.556,650.154 656.306,647.582Z" style="fill:rgb(255,144,8);stroke:rgb(77,47,10);stroke-width:8.37px;"/>
</g>
</g>
<g id="Eye" transform="matrix(1.10262,0,0,1.07214,-44.321,-97.3476)">
<ellipse cx="266.665" cy="704.812" rx="8.291" ry="8.611" style="fill:rgb(39,39,39);"/>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(9.72367e-06,-741.672,741.672,9.72367e-06,492.717,959.26)"><stop offset="0" style="stop-color:rgb(255,228,187);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(196,225,215);stop-opacity:1"/></linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

59
vendor/petgraph/assets/pridosaurus.svg vendored Normal file
View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 1080 1080" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.4939;">
<g id="BG" transform="matrix(1.45617,0,0,1.45617,-177.479,-316.846)">
<circle cx="492.717" cy="588.424" r="370.836" style="fill:url(#_Linear1);"/>
</g>
<g id="Ebene1" transform="matrix(1.31121,0,0,1.31121,-194.149,-216.518)">
<path d="M849.974,624.265L850.95,622.319C850.95,622.319 856.174,602.696 870.25,602.561C880.629,602.461 885.607,611.627 885.607,611.627C885.607,611.627 887.33,601.757 895.307,601.875C901.361,601.964 902.461,606.953 902.461,606.953C902.457,608.118 877.37,619.998 849.974,624.265Z" style="fill:rgb(255,238,0);stroke:rgb(153,143,0);stroke-width:8.37px;"/>
<g>
<path d="M852.451,623.824C841.76,625.945 832.594,626.704 822.806,625.673C810.942,624.424 800.185,623.203 787.453,616.549L791.394,611.758C791.394,611.758 801.439,598.091 816.261,592.639C821.478,590.72 828.538,591.133 834.232,591.703C851.62,593.443 850.95,622.319 850.95,622.319L852.451,623.824Z" style="fill:rgb(255,141,0);stroke:rgb(153,85,0);stroke-width:8.37px;"/>
<path d="M829.04,622.594C829.111,620.298 829.167,618.137 829.438,615.906C829.62,614.411 829.804,613.009 830.151,611.568C830.603,610.571 830.16,609.393 829.163,608.941C828.165,608.489 826.988,608.931 826.535,609.929C825.575,611.288 824.794,612.671 823.983,614.154C822.808,616.303 821.871,618.465 820.872,620.761C820.367,623.015 821.786,625.256 824.04,625.761C826.294,626.267 828.534,624.848 829.04,622.594Z" style="fill:rgb(211,117,0);"/>
</g>
<g>
<path d="M790.473,617.945C773.23,611.174 756.936,598.304 741.012,567.365L746.279,563.679C746.279,563.679 763.19,551.794 778.493,549.443C786.068,548.279 795.042,551.478 799.829,555.673C819.262,572.702 791.394,611.758 791.394,611.758L790.473,617.945Z" style="fill:rgb(229,0,0);stroke:rgb(128,0,0);stroke-width:8.37px;"/>
<path d="M762.355,592.909C765.432,589.398 768.512,585.961 772.094,582.864C774.381,580.887 776.79,579.046 779.522,577.434C780.512,576.966 780.936,575.781 780.467,574.791C779.999,573.801 778.815,573.377 777.825,573.845C774.567,575.036 771.61,576.535 768.758,578.206C764.402,580.759 760.497,583.755 756.59,586.84C754.915,588.431 754.847,591.082 756.438,592.757C758.028,594.431 760.68,594.5 762.355,592.909Z" style="fill:rgb(180,0,0);"/>
</g>
<g>
<path d="M742.944,570.112C734.655,555.2 727.229,536.9 720.089,512.441C715.874,498.002 707.012,488.3 699.635,478.234C698.984,477.346 699.22,477.64 698.553,476.78L701.392,476.439C701.392,476.439 717.331,461.164 737.597,458.735C753.393,456.842 772.367,458.317 783.095,477.345C803.737,513.954 746.279,563.679 746.279,563.679L742.944,570.112Z" style="fill:rgb(119,0,136);stroke:rgb(57,0,65);stroke-width:8.37px;"/>
<path d="M730.423,520.994C733.375,516.956 736.371,513.363 739.528,510.215C743.065,506.689 746.674,503.717 750.471,501.32C751.438,500.806 751.806,499.603 751.293,498.636C750.779,497.668 749.576,497.3 748.609,497.814C744.176,499.758 739.849,502.343 735.511,505.532C731.635,508.382 727.856,511.729 724.055,515.561C722.556,517.318 722.765,519.962 724.523,521.461C726.28,522.96 728.924,522.751 730.423,520.994Z" style="fill:rgb(86,0,98);"/>
</g>
<g>
<path d="M699.783,477.846C674.315,443.097 636.753,431.752 601.76,425.593L604.834,416.791C603.86,419.188 615.694,390.81 638.086,373.982C653.254,362.583 675.954,358.705 692.466,364.739C727.903,377.689 726.41,418.417 721.78,435.169C714.039,463.173 701.392,476.439 701.392,476.439L699.783,477.846Z" style="fill:rgb(0,76,255);stroke:rgb(0,31,104);stroke-width:8.37px;"/>
<path d="M662.299,439.844C665.211,432.962 668.352,426.402 671.929,420.301C675.697,413.871 679.874,407.973 684.7,402.784C685.484,402.02 685.501,400.763 684.737,399.978C683.972,399.193 682.715,399.176 681.93,399.941C676.349,404.862 671.37,410.593 666.766,416.922C662.428,422.884 658.49,429.365 654.761,436.205C653.757,438.285 654.63,440.789 656.711,441.793C658.791,442.798 661.295,441.924 662.299,439.844Z" style="fill:rgb(0,60,202);"/>
</g>
<g>
<path d="M603.922,425.001C579.196,419.858 561.233,419.863 543.985,417.099C531.061,415.028 513.369,419.626 491.467,430.824L489.35,420.373C489.35,420.373 483.894,389.2 497.626,355.227C506.318,333.724 523.567,310.411 551.363,310.953C585.811,311.625 600.113,340.976 605.598,366.84C611.701,395.623 604.834,416.791 604.834,416.791C604.427,417.791 603.922,425.001 603.922,425.001Z" style="fill:rgb(2,129,33);stroke:rgb(1,64,16);stroke-width:8.37px;"/>
<path d="M551.438,410.493C550.328,400.074 549.541,389.985 549.413,380.444C549.319,373.436 549.56,366.759 550.291,360.488C550.465,359.407 549.728,358.387 548.646,358.213C547.565,358.04 546.545,358.776 546.372,359.858C545.061,366.232 544.215,373.067 543.685,380.272C542.971,389.989 542.876,400.321 543.084,411.018C543.229,413.323 545.218,415.077 547.523,414.932C549.829,414.787 551.583,412.798 551.438,410.493Z" style="fill:rgb(1,83,21);"/>
</g>
<g>
<path d="M496.749,428.279C496.749,428.279 448.567,456.705 423.904,480.11L414.052,469.675C414.052,469.675 396.39,446.84 390.528,422.13C386.016,403.11 390.364,381.847 410.371,371.779C455.802,348.915 489.35,420.373 489.35,420.373L496.749,428.279Z" style="fill:rgb(255,238,0);stroke:rgb(153,143,0);stroke-width:8.37px;"/>
<path d="M451.391,437.895C447.116,433.573 442.991,428.935 439.178,423.548C435.751,418.708 432.564,413.341 429.733,407.126C429.336,406.105 428.185,405.599 427.164,405.996C426.143,406.393 425.636,407.544 426.033,408.565C428.251,415.387 430.946,421.364 433.948,426.823C437.327,432.967 441.122,438.36 445.117,443.435C446.646,445.167 449.293,445.331 451.024,443.802C452.755,442.273 452.92,439.626 451.391,437.895Z" style="fill:rgb(204,190,0);"/>
</g>
<g>
<path d="M423.894,478.078C400.253,499.855 378.561,526.43 366.065,553.819L361.823,550.315C361.823,550.315 301.592,487.382 337.387,455.659C372.587,424.463 414.052,469.675 414.052,469.675L423.894,478.078Z" style="fill:rgb(255,141,0);stroke:rgb(153,85,0);stroke-width:8.37px;"/>
<path d="M389.282,499.105C384.076,497.303 378.951,495.119 373.948,492.065C369.388,489.282 364.942,485.876 360.645,481.479C359.929,480.65 358.675,480.557 357.845,481.273C357.016,481.988 356.923,483.242 357.639,484.072C361.632,489.332 365.923,493.547 370.411,497.122C375.414,501.107 380.664,504.172 386.057,506.829C388.189,507.719 390.642,506.711 391.532,504.579C392.422,502.448 391.414,499.995 389.282,499.105Z" style="fill:rgb(204,113,0);"/>
</g>
<g>
<path d="M366.091,553.762C360.744,565.471 356.946,577.449 355.151,589.488L344.381,624.427C352.952,630.783 291.743,593.515 305.989,554.967C309.656,545.043 327.367,538.101 337.698,539.727C352.535,542.061 361.823,550.315 361.823,550.315L366.091,553.762Z" style="fill:rgb(229,0,0);stroke:rgb(128,0,0);stroke-width:8.37px;"/>
<path d="M350.324,579.188C347.175,578.532 344.109,577.81 341.095,576.712C338.153,575.64 335.323,574.359 332.607,572.548C331.768,571.844 330.515,571.954 329.811,572.793C329.108,573.633 329.218,574.886 330.057,575.589C332.598,578.244 335.392,580.347 338.363,582.244C341.355,584.154 344.488,585.682 347.732,587.147C349.928,587.862 352.292,586.66 353.007,584.464C353.723,582.267 352.52,579.903 350.324,579.188Z" style="fill:rgb(180,0,0);"/>
</g>
<path d="M338.634,620.121C342.3,604.078 384.038,411.662 548.588,410.744C608.922,410.407 659.271,430.309 690.072,463.237C740.152,516.776 743.248,578.944 765.584,596.255C787.919,613.566 816.363,623.423 843.686,622.893C871.175,622.359 897.605,602.106 906.153,608.041C915.712,614.68 898.348,634.112 894.237,641.08C890.125,648.049 829.318,709.148 735.453,731.686C735.088,739.273 737.911,779.304 707.467,779.154C677.023,779.004 679.842,741.328 679.826,731.938C679.826,731.938 602.452,736.145 565.23,735.794C527.688,735.439 451.631,731.938 451.631,731.938C451.631,731.938 456.748,779.154 423.99,779.154C391.231,779.154 397.686,733.898 396.004,731.686C392.109,731.235 383.289,730.094 371.553,731.615C333.414,736.558 273.886,753.504 244.862,740.618C219.677,729.437 213.02,718.784 210.942,696.892C209.148,677.996 227.065,641.931 253.045,627.718C279.128,613.45 315.372,619.822 338.634,620.121Z" style="fill:rgb(255,196,70);stroke:rgb(68,51,14);stroke-width:8.37px;"/>
<path d="M700.432,581.919L674.794,511.529L636.404,558.23L619.068,510.05L559.588,553.092" style="fill:none;stroke:rgb(150,103,46);stroke-width:8.37px;"/>
<path d="M601.785,596.577L700.432,581.919L663.929,637.373L700.432,581.919L736.6,626.852L700.432,581.919L636.404,558.23L559.588,553.092L619.068,510.05L674.794,511.529L619.068,510.05" style="fill:none;stroke:rgb(150,103,46);stroke-width:8.37px;"/>
<path d="M676.726,588.454C675.828,586.355 668.228,561.104 676.667,549.971C685.573,538.223 716.288,578.617 715.01,587.942C714.208,593.793 706.164,599.058 698.929,598.673C694.138,598.419 679.477,594.885 676.726,588.454Z" style="fill:rgb(255,144,8);stroke:rgb(77,47,10);stroke-width:8.37px;"/>
<path d="M732.943,641.686C729.307,639.169 718.604,623.417 728.11,616.323C739.315,607.962 747.221,625.727 743.344,632.664C740.495,637.761 736.314,644.019 732.943,641.686Z" style="fill:rgb(255,144,8);stroke:rgb(77,47,10);stroke-width:8.37px;"/>
<path d="M585.689,608.455C581.52,603.031 592.753,577.973 596.473,574.228C601.566,569.101 622.85,599.263 621.489,606.773C620.612,611.608 589.858,613.879 585.689,608.455Z" style="fill:rgb(255,144,8);stroke:rgb(77,47,10);stroke-width:8.37px;"/>
<path d="M556.812,537.246C562.629,536.033 578.739,557.291 576.127,560.606C573.515,563.922 564.016,564.735 557.847,561.571C552.582,558.872 546.114,555.025 546.564,550.146C547.014,545.267 554.137,537.803 556.812,537.246Z" style="fill:rgb(255,144,8);stroke:rgb(77,47,10);stroke-width:8.37px;"/>
<path d="M623.545,565.917C619.162,558.48 620.21,550.615 630.296,547.563C639.174,544.876 644.977,538.675 647.806,551.585C650.635,564.495 650.511,574.753 646.509,579.203C642.507,583.653 626.602,571.105 623.545,565.917Z" style="fill:rgb(255,144,8);stroke:rgb(77,47,10);stroke-width:8.37px;"/>
<path d="M611.474,524.301C602.774,515.729 607.242,497.654 611.814,495.014C616.714,492.184 623.795,498.523 631.415,504.419C639.673,510.81 646.482,518.434 641.52,524.166C636.557,529.898 612.235,525.051 611.474,524.301Z" style="fill:rgb(255,144,8);stroke:rgb(77,47,10);stroke-width:8.37px;"/>
<path d="M661.515,524.417C658.661,521.165 658.698,515.164 660.993,503.893C662.709,495.464 673.107,488.38 687.905,504.808C701.044,519.394 705.301,526.544 700.571,530.366C695.841,534.188 664.688,528.033 661.515,524.417Z" style="fill:rgb(255,144,8);stroke:rgb(77,47,10);stroke-width:8.37px;"/>
<path d="M656.306,647.582C654.429,646.446 644.397,636.963 653.58,629.001C663.296,620.576 673.542,630.844 671.782,639.692C670.351,646.891 660.556,650.154 656.306,647.582Z" style="fill:rgb(255,144,8);stroke:rgb(77,47,10);stroke-width:8.37px;"/>
<g transform="matrix(1.10262,0,0,1.07214,-24.4192,-54.9094)">
<ellipse cx="266.665" cy="704.812" rx="8.291" ry="8.611" style="fill:rgb(39,39,39);"/>
</g>
</g>
<defs>
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(9.72367e-06,-741.672,741.672,9.72367e-06,492.717,959.26)"><stop offset="0" style="stop-color:rgb(255,228,187);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(196,225,215);stop-opacity:1"/></linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

58
vendor/petgraph/benches/acyclic.rs vendored Normal file
View File

@@ -0,0 +1,58 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use petgraph::algo::{toposort, DfsSpace};
use petgraph::prelude::*;
use petgraph::{acyclic::Acyclic, data::Build};
use std::cmp::max;
use test::Bencher;
/// Dynamic toposort using Acyclic<G>
#[bench]
#[allow(clippy::needless_range_loop)]
fn acyclic_bench(bench: &mut Bencher) {
static NODE_COUNT: usize = 100;
let mut g = Acyclic::<DiGraph<usize, ()>>::new();
let nodes: Vec<NodeIndex<_>> = (0..NODE_COUNT).map(|i| g.add_node(i)).collect();
bench.iter(|| {
let mut g = g.clone();
for i in 0..NODE_COUNT {
let n1 = nodes[i];
let neighbour_count = i % 8 + 3;
let j_from = max(0, i as i32 - neighbour_count as i32) as usize;
let j_to = i;
for j in j_from..j_to {
let n2 = nodes[j];
g.try_add_edge(n1, n2, ()).unwrap();
}
}
});
}
/// As a baseline: build the graph and toposort it every time a new edge is added
#[bench]
#[allow(clippy::needless_range_loop)]
fn toposort_baseline_bench(bench: &mut Bencher) {
static NODE_COUNT: usize = 100;
let mut g = DiGraph::<usize, ()>::new();
let nodes: Vec<NodeIndex<_>> = (0..NODE_COUNT).map(|i| g.add_node(i)).collect();
bench.iter(|| {
let mut g = g.clone();
let mut space = DfsSpace::new(&g);
for i in 0..NODE_COUNT {
let n1 = nodes[i];
let neighbour_count = i % 8 + 3;
let j_from = max(0, i as i32 - neighbour_count as i32) as usize;
let j_to = i;
for j in j_from..j_to {
let n2 = nodes[j];
g.add_edge(n1, n2, ());
let _order = toposort(&g, Some(&mut space));
}
}
});
}

62
vendor/petgraph/benches/bellman_ford.rs vendored Normal file
View File

@@ -0,0 +1,62 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use petgraph::prelude::*;
use std::cmp::{max, min};
use test::Bencher;
use petgraph::algo::{bellman_ford, find_negative_cycle};
#[bench]
#[allow(clippy::needless_range_loop)]
fn bellman_ford_bench(bench: &mut Bencher) {
static NODE_COUNT: usize = 100;
let mut g = Graph::new();
let nodes: Vec<NodeIndex<_>> = (0..NODE_COUNT).map(|i| g.add_node(i)).collect();
for i in 0..NODE_COUNT {
let n1 = nodes[i];
let neighbour_count = i % 8 + 3;
let j_from = max(0, i as i32 - neighbour_count as i32 / 2) as usize;
let j_to = min(NODE_COUNT, j_from + neighbour_count);
for j in j_from..j_to {
let n2 = nodes[j];
let mut distance: f64 = ((i + 3) % 10) as f64;
if n1 != n2 {
distance -= 1.0
}
g.add_edge(n1, n2, distance);
}
}
bench.iter(|| {
let _scores = bellman_ford(&g, nodes[0]);
});
}
#[bench]
#[allow(clippy::needless_range_loop)]
fn find_negative_cycle_bench(bench: &mut Bencher) {
static NODE_COUNT: usize = 100;
let mut g = Graph::new();
let nodes: Vec<NodeIndex<_>> = (0..NODE_COUNT).map(|i| g.add_node(i)).collect();
for i in 0..NODE_COUNT {
let n1 = nodes[i];
let neighbour_count = i % 8 + 3;
let j_from = max(0, i as i32 - neighbour_count as i32 / 2) as usize;
let j_to = min(NODE_COUNT, j_from + neighbour_count);
for j in j_from..j_to {
let n2 = nodes[j];
let mut distance: f64 = ((i + 3) % 10) as f64;
if n1 != n2 {
distance -= 1.0
}
g.add_edge(n1, n2, distance);
}
}
bench.iter(|| {
let _scores = find_negative_cycle(&g, nodes[0]);
});
}

31
vendor/petgraph/benches/coloring.rs vendored Normal file
View File

@@ -0,0 +1,31 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use petgraph::prelude::*;
use std::cmp::{max, min};
use test::Bencher;
use petgraph::algo::dsatur_coloring;
#[bench]
fn dsatur_coloring_bench(bench: &mut Bencher) {
static NODE_COUNT: usize = 10_000;
let mut g = Graph::new_undirected();
let nodes: Vec<NodeIndex<_>> = (0..NODE_COUNT).into_iter().map(|i| g.add_node(i)).collect();
for i in 0..NODE_COUNT {
let n1 = nodes[i];
let neighbour_count = i % 8 + 3;
let j_from = max(0, i as i32 - neighbour_count as i32 / 2) as usize;
let j_to = min(NODE_COUNT, j_from + neighbour_count);
for j in j_from..j_to {
let n2 = nodes[j];
g.add_edge(n1, n2, ());
}
}
bench.iter(|| {
let _scores = dsatur_coloring(&g);
});
}

View File

@@ -0,0 +1,334 @@
use std::marker::PhantomData;
use petgraph::data::Build;
use petgraph::prelude::*;
use petgraph::visit::NodeIndexable;
use petgraph::EdgeType;
/// Petersen A and B are isomorphic
///
/// http://www.dharwadker.org/tevet/isomorphism/
const PETERSEN_A: &str = "
0 1 0 0 1 0 1 0 0 0
1 0 1 0 0 0 0 1 0 0
0 1 0 1 0 0 0 0 1 0
0 0 1 0 1 0 0 0 0 1
1 0 0 1 0 1 0 0 0 0
0 0 0 0 1 0 0 1 1 0
1 0 0 0 0 0 0 0 1 1
0 1 0 0 0 1 0 0 0 1
0 0 1 0 0 1 1 0 0 0
0 0 0 1 0 0 1 1 0 0
";
const PETERSEN_B: &str = "
0 0 0 1 0 1 0 0 0 1
0 0 0 1 1 0 1 0 0 0
0 0 0 0 0 0 1 1 0 1
1 1 0 0 0 0 0 1 0 0
0 1 0 0 0 0 0 0 1 1
1 0 0 0 0 0 1 0 1 0
0 1 1 0 0 1 0 0 0 0
0 0 1 1 0 0 0 0 1 0
0 0 0 0 1 1 0 1 0 0
1 0 1 0 1 0 0 0 0 0
";
/// An almost full set, isomorphic
const FULL_A: &str = "
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 0 1 1 1 0 1
1 1 1 1 1 1 1 1 1 1
";
const FULL_B: &str = "
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 0 1 1 1 0 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
";
/// Praust A and B are not isomorphic
const PRAUST_A: &str = "
0 1 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
1 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0
1 1 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0
1 1 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0
1 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0
0 1 0 0 1 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0
0 0 1 0 1 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0
0 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 1 0 0
0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1
0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 1 0 0
0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 1
0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 1 0
0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 1
0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 1 1
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 1
0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 1 0
";
const PRAUST_B: &str = "
0 1 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
1 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0
1 1 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0
1 1 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0
1 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0
0 1 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1
0 0 1 0 1 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0
1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0
0 1 0 0 0 0 0 0 1 0 1 1 0 1 0 0 0 0 0 0
0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 1 0 1
0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 1 1 0 1 0
0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 1 0 1
0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 0 1 0 1 0
0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 1 0 1 1 0
0 0 0 0 0 0 0 1 0 0 0 0 1 0 1 0 1 0 0 1
0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 0 0 1
0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 0 0 1 1 0
";
const BIGGER: &str = "
0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 1 0 1 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 0 1 0 1 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 1 0 0
0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 1
0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 1 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 1
0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 1 1 0 1 1 1 0 0 0 0 0 1 0 0 1 0 0 0 1 0 1 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 1
0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 1 0
0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
1 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 1 0 1 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 1 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0
0 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 1 0 0
0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1
0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 1 0 0
0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0
0 1 0 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 1
0 1 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 1 0
0 1 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 1
0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 1 1
0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 1
0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 1 0
";
/// A random bipartite graph.
const BIPARTITE: &str = "
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 1 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 1 1
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 1 1
1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0
0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0
0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
1 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0
";
/// Parse a text adjacency matrix format into a directed graph
fn parse_graph<Ty, G>(s: &str) -> G
where
Ty: EdgeType,
G: Default + Build<NodeWeight = (), EdgeWeight = ()> + NodeIndexable,
{
let mut g: G = Default::default();
let s = s.trim();
let lines = s.lines().filter(|l| !l.is_empty());
for (row, line) in lines.enumerate() {
for (col, word) in line.split(' ').filter(|s| !s.is_empty()).enumerate() {
let has_edge = word.parse::<i32>().unwrap();
assert!(has_edge == 0 || has_edge == 1);
if has_edge == 0 {
continue;
}
while col >= g.node_count() || row >= g.node_count() {
g.add_node(());
}
let a = g.from_index(row);
let b = g.from_index(col);
g.update_edge(a, b, ());
}
}
g
}
pub struct GraphFactory<Ty, G = Graph<(), (), Ty>> {
ty: PhantomData<Ty>,
g: PhantomData<G>,
}
impl<Ty, G> GraphFactory<Ty, G>
where
Ty: EdgeType,
G: Default + Build<NodeWeight = (), EdgeWeight = ()> + NodeIndexable,
{
fn new() -> Self {
GraphFactory {
ty: PhantomData,
g: PhantomData,
}
}
pub fn petersen_a(self) -> G {
parse_graph::<Ty, _>(PETERSEN_A)
}
pub fn petersen_b(self) -> G {
parse_graph::<Ty, _>(PETERSEN_B)
}
pub fn full_a(self) -> G {
parse_graph::<Ty, _>(FULL_A)
}
pub fn full_b(self) -> G {
parse_graph::<Ty, _>(FULL_B)
}
pub fn praust_a(self) -> G {
parse_graph::<Ty, _>(PRAUST_A)
}
pub fn praust_b(self) -> G {
parse_graph::<Ty, _>(PRAUST_B)
}
pub fn bigger(self) -> G {
parse_graph::<Ty, _>(BIGGER)
}
pub fn bipartite(self) -> G {
parse_graph::<Ty, _>(BIPARTITE)
}
}
pub fn graph<Ty: EdgeType>() -> GraphFactory<Ty, Graph<(), (), Ty>> {
GraphFactory::new()
}
pub fn ungraph() -> GraphFactory<Undirected, Graph<(), (), Undirected>> {
graph()
}
pub fn digraph() -> GraphFactory<Directed, Graph<(), (), Directed>> {
graph()
}
pub fn stable_graph<Ty: EdgeType>() -> GraphFactory<Ty, StableGraph<(), (), Ty>> {
GraphFactory::new()
}
pub fn stable_ungraph() -> GraphFactory<Undirected, StableGraph<(), (), Undirected>> {
stable_graph()
}
pub fn stable_digraph() -> GraphFactory<Directed, StableGraph<(), (), Directed>> {
stable_graph()
}
pub fn tournament(node_count: usize) -> DiGraph<(), ()> {
let mut edge_forward = true;
let mut g = DiGraph::new();
for _ in 0..node_count {
g.add_node(());
}
for i in g.node_indices() {
for j in g.node_indices() {
if i >= j {
continue;
}
let (source, target) = if edge_forward { (i, j) } else { (j, i) };
g.add_edge(source, target, ());
edge_forward = !edge_forward;
}
}
g
}
/// An F_(1,n) graph (where **|E| == 2(|N|) - 1**) with pseudo-random edge directions.
pub fn directed_fan(n: usize) -> DiGraph<(), ()> {
let mut g = DiGraph::new();
for _ in 0..(n + 1) {
g.add_node(());
}
let mut indices = g.node_indices();
let ix_0 = indices.next().unwrap();
let mut edge_forward = true;
let mut prev_ix = None;
for ix in indices {
let (source, target) = if edge_forward { (ix_0, ix) } else { (ix, ix_0) };
g.add_edge(source, target, ());
if let Some(prev_ix) = prev_ix {
let (source, target) = if edge_forward {
(prev_ix, ix)
} else {
(ix, prev_ix)
};
g.add_edge(source, target, ());
}
edge_forward = !edge_forward;
prev_ix = Some(ix);
}
g
}

2
vendor/petgraph/benches/common/mod.rs vendored Normal file
View File

@@ -0,0 +1,2 @@
mod factories;
pub use factories::*;

33
vendor/petgraph/benches/dijkstra.rs vendored Normal file
View File

@@ -0,0 +1,33 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use petgraph::prelude::*;
use std::cmp::{max, min};
use test::Bencher;
use petgraph::algo::dijkstra;
#[bench]
#[allow(clippy::needless_range_loop)]
fn dijkstra_bench(bench: &mut Bencher) {
static NODE_COUNT: usize = 10_000;
let mut g = Graph::new_undirected();
let nodes: Vec<NodeIndex<_>> = (0..NODE_COUNT).map(|i| g.add_node(i)).collect();
for i in 0..NODE_COUNT {
let n1 = nodes[i];
let neighbour_count = i % 8 + 3;
let j_from = max(0, i as i32 - neighbour_count as i32 / 2) as usize;
let j_to = min(NODE_COUNT, j_from + neighbour_count);
for j in j_from..j_to {
let n2 = nodes[j];
let distance = (i + 3) % 10;
g.add_edge(n1, n2, distance);
}
}
bench.iter(|| {
let _scores = dijkstra(&g, nodes[0], None, |e| *e.weight());
});
}

View File

@@ -0,0 +1,55 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use test::Bencher;
use petgraph::algo::greedy_feedback_arc_set;
#[allow(dead_code)]
mod common;
use common::{directed_fan, tournament};
#[bench]
fn greedy_fas_tournament_10_bench(bench: &mut Bencher) {
let g = tournament(10);
bench.iter(|| greedy_feedback_arc_set(&g).for_each(|_| ()))
}
#[bench]
fn greedy_fas_tournament_50_bench(bench: &mut Bencher) {
let g = tournament(50);
bench.iter(|| greedy_feedback_arc_set(&g).for_each(|_| ()))
}
#[bench]
fn greedy_fas_tournament_200_bench(bench: &mut Bencher) {
let g = tournament(200);
bench.iter(|| greedy_feedback_arc_set(&g).for_each(|_| ()))
}
#[bench]
fn greedy_fas_fan_10_bench(bench: &mut Bencher) {
let g = directed_fan(10);
bench.iter(|| greedy_feedback_arc_set(&g).for_each(|_| ()))
}
#[bench]
fn greedy_fas_fan_200_bench(bench: &mut Bencher) {
let g = directed_fan(200);
bench.iter(|| greedy_feedback_arc_set(&g).for_each(|_| ()))
}
#[bench]
fn greedy_fas_fan_1000_bench(bench: &mut Bencher) {
let g = directed_fan(1000);
bench.iter(|| greedy_feedback_arc_set(&g).for_each(|_| ()))
}

View File

@@ -0,0 +1,33 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use petgraph::prelude::*;
use std::cmp::{max, min};
use test::Bencher;
use petgraph::algo::floyd_warshall;
#[bench]
#[allow(clippy::needless_range_loop)]
fn floyd_warshall_bench(bench: &mut Bencher) {
static NODE_COUNT: usize = 100;
let mut g = Graph::new_undirected();
let nodes: Vec<NodeIndex<_>> = (0..NODE_COUNT).map(|i| g.add_node(i)).collect();
for i in 0..NODE_COUNT {
let n1 = nodes[i];
let neighbour_count = i % 8 + 3;
let j_from = max(0, i as i32 - neighbour_count as i32 / 2) as usize;
let j_to = min(NODE_COUNT, j_from + neighbour_count);
for j in j_from..j_to {
let n2 = nodes[j];
let distance = (i + 3) % 10;
g.add_edge(n1, n2, distance);
}
}
bench.iter(|| {
let _scores = floyd_warshall(&g, |e| *e.weight());
});
}

View File

@@ -0,0 +1,24 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use petgraph::algo::ford_fulkerson;
use petgraph::prelude::{Graph, NodeIndex};
use test::Bencher;
#[bench]
fn ford_fulkerson_bench(bench: &mut Bencher) {
static NODE_COUNT: usize = 1_000;
let mut g: Graph<usize, usize> = Graph::new();
let nodes: Vec<NodeIndex<_>> = (0..NODE_COUNT).map(|i| g.add_node(i)).collect();
for i in 0..NODE_COUNT - 1 {
g.add_edge(nodes[i], nodes[i + 1], 1);
}
bench.iter(|| {
let _flow = ford_fulkerson(
&g,
NodeIndex::from(0),
NodeIndex::from(g.node_count() as u32 - 1),
);
});
}

View File

@@ -0,0 +1,37 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use petgraph::graph6::from_graph6_representation;
use test::Bencher;
#[bench]
fn from_graph6_str_complete_7(bench: &mut Bencher) {
from_graph6_bench(bench, r"F~~~w");
}
#[bench]
fn from_graph6_str_petersen(bench: &mut Bencher) {
from_graph6_bench(bench, r"IheA@GUAo");
}
#[bench]
fn from_graph6_str_62(bench: &mut Bencher) {
from_graph6_bench(
bench,
r"}x@?xx|G[RO{QRDDMWAJ@XAT\M@IBsP?P[jJKOECP_QKSsL@_Th?mUp@@WC_woIl_nI?AF_ISAGNGxe?pikrJVOwWEqoMKhWGAjk[XPn?WUGrWC]jUjwPJLF@?OU?IGSoqT_rpEM[KCpTvGYBgRvOyJ`\adaY?qsESfR{IQWs?mT}bB@[|?p}MOCOEUZKMw]xKeV[en_EK{eBN?Add?H_@GeE_Bo@?_?PmabQuWc?FHVWcwCLWUF]l??WdIOtyePOc`Sb{SGCU[[__b[OiWnDeCXB@CwW@q_GAYY^eWD[tmoPDf{W]eKjzWCCKOj_",
);
}
#[bench]
fn from_graph6_str_63(bench: &mut Bencher) {
from_graph6_bench(
bench,
r"~??~`U@aoLr_G\V`YnUdSA[@PG?CjSvrrFONaJODKrXQMOMEcExcwEILVHfUDsB[rGLhVVYJgI?DRSBAgsFwAVzs@gct_AL`NkAoRCaHOaTGWcgPs{@a_s^HLZBaB_[W_o__U|aRGLpdK@{EJ?xQOCcOksK_X@AI`aleB\KDwlOX?_@`_K@SD?QOQ?dAz]?hb{UYvdRRoQPrGKdgfUKIDQM\mZCjJW|?~XcoyIHEr~HycEDToBFD?_DT?bYNaQaQ`BMAYWuyo@Uz{dQwViiepaHfAdaaGO[CHW]ggCka?s@g@b?cbI[a@`BlU^nFxy?YL?R[GKIPm_",
);
}
fn from_graph6_bench(bench: &mut Bencher, graph6_str: &str) {
bench.iter(|| (from_graph6_representation::<u16>(graph6_str.to_string())));
}

View File

@@ -0,0 +1,35 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use petgraph::graph6::ToGraph6;
use test::Bencher;
#[allow(dead_code)]
mod common;
use common::ungraph;
#[bench]
fn graph6_string_praust_bench(bench: &mut Bencher) {
let a = ungraph().praust_a();
let b = ungraph().praust_b();
bench.iter(|| (a.graph6_string(), b.graph6_string()));
}
#[bench]
fn graph6_string_full_bench(bench: &mut Bencher) {
let a = ungraph().full_a();
let b = ungraph().full_b();
bench.iter(|| (a.graph6_string(), b.graph6_string()));
}
#[bench]
fn graph6_string_petersen_bench(bench: &mut Bencher) {
let a = ungraph().petersen_a();
let b = ungraph().petersen_b();
bench.iter(|| (a.graph6_string(), b.graph6_string()));
}

94
vendor/petgraph/benches/graphmap.rs vendored Normal file
View File

@@ -0,0 +1,94 @@
#![feature(test)]
#![cfg(feature = "rayon")]
extern crate petgraph;
extern crate test;
use petgraph::prelude::*;
use rayon::iter::ParallelIterator;
use std::hash::BuildHasher;
use test::Bencher;
#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
struct MyStruct {
u: String,
v: String,
w: String,
}
fn test_nodes() -> Vec<MyStruct> {
let mut nodes = vec![];
for i in 0..2500 {
nodes.push(MyStruct {
u: format!("X {}", i),
v: format!("Y {} Y", i),
w: format!("{}Z", i),
});
}
nodes
}
fn test_graph<H: BuildHasher + Default>(
data: &Vec<MyStruct>,
) -> GraphMap<&MyStruct, usize, Directed, H> {
let mut gr = GraphMap::new();
for i in 0..2500 {
gr.add_node(&data[i]);
}
for i in 0..1_000 {
for j in 999..2000 {
gr.add_edge(&data[i], &data[j], i * j);
}
}
gr
}
macro_rules! test_case_with_hasher {
($name:ident, $hasher:path) => {
#[bench]
fn $name(bench: &mut Bencher) {
let data = test_nodes();
let gr = test_graph::<$hasher>(&data);
bench.iter(|| {
let mut sources = vec![];
for n in gr.nodes() {
for (src, _, e) in gr.edges_directed(n, Direction::Outgoing) {
if *e == 500 {
sources.push(src.clone());
}
}
}
});
}
};
}
test_case_with_hasher!(graphmap_serial_bench, std::hash::RandomState);
test_case_with_hasher!(graphmap_serial_bench_fxhash, fxhash::FxBuildHasher);
test_case_with_hasher!(graphmap_serial_bench_ahash, ahash::RandomState);
#[bench]
fn graphmap_parallel_bench(bench: &mut Bencher) {
let data = test_nodes();
let gr = test_graph::<std::hash::RandomState>(&data);
bench.iter(|| {
let sources: Vec<MyStruct> = gr
.par_nodes()
.map(|n| {
let mut sources = vec![];
for (src, _, e) in gr.edges_directed(n, Direction::Outgoing) {
if *e == 500 {
sources.push(src.clone());
}
}
sources
})
.flatten()
.collect();
});
}

57
vendor/petgraph/benches/iso.rs vendored Normal file
View File

@@ -0,0 +1,57 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use test::Bencher;
#[allow(dead_code)]
mod common;
use common::*;
use petgraph::algo::is_isomorphic;
#[bench]
fn petersen_iso_bench(bench: &mut Bencher) {
let a = digraph().petersen_a();
let b = digraph().petersen_b();
bench.iter(|| is_isomorphic(&a, &b));
assert!(is_isomorphic(&a, &b));
}
#[bench]
fn petersen_undir_iso_bench(bench: &mut Bencher) {
let a = ungraph().petersen_a();
let b = ungraph().petersen_b();
bench.iter(|| is_isomorphic(&a, &b));
assert!(is_isomorphic(&a, &b));
}
#[bench]
fn full_iso_bench(bench: &mut Bencher) {
let a = ungraph().full_a();
let b = ungraph().full_b();
bench.iter(|| is_isomorphic(&a, &b));
assert!(is_isomorphic(&a, &b));
}
#[bench]
fn praust_dir_no_iso_bench(bench: &mut Bencher) {
let a = digraph().praust_a();
let b = digraph().praust_b();
bench.iter(|| is_isomorphic(&a, &b));
assert!(!is_isomorphic(&a, &b));
}
#[bench]
fn praust_undir_no_iso_bench(bench: &mut Bencher) {
let a = ungraph().praust_a();
let b = ungraph().praust_b();
bench.iter(|| is_isomorphic(&a, &b));
assert!(!is_isomorphic(&a, &b));
}

View File

@@ -0,0 +1,31 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use petgraph::prelude::*;
use std::cmp::{max, min};
use test::Bencher;
use petgraph::algo::k_shortest_path;
#[bench]
#[allow(clippy::needless_range_loop)]
fn k_shortest_path_bench(bench: &mut Bencher) {
static NODE_COUNT: usize = 10_000;
let mut g = Graph::new_undirected();
let nodes: Vec<NodeIndex<_>> = (0..NODE_COUNT).map(|i| g.add_node(i)).collect();
for i in 0..NODE_COUNT {
let n1 = nodes[i];
let neighbour_count = i % 8 + 3;
let j_from = max(0, i as i32 - neighbour_count as i32 / 2) as usize;
let j_to = min(NODE_COUNT, j_from + neighbour_count);
for j in j_from..j_to {
let n2 = nodes[j];
let distance = (i + 3) % 10;
g.add_edge(n1, n2, distance);
}
}
bench.iter(|| k_shortest_path(&g, nodes[0], None, 2, |e| *e.weight()));
}

78
vendor/petgraph/benches/matching.rs vendored Normal file
View File

@@ -0,0 +1,78 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use test::Bencher;
#[allow(dead_code)]
mod common;
use common::*;
use petgraph::algo::{greedy_matching, maximum_matching};
use petgraph::graph::UnGraph;
fn huge() -> UnGraph<(), ()> {
static NODE_COUNT: u32 = 1_000;
let mut edges = Vec::new();
for i in 0..NODE_COUNT {
for j in i..NODE_COUNT {
if i % 3 == 0 && j % 2 == 0 {
edges.push((i, j));
}
}
}
// 999 nodes, 83500 edges
UnGraph::from_edges(&edges)
}
#[bench]
fn greedy_matching_bipartite(bench: &mut Bencher) {
let g = ungraph().bipartite();
bench.iter(|| greedy_matching(&g));
}
#[bench]
fn greedy_matching_full(bench: &mut Bencher) {
let g = ungraph().full_a();
bench.iter(|| greedy_matching(&g));
}
#[bench]
fn greedy_matching_bigger(bench: &mut Bencher) {
let g = ungraph().bigger();
bench.iter(|| greedy_matching(&g));
}
#[bench]
fn greedy_matching_huge(bench: &mut Bencher) {
let g = huge();
bench.iter(|| greedy_matching(&g));
}
#[bench]
fn maximum_matching_bipartite(bench: &mut Bencher) {
let g = ungraph().bipartite();
bench.iter(|| maximum_matching(&g));
}
#[bench]
fn maximum_matching_full(bench: &mut Bencher) {
let g = ungraph().full_a();
bench.iter(|| maximum_matching(&g));
}
#[bench]
fn maximum_matching_bigger(bench: &mut Bencher) {
let g = ungraph().bigger();
bench.iter(|| maximum_matching(&g));
}
#[bench]
fn maximum_matching_huge(bench: &mut Bencher) {
let g = huge();
bench.iter(|| maximum_matching(&g));
}

246
vendor/petgraph/benches/matrix_graph.rs vendored Normal file
View File

@@ -0,0 +1,246 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use test::Bencher;
use petgraph::algo;
use petgraph::matrix_graph::{node_index, MatrixGraph};
use petgraph::{Directed, EdgeType, Incoming, Outgoing};
#[bench]
fn add_100_nodes(b: &mut test::Bencher) {
b.iter(|| {
let mut g = MatrixGraph::<(), ()>::with_capacity(100);
for _ in 0..100 {
let _ = g.add_node(());
}
});
}
#[bench]
fn add_100_edges_to_self(b: &mut test::Bencher) {
let mut g = MatrixGraph::<(), ()>::with_capacity(100);
let nodes: Vec<_> = (0..100).map(|_| g.add_node(())).collect();
let g = g;
b.iter(|| {
let mut g = g.clone();
for &node in nodes.iter() {
g.add_edge(node, node, ());
}
});
}
#[bench]
fn add_5_edges_for_each_of_100_nodes(b: &mut test::Bencher) {
let mut g = MatrixGraph::<(), ()>::with_capacity(100);
let nodes: Vec<_> = (0..100).map(|_| g.add_node(())).collect();
let g = g;
let edges_to_add: Vec<_> = nodes
.iter()
.enumerate()
.flat_map(|(i, &node)| {
let edges: Vec<_> = (0..5)
.map(|j| (i + j + 1) % nodes.len())
.map(|j| (node, nodes[j]))
.collect();
edges
})
.collect();
b.iter(|| {
let mut g = g.clone();
for &(source, target) in edges_to_add.iter() {
g.add_edge(source, target, ());
}
});
}
#[bench]
fn add_edges_from_root(bench: &mut test::Bencher) {
bench.iter(|| {
let mut gr = MatrixGraph::new();
let a = gr.add_node(());
for _ in 0..100 {
let b = gr.add_node(());
gr.add_edge(a, b, ());
}
});
}
#[bench]
fn add_adjacent_edges(bench: &mut test::Bencher) {
bench.iter(|| {
let mut gr = MatrixGraph::new();
let mut prev = None;
for _ in 0..100 {
let b = gr.add_node(());
if let Some(a) = prev {
gr.add_edge(a, b, ());
}
prev = Some(b);
}
});
}
/// An almost full set
const FULL: &str = "
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 0 1 1 1 0 1
1 1 1 1 1 1 1 1 1 1
";
const BIGGER: &str = "
0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 1 0 1 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 0 1 0 1 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 1 0 0
0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 1
0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 1 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 1
0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 1 1 0 1 1 1 0 0 0 0 0 1 0 0 1 0 0 0 1 0 1 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 1
0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 1 0
0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
1 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 1 0 1 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 1 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 1 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 0 0
0 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 1 0 0
0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1
0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 0 1 0 0
0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 1 1 0 0 0
0 1 0 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 1
0 1 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 1 0
0 1 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 1 1 1
0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 1 1
0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1 0 1
0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 1 1 0
";
/// Parse a text adjacency matrix format into a directed graph
fn parse_matrix<Ty: EdgeType>(s: &str) -> MatrixGraph<(), (), Ty> {
let mut gr = MatrixGraph::default();
let s = s.trim();
let lines = s.lines().filter(|l| !l.is_empty());
for (row, line) in lines.enumerate() {
for (col, word) in line.split(' ').filter(|s| !s.is_empty()).enumerate() {
let has_edge = word.parse::<i32>().unwrap();
assert!(has_edge == 0 || has_edge == 1);
if has_edge == 0 {
continue;
}
while col >= gr.node_count() || row >= gr.node_count() {
gr.add_node(());
}
gr.add_edge(node_index(row), node_index(col), ());
}
}
gr
}
#[bench]
fn full_edges_out(bench: &mut Bencher) {
let a = parse_matrix::<Directed>(FULL);
bench.iter(|| a.edges_directed(node_index(1), Outgoing).count())
}
#[bench]
fn full_edges_in(bench: &mut Bencher) {
let a = parse_matrix::<Directed>(FULL);
bench.iter(|| a.edges_directed(node_index(1), Incoming).count())
}
#[bench]
fn full_neighbors_out(bench: &mut Bencher) {
let a = parse_matrix::<Directed>(FULL);
bench.iter(|| a.neighbors_directed(node_index(1), Outgoing).count())
}
#[bench]
fn full_neighbors_in(bench: &mut Bencher) {
let a = parse_matrix::<Directed>(FULL);
bench.iter(|| a.neighbors_directed(node_index(1), Incoming).count())
}
#[bench]
fn full_kosaraju_sccs(bench: &mut Bencher) {
let a = parse_matrix::<Directed>(FULL);
bench.iter(|| algo::kosaraju_scc(&a));
}
#[bench]
fn full_tarjan_sccs(bench: &mut Bencher) {
let a = parse_matrix::<Directed>(FULL);
bench.iter(|| algo::tarjan_scc(&a));
}
#[bench]
fn bigger_edges_out(bench: &mut Bencher) {
let a = parse_matrix::<Directed>(BIGGER);
bench.iter(|| a.edges_directed(node_index(1), Outgoing).count())
}
#[bench]
fn bigger_edges_in(bench: &mut Bencher) {
let a = parse_matrix::<Directed>(BIGGER);
bench.iter(|| a.edges_directed(node_index(1), Incoming).count())
}
#[bench]
fn bigger_neighbors_out(bench: &mut Bencher) {
let a = parse_matrix::<Directed>(BIGGER);
bench.iter(|| a.neighbors_directed(node_index(1), Outgoing).count())
}
#[bench]
fn bigger_neighbors_in(bench: &mut Bencher) {
let a = parse_matrix::<Directed>(BIGGER);
bench.iter(|| a.neighbors_directed(node_index(1), Incoming).count())
}
#[bench]
fn bigger_kosaraju_sccs(bench: &mut Bencher) {
let a = parse_matrix::<Directed>(BIGGER);
bench.iter(|| algo::kosaraju_scc(&a));
}
#[bench]
fn bigger_tarjan_sccs(bench: &mut Bencher) {
let a = parse_matrix::<Directed>(BIGGER);
bench.iter(|| algo::tarjan_scc(&a));
}

View File

@@ -0,0 +1,60 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use test::Bencher;
#[allow(dead_code)]
mod common;
use common::{digraph, ungraph};
use petgraph::algo::min_spanning_tree;
#[bench]
fn min_spanning_tree_praust_undir_bench(bench: &mut Bencher) {
let a = ungraph().praust_a();
let b = ungraph().praust_b();
bench.iter(|| (min_spanning_tree(&a), min_spanning_tree(&b)));
}
#[bench]
fn min_spanning_tree_praust_dir_bench(bench: &mut Bencher) {
let a = digraph().praust_a();
let b = digraph().praust_b();
bench.iter(|| (min_spanning_tree(&a), min_spanning_tree(&b)));
}
#[bench]
fn min_spanning_tree_full_undir_bench(bench: &mut Bencher) {
let a = ungraph().full_a();
let b = ungraph().full_b();
bench.iter(|| (min_spanning_tree(&a), min_spanning_tree(&b)));
}
#[bench]
fn min_spanning_tree_full_dir_bench(bench: &mut Bencher) {
let a = digraph().full_a();
let b = digraph().full_b();
bench.iter(|| (min_spanning_tree(&a), min_spanning_tree(&b)));
}
#[bench]
fn min_spanning_tree_petersen_undir_bench(bench: &mut Bencher) {
let a = ungraph().petersen_a();
let b = ungraph().petersen_b();
bench.iter(|| (min_spanning_tree(&a), min_spanning_tree(&b)));
}
#[bench]
fn min_spanning_tree_petersen_dir_bench(bench: &mut Bencher) {
let a = digraph().petersen_a();
let b = digraph().petersen_b();
bench.iter(|| (min_spanning_tree(&a), min_spanning_tree(&b)));
}

52
vendor/petgraph/benches/ograph.rs vendored Normal file
View File

@@ -0,0 +1,52 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use petgraph::graph::Graph;
#[bench]
fn bench_inser(b: &mut test::Bencher) {
let mut og = Graph::new();
let fst = og.add_node(0i32);
for x in 1..125 {
let n = og.add_node(x);
og.add_edge(fst, n, ());
}
b.iter(|| og.add_node(1))
}
#[bench]
fn bench_add_edge(b: &mut test::Bencher) {
let mut og = Graph::new();
for _ in 0..100 {
og.add_node(());
}
b.iter(|| {
for (a, b) in og.node_indices().zip(og.node_indices().skip(1)) {
og.add_edge(a, b, ());
}
og.clear_edges();
})
}
#[bench]
fn bench_remove(b: &mut test::Bencher) {
// removal is very slow in a big graph.
// and this one doesn't even have many nodes.
let mut og = Graph::new();
let fst = og.add_node(0i32);
let mut prev = fst;
for x in 1..1250 {
let n = og.add_node(x);
og.add_edge(prev, n, ());
prev = n;
}
//println!("{}", og);
b.iter(|| {
for _ in 0..100 {
og.remove_node(fst);
}
})
}

36
vendor/petgraph/benches/page_rank.rs vendored Normal file
View File

@@ -0,0 +1,36 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use test::Bencher;
use petgraph::algo::page_rank;
#[allow(dead_code)]
mod common;
use common::directed_fan;
#[cfg(feature = "rayon")]
use petgraph::algo::page_rank::parallel_page_rank;
#[cfg(feature = "rayon")]
use rayon::prelude::*;
#[bench]
fn page_rank_bench(bench: &mut Bencher) {
static NODE_COUNT: usize = 500;
let g = directed_fan(NODE_COUNT);
bench.iter(|| {
let _ranks = page_rank(&g, 0.6_f64, 10);
});
}
#[bench]
#[cfg(feature = "rayon")]
fn par_page_rank_bench(bench: &mut Bencher) {
static NODE_COUNT: usize = 2_000;
let g = directed_fan(NODE_COUNT);
bench.iter(|| {
let _ranks = parallel_page_rank(&g, 0.6_f64, 100, None);
});
}

55
vendor/petgraph/benches/serialize.rs vendored Normal file
View File

@@ -0,0 +1,55 @@
#![feature(test)]
#[cfg(feature = "serde-1")]
mod serialize {
extern crate petgraph;
extern crate test;
use petgraph::prelude::*;
use rand::Rng;
use test::Bencher;
const NUM_NODES: usize = 1_000_000;
const NUM_EDGES: usize = 100_000;
const NUM_HOLES: usize = 1_000_000;
fn make_stable_graph() -> StableGraph<u32, u32> {
let mut g = StableGraph::with_capacity(NUM_NODES + NUM_HOLES, NUM_EDGES);
let indices: Vec<_> = (0..NUM_NODES + NUM_HOLES)
.map(|i| g.add_node(i as u32))
.collect();
let mut rng = rand::thread_rng();
g.extend_with_edges((0..NUM_EDGES).map(|_| {
let first = rng.gen_range(0, NUM_NODES + NUM_HOLES);
let second = rng.gen_range(0, NUM_NODES + NUM_HOLES - 1);
let second = second + (second >= first) as usize;
let weight: u32 = rng.gen();
(indices[first], indices[second], weight)
}));
// Remove nodes to make the structure a bit more interesting
while g.node_count() > NUM_NODES {
let idx = rng.gen_range(0, indices.len());
g.remove_node(indices[idx]);
}
g
}
#[bench]
fn serialize_stable_graph(bench: &mut Bencher) {
let graph = make_stable_graph();
bench.iter(|| bincode::serialize(&graph).unwrap());
}
#[bench]
fn deserialize_stable_graph(bench: &mut Bencher) {
let graph = make_stable_graph();
let data = bincode::serialize(&graph).unwrap();
bench.iter(|| {
let graph2: StableGraph<u32, u32> = bincode::deserialize(&data).unwrap();
graph2
});
}
}

97
vendor/petgraph/benches/stable_graph.rs vendored Normal file
View File

@@ -0,0 +1,97 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use petgraph::prelude::*;
use test::Bencher;
#[allow(dead_code)]
mod common;
use common::*;
use petgraph::stable_graph::node_index;
#[bench]
fn full_edges_default(bench: &mut Bencher) {
let a = stable_digraph().full_a();
bench.iter(|| a.edges(node_index(1)).count())
}
#[bench]
fn full_edges_out(bench: &mut Bencher) {
let a = stable_digraph().full_a();
bench.iter(|| a.edges_directed(node_index(1), Outgoing).count())
}
#[bench]
fn full_edges_in(bench: &mut Bencher) {
let a = stable_digraph().full_a();
bench.iter(|| a.edges_directed(node_index(1), Incoming).count())
}
#[bench]
fn neighbors_default(bench: &mut Bencher) {
let a = stable_digraph().full_a();
bench.iter(|| a.neighbors(node_index(1)).count())
}
#[bench]
fn neighbors_out(bench: &mut Bencher) {
let a = stable_digraph().full_a();
bench.iter(|| a.neighbors_directed(node_index(1), Outgoing).count())
}
#[bench]
fn neighbors_in(bench: &mut Bencher) {
let a = stable_digraph().full_a();
bench.iter(|| a.neighbors_directed(node_index(1), Incoming).count())
}
#[bench]
fn sccs_kosaraju_stable_graph(bench: &mut Bencher) {
let a = stable_digraph().bigger();
bench.iter(|| petgraph::algo::kosaraju_scc(&a));
}
#[bench]
fn sccs_kosaraju_graph(bench: &mut Bencher) {
let a = digraph().bigger();
bench.iter(|| petgraph::algo::kosaraju_scc(&a));
}
#[bench]
fn sccs_tarjan_stable_graph(bench: &mut Bencher) {
let a = stable_digraph().bigger();
bench.iter(|| petgraph::algo::tarjan_scc(&a));
}
#[bench]
fn sccs_tarjan_graph(bench: &mut Bencher) {
let a = digraph().bigger();
bench.iter(|| petgraph::algo::tarjan_scc(&a));
}
#[bench]
fn stable_graph_map(bench: &mut Bencher) {
let a = stable_digraph().bigger();
bench.iter(|| a.map(|i, _| i, |i, _| i));
}
#[bench]
fn graph_map(bench: &mut Bencher) {
let a = digraph().bigger();
bench.iter(|| a.map(|i, _| i, |i, _| i));
}
#[bench]
fn stable_graph_retain_nodes(bench: &mut Bencher) {
let mut a = stable_digraph().bigger();
bench.iter(|| a.retain_nodes(|_gr, i| (i.index() + 1) % 3700 != 0));
}
#[bench]
fn stable_graph_retain_edges(bench: &mut Bencher) {
let mut a = stable_digraph().bigger();
bench.iter(|| a.retain_edges(|_gr, i| (i.index() + 1) % 3700 != 0));
}

108
vendor/petgraph/benches/unionfind.rs vendored Normal file
View File

@@ -0,0 +1,108 @@
#![feature(test)]
extern crate petgraph;
extern crate test;
use test::Bencher;
#[allow(dead_code)]
mod common;
use common::*;
use petgraph::algo::{connected_components, is_cyclic_undirected};
#[bench]
fn connected_components_praust_undir_bench(bench: &mut Bencher) {
let a = ungraph().praust_a();
let b = ungraph().praust_b();
bench.iter(|| (connected_components(&a), connected_components(&b)));
}
#[bench]
fn connected_components_praust_dir_bench(bench: &mut Bencher) {
let a = digraph().praust_a();
let b = digraph().praust_b();
bench.iter(|| (connected_components(&a), connected_components(&b)));
}
#[bench]
fn connected_components_full_undir_bench(bench: &mut Bencher) {
let a = ungraph().full_a();
let b = ungraph().full_b();
bench.iter(|| (connected_components(&a), connected_components(&b)));
}
#[bench]
fn connected_components_full_dir_bench(bench: &mut Bencher) {
let a = digraph().full_a();
let b = digraph().full_b();
bench.iter(|| (connected_components(&a), connected_components(&b)));
}
#[bench]
fn connected_components_petersen_undir_bench(bench: &mut Bencher) {
let a = ungraph().petersen_a();
let b = ungraph().petersen_b();
bench.iter(|| (connected_components(&a), connected_components(&b)));
}
#[bench]
fn connected_components_petersen_dir_bench(bench: &mut Bencher) {
let a = digraph().petersen_a();
let b = digraph().petersen_b();
bench.iter(|| (connected_components(&a), connected_components(&b)));
}
#[bench]
fn is_cyclic_undirected_praust_undir_bench(bench: &mut Bencher) {
let a = ungraph().praust_a();
let b = ungraph().praust_b();
bench.iter(|| (is_cyclic_undirected(&a), is_cyclic_undirected(&b)));
}
#[bench]
fn is_cyclic_undirected_praust_dir_bench(bench: &mut Bencher) {
let a = digraph().praust_a();
let b = digraph().praust_b();
bench.iter(|| (is_cyclic_undirected(&a), is_cyclic_undirected(&b)));
}
#[bench]
fn is_cyclic_undirected_full_undir_bench(bench: &mut Bencher) {
let a = ungraph().full_a();
let b = ungraph().full_b();
bench.iter(|| (is_cyclic_undirected(&a), is_cyclic_undirected(&b)));
}
#[bench]
fn is_cyclic_undirected_full_dir_bench(bench: &mut Bencher) {
let a = digraph().full_a();
let b = digraph().full_b();
bench.iter(|| (is_cyclic_undirected(&a), is_cyclic_undirected(&b)));
}
#[bench]
fn is_cyclic_undirected_petersen_undir_bench(bench: &mut Bencher) {
let a = ungraph().petersen_a();
let b = ungraph().petersen_b();
bench.iter(|| (is_cyclic_undirected(&a), is_cyclic_undirected(&b)));
}
#[bench]
fn is_cyclic_undirected_petersen_dir_bench(bench: &mut Bencher) {
let a = digraph().petersen_a();
let b = digraph().petersen_b();
bench.iter(|| (is_cyclic_undirected(&a), is_cyclic_undirected(&b)));
}

1
vendor/petgraph/clippy.toml vendored Normal file
View File

@@ -0,0 +1 @@
msrv = "1.41.0"

25
vendor/petgraph/custom.css vendored Normal file
View File

@@ -0,0 +1,25 @@
.docblock pre.rust { background: #eeeeff; }
pre.trait, pre.fn, pre.struct, pre.enum, pre.typedef { background: #fcfefc; }
/* Small “example” label for doc examples */
.docblock pre.rust::before {
content: "example";
float: right;
font-style: italic;
font-size: 0.8em;
margin-top: -10px;
margin-right: -5px;
}
/* Fixup where display in trait listing */
pre.trait .where::before {
content: '\a ';
}
.docblock code {
background-color: inherit;
font-weight: bold;
padding: 0 0.1em;
}

15
vendor/petgraph/graph-example.dot vendored Normal file
View File

@@ -0,0 +1,15 @@
digraph {
rankdir = "LR";
splines = true;
0 [label="petgraph"]
1 [label="fixedbitset"]
2 [label="quickcheck"]
3 [label="rand"]
4 [label="libc"]
0 -> 1
0 -> 2
2 -> 3
3 -> 4
2 -> 4
}

867
vendor/petgraph/src/acyclic.rs vendored Normal file
View File

@@ -0,0 +1,867 @@
//! A wrapper around graph types that enforces an acyclicity invariant.
use std::{
cell::RefCell,
cmp::Ordering,
collections::{BTreeMap, BTreeSet},
convert::TryFrom,
ops::{Deref, RangeBounds},
};
use crate::{
adj::IndexType,
algo::Cycle,
data::{Build, Create, DataMap, DataMapMut},
graph::NodeIndex,
prelude::DiGraph,
visit::{
dfs_visitor, Control, Data, DfsEvent, EdgeCount, EdgeIndexable, GetAdjacencyMatrix,
GraphBase, GraphProp, IntoEdgeReferences, IntoEdges, IntoEdgesDirected, IntoNeighbors,
IntoNeighborsDirected, IntoNodeIdentifiers, IntoNodeReferences, NodeCompactIndexable,
NodeCount, NodeIndexable, Reversed, Time, Visitable,
},
Direction,
};
#[cfg(feature = "stable_graph")]
use crate::stable_graph::StableDiGraph;
mod order_map;
use fixedbitset::FixedBitSet;
use order_map::OrderMap;
pub use order_map::TopologicalPosition;
/// A directed acyclic graph.
///
/// Wrap directed acyclic graphs and expose an API that ensures the invariant
/// is maintained, i.e. no cycles can be created. This uses a topological order
/// that is dynamically updated when edges are added. In the worst case, the
/// runtime may be linear in the number of vertices, but it has been shown to
/// be fast in practice, particularly on sparse graphs (Pierce and Kelly, 2004).
///
/// To be modifiable (and hence to be useful), the graphs of generic type `G`
/// should implement the [`Build`] trait. Good candidates for `G` are thus
/// [`crate::graph::DiGraph`] and [`crate::stable_graph::StableDiGraph`].
///
/// ## Algorithm
/// This implements the PK algorithm for dynamic topological sort described in
/// "A Dynamic Topological Sort Algorithm for Directed Acyclic Graphs" by
/// D. Pierce and P. Kelly, JEA, 2004. It maintains a topological order of the
/// nodes that can be efficiently updated when edges are added. Achieves a good
/// balance between simplicity and performance in practice, see the paper for
/// discussions of the running time.
///
/// ## Graph traits
/// All graph traits are delegated to the inner graph, with the exception of
/// the graph construction trait [`Build`]. The wrapped graph can thus only
/// be modified through the wrapped API that ensures no cycles are created.
///
/// ## Behaviour on cycles
/// By design, edge additions to this datatype may fail. It is recommended to
/// prefer the dedicated [`Acyclic::try_add_edge`] and
/// [`Acyclic::try_update_edge`] methods whenever possible. The
/// [`Build::update_edge`] methods will panic if it is attempted to add an edge
/// that would create a cycle. The [`Build::add_edge`] on the other hand method
/// will return `None` if the edge cannot be added (either it already exists on
/// a graph type that does not support it or would create a cycle).
#[derive(Clone, Debug)]
pub struct Acyclic<G: Visitable> {
/// The underlying graph, accessible through the `inner` method.
graph: G,
/// The current topological order of the nodes.
order_map: OrderMap<G::NodeId>,
// We fix the internal DFS maps to FixedBitSet instead of G::VisitMap to do
// faster resets (by just setting bits to false)
/// Helper map for DFS tracking discovered nodes.
discovered: RefCell<FixedBitSet>,
/// Helper map for DFS tracking finished nodes.
finished: RefCell<FixedBitSet>,
}
/// An error that can occur during edge addition for acyclic graphs.
#[derive(Clone, Debug, PartialEq)]
pub enum AcyclicEdgeError<N> {
/// The edge would create a cycle.
Cycle(Cycle<N>),
/// The edge would create a self-loop.
SelfLoop,
/// Could not successfully add the edge to the underlying graph.
InvalidEdge,
}
impl<N> From<Cycle<N>> for AcyclicEdgeError<N> {
fn from(cycle: Cycle<N>) -> Self {
AcyclicEdgeError::Cycle(cycle)
}
}
impl<G: Visitable> Acyclic<G> {
/// Create a new empty acyclic graph.
pub fn new() -> Self
where
G: Default,
{
Default::default()
}
/// Get an iterator over the nodes, ordered by their position.
pub fn nodes_iter(&self) -> impl Iterator<Item = G::NodeId> + '_ {
self.order_map.nodes_iter()
}
/// Get an iterator over the nodes within the range of positions.
///
/// The nodes are ordered by their position in the topological sort.
pub fn range<'r>(
&'r self,
range: impl RangeBounds<TopologicalPosition> + 'r,
) -> impl Iterator<Item = G::NodeId> + 'r {
self.order_map.range(range)
}
/// Get the underlying graph.
pub fn inner(&self) -> &G {
&self.graph
}
/// Get the underlying graph mutably.
///
/// This cannot be public because it might break the acyclicity invariant.
fn inner_mut(&mut self) -> &mut G {
&mut self.graph
}
/// Consume the `Acyclic` wrapper and return the underlying graph.
pub fn into_inner(self) -> G {
self.graph
}
}
impl<G: Visitable + NodeIndexable> Acyclic<G>
where
for<'a> &'a G: IntoNeighborsDirected + IntoNodeIdentifiers + GraphBase<NodeId = G::NodeId>,
{
/// Wrap a graph into an acyclic graph.
///
/// The graph types [`DiGraph`] and [`StableDiGraph`] also implement
/// [`TryFrom`], which can be used instead of this method and have looser
/// type bounds.
pub fn try_from_graph(graph: G) -> Result<Self, Cycle<G::NodeId>> {
let order_map = OrderMap::try_from_graph(&graph)?;
let discovered = RefCell::new(FixedBitSet::with_capacity(graph.node_bound()));
let finished = RefCell::new(FixedBitSet::with_capacity(graph.node_bound()));
Ok(Self {
graph,
order_map,
discovered,
finished,
})
}
/// Add an edge to the graph using [`Build::add_edge`].
///
/// Returns the id of the added edge, or an [`AcyclicEdgeError`] if the edge
/// would create a cycle, a self-loop or if the edge addition failed in
/// the underlying graph.
///
/// In cases where edge addition cannot fail in the underlying graph (e.g.
/// when multi-edges are allowed, as in [`DiGraph`] and [`StableDiGraph`]),
/// this will return an error if and only if [`Self::is_valid_edge`]
/// returns `false`.
pub fn try_add_edge(
&mut self,
a: G::NodeId,
b: G::NodeId,
weight: G::EdgeWeight,
) -> Result<G::EdgeId, AcyclicEdgeError<G::NodeId>>
where
G: Build,
G::NodeId: IndexType,
{
if a == b {
// No self-loops allowed
return Err(AcyclicEdgeError::SelfLoop);
}
self.update_ordering(a, b)?;
self.graph
.add_edge(a, b, weight)
.ok_or(AcyclicEdgeError::InvalidEdge)
}
/// Update an edge in a graph using [`Build::update_edge`].
///
/// Returns the id of the updated edge, or an [`AcyclicEdgeError`] if the edge
/// would create a cycle or a self-loop. If the edge does not exist, the
/// edge is created.
///
/// This will return an error if and only if [`Self::is_valid_edge`] returns
/// `false`.
pub fn try_update_edge(
&mut self,
a: G::NodeId,
b: G::NodeId,
weight: G::EdgeWeight,
) -> Result<G::EdgeId, AcyclicEdgeError<G::NodeId>>
where
G: Build,
G::NodeId: IndexType,
{
if a == b {
// No self-loops allowed
return Err(AcyclicEdgeError::SelfLoop);
}
self.update_ordering(a, b)?;
Ok(self.graph.update_edge(a, b, weight))
}
/// Check if an edge would be valid, i.e. adding it would not create a cycle.
pub fn is_valid_edge(&self, a: G::NodeId, b: G::NodeId) -> bool
where
G::NodeId: IndexType,
{
if a == b {
false // No self-loops
} else if self.get_position(a) < self.get_position(b) {
true // valid edge in the current topological order
} else {
// Check if the future of `b` is disjoint from the past of `a`
// (in which case the topological order could be adjusted)
self.causal_cones(b, a).is_ok()
}
}
/// Update the ordering of the nodes in the order map resulting from adding an
/// edge a -> b.
///
/// If a cycle is detected, an error is returned and `self` remains unchanged.
///
/// Implements the core update logic of the PK algorithm.
fn update_ordering(&mut self, a: G::NodeId, b: G::NodeId) -> Result<(), Cycle<G::NodeId>>
where
G::NodeId: IndexType,
{
let min_order = self.get_position(b);
let max_order = self.get_position(a);
if min_order >= max_order {
// Order is already correct
return Ok(());
}
// Get the nodes reachable from `b` and the nodes that can reach `a`
// between `min_order` and `max_order`
let (b_fut, a_past) = self.causal_cones(b, a)?;
// Now reorder of nodes in a_past and b_fut such that
// i) within each vec, the nodes are in topological order,
// ii) all elements of b_fut come before all elements of a_past in the new order.
let all_positions: BTreeSet<_> = b_fut.keys().chain(a_past.keys()).copied().collect();
let all_nodes = a_past.values().chain(b_fut.values()).copied();
debug_assert_eq!(all_positions.len(), b_fut.len() + a_past.len());
for (pos, node) in all_positions.into_iter().zip(all_nodes) {
self.order_map.set_position(node, pos, &self.graph);
}
Ok(())
}
/// Use DFS to find the future causal cone of `min_node` and the past causal
/// cone of `max_node`.
///
/// The cones are trimmed to the range `[min_order, max_order]`. The cones
/// are returned if they are disjoint. Otherwise, a [`Cycle`] error is returned.
///
/// If `return_result` is false, then the cones are not constructed and the
/// method only checks for disjointness.
#[allow(clippy::type_complexity)]
fn causal_cones(
&self,
min_node: G::NodeId,
max_node: G::NodeId,
) -> Result<
(
BTreeMap<TopologicalPosition, G::NodeId>,
BTreeMap<TopologicalPosition, G::NodeId>,
),
Cycle<G::NodeId>,
>
where
G::NodeId: IndexType,
{
debug_assert!(self.discovered.borrow().is_clear());
debug_assert!(self.finished.borrow().is_clear());
let min_order = self.get_position(min_node);
let max_order = self.get_position(max_node);
// Prepare DFS scratch space: make sure the maps have enough capacity
if self.discovered.borrow().len() < self.graph.node_bound() {
self.discovered.borrow_mut().grow(self.graph.node_bound());
self.finished.borrow_mut().grow(self.graph.node_bound());
}
// Get all nodes reachable from b with min_order <= order < max_order
let mut forward_cone = BTreeMap::new();
let mut backward_cone = BTreeMap::new();
// The main logic: run DFS twice. We run this in a closure to catch
// errors and reset the maps properly at the end.
let mut run_dfs = || {
// Get all nodes reachable from min_node with min_order < order <= max_order
self.future_cone(min_node, min_order, max_order, &mut forward_cone)?;
// Get all nodes that can reach a with min_order < order <= max_order
// These are disjoint from the nodes in the forward cone, otherwise
// we would have a cycle.
self.past_cone(max_node, min_order, max_order, &mut backward_cone)
.expect("cycles already detected in future_cone");
Ok(())
};
let success = run_dfs();
// Cleanup: reset map to 0. This is faster than a full reset, especially
// on large sparse graphs.
for &v in forward_cone.values().chain(backward_cone.values()) {
self.discovered.borrow_mut().set(v.index(), false);
self.finished.borrow_mut().set(v.index(), false);
}
debug_assert!(self.discovered.borrow().is_clear());
debug_assert!(self.finished.borrow().is_clear());
match success {
Ok(()) => Ok((forward_cone, backward_cone)),
Err(cycle) => Err(cycle),
}
}
fn future_cone(
&self,
start: G::NodeId,
min_position: TopologicalPosition,
max_position: TopologicalPosition,
res: &mut BTreeMap<TopologicalPosition, G::NodeId>,
) -> Result<(), Cycle<G::NodeId>>
where
G::NodeId: IndexType,
{
dfs(
&self.graph,
start,
&self.order_map,
|order| {
debug_assert!(order >= min_position, "invalid topological order");
match order.cmp(&max_position) {
Ordering::Less => Ok(true), // node within [min_node, max_node]
Ordering::Equal => Err(Cycle(start)), // cycle!
Ordering::Greater => Ok(false), // node beyond [min_node, max_node]
}
},
res,
&mut self.discovered.borrow_mut(),
&mut self.finished.borrow_mut(),
)
}
fn past_cone(
&self,
start: G::NodeId,
min_position: TopologicalPosition,
max_position: TopologicalPosition,
res: &mut BTreeMap<TopologicalPosition, G::NodeId>,
) -> Result<(), Cycle<G::NodeId>>
where
G::NodeId: IndexType,
{
dfs(
Reversed(&self.graph),
start,
&self.order_map,
|order| {
debug_assert!(order <= max_position, "invalid topological order");
match order.cmp(&min_position) {
Ordering::Less => Ok(false), // node beyond [min_node, max_node]
Ordering::Equal => panic!("found by future_cone"), // cycle!
Ordering::Greater => Ok(true), // node within [min_node, max_node]
}
},
res,
&mut self.discovered.borrow_mut(),
&mut self.finished.borrow_mut(),
)
}
}
impl<G: Visitable> GraphBase for Acyclic<G> {
type NodeId = G::NodeId;
type EdgeId = G::EdgeId;
}
impl<G: Default + Visitable> Default for Acyclic<G> {
fn default() -> Self {
let graph: G = Default::default();
let order_map = Default::default();
let discovered = RefCell::new(FixedBitSet::default());
let finished = RefCell::new(FixedBitSet::default());
Self {
graph,
order_map,
discovered,
finished,
}
}
}
impl<G: Build + Visitable + NodeIndexable> Build for Acyclic<G>
where
for<'a> &'a G: IntoNeighborsDirected
+ IntoNodeIdentifiers
+ Visitable<Map = G::Map>
+ GraphBase<NodeId = G::NodeId>,
G::NodeId: IndexType,
{
fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId {
let n = self.graph.add_node(weight);
self.order_map.add_node(n, &self.graph);
n
}
fn add_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Option<Self::EdgeId> {
self.try_add_edge(a, b, weight).ok()
}
fn update_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Self::EdgeId {
self.try_update_edge(a, b, weight).unwrap()
}
}
impl<G: Create + Visitable + NodeIndexable> Create for Acyclic<G>
where
for<'a> &'a G: IntoNeighborsDirected
+ IntoNodeIdentifiers
+ Visitable<Map = G::Map>
+ GraphBase<NodeId = G::NodeId>,
G::NodeId: IndexType,
{
fn with_capacity(nodes: usize, edges: usize) -> Self {
let graph = G::with_capacity(nodes, edges);
let order_map = OrderMap::with_capacity(nodes);
let discovered = FixedBitSet::with_capacity(nodes);
let finished = FixedBitSet::with_capacity(nodes);
Self {
graph,
order_map,
discovered: RefCell::new(discovered),
finished: RefCell::new(finished),
}
}
}
impl<G: Visitable> Deref for Acyclic<G> {
type Target = G;
fn deref(&self) -> &Self::Target {
&self.graph
}
}
/// Traverse nodes in `graph` in DFS order, starting from `start`, for as long
/// as the predicate `valid_order` returns `true` on the current node's order.
fn dfs<G: NodeIndexable + IntoNeighborsDirected + IntoNodeIdentifiers + Visitable>(
graph: G,
start: G::NodeId,
order_map: &OrderMap<G::NodeId>,
// A predicate that returns whether to continue the search from a node,
// or an error to stop and shortcircuit the search.
mut valid_order: impl FnMut(TopologicalPosition) -> Result<bool, Cycle<G::NodeId>>,
res: &mut BTreeMap<TopologicalPosition, G::NodeId>,
discovered: &mut FixedBitSet,
finished: &mut FixedBitSet,
) -> Result<(), Cycle<G::NodeId>>
where
G::NodeId: IndexType,
{
dfs_visitor(
graph,
start,
&mut |ev| -> Result<Control<()>, Cycle<G::NodeId>> {
match ev {
DfsEvent::Discover(u, _) => {
// We are visiting u
let order = order_map.get_position(u, &graph);
res.insert(order, u);
Ok(Control::Continue)
}
DfsEvent::TreeEdge(_, u) => {
// Should we visit u?
let order = order_map.get_position(u, &graph);
match valid_order(order) {
Ok(true) => Ok(Control::Continue),
Ok(false) => Ok(Control::Prune),
Err(cycle) => Err(cycle),
}
}
_ => Ok(Control::Continue),
}
},
discovered,
finished,
&mut Time::default(),
)?;
Ok(())
}
/////////////////////// Pass-through graph traits ///////////////////////
// We implement all the following traits by delegating to the inner graph:
// - Data
// - DataMap
// - DataMapMut
// - EdgeCount
// - EdgeIndexable
// - GetAdjacencyMatrix
// - GraphProp
// - NodeCompactIndexable
// - NodeCount
// - NodeIndexable
// - Visitable
//
// Furthermore, we also implement the `remove_node` and `remove_edge` methods,
// as well as the following traits for `DiGraph` and `StableDiGraph` (these
// are hard/impossible to implement generically):
// - TryFrom
// - IntoEdgeReferences
// - IntoEdges
// - IntoEdgesDirected
// - IntoNeighbors
// - IntoNeighborsDirected
// - IntoNodeIdentifiers
// - IntoNodeReferences
impl<G: Visitable + Data> Data for Acyclic<G> {
type NodeWeight = G::NodeWeight;
type EdgeWeight = G::EdgeWeight;
}
impl<G: Visitable + DataMap> DataMap for Acyclic<G> {
fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
self.inner().node_weight(id)
}
fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
self.inner().edge_weight(id)
}
}
impl<G: Visitable + DataMapMut> DataMapMut for Acyclic<G> {
fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight> {
self.inner_mut().node_weight_mut(id)
}
fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight> {
self.inner_mut().edge_weight_mut(id)
}
}
impl<G: Visitable + EdgeCount> EdgeCount for Acyclic<G> {
fn edge_count(&self) -> usize {
self.inner().edge_count()
}
}
impl<G: Visitable + EdgeIndexable> EdgeIndexable for Acyclic<G> {
fn edge_bound(&self) -> usize {
self.inner().edge_bound()
}
fn to_index(&self, a: Self::EdgeId) -> usize {
self.inner().to_index(a)
}
fn from_index(&self, i: usize) -> Self::EdgeId {
self.inner().from_index(i)
}
}
impl<G: Visitable + GetAdjacencyMatrix> GetAdjacencyMatrix for Acyclic<G> {
type AdjMatrix = G::AdjMatrix;
fn adjacency_matrix(&self) -> Self::AdjMatrix {
self.inner().adjacency_matrix()
}
fn is_adjacent(&self, matrix: &Self::AdjMatrix, a: Self::NodeId, b: Self::NodeId) -> bool {
self.inner().is_adjacent(matrix, a, b)
}
}
impl<G: Visitable + GraphProp> GraphProp for Acyclic<G> {
type EdgeType = G::EdgeType;
}
impl<G: Visitable + NodeCompactIndexable> NodeCompactIndexable for Acyclic<G> {}
impl<G: Visitable + NodeCount> NodeCount for Acyclic<G> {
fn node_count(&self) -> usize {
self.inner().node_count()
}
}
impl<G: Visitable + NodeIndexable> NodeIndexable for Acyclic<G> {
fn node_bound(&self) -> usize {
self.inner().node_bound()
}
fn to_index(&self, a: Self::NodeId) -> usize {
self.inner().to_index(a)
}
fn from_index(&self, i: usize) -> Self::NodeId {
self.inner().from_index(i)
}
}
impl<G: Visitable> Visitable for Acyclic<G> {
type Map = G::Map;
fn visit_map(&self) -> Self::Map {
self.inner().visit_map()
}
fn reset_map(&self, map: &mut Self::Map) {
self.inner().reset_map(map)
}
}
macro_rules! impl_graph_traits {
($graph_type:ident) => {
// Remove edge and node methods (not available through traits)
impl<N, E, Ix: IndexType> Acyclic<$graph_type<N, E, Ix>> {
/// Remove an edge and return its edge weight, or None if it didn't exist.
///
/// Pass through to underlying graph.
pub fn remove_edge(
&mut self,
e: <$graph_type<N, E, Ix> as GraphBase>::EdgeId,
) -> Option<E> {
self.graph.remove_edge(e)
}
/// Remove a node from the graph if it exists, and return its
/// weight. If it doesn't exist in the graph, return None.
///
/// This updates the order in O(v) runtime and removes the node in
/// the underlying graph.
pub fn remove_node(
&mut self,
n: <$graph_type<N, E, Ix> as GraphBase>::NodeId,
) -> Option<N> {
self.order_map.remove_node(n, &self.graph);
self.graph.remove_node(n)
}
}
impl<N, E, Ix: IndexType> TryFrom<$graph_type<N, E, Ix>>
for Acyclic<$graph_type<N, E, Ix>>
{
type Error = Cycle<NodeIndex<Ix>>;
fn try_from(graph: $graph_type<N, E, Ix>) -> Result<Self, Self::Error> {
let order_map = OrderMap::try_from_graph(&graph)?;
let discovered = RefCell::new(FixedBitSet::with_capacity(graph.node_bound()));
let finished = RefCell::new(FixedBitSet::with_capacity(graph.node_bound()));
Ok(Self {
graph,
order_map,
discovered,
finished,
})
}
}
impl<'a, N, E, Ix: IndexType> IntoEdgeReferences for &'a Acyclic<$graph_type<N, E, Ix>> {
type EdgeRef = <&'a $graph_type<N, E, Ix> as IntoEdgeReferences>::EdgeRef;
type EdgeReferences = <&'a $graph_type<N, E, Ix> as IntoEdgeReferences>::EdgeReferences;
fn edge_references(self) -> Self::EdgeReferences {
self.inner().edge_references()
}
}
impl<'a, N, E, Ix: IndexType> IntoEdges for &'a Acyclic<$graph_type<N, E, Ix>> {
type Edges = <&'a $graph_type<N, E, Ix> as IntoEdges>::Edges;
fn edges(self, a: Self::NodeId) -> Self::Edges {
self.inner().edges(a)
}
}
impl<'a, N, E, Ix: IndexType> IntoEdgesDirected for &'a Acyclic<$graph_type<N, E, Ix>> {
type EdgesDirected = <&'a $graph_type<N, E, Ix> as IntoEdgesDirected>::EdgesDirected;
fn edges_directed(self, a: Self::NodeId, dir: Direction) -> Self::EdgesDirected {
self.inner().edges_directed(a, dir)
}
}
impl<'a, N, E, Ix: IndexType> IntoNeighbors for &'a Acyclic<$graph_type<N, E, Ix>> {
type Neighbors = <&'a $graph_type<N, E, Ix> as IntoNeighbors>::Neighbors;
fn neighbors(self, a: Self::NodeId) -> Self::Neighbors {
self.inner().neighbors(a)
}
}
impl<'a, N, E, Ix: IndexType> IntoNeighborsDirected for &'a Acyclic<$graph_type<N, E, Ix>> {
type NeighborsDirected =
<&'a $graph_type<N, E, Ix> as IntoNeighborsDirected>::NeighborsDirected;
fn neighbors_directed(self, n: Self::NodeId, d: Direction) -> Self::NeighborsDirected {
self.inner().neighbors_directed(n, d)
}
}
impl<'a, N, E, Ix: IndexType> IntoNodeIdentifiers for &'a Acyclic<$graph_type<N, E, Ix>> {
type NodeIdentifiers =
<&'a $graph_type<N, E, Ix> as IntoNodeIdentifiers>::NodeIdentifiers;
fn node_identifiers(self) -> Self::NodeIdentifiers {
self.inner().node_identifiers()
}
}
impl<'a, N, E, Ix: IndexType> IntoNodeReferences for &'a Acyclic<$graph_type<N, E, Ix>> {
type NodeRef = <&'a $graph_type<N, E, Ix> as IntoNodeReferences>::NodeRef;
type NodeReferences = <&'a $graph_type<N, E, Ix> as IntoNodeReferences>::NodeReferences;
fn node_references(self) -> Self::NodeReferences {
self.inner().node_references()
}
}
};
}
impl_graph_traits!(DiGraph);
#[cfg(feature = "stable_graph")]
impl_graph_traits!(StableDiGraph);
#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::DiGraph;
#[cfg(feature = "stable_graph")]
use crate::prelude::StableDiGraph;
use crate::visit::IntoNodeReferences;
#[test]
fn test_acyclic_graph() {
// Create an acyclic DiGraph
let mut graph = DiGraph::<(), ()>::new();
let a = graph.add_node(());
let c = graph.add_node(());
let b = graph.add_node(());
graph.add_edge(a, b, ());
graph.add_edge(b, c, ());
// Create an Acyclic object
let mut acyclic = Acyclic::try_from_graph(graph).unwrap();
// Test initial topological order
assert_valid_topological_order(&acyclic);
// Add a valid edge
assert!(acyclic.try_add_edge(a, c, ()).is_ok());
assert_valid_topological_order(&acyclic);
// Try to add an edge that would create a cycle
assert!(acyclic.try_add_edge(c, a, ()).is_err());
// Add another valid edge
let d = acyclic.add_node(());
assert!(acyclic.try_add_edge(c, d, ()).is_ok());
assert_valid_topological_order(&acyclic);
// Try to add an edge that would create a cycle (using the Build trait)
assert!(acyclic.add_edge(d, a, ()).is_none());
}
#[cfg(feature = "stable_graph")]
#[test]
fn test_acyclic_graph_add_remove() {
// Create an initial Acyclic graph with two nodes and one edge
let mut acyclic = Acyclic::<StableDiGraph<(), ()>>::new();
let a = acyclic.add_node(());
let b = acyclic.add_node(());
assert!(acyclic.try_add_edge(a, b, ()).is_ok());
// Check initial topological order
assert_valid_topological_order(&acyclic);
// Add a new node and an edge
let c = acyclic.add_node(());
assert!(acyclic.try_add_edge(b, c, ()).is_ok());
// Check topological order after addition
assert_valid_topological_order(&acyclic);
// Remove the node connected to two edges (node b)
acyclic.remove_node(b);
// Check topological order after removal
assert_valid_topological_order(&acyclic);
// Verify the remaining structure
let remaining_nodes: Vec<_> = acyclic
.inner()
.node_references()
.map(|(id, _)| id)
.collect();
assert_eq!(remaining_nodes.len(), 2);
assert!(remaining_nodes.contains(&a));
assert!(remaining_nodes.contains(&c));
assert!(!acyclic.inner().contains_edge(a, c));
}
fn assert_valid_topological_order<'a, G>(acyclic: &'a Acyclic<G>)
where
G: Visitable + NodeCount + NodeIndexable,
&'a G: NodeIndexable
+ IntoNodeReferences
+ IntoNeighborsDirected
+ GraphBase<NodeId = G::NodeId>,
G::NodeId: std::fmt::Debug,
{
let ordered_nodes: Vec<_> = acyclic.nodes_iter().collect();
assert_eq!(ordered_nodes.len(), acyclic.node_count());
let nodes: Vec<_> = acyclic.inner().node_identifiers().collect();
// Check that the nodes are in topological order
let mut last_position = None;
for (idx, &node) in ordered_nodes.iter().enumerate() {
assert!(nodes.contains(&node));
// Check that the node positions are monotonically increasing
let pos = acyclic.get_position(node);
assert!(Some(pos) > last_position);
last_position = Some(pos);
// Check that the neighbors are in the future of the current node
for neighbor in acyclic.inner().neighbors(node) {
let neighbour_idx = ordered_nodes.iter().position(|&n| n == neighbor).unwrap();
assert!(neighbour_idx > idx);
}
}
}
}

193
vendor/petgraph/src/acyclic/order_map.rs vendored Normal file
View File

@@ -0,0 +1,193 @@
//! A bijective map between node indices and a `TopologicalPosition`, to store
//! the total topological order of the graph.
//!
//! This data structure is an implementation detail and is not exposed in the
//! public API.
use std::{collections::BTreeMap, fmt, ops::RangeBounds};
use crate::{
algo::{toposort, Cycle},
visit::{GraphBase, IntoNeighborsDirected, IntoNodeIdentifiers, NodeIndexable, Visitable},
};
/// A position in the topological order of the graph.
///
/// This defines a total order over the set of nodes in the graph.
///
/// Note that the positions of all nodes in a graph may not form a contiguous
/// interval.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
#[repr(transparent)]
pub struct TopologicalPosition(pub(super) usize);
/// A bijective map between node indices and their position in a topological order.
///
/// Note that this map does not check for injectivity or surjectivity, this
/// must be enforced by the user. Map mutations that invalidate these properties
/// are allowed to make it easy to perform batch modifications that temporarily
/// break the invariants.
#[derive(Clone)]
pub(super) struct OrderMap<N> {
/// Map topological position to node index.
pos_to_node: BTreeMap<TopologicalPosition, N>,
/// The inverse of `pos_to_node`, i.e. map node indices to their position.
///
/// This is a Vec, relying on `N: NodeIndexable` for indexing.
node_to_pos: Vec<TopologicalPosition>,
}
impl<N> Default for OrderMap<N> {
fn default() -> Self {
Self {
pos_to_node: Default::default(),
node_to_pos: Default::default(),
}
}
}
impl<N: fmt::Debug> fmt::Debug for OrderMap<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OrderMap")
.field("order", &self.pos_to_node)
.finish()
}
}
impl<N: Copy> OrderMap<N> {
pub(super) fn try_from_graph<G>(graph: G) -> Result<Self, Cycle<G::NodeId>>
where
G: NodeIndexable<NodeId = N> + IntoNeighborsDirected + IntoNodeIdentifiers + Visitable,
{
// Compute the topological order.
let topo_vec = toposort(graph, None)?;
// Create the two map directions.
let mut pos_to_node = BTreeMap::new();
let mut node_to_pos = vec![TopologicalPosition::default(); graph.node_bound()];
// Populate the maps.
for (i, &id) in topo_vec.iter().enumerate() {
let pos = TopologicalPosition(i);
pos_to_node.insert(pos, id);
node_to_pos[graph.to_index(id)] = pos;
}
Ok(Self {
pos_to_node,
node_to_pos,
})
}
pub(super) fn with_capacity(nodes: usize) -> Self {
Self {
pos_to_node: BTreeMap::new(),
node_to_pos: Vec::with_capacity(nodes),
}
}
/// Map a node to its position in the topological order.
///
/// Panics if the node index is out of bounds.
pub(super) fn get_position(
&self,
id: N,
graph: impl NodeIndexable<NodeId = N>,
) -> TopologicalPosition {
let idx = graph.to_index(id);
assert!(idx < self.node_to_pos.len());
self.node_to_pos[idx]
}
/// Map a position in the topological order to a node, if it exists.
pub(super) fn at_position(&self, pos: TopologicalPosition) -> Option<N> {
self.pos_to_node.get(&pos).copied()
}
/// Get an iterator over the nodes, ordered by their position.
pub(super) fn nodes_iter(&self) -> impl Iterator<Item = N> + '_ {
self.pos_to_node.values().copied()
}
/// Get an iterator over the nodes within the range of positions.
pub(super) fn range(
&self,
range: impl RangeBounds<TopologicalPosition>,
) -> impl Iterator<Item = N> + '_ {
self.pos_to_node.range(range).map(|(_, &n)| n)
}
/// Add a node to the order map and assign it an arbitrary position.
///
/// Return the position of the new node.
pub(super) fn add_node(
&mut self,
id: N,
graph: impl NodeIndexable<NodeId = N>,
) -> TopologicalPosition {
// The position and node index
let new_pos = self
.pos_to_node
.iter()
.next_back()
.map(|(TopologicalPosition(idx), _)| TopologicalPosition(idx + 1))
.unwrap_or_default();
let idx = graph.to_index(id);
// Make sure the order_inv is large enough.
if idx >= self.node_to_pos.len() {
self.node_to_pos
.resize(graph.node_bound(), TopologicalPosition::default());
}
// Insert both map directions.
self.pos_to_node.insert(new_pos, id);
self.node_to_pos[idx] = new_pos;
new_pos
}
/// Remove a node from the order map.
///
/// Panics if the node index is out of bounds.
pub(super) fn remove_node(&mut self, id: N, graph: impl NodeIndexable<NodeId = N>) {
let idx = graph.to_index(id);
assert!(idx < self.node_to_pos.len());
let pos = self.node_to_pos[idx];
self.node_to_pos[idx] = TopologicalPosition::default();
self.pos_to_node.remove(&pos);
}
/// Set the position of a node.
///
/// Panics if the node index is out of bounds.
pub(super) fn set_position(
&mut self,
id: N,
pos: TopologicalPosition,
graph: impl NodeIndexable<NodeId = N>,
) {
let idx = graph.to_index(id);
assert!(idx < self.node_to_pos.len());
self.pos_to_node.insert(pos, id);
self.node_to_pos[idx] = pos;
}
}
impl<G: Visitable> super::Acyclic<G> {
/// Get the position of a node in the topological sort.
///
/// Panics if the node index is out of bounds.
pub fn get_position<'a>(&'a self, id: G::NodeId) -> TopologicalPosition
where
&'a G: NodeIndexable + GraphBase<NodeId = G::NodeId>,
{
self.order_map.get_position(id, &self.graph)
}
/// Get the node at a given position in the topological sort, if it exists.
pub fn at_position(&self, pos: TopologicalPosition) -> Option<G::NodeId> {
self.order_map.at_position(pos)
}
}

653
vendor/petgraph/src/adj.rs vendored Normal file
View File

@@ -0,0 +1,653 @@
//! Simple adjacency list.
use crate::data::{Build, DataMap, DataMapMut};
use crate::iter_format::NoPretty;
use crate::visit::{
self, EdgeCount, EdgeRef, GetAdjacencyMatrix, IntoEdgeReferences, IntoNeighbors, NodeCount,
};
use fixedbitset::FixedBitSet;
use std::fmt;
use std::ops::Range;
#[doc(no_inline)]
pub use crate::graph::{DefaultIx, IndexType};
/// Adjacency list node index type, a plain integer.
pub type NodeIndex<Ix = DefaultIx> = Ix;
/// Adjacency list edge index type, a pair of integers.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct EdgeIndex<Ix = DefaultIx>
where
Ix: IndexType,
{
/// Source of the edge.
from: NodeIndex<Ix>,
/// Index of the sucessor in the successor list.
successor_index: usize,
}
iterator_wrap! {
impl (Iterator) for
/// An Iterator over the indices of the outgoing edges from a node.
///
/// It does not borrow the graph during iteration.
#[derive(Debug, Clone)]
struct OutgoingEdgeIndices <Ix> where { Ix: IndexType }
item: EdgeIndex<Ix>,
iter: std::iter::Map<std::iter::Zip<Range<usize>, std::iter::Repeat<NodeIndex<Ix>>>, fn((usize, NodeIndex<Ix>)) -> EdgeIndex<Ix>>,
}
/// Weighted sucessor
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct WSuc<E, Ix: IndexType> {
/// Index of the sucessor.
suc: Ix,
/// Weight of the edge to `suc`.
weight: E,
}
/// One row of the adjacency list.
type Row<E, Ix> = Vec<WSuc<E, Ix>>;
type RowIter<'a, E, Ix> = std::slice::Iter<'a, WSuc<E, Ix>>;
iterator_wrap! {
impl (Iterator DoubleEndedIterator ExactSizeIterator) for
/// An iterator over the indices of the neighbors of a node.
#[derive(Debug, Clone)]
struct Neighbors<'a, E, Ix> where { Ix: IndexType }
item: NodeIndex<Ix>,
iter: std::iter::Map<RowIter<'a, E, Ix>, fn(&WSuc<E, Ix>) -> NodeIndex<Ix>>,
}
/// A reference to an edge of the graph.
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct EdgeReference<'a, E, Ix: IndexType> {
/// index of the edge
id: EdgeIndex<Ix>,
/// a reference to the corresponding item in the adjacency list
edge: &'a WSuc<E, Ix>,
}
impl<E, Ix: IndexType> Copy for EdgeReference<'_, E, Ix> {}
impl<E, Ix: IndexType> Clone for EdgeReference<'_, E, Ix> {
fn clone(&self) -> Self {
*self
}
}
impl<E, Ix: IndexType> visit::EdgeRef for EdgeReference<'_, E, Ix> {
type NodeId = NodeIndex<Ix>;
type EdgeId = EdgeIndex<Ix>;
type Weight = E;
fn source(&self) -> Self::NodeId {
self.id.from
}
fn target(&self) -> Self::NodeId {
self.edge.suc
}
fn id(&self) -> Self::EdgeId {
self.id
}
fn weight(&self) -> &Self::Weight {
&self.edge.weight
}
}
#[derive(Debug, Clone)]
pub struct EdgeIndices<'a, E, Ix: IndexType> {
rows: std::iter::Enumerate<std::slice::Iter<'a, Row<E, Ix>>>,
row_index: usize,
row_len: usize,
cur: usize,
}
impl<E, Ix: IndexType> Iterator for EdgeIndices<'_, E, Ix> {
type Item = EdgeIndex<Ix>;
fn next(&mut self) -> Option<EdgeIndex<Ix>> {
loop {
if self.cur < self.row_len {
let res = self.cur;
self.cur += 1;
return Some(EdgeIndex {
from: Ix::new(self.row_index),
successor_index: res,
});
} else {
match self.rows.next() {
Some((index, row)) => {
self.row_index = index;
self.cur = 0;
self.row_len = row.len();
}
None => return None,
}
}
}
}
}
iterator_wrap! {
impl (Iterator DoubleEndedIterator ExactSizeIterator) for
/// An iterator over all node indices in the graph.
#[derive(Debug, Clone)]
struct NodeIndices <Ix> where {}
item: Ix,
iter: std::iter::Map<Range<usize>, fn(usize) -> Ix>,
}
/// An adjacency list with labeled edges.
///
/// Can be interpreted as a directed graph
/// with unweighted nodes.
///
/// This is the most simple adjacency list you can imagine. [`Graph`](../graph/struct.Graph.html), in contrast,
/// maintains both the list of successors and predecessors for each node,
/// which is a different trade-off.
///
/// Allows parallel edges and self-loops.
///
/// This data structure is append-only (except for [`clear`](#method.clear)), so indices
/// returned at some point for a given graph will stay valid with this same
/// graph until it is dropped or [`clear`](#method.clear) is called.
///
/// Space consumption: **O(|E|)**.
#[derive(Clone, Default)]
pub struct List<E, Ix = DefaultIx>
where
Ix: IndexType,
{
suc: Vec<Row<E, Ix>>,
}
impl<E, Ix: IndexType> List<E, Ix> {
/// Creates a new, empty adjacency list.
pub fn new() -> List<E, Ix> {
List { suc: Vec::new() }
}
/// Creates a new, empty adjacency list tailored for `nodes` nodes.
pub fn with_capacity(nodes: usize) -> List<E, Ix> {
List {
suc: Vec::with_capacity(nodes),
}
}
/// Removes all nodes and edges from the list.
pub fn clear(&mut self) {
self.suc.clear()
}
/// Returns the number of edges in the list
///
/// Computes in **O(|V|)** time.
pub fn edge_count(&self) -> usize {
self.suc.iter().map(|x| x.len()).sum()
}
/// Adds a new node to the list. This allocates a new `Vec` and then should
/// run in amortized **O(1)** time.
pub fn add_node(&mut self) -> NodeIndex<Ix> {
let i = self.suc.len();
self.suc.push(Vec::new());
Ix::new(i)
}
/// Adds a new node to the list. This allocates a new `Vec` and then should
/// run in amortized **O(1)** time.
pub fn add_node_with_capacity(&mut self, successors: usize) -> NodeIndex<Ix> {
let i = self.suc.len();
self.suc.push(Vec::with_capacity(successors));
Ix::new(i)
}
/// Adds a new node to the list by giving its list of successors and the corresponding
/// weigths.
pub fn add_node_from_edges<I: Iterator<Item = (NodeIndex<Ix>, E)>>(
&mut self,
edges: I,
) -> NodeIndex<Ix> {
let i = self.suc.len();
self.suc
.push(edges.map(|(suc, weight)| WSuc { suc, weight }).collect());
Ix::new(i)
}
/// Add an edge from `a` to `b` to the graph, with its associated
/// data `weight`.
///
/// Return the index of the new edge.
///
/// Computes in **O(1)** time.
///
/// **Panics** if the source node does not exist.<br>
///
/// **Note:** `List` allows adding parallel (“duplicate”) edges. If you want
/// to avoid this, use [`.update_edge(a, b, weight)`](#method.update_edge) instead.
pub fn add_edge(&mut self, a: NodeIndex<Ix>, b: NodeIndex<Ix>, weight: E) -> EdgeIndex<Ix> {
if b.index() >= self.suc.len() {
panic!(
"{} is not a valid node index for a {} nodes adjacency list",
b.index(),
self.suc.len()
);
}
let row = &mut self.suc[a.index()];
let rank = row.len();
row.push(WSuc { suc: b, weight });
EdgeIndex {
from: a,
successor_index: rank,
}
}
fn get_edge(&self, e: EdgeIndex<Ix>) -> Option<&WSuc<E, Ix>> {
self.suc
.get(e.from.index())
.and_then(|row| row.get(e.successor_index))
}
fn get_edge_mut(&mut self, e: EdgeIndex<Ix>) -> Option<&mut WSuc<E, Ix>> {
self.suc
.get_mut(e.from.index())
.and_then(|row| row.get_mut(e.successor_index))
}
/// Accesses the source and target of edge `e`
///
/// Computes in **O(1)**
pub fn edge_endpoints(&self, e: EdgeIndex<Ix>) -> Option<(NodeIndex<Ix>, NodeIndex<Ix>)> {
self.get_edge(e).map(|x| (e.from, x.suc))
}
pub fn edge_indices_from(&self, a: NodeIndex<Ix>) -> OutgoingEdgeIndices<Ix> {
let proj: fn((usize, NodeIndex<Ix>)) -> EdgeIndex<Ix> =
|(successor_index, from)| EdgeIndex {
from,
successor_index,
};
let iter = (0..(self.suc[a.index()].len()))
.zip(std::iter::repeat(a))
.map(proj);
OutgoingEdgeIndices { iter }
}
/// Lookups whether there is an edge from `a` to `b`.
///
/// Computes in **O(e')** time, where **e'** is the number of successors of `a`.
pub fn contains_edge(&self, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> bool {
match self.suc.get(a.index()) {
None => false,
Some(row) => row.iter().any(|x| x.suc == b),
}
}
/// Lookups whether there is an edge from `a` to `b`.
///
/// Computes in **O(e')** time, where **e'** is the number of successors of `a`.
pub fn find_edge(&self, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> Option<EdgeIndex<Ix>> {
self.suc.get(a.index()).and_then(|row| {
row.iter()
.enumerate()
.find(|(_, x)| x.suc == b)
.map(|(i, _)| EdgeIndex {
from: a,
successor_index: i,
})
})
}
/// Returns an iterator over all node indices of the graph.
///
/// Consuming the whole iterator take **O(|V|)**.
pub fn node_indices(&self) -> NodeIndices<Ix> {
NodeIndices {
iter: (0..self.suc.len()).map(Ix::new),
}
}
/// Returns an iterator over all edge indices of the graph.
///
/// Consuming the whole iterator take **O(|V| + |E|)**.
pub fn edge_indices(&self) -> EdgeIndices<E, Ix> {
EdgeIndices {
rows: self.suc.iter().enumerate(),
row_index: 0,
row_len: 0,
cur: 0,
}
}
}
/// A very simple adjacency list with no node or label weights.
pub type UnweightedList<Ix> = List<(), Ix>;
impl<E, Ix: IndexType> Build for List<E, Ix> {
/// Adds a new node to the list. This allocates a new `Vec` and then should
/// run in amortized **O(1)** time.
fn add_node(&mut self, _weight: ()) -> NodeIndex<Ix> {
self.add_node()
}
/// Add an edge from `a` to `b` to the graph, with its associated
/// data `weight`.
///
/// Return the index of the new edge.
///
/// Computes in **O(1)** time.
///
/// **Panics** if the source node does not exist.<br>
///
/// **Note:** `List` allows adding parallel (“duplicate”) edges. If you want
/// to avoid this, use [`.update_edge(a, b, weight)`](#method.update_edge) instead.
fn add_edge(&mut self, a: NodeIndex<Ix>, b: NodeIndex<Ix>, weight: E) -> Option<EdgeIndex<Ix>> {
Some(self.add_edge(a, b, weight))
}
/// Updates or adds an edge from `a` to `b` to the graph, with its associated
/// data `weight`.
///
/// Return the index of the new edge.
///
/// Computes in **O(e')** time, where **e'** is the number of successors of `a`.
///
/// **Panics** if the source node does not exist.<br>
fn update_edge(&mut self, a: NodeIndex<Ix>, b: NodeIndex<Ix>, weight: E) -> EdgeIndex<Ix> {
let row = &mut self.suc[a.index()];
for (i, info) in row.iter_mut().enumerate() {
if info.suc == b {
info.weight = weight;
return EdgeIndex {
from: a,
successor_index: i,
};
}
}
let rank = row.len();
row.push(WSuc { suc: b, weight });
EdgeIndex {
from: a,
successor_index: rank,
}
}
}
impl<E, Ix> fmt::Debug for EdgeReferences<'_, E, Ix>
where
E: fmt::Debug,
Ix: IndexType,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut edge_list = f.debug_list();
let iter: Self = self.clone();
for e in iter {
if std::mem::size_of::<E>() != 0 {
edge_list.entry(&(
NoPretty((e.source().index(), e.target().index())),
e.weight(),
));
} else {
edge_list.entry(&NoPretty((e.source().index(), e.target().index())));
}
}
edge_list.finish()
}
}
impl<E, Ix> fmt::Debug for List<E, Ix>
where
E: fmt::Debug,
Ix: IndexType,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut fmt_struct = f.debug_struct("adj::List");
fmt_struct.field("node_count", &self.node_count());
fmt_struct.field("edge_count", &self.edge_count());
if self.edge_count() > 0 {
fmt_struct.field("edges", &self.edge_references());
}
fmt_struct.finish()
}
}
impl<E, Ix> visit::GraphBase for List<E, Ix>
where
Ix: IndexType,
{
type NodeId = NodeIndex<Ix>;
type EdgeId = EdgeIndex<Ix>;
}
impl<E, Ix> visit::Visitable for List<E, Ix>
where
Ix: IndexType,
{
type Map = FixedBitSet;
fn visit_map(&self) -> FixedBitSet {
FixedBitSet::with_capacity(self.node_count())
}
fn reset_map(&self, map: &mut Self::Map) {
map.clear();
map.grow(self.node_count());
}
}
impl<E, Ix: IndexType> visit::IntoNodeIdentifiers for &List<E, Ix> {
type NodeIdentifiers = NodeIndices<Ix>;
fn node_identifiers(self) -> NodeIndices<Ix> {
self.node_indices()
}
}
impl<Ix: IndexType> visit::NodeRef for NodeIndex<Ix> {
type NodeId = NodeIndex<Ix>;
type Weight = ();
fn id(&self) -> Self::NodeId {
*self
}
fn weight(&self) -> &Self::Weight {
&()
}
}
impl<Ix: IndexType, E> visit::IntoNodeReferences for &List<E, Ix> {
type NodeRef = NodeIndex<Ix>;
type NodeReferences = NodeIndices<Ix>;
fn node_references(self) -> Self::NodeReferences {
self.node_indices()
}
}
impl<E, Ix: IndexType> visit::Data for List<E, Ix> {
type NodeWeight = ();
type EdgeWeight = E;
}
impl<'a, E, Ix: IndexType> IntoNeighbors for &'a List<E, Ix> {
type Neighbors = Neighbors<'a, E, Ix>;
/// Returns an iterator of all nodes with an edge starting from `a`.
/// Panics if `a` is out of bounds.
/// Use [`List::edge_indices_from`] instead if you do not want to borrow the adjacency list while
/// iterating.
fn neighbors(self, a: NodeIndex<Ix>) -> Self::Neighbors {
let proj: fn(&WSuc<E, Ix>) -> NodeIndex<Ix> = |x| x.suc;
let iter = self.suc[a.index()].iter().map(proj);
Neighbors { iter }
}
}
type SomeIter<'a, E, Ix> = std::iter::Map<
std::iter::Zip<std::iter::Enumerate<RowIter<'a, E, Ix>>, std::iter::Repeat<Ix>>,
fn(((usize, &'a WSuc<E, Ix>), Ix)) -> EdgeReference<'a, E, Ix>,
>;
iterator_wrap! {
impl (Iterator) for
/// An iterator over the [`EdgeReference`] of all the edges of the graph.
struct EdgeReferences<'a, E, Ix> where { Ix: IndexType }
item: EdgeReference<'a, E, Ix>,
iter: std::iter::FlatMap<
std::iter::Enumerate<
std::slice::Iter<'a, Row<E, Ix>>
>,
SomeIter<'a, E, Ix>,
fn(
(usize, &'a Vec<WSuc<E, Ix>>)
) -> SomeIter<'a, E, Ix>,
>,
}
impl<E, Ix: IndexType> Clone for EdgeReferences<'_, E, Ix> {
fn clone(&self) -> Self {
EdgeReferences {
iter: self.iter.clone(),
}
}
}
fn proj1<E, Ix: IndexType>(
((successor_index, edge), from): ((usize, &WSuc<E, Ix>), Ix),
) -> EdgeReference<E, Ix> {
let id = EdgeIndex {
from,
successor_index,
};
EdgeReference { id, edge }
}
fn proj2<E, Ix: IndexType>((row_index, row): (usize, &Vec<WSuc<E, Ix>>)) -> SomeIter<E, Ix> {
row.iter()
.enumerate()
.zip(std::iter::repeat(Ix::new(row_index)))
.map(proj1 as _)
}
impl<'a, Ix: IndexType, E> visit::IntoEdgeReferences for &'a List<E, Ix> {
type EdgeRef = EdgeReference<'a, E, Ix>;
type EdgeReferences = EdgeReferences<'a, E, Ix>;
fn edge_references(self) -> Self::EdgeReferences {
let iter = self.suc.iter().enumerate().flat_map(proj2 as _);
EdgeReferences { iter }
}
}
iterator_wrap! {
impl (Iterator) for
/// Iterator over the [`EdgeReference`] of the outgoing edges from a node.
#[derive(Debug, Clone)]
struct OutgoingEdgeReferences<'a, E, Ix> where { Ix: IndexType }
item: EdgeReference<'a, E, Ix>,
iter: SomeIter<'a, E, Ix>,
}
impl<'a, Ix: IndexType, E> visit::IntoEdges for &'a List<E, Ix> {
type Edges = OutgoingEdgeReferences<'a, E, Ix>;
fn edges(self, a: Self::NodeId) -> Self::Edges {
let iter = self.suc[a.index()]
.iter()
.enumerate()
.zip(std::iter::repeat(a))
.map(proj1 as _);
OutgoingEdgeReferences { iter }
}
}
impl<E, Ix: IndexType> visit::GraphProp for List<E, Ix> {
type EdgeType = crate::Directed;
fn is_directed(&self) -> bool {
true
}
}
impl<E, Ix: IndexType> NodeCount for List<E, Ix> {
/// Returns the number of nodes in the list
///
/// Computes in **O(1)** time.
fn node_count(&self) -> usize {
self.suc.len()
}
}
impl<E, Ix: IndexType> EdgeCount for List<E, Ix> {
/// Returns the number of edges in the list
///
/// Computes in **O(|V|)** time.
fn edge_count(&self) -> usize {
List::edge_count(self)
}
}
impl<E, Ix: IndexType> visit::NodeIndexable for List<E, Ix> {
fn node_bound(&self) -> usize {
self.node_count()
}
#[inline]
fn to_index(&self, a: Self::NodeId) -> usize {
a.index()
}
#[inline]
fn from_index(&self, i: usize) -> Self::NodeId {
Ix::new(i)
}
}
impl<E, Ix: IndexType> visit::NodeCompactIndexable for List<E, Ix> {}
impl<E, Ix: IndexType> DataMap for List<E, Ix> {
fn node_weight(&self, n: Self::NodeId) -> Option<&()> {
if n.index() < self.suc.len() {
Some(&())
} else {
None
}
}
/// Accesses the weight of edge `e`
///
/// Computes in **O(1)**
fn edge_weight(&self, e: EdgeIndex<Ix>) -> Option<&E> {
self.get_edge(e).map(|x| &x.weight)
}
}
impl<E, Ix: IndexType> DataMapMut for List<E, Ix> {
fn node_weight_mut(&mut self, n: Self::NodeId) -> Option<&mut ()> {
if n.index() < self.suc.len() {
// A hack to produce a &'static mut ()
// It does not actually allocate according to godbolt
let b = Box::new(());
Some(Box::leak(b))
} else {
None
}
}
/// Accesses the weight of edge `e`
///
/// Computes in **O(1)**
fn edge_weight_mut(&mut self, e: EdgeIndex<Ix>) -> Option<&mut E> {
self.get_edge_mut(e).map(|x| &mut x.weight)
}
}
/// The adjacency matrix for **List** is a bitmap that's computed by
/// `.adjacency_matrix()`.
impl<E, Ix> GetAdjacencyMatrix for List<E, Ix>
where
Ix: IndexType,
{
type AdjMatrix = FixedBitSet;
fn adjacency_matrix(&self) -> FixedBitSet {
let n = self.node_count();
let mut matrix = FixedBitSet::with_capacity(n * n);
for edge in self.edge_references() {
let i = edge.source().index() * n + edge.target().index();
matrix.put(i);
}
matrix
}
fn is_adjacent(&self, matrix: &FixedBitSet, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> bool {
let n = self.node_count();
let index = n * a.index() + b.index();
matrix.contains(index)
}
}

178
vendor/petgraph/src/algo/astar.rs vendored Normal file
View File

@@ -0,0 +1,178 @@
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::{BinaryHeap, HashMap};
use std::hash::Hash;
use crate::scored::MinScored;
use crate::visit::{EdgeRef, GraphBase, IntoEdges, Visitable};
use crate::algo::Measure;
/// \[Generic\] A* shortest path algorithm.
///
/// Computes the shortest path from `start` to `finish`, including the total path cost.
///
/// `finish` is implicitly given via the `is_goal` callback, which should return `true` if the
/// given node is the finish node.
///
/// The function `edge_cost` should return the cost for a particular edge. Edge costs must be
/// non-negative.
///
/// The function `estimate_cost` should return the estimated cost to the finish for a particular
/// node. For the algorithm to find the actual shortest path, it should be admissible, meaning that
/// it should never overestimate the actual cost to get to the nearest goal node. Estimate costs
/// must also be non-negative.
///
/// The graph should be `Visitable` and implement `IntoEdges`.
///
/// # Example
/// ```
/// use petgraph::Graph;
/// use petgraph::algo::astar;
///
/// let mut g = Graph::new();
/// let a = g.add_node((0., 0.));
/// let b = g.add_node((2., 0.));
/// let c = g.add_node((1., 1.));
/// let d = g.add_node((0., 2.));
/// let e = g.add_node((3., 3.));
/// let f = g.add_node((4., 2.));
/// g.extend_with_edges(&[
/// (a, b, 2),
/// (a, d, 4),
/// (b, c, 1),
/// (b, f, 7),
/// (c, e, 5),
/// (e, f, 1),
/// (d, e, 1),
/// ]);
///
/// // Graph represented with the weight of each edge
/// // Edges with '*' are part of the optimal path.
/// //
/// // 2 1
/// // a ----- b ----- c
/// // | 4* | 7 |
/// // d f | 5
/// // | 1* | 1* |
/// // \------ e ------/
///
/// let path = astar(&g, a, |finish| finish == f, |e| *e.weight(), |_| 0);
/// assert_eq!(path, Some((6, vec![a, d, e, f])));
/// ```
///
/// Returns the total cost + the path of subsequent `NodeId` from start to finish, if one was
/// found.
pub fn astar<G, F, H, K, IsGoal>(
graph: G,
start: G::NodeId,
mut is_goal: IsGoal,
mut edge_cost: F,
mut estimate_cost: H,
) -> Option<(K, Vec<G::NodeId>)>
where
G: IntoEdges + Visitable,
IsGoal: FnMut(G::NodeId) -> bool,
G::NodeId: Eq + Hash,
F: FnMut(G::EdgeRef) -> K,
H: FnMut(G::NodeId) -> K,
K: Measure + Copy,
{
let mut visit_next = BinaryHeap::new();
let mut scores = HashMap::new(); // g-values, cost to reach the node
let mut estimate_scores = HashMap::new(); // f-values, cost to reach + estimate cost to goal
let mut path_tracker = PathTracker::<G>::new();
let zero_score = K::default();
scores.insert(start, zero_score);
visit_next.push(MinScored(estimate_cost(start), start));
while let Some(MinScored(estimate_score, node)) = visit_next.pop() {
if is_goal(node) {
let path = path_tracker.reconstruct_path_to(node);
let cost = scores[&node];
return Some((cost, path));
}
// This lookup can be unwrapped without fear of panic since the node was necessarily scored
// before adding it to `visit_next`.
let node_score = scores[&node];
match estimate_scores.entry(node) {
Occupied(mut entry) => {
// If the node has already been visited with an equal or lower score than now, then
// we do not need to re-visit it.
if *entry.get() <= estimate_score {
continue;
}
entry.insert(estimate_score);
}
Vacant(entry) => {
entry.insert(estimate_score);
}
}
for edge in graph.edges(node) {
let next = edge.target();
let next_score = node_score + edge_cost(edge);
match scores.entry(next) {
Occupied(mut entry) => {
// No need to add neighbors that we have already reached through a shorter path
// than now.
if *entry.get() <= next_score {
continue;
}
entry.insert(next_score);
}
Vacant(entry) => {
entry.insert(next_score);
}
}
path_tracker.set_predecessor(next, node);
let next_estimate_score = next_score + estimate_cost(next);
visit_next.push(MinScored(next_estimate_score, next));
}
}
None
}
struct PathTracker<G>
where
G: GraphBase,
G::NodeId: Eq + Hash,
{
came_from: HashMap<G::NodeId, G::NodeId>,
}
impl<G> PathTracker<G>
where
G: GraphBase,
G::NodeId: Eq + Hash,
{
fn new() -> PathTracker<G> {
PathTracker {
came_from: HashMap::new(),
}
}
fn set_predecessor(&mut self, node: G::NodeId, previous: G::NodeId) {
self.came_from.insert(node, previous);
}
fn reconstruct_path_to(&self, last: G::NodeId) -> Vec<G::NodeId> {
let mut path = vec![last];
let mut current = last;
while let Some(&previous) = self.came_from.get(&current) {
path.push(previous);
current = previous;
}
path.reverse();
path
}
}

244
vendor/petgraph/src/algo/bellman_ford.rs vendored Normal file
View File

@@ -0,0 +1,244 @@
//! Bellman-Ford algorithms.
use crate::prelude::*;
use crate::visit::{IntoEdges, IntoNodeIdentifiers, NodeCount, NodeIndexable, VisitMap, Visitable};
use super::{FloatMeasure, NegativeCycle};
#[derive(Debug, Clone)]
pub struct Paths<NodeId, EdgeWeight> {
pub distances: Vec<EdgeWeight>,
pub predecessors: Vec<Option<NodeId>>,
}
/// \[Generic\] Compute shortest paths from node `source` to all other.
///
/// Using the [BellmanFord algorithm][bf]; negative edge costs are
/// permitted, but the graph must not have a cycle of negative weights
/// (in that case it will return an error).
///
/// On success, return one vec with path costs, and another one which points
/// out the predecessor of a node along a shortest path. The vectors
/// are indexed by the graph's node indices.
///
/// [bf]: https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm
///
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::algo::bellman_ford;
/// use petgraph::prelude::*;
///
/// let mut g = Graph::new();
/// let a = g.add_node(()); // node with no weight
/// let b = g.add_node(());
/// let c = g.add_node(());
/// let d = g.add_node(());
/// let e = g.add_node(());
/// let f = g.add_node(());
/// g.extend_with_edges(&[
/// (0, 1, 2.0),
/// (0, 3, 4.0),
/// (1, 2, 1.0),
/// (1, 5, 7.0),
/// (2, 4, 5.0),
/// (4, 5, 1.0),
/// (3, 4, 1.0),
/// ]);
///
/// // Graph represented with the weight of each edge
/// //
/// // 2 1
/// // a ----- b ----- c
/// // | 4 | 7 |
/// // d f | 5
/// // | 1 | 1 |
/// // \------ e ------/
///
/// let path = bellman_ford(&g, a);
/// assert!(path.is_ok());
/// let path = path.unwrap();
/// assert_eq!(path.distances, vec![ 0.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
/// assert_eq!(path.predecessors, vec![None, Some(a),Some(b),Some(a), Some(d), Some(e)]);
///
/// // Node f (indice 5) can be reach from a with a path costing 6.
/// // Predecessor of f is Some(e) which predecessor is Some(d) which predecessor is Some(a).
/// // Thus the path from a to f is a <-> d <-> e <-> f
///
/// let graph_with_neg_cycle = Graph::<(), f32, Undirected>::from_edges(&[
/// (0, 1, -2.0),
/// (0, 3, -4.0),
/// (1, 2, -1.0),
/// (1, 5, -25.0),
/// (2, 4, -5.0),
/// (4, 5, -25.0),
/// (3, 4, -1.0),
/// ]);
///
/// assert!(bellman_ford(&graph_with_neg_cycle, NodeIndex::new(0)).is_err());
/// ```
pub fn bellman_ford<G>(
g: G,
source: G::NodeId,
) -> Result<Paths<G::NodeId, G::EdgeWeight>, NegativeCycle>
where
G: NodeCount + IntoNodeIdentifiers + IntoEdges + NodeIndexable,
G::EdgeWeight: FloatMeasure,
{
let ix = |i| g.to_index(i);
// Step 1 and Step 2: initialize and relax
let (distances, predecessors) = bellman_ford_initialize_relax(g, source);
// Step 3: check for negative weight cycle
for i in g.node_identifiers() {
for edge in g.edges(i) {
let j = edge.target();
let w = *edge.weight();
if distances[ix(i)] + w < distances[ix(j)] {
return Err(NegativeCycle(()));
}
}
}
Ok(Paths {
distances,
predecessors,
})
}
/// \[Generic\] Find the path of a negative cycle reachable from node `source`.
///
/// Using the [find_negative_cycle][nc]; will search the Graph for negative cycles using
/// [BellmanFord algorithm][bf]. If no negative cycle is found the function will return `None`.
///
/// If a negative cycle is found from source, return one vec with a path of `NodeId`s.
///
/// The time complexity of this algorithm should be the same as the Bellman-Ford (O(|V|·|E|)).
///
/// [nc]: https://blogs.asarkar.com/assets/docs/algorithms-curated/Negative-Weight%20Cycle%20Algorithms%20-%20Huang.pdf
/// [bf]: https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm
///
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::algo::find_negative_cycle;
/// use petgraph::prelude::*;
///
/// let graph_with_neg_cycle = Graph::<(), f32, Directed>::from_edges(&[
/// (0, 1, 1.),
/// (0, 2, 1.),
/// (0, 3, 1.),
/// (1, 3, 1.),
/// (2, 1, 1.),
/// (3, 2, -3.),
/// ]);
///
/// let path = find_negative_cycle(&graph_with_neg_cycle, NodeIndex::new(0));
/// assert_eq!(
/// path,
/// Some([NodeIndex::new(1), NodeIndex::new(3), NodeIndex::new(2)].to_vec())
/// );
/// ```
pub fn find_negative_cycle<G>(g: G, source: G::NodeId) -> Option<Vec<G::NodeId>>
where
G: NodeCount + IntoNodeIdentifiers + IntoEdges + NodeIndexable + Visitable,
G::EdgeWeight: FloatMeasure,
{
let ix = |i| g.to_index(i);
let mut path = Vec::<G::NodeId>::new();
// Step 1: initialize and relax
let (distance, predecessor) = bellman_ford_initialize_relax(g, source);
// Step 2: Check for negative weight cycle
'outer: for i in g.node_identifiers() {
for edge in g.edges(i) {
let j = edge.target();
let w = *edge.weight();
if distance[ix(i)] + w < distance[ix(j)] {
// Step 3: negative cycle found
let start = j;
let mut node = start;
let mut visited = g.visit_map();
// Go backward in the predecessor chain
loop {
let ancestor = match predecessor[ix(node)] {
Some(predecessor_node) => predecessor_node,
None => node, // no predecessor, self cycle
};
// We have only 2 ways to find the cycle and break the loop:
// 1. start is reached
if ancestor == start {
path.push(ancestor);
break;
}
// 2. some node was reached twice
else if visited.is_visited(&ancestor) {
// Drop any node in path that is before the first ancestor
let pos = path
.iter()
.position(|&p| p == ancestor)
.expect("we should always have a position");
path = path[pos..path.len()].to_vec();
break;
}
// None of the above, some middle path node
path.push(ancestor);
visited.visit(ancestor);
node = ancestor;
}
// We are done here
break 'outer;
}
}
}
if !path.is_empty() {
// Users will probably need to follow the path of the negative cycle
// so it should be in the reverse order than it was found by the algorithm.
path.reverse();
Some(path)
} else {
None
}
}
// Perform Step 1 and Step 2 of the Bellman-Ford algorithm.
#[inline(always)]
fn bellman_ford_initialize_relax<G>(
g: G,
source: G::NodeId,
) -> (Vec<G::EdgeWeight>, Vec<Option<G::NodeId>>)
where
G: NodeCount + IntoNodeIdentifiers + IntoEdges + NodeIndexable,
G::EdgeWeight: FloatMeasure,
{
// Step 1: initialize graph
let mut predecessor = vec![None; g.node_bound()];
let mut distance = vec![<_>::infinite(); g.node_bound()];
let ix = |i| g.to_index(i);
distance[ix(source)] = <_>::zero();
// Step 2: relax edges repeatedly
for _ in 1..g.node_count() {
let mut did_update = false;
for i in g.node_identifiers() {
for edge in g.edges(i) {
let j = edge.target();
let w = *edge.weight();
if distance[ix(i)] + w < distance[ix(j)] {
distance[ix(j)] = distance[ix(i)] + w;
predecessor[ix(j)] = Some(i);
did_update = true;
}
}
}
if !did_update {
break;
}
}
(distance, predecessor)
}

96
vendor/petgraph/src/algo/coloring.rs vendored Normal file
View File

@@ -0,0 +1,96 @@
use std::collections::{BinaryHeap, HashMap, HashSet};
use std::hash::Hash;
use crate::scored::MaxScored;
use crate::visit::{IntoEdges, IntoNodeIdentifiers, NodeIndexable, VisitMap, Visitable};
/// \[Generic\] DStatur algorithm to properly color a non weighted undirected graph.
/// https://en.wikipedia.org/wiki/DSatur
///
/// This is a heuristic. So, it does not necessarily return a minimum coloring.
///
/// The graph must be undirected. It should not contain loops.
/// It must implement `IntoEdges`, `IntoNodeIdentifiers` and `Visitable`
/// Returns a tuple composed of a HashMap that associates to each `NodeId` its color and the number of used colors.
///
/// Computes in **O((|V| + |E|)*log(|V|)** time
///
/// # Example
/// ```rust
/// use petgraph::{Graph, Undirected};
/// use petgraph::algo::dsatur_coloring;
///
/// let mut graph: Graph<(), (), Undirected> = Graph::new_undirected();
/// let a = graph.add_node(());
/// let b = graph.add_node(());
/// let c = graph.add_node(());
/// let d = graph.add_node(());
/// let e = graph.add_node(());
/// let f = graph.add_node(());
///
/// graph.extend_with_edges(&[
/// (a, b),
/// (b, c),
/// (c, d),
/// (d, e),
/// (e, f),
/// (f, a),
/// ]);
///
/// // a ----- b ----- c
/// // | |
/// // | |
/// // | |
/// // f ----- e------ d
///
/// let (coloring, nb_colors) = dsatur_coloring(&graph);
/// assert_eq!(nb_colors, 2);
/// assert_ne!(coloring[&a], coloring[&b]);
/// ```
pub fn dsatur_coloring<G>(graph: G) -> (HashMap<G::NodeId, usize>, usize)
where
G: IntoEdges + IntoNodeIdentifiers + Visitable + NodeIndexable,
G::NodeId: Eq + Hash,
{
let ix = |v| graph.to_index(v);
let n = graph.node_bound();
let mut degree_map = vec![0; n];
let mut queue = BinaryHeap::with_capacity(n);
let mut colored = HashMap::with_capacity(n);
let mut adj_color_map = vec![HashSet::new(); n];
let mut seen = graph.visit_map();
let mut max_color = 0;
for node in graph.node_identifiers() {
let degree = graph.edges(node).count();
queue.push(MaxScored((0, degree), node));
degree_map[ix(node)] = degree;
}
while let Some(MaxScored(_, node)) = queue.pop() {
if seen.is_visited(&node) {
continue;
}
seen.visit(node);
let adj_color = &adj_color_map[ix(node)];
let mut color = 0;
while adj_color.contains(&color) {
color += 1;
}
colored.insert(node, color);
max_color = max_color.max(color);
for nbor in graph.neighbors(node) {
if let Some(adj_color) = adj_color_map.get_mut(ix(nbor)) {
adj_color.insert(color);
queue.push(MaxScored((adj_color.len(), degree_map[ix(nbor)]), nbor));
}
}
}
(colored, max_color + 1)
}

122
vendor/petgraph/src/algo/dijkstra.rs vendored Normal file
View File

@@ -0,0 +1,122 @@
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::collections::{BinaryHeap, HashMap};
use std::hash::Hash;
use crate::algo::Measure;
use crate::scored::MinScored;
use crate::visit::{EdgeRef, IntoEdges, VisitMap, Visitable};
/// \[Generic\] Dijkstra's shortest path algorithm.
///
/// Compute the length of the shortest path from `start` to every reachable
/// node.
///
/// The graph should be `Visitable` and implement `IntoEdges`. The function
/// `edge_cost` should return the cost for a particular edge, which is used
/// to compute path costs. Edge costs must be non-negative.
///
/// If `goal` is not `None`, then the algorithm terminates once the `goal` node's
/// cost is calculated.
///
/// Returns a `HashMap` that maps `NodeId` to path cost.
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::algo::dijkstra;
/// use petgraph::prelude::*;
/// use std::collections::HashMap;
///
/// let mut graph: Graph<(), (), Directed> = Graph::new();
/// let a = graph.add_node(()); // node with no weight
/// let b = graph.add_node(());
/// let c = graph.add_node(());
/// let d = graph.add_node(());
/// let e = graph.add_node(());
/// let f = graph.add_node(());
/// let g = graph.add_node(());
/// let h = graph.add_node(());
/// // z will be in another connected component
/// let z = graph.add_node(());
///
/// graph.extend_with_edges(&[
/// (a, b),
/// (b, c),
/// (c, d),
/// (d, a),
/// (e, f),
/// (b, e),
/// (f, g),
/// (g, h),
/// (h, e),
/// ]);
/// // a ----> b ----> e ----> f
/// // ^ | ^ |
/// // | v | v
/// // d <---- c h <---- g
///
/// let expected_res: HashMap<NodeIndex, usize> = [
/// (a, 3),
/// (b, 0),
/// (c, 1),
/// (d, 2),
/// (e, 1),
/// (f, 2),
/// (g, 3),
/// (h, 4),
/// ].iter().cloned().collect();
/// let res = dijkstra(&graph, b, None, |_| 1);
/// assert_eq!(res, expected_res);
/// // z is not inside res because there is not path from b to z.
/// ```
pub fn dijkstra<G, F, K>(
graph: G,
start: G::NodeId,
goal: Option<G::NodeId>,
mut edge_cost: F,
) -> HashMap<G::NodeId, K>
where
G: IntoEdges + Visitable,
G::NodeId: Eq + Hash,
F: FnMut(G::EdgeRef) -> K,
K: Measure + Copy,
{
let mut visited = graph.visit_map();
let mut scores = HashMap::new();
//let mut predecessor = HashMap::new();
let mut visit_next = BinaryHeap::new();
let zero_score = K::default();
scores.insert(start, zero_score);
visit_next.push(MinScored(zero_score, start));
while let Some(MinScored(node_score, node)) = visit_next.pop() {
if visited.is_visited(&node) {
continue;
}
if goal.as_ref() == Some(&node) {
break;
}
for edge in graph.edges(node) {
let next = edge.target();
if visited.is_visited(&next) {
continue;
}
let next_score = node_score + edge_cost(edge);
match scores.entry(next) {
Occupied(ent) => {
if next_score < *ent.get() {
*ent.into_mut() = next_score;
visit_next.push(MinScored(next_score, next));
//predecessor.insert(next.clone(), node.clone());
}
}
Vacant(ent) => {
ent.insert(next_score);
visit_next.push(MinScored(next_score, next));
//predecessor.insert(next.clone(), node.clone());
}
}
}
visited.visit(node);
}
scores
}

333
vendor/petgraph/src/algo/dominators.rs vendored Normal file
View File

@@ -0,0 +1,333 @@
//! Compute dominators of a control-flow graph.
//!
//! # The Dominance Relation
//!
//! In a directed graph with a root node **R**, a node **A** is said to *dominate* a
//! node **B** iff every path from **R** to **B** contains **A**.
//!
//! The node **A** is said to *strictly dominate* the node **B** iff **A** dominates
//! **B** and **A ≠ B**.
//!
//! The node **A** is said to be the *immediate dominator* of a node **B** iff it
//! strictly dominates **B** and there does not exist any node **C** where **A**
//! dominates **C** and **C** dominates **B**.
use std::cmp::Ordering;
use std::collections::{hash_map::Iter, HashMap, HashSet};
use std::hash::Hash;
use crate::visit::{DfsPostOrder, GraphBase, IntoNeighbors, Visitable, Walker};
/// The dominance relation for some graph and root.
#[derive(Debug, Clone)]
pub struct Dominators<N>
where
N: Copy + Eq + Hash,
{
root: N,
dominators: HashMap<N, N>,
}
impl<N> Dominators<N>
where
N: Copy + Eq + Hash,
{
/// Get the root node used to construct these dominance relations.
pub fn root(&self) -> N {
self.root
}
/// Get the immediate dominator of the given node.
///
/// Returns `None` for any node that is not reachable from the root, and for
/// the root itself.
pub fn immediate_dominator(&self, node: N) -> Option<N> {
if node == self.root {
None
} else {
self.dominators.get(&node).cloned()
}
}
/// Iterate over the given node's strict dominators.
///
/// If the given node is not reachable from the root, then `None` is
/// returned.
pub fn strict_dominators(&self, node: N) -> Option<DominatorsIter<N>> {
if self.dominators.contains_key(&node) {
Some(DominatorsIter {
dominators: self,
node: self.immediate_dominator(node),
})
} else {
None
}
}
/// Iterate over all of the given node's dominators (including the given
/// node itself).
///
/// If the given node is not reachable from the root, then `None` is
/// returned.
pub fn dominators(&self, node: N) -> Option<DominatorsIter<N>> {
if self.dominators.contains_key(&node) {
Some(DominatorsIter {
dominators: self,
node: Some(node),
})
} else {
None
}
}
/// Iterate over all nodes immediately dominated by the given node (not
/// including the given node itself).
pub fn immediately_dominated_by(&self, node: N) -> DominatedByIter<N> {
DominatedByIter {
iter: self.dominators.iter(),
node,
}
}
}
/// Iterator for a node's dominators.
#[derive(Debug, Clone)]
pub struct DominatorsIter<'a, N>
where
N: 'a + Copy + Eq + Hash,
{
dominators: &'a Dominators<N>,
node: Option<N>,
}
impl<'a, N> Iterator for DominatorsIter<'a, N>
where
N: 'a + Copy + Eq + Hash,
{
type Item = N;
fn next(&mut self) -> Option<Self::Item> {
let next = self.node.take();
if let Some(next) = next {
self.node = self.dominators.immediate_dominator(next);
}
next
}
}
/// Iterator for nodes dominated by a given node.
#[derive(Debug, Clone)]
pub struct DominatedByIter<'a, N>
where
N: 'a + Copy + Eq + Hash,
{
iter: Iter<'a, N, N>,
node: N,
}
impl<'a, N> Iterator for DominatedByIter<'a, N>
where
N: 'a + Copy + Eq + Hash,
{
type Item = N;
fn next(&mut self) -> Option<Self::Item> {
for (dominator, dominated) in self.iter.by_ref() {
// The root node dominates itself, but it should not be included in
// the results.
if dominated == &self.node && dominated != dominator {
return Some(*dominator);
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}
/// The undefined dominator sentinel, for when we have not yet discovered a
/// node's dominator.
const UNDEFINED: usize = ::std::usize::MAX;
/// This is an implementation of the engineered ["Simple, Fast Dominance
/// Algorithm"][0] discovered by Cooper et al.
///
/// This algorithm is **O(|V|²)**, and therefore has slower theoretical running time
/// than the Lengauer-Tarjan algorithm (which is **O(|E| log |V|)**. However,
/// Cooper et al found it to be faster in practice on control flow graphs of up
/// to ~30,000 vertices.
///
/// [0]: http://www.hipersoft.rice.edu/grads/publications/dom14.pdf
pub fn simple_fast<G>(graph: G, root: G::NodeId) -> Dominators<G::NodeId>
where
G: IntoNeighbors + Visitable,
<G as GraphBase>::NodeId: Eq + Hash,
{
let (post_order, predecessor_sets) = simple_fast_post_order(graph, root);
let length = post_order.len();
debug_assert!(length > 0);
debug_assert!(post_order.last() == Some(&root));
// From here on out we use indices into `post_order` instead of actual
// `NodeId`s wherever possible. This greatly improves the performance of
// this implementation, but we have to pay a little bit of upfront cost to
// convert our data structures to play along first.
// Maps a node to its index into `post_order`.
let node_to_post_order_idx: HashMap<_, _> = post_order
.iter()
.enumerate()
.map(|(idx, &node)| (node, idx))
.collect();
// Maps a node's `post_order` index to its set of predecessors's indices
// into `post_order` (as a vec).
let idx_to_predecessor_vec =
predecessor_sets_to_idx_vecs(&post_order, &node_to_post_order_idx, predecessor_sets);
let mut dominators = vec![UNDEFINED; length];
dominators[length - 1] = length - 1;
let mut changed = true;
while changed {
changed = false;
// Iterate in reverse post order, skipping the root.
for idx in (0..length - 1).rev() {
debug_assert!(post_order[idx] != root);
// Take the intersection of every predecessor's dominator set; that
// is the current best guess at the immediate dominator for this
// node.
let new_idom_idx = {
let mut predecessors = idx_to_predecessor_vec[idx]
.iter()
.filter(|&&p| dominators[p] != UNDEFINED);
let new_idom_idx = predecessors.next().expect(
"Because the root is initialized to dominate itself, and is the \
first node in every path, there must exist a predecessor to this \
node that also has a dominator",
);
predecessors.fold(*new_idom_idx, |new_idom_idx, &predecessor_idx| {
intersect(&dominators, new_idom_idx, predecessor_idx)
})
};
debug_assert!(new_idom_idx < length);
if new_idom_idx != dominators[idx] {
dominators[idx] = new_idom_idx;
changed = true;
}
}
}
// All done! Translate the indices back into proper `G::NodeId`s.
debug_assert!(!dominators.iter().any(|&dom| dom == UNDEFINED));
Dominators {
root,
dominators: dominators
.into_iter()
.enumerate()
.map(|(idx, dom_idx)| (post_order[idx], post_order[dom_idx]))
.collect(),
}
}
fn intersect(dominators: &[usize], mut finger1: usize, mut finger2: usize) -> usize {
loop {
match finger1.cmp(&finger2) {
Ordering::Less => finger1 = dominators[finger1],
Ordering::Greater => finger2 = dominators[finger2],
Ordering::Equal => return finger1,
}
}
}
fn predecessor_sets_to_idx_vecs<N>(
post_order: &[N],
node_to_post_order_idx: &HashMap<N, usize>,
mut predecessor_sets: HashMap<N, HashSet<N>>,
) -> Vec<Vec<usize>>
where
N: Copy + Eq + Hash,
{
post_order
.iter()
.map(|node| {
predecessor_sets
.remove(node)
.map(|predecessors| {
predecessors
.into_iter()
.map(|p| *node_to_post_order_idx.get(&p).unwrap())
.collect()
})
.unwrap_or_default()
})
.collect()
}
type PredecessorSets<NodeId> = HashMap<NodeId, HashSet<NodeId>>;
fn simple_fast_post_order<G>(
graph: G,
root: G::NodeId,
) -> (Vec<G::NodeId>, PredecessorSets<G::NodeId>)
where
G: IntoNeighbors + Visitable,
<G as GraphBase>::NodeId: Eq + Hash,
{
let mut post_order = vec![];
let mut predecessor_sets = HashMap::new();
for node in DfsPostOrder::new(graph, root).iter(graph) {
post_order.push(node);
for successor in graph.neighbors(node) {
predecessor_sets
.entry(successor)
.or_insert_with(HashSet::new)
.insert(node);
}
}
(post_order, predecessor_sets)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_iter_dominators() {
let doms: Dominators<u32> = Dominators {
root: 0,
dominators: [(2, 1), (1, 0), (0, 0)].iter().cloned().collect(),
};
let all_doms: Vec<_> = doms.dominators(2).unwrap().collect();
assert_eq!(vec![2, 1, 0], all_doms);
assert_eq!(None::<()>, doms.dominators(99).map(|_| unreachable!()));
let strict_doms: Vec<_> = doms.strict_dominators(2).unwrap().collect();
assert_eq!(vec![1, 0], strict_doms);
assert_eq!(
None::<()>,
doms.strict_dominators(99).map(|_| unreachable!())
);
let dom_by: Vec<_> = doms.immediately_dominated_by(1).collect();
assert_eq!(vec![2], dom_by);
assert_eq!(None, doms.immediately_dominated_by(99).next());
assert_eq!(1, doms.immediately_dominated_by(0).count());
}
}

View File

@@ -0,0 +1,449 @@
use std::{
collections::{HashMap, VecDeque},
ops::{Index, IndexMut},
};
use crate::{
graph::{GraphIndex, NodeIndex},
visit::{EdgeRef, GraphProp, IntoEdgeReferences},
Directed,
};
use self::linked_list::{LinkedList, LinkedListEntry};
/// \[Generic\] Finds a [feedback arc set]: a set of edges in the given directed graph, which when
/// removed, make the graph acyclic.
///
/// Uses a [greedy heuristic algorithm] to select a small number of edges, but does not necessarily
/// find the minimum feedback arc set. Time complexity is roughly **O(|E|)** for an input graph with
/// edges **E**.
///
/// Does not consider edge/node weights when selecting edges for the feedback arc set.
///
/// Loops (edges to and from the same node) are always included in the returned set.
///
/// # Example
///
/// ```
/// # #[cfg(feature = "stable_graph")] {
/// use petgraph::{
/// algo::{greedy_feedback_arc_set, is_cyclic_directed},
/// graph::EdgeIndex,
/// stable_graph::StableGraph,
/// visit::EdgeRef,
/// };
///
/// let mut g: StableGraph<(), ()> = StableGraph::from_edges(&[
/// (0, 1),
/// (1, 2),
/// (2, 3),
/// (3, 4),
/// (4, 5),
/// (5, 0),
/// (4, 1),
/// (1, 3),
/// ]);
///
/// assert!(is_cyclic_directed(&g));
///
/// let fas: Vec<EdgeIndex> = greedy_feedback_arc_set(&g).map(|e| e.id()).collect();
///
/// // Remove edges in feedback arc set from original graph
/// for edge_id in fas {
/// g.remove_edge(edge_id);
/// }
///
/// assert!(!is_cyclic_directed(&g));
/// # }
/// ```
///
/// [feedback arc set]: https://en.wikipedia.org/wiki/Feedback_arc_set
/// [greedy heuristic algorithm]: https://doi.org/10.1016/0020-0190(93)90079-O
pub fn greedy_feedback_arc_set<G>(g: G) -> impl Iterator<Item = G::EdgeRef>
where
G: IntoEdgeReferences + GraphProp<EdgeType = Directed>,
G::NodeId: GraphIndex,
G: crate::visit::NodeCount,
{
let node_seq = good_node_sequence(g.edge_references().map(|e| {
(
NodeIndex::new(e.source().index()),
NodeIndex::new(e.target().index()),
)
}));
g.edge_references()
.filter(move |e| node_seq[&e.source().index()] >= node_seq[&e.target().index()])
}
fn good_node_sequence(
edge_refs: impl Iterator<Item = (NodeIndex<usize>, NodeIndex<usize>)>,
) -> HashMap<usize, usize> {
let mut nodes = FasNodeContainer { nodes: Vec::new() };
let mut buckets = Buckets {
sinks_or_isolated: NodeLinkedList::new(),
sources: NodeLinkedList::new(),
bidirectional_pve_dd: Vec::new(),
bidirectional_nve_dd: Vec::new(),
};
// Lookup of node indices from input graph to indices into `nodes`
let mut graph_ix_lookup = HashMap::new();
// Build node entries
for (from_g_ix, to_g_ix) in edge_refs {
let mut fas_node_entry = |g_ix: NodeIndex<usize>| -> FasNodeIndex {
match graph_ix_lookup.get(&g_ix) {
Some(fas_ix) => *fas_ix,
None => {
let fas_ix = FasNodeIndex(nodes.nodes.len());
nodes.nodes.push(LinkedListEntry::new(FasNode {
graph_ix: g_ix,
out_edges: Vec::new(),
in_edges: Vec::new(),
out_degree: 0,
in_degree: 0,
}));
graph_ix_lookup.insert(g_ix, fas_ix);
fas_ix
}
}
};
let from_fas_ix = fas_node_entry(from_g_ix);
let to_fas_ix = fas_node_entry(to_g_ix);
nodes[from_fas_ix].data().out_edges.push(to_fas_ix);
nodes[to_fas_ix].data().in_edges.push(from_fas_ix);
}
// Set initial in/out-degrees
for entry in nodes.nodes.iter_mut() {
let node = entry.data();
node.out_degree = node.out_edges.len();
node.in_degree = node.in_edges.len();
}
// Add nodes to initial lists
for i in 0..nodes.nodes.len() {
let fas_ix = FasNodeIndex(i);
buckets
.suitable_bucket(fas_ix, &mut nodes)
.push_front(fas_ix, &mut nodes);
}
let mut s_1 = VecDeque::new();
let mut s_2 = VecDeque::new();
loop {
let mut some_moved = false;
while let Some(sink_fas_ix) = buckets.sinks_or_isolated.pop(&mut nodes) {
some_moved = true;
buckets.update_neighbour_node_buckets(sink_fas_ix, &mut nodes);
s_2.push_front(nodes[sink_fas_ix].data().graph_ix);
}
while let Some(source_fas_ix) = buckets.sources.pop(&mut nodes) {
some_moved = true;
buckets.update_neighbour_node_buckets(source_fas_ix, &mut nodes);
s_1.push_back(nodes[source_fas_ix].data().graph_ix);
}
if let Some(list) = buckets
.bidirectional_pve_dd
.iter_mut()
.rev()
.chain(buckets.bidirectional_nve_dd.iter_mut())
.find(|b| b.start.is_some())
{
let highest_dd_fas_ix = list.pop(&mut nodes).unwrap();
some_moved = true;
buckets.update_neighbour_node_buckets(highest_dd_fas_ix, &mut nodes);
s_1.push_back(nodes[highest_dd_fas_ix].data().graph_ix);
Buckets::trim_bucket_list(&mut buckets.bidirectional_pve_dd);
Buckets::trim_bucket_list(&mut buckets.bidirectional_nve_dd);
}
if !some_moved {
break;
}
}
s_1.into_iter()
.chain(s_2)
.enumerate()
.map(|(seq_order, node_index)| (node_index.index(), seq_order))
.collect()
}
type NodeLinkedList = LinkedList<FasNode, FasNodeContainer, FasNodeIndex>;
#[derive(Debug)]
struct FasNodeContainer {
nodes: Vec<LinkedListEntry<FasNode, FasNodeIndex>>,
}
impl Index<FasNodeIndex> for FasNodeContainer {
type Output = LinkedListEntry<FasNode, FasNodeIndex>;
fn index(&self, index: FasNodeIndex) -> &Self::Output {
&self.nodes[index.0]
}
}
impl IndexMut<FasNodeIndex> for FasNodeContainer {
fn index_mut(&mut self, index: FasNodeIndex) -> &mut Self::Output {
&mut self.nodes[index.0]
}
}
#[derive(Debug)]
struct Buckets {
sinks_or_isolated: NodeLinkedList,
sources: NodeLinkedList,
/// Bidirectional nodes with positive-or-0 delta degree
bidirectional_pve_dd: Vec<NodeLinkedList>,
/// Bidirectional nodes with negative delta degree (index 0 is -1 dd, 1 is -2 etc)
bidirectional_nve_dd: Vec<NodeLinkedList>,
}
#[derive(Clone, Copy, PartialEq, Debug)]
struct FasNodeIndex(usize);
/// Represents a node from the input graph, tracking its current delta degree
#[derive(Debug)]
struct FasNode {
/// Node index in input graph.
graph_ix: NodeIndex<usize>,
/// All outward edges from this node (not removed during processing)
out_edges: Vec<FasNodeIndex>,
/// All inward edges from this node (not removed during processing)
in_edges: Vec<FasNodeIndex>,
/// Current out-degree of this node (decremented during processing as connected nodes are
/// removed)
out_degree: usize,
/// Current in-degree of this node (decremented during processing as connected nodes are
/// removed)
in_degree: usize,
}
impl Buckets {
fn suitable_bucket(
&mut self,
ix: FasNodeIndex,
nodes: &mut FasNodeContainer,
) -> &mut NodeLinkedList {
let node = nodes[ix].data();
if node.out_degree == 0 {
&mut self.sinks_or_isolated
} else if node.in_degree == 0 {
&mut self.sources
} else {
let delta_degree = node.out_degree as isize - node.in_degree as isize;
if delta_degree >= 0 {
let bucket_ix = delta_degree as usize;
if self.bidirectional_pve_dd.len() <= bucket_ix {
self.bidirectional_pve_dd
.resize_with(bucket_ix + 1, NodeLinkedList::new);
}
&mut self.bidirectional_pve_dd[bucket_ix]
} else {
let bucket_ix = (-delta_degree - 1) as usize;
if self.bidirectional_nve_dd.len() <= bucket_ix {
self.bidirectional_nve_dd
.resize_with(bucket_ix + 1, NodeLinkedList::new);
}
&mut self.bidirectional_nve_dd[bucket_ix]
}
}
}
fn update_neighbour_node_buckets(&mut self, ix: FasNodeIndex, nodes: &mut FasNodeContainer) {
for i in 0..nodes[ix].data().out_edges.len() {
let out_ix = nodes[ix].data().out_edges[i];
if out_ix == ix {
continue;
}
// Ignore nodes which have already been moved to the good sequence
if !nodes[out_ix].is_in_list() {
continue;
}
self.suitable_bucket(out_ix, nodes).remove(out_ix, nodes);
// Other node has lost an in-edge; reduce in-degree by 1
nodes[out_ix].data().in_degree -= 1;
self.suitable_bucket(out_ix, nodes)
.push_front(out_ix, nodes);
}
for i in 0..nodes[ix].data().in_edges.len() {
let in_ix = nodes[ix].data().in_edges[i];
if in_ix == ix {
continue;
}
// Ignore nodes which have already been moved to the good sequence
if !nodes[in_ix].is_in_list() {
continue;
}
self.suitable_bucket(in_ix, nodes).remove(in_ix, nodes);
// Other node has lost an out-edge; reduce out-degree by 1
nodes[in_ix].data().out_degree -= 1;
self.suitable_bucket(in_ix, nodes).push_front(in_ix, nodes);
}
}
fn trim_bucket_list(list: &mut Vec<NodeLinkedList>) {
let trunc_len = if let Some(highest_populated_index) =
(0..list.len()).rev().find(|i| list[*i].start.is_some())
{
highest_populated_index + 1
} else {
0
};
list.truncate(trunc_len);
}
}
mod linked_list {
use std::{marker::PhantomData, ops::IndexMut};
#[derive(PartialEq, Debug)]
pub struct LinkedList<Data, Container, Ix> {
pub start: Option<Ix>,
marker: PhantomData<(Data, Container)>,
}
#[derive(Debug)]
pub struct LinkedListEntry<Data, Ix> {
pos: Option<LinkedListPosition<Ix>>,
data: Data,
}
#[derive(Debug)]
struct LinkedListPosition<Ix> {
prev: Option<Ix>,
next: Option<Ix>,
}
impl<Data, Ix> LinkedListEntry<Data, Ix> {
pub fn new(data: Data) -> Self {
LinkedListEntry { pos: None, data }
}
pub fn data(&mut self) -> &mut Data {
&mut self.data
}
pub fn is_in_list(&mut self) -> bool {
self.pos.is_some()
}
fn pos_mut(&mut self) -> &mut LinkedListPosition<Ix> {
self.pos
.as_mut()
.expect("expected linked list entry to have populated position")
}
}
impl<Data, Container, Ix> LinkedList<Data, Container, Ix>
where
Container: IndexMut<Ix, Output = LinkedListEntry<Data, Ix>>,
Ix: PartialEq + Copy,
{
pub fn new() -> Self {
LinkedList {
start: None,
marker: PhantomData,
}
}
pub fn push_front(&mut self, push_ix: Ix, container: &mut Container) {
if let Some(start_ix) = self.start {
let entry = &mut container[start_ix];
entry.pos_mut().prev = Some(push_ix);
}
let push_entry = &mut container[push_ix];
push_entry.pos = Some(LinkedListPosition {
next: self.start,
prev: None,
});
self.start = Some(push_ix);
}
pub fn pop(&mut self, container: &mut Container) -> Option<Ix> {
if let Some(remove_ix) = self.start {
self.remove(remove_ix, container);
Some(remove_ix)
} else {
None
}
}
/// `remove_ix` **must** be a member of the list headed by `self`
pub fn remove(&mut self, remove_ix: Ix, container: &mut Container) {
debug_assert!(
self.to_vec(container).contains(&remove_ix),
"node to remove should be member of current linked list"
);
let remove_entry = &mut container[remove_ix];
let ll_entry = remove_entry.pos.take().unwrap();
if let Some(prev_ix) = ll_entry.prev {
let prev_node = &mut container[prev_ix];
prev_node.pos_mut().next = ll_entry.next;
}
if let Some(next_ix) = ll_entry.next {
let next_node = &mut container[next_ix];
next_node.pos_mut().prev = ll_entry.prev;
}
// If the removed node was head of the list
if self.start == Some(remove_ix) {
self.start = ll_entry.next;
}
}
/// For debug purposes
fn to_vec(&self, container: &mut Container) -> Vec<Ix> {
let mut ixs = Vec::new();
let mut node_ix = self.start;
while let Some(n_ix) = node_ix {
ixs.push(n_ix);
node_ix = container[n_ix].pos_mut().next;
}
ixs
}
}
}

View File

@@ -0,0 +1,143 @@
use std::collections::HashMap;
use std::hash::Hash;
use crate::algo::{BoundedMeasure, NegativeCycle};
use crate::visit::{
EdgeRef, GraphProp, IntoEdgeReferences, IntoNodeIdentifiers, NodeCompactIndexable,
};
#[allow(clippy::type_complexity, clippy::needless_range_loop)]
/// \[Generic\] [FloydWarshall algorithm](https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm) is an algorithm for all pairs shortest path problem
///
/// Compute shortest paths in a weighted graph with positive or negative edge weights (but with no negative cycles)
///
/// # Arguments
/// * `graph`: graph with no negative cycle
/// * `edge_cost`: closure that returns cost of a particular edge
///
/// # Returns
/// * `Ok`: (if graph contains no negative cycle) a hashmap containing all pairs shortest paths
/// * `Err`: if graph contains negative cycle.
///
/// # Examples
/// ```rust
/// use petgraph::{prelude::*, Graph, Directed};
/// use petgraph::algo::floyd_warshall;
/// use std::collections::HashMap;
///
/// let mut graph: Graph<(), (), Directed> = Graph::new();
/// let a = graph.add_node(());
/// let b = graph.add_node(());
/// let c = graph.add_node(());
/// let d = graph.add_node(());
///
/// graph.extend_with_edges(&[
/// (a, b),
/// (a, c),
/// (a, d),
/// (b, c),
/// (b, d),
/// (c, d)
/// ]);
///
/// let weight_map: HashMap<(NodeIndex, NodeIndex), i32> = [
/// ((a, a), 0), ((a, b), 1), ((a, c), 4), ((a, d), 10),
/// ((b, b), 0), ((b, c), 2), ((b, d), 2),
/// ((c, c), 0), ((c, d), 2)
/// ].iter().cloned().collect();
/// // ----- b --------
/// // | ^ | 2
/// // | 1 | 4 v
/// // 2 | a ------> c
/// // | 10 | | 2
/// // | v v
/// // ---> d <-------
///
/// let inf = std::i32::MAX;
/// let expected_res: HashMap<(NodeIndex, NodeIndex), i32> = [
/// ((a, a), 0), ((a, b), 1), ((a, c), 3), ((a, d), 3),
/// ((b, a), inf), ((b, b), 0), ((b, c), 2), ((b, d), 2),
/// ((c, a), inf), ((c, b), inf), ((c, c), 0), ((c, d), 2),
/// ((d, a), inf), ((d, b), inf), ((d, c), inf), ((d, d), 0),
/// ].iter().cloned().collect();
///
///
/// let res = floyd_warshall(&graph, |edge| {
/// if let Some(weight) = weight_map.get(&(edge.source(), edge.target())) {
/// *weight
/// } else {
/// inf
/// }
/// }).unwrap();
///
/// let nodes = [a, b, c, d];
/// for node1 in &nodes {
/// for node2 in &nodes {
/// assert_eq!(res.get(&(*node1, *node2)).unwrap(), expected_res.get(&(*node1, *node2)).unwrap());
/// }
/// }
/// ```
pub fn floyd_warshall<G, F, K>(
graph: G,
mut edge_cost: F,
) -> Result<HashMap<(G::NodeId, G::NodeId), K>, NegativeCycle>
where
G: NodeCompactIndexable + IntoEdgeReferences + IntoNodeIdentifiers + GraphProp,
G::NodeId: Eq + Hash,
F: FnMut(G::EdgeRef) -> K,
K: BoundedMeasure + Copy,
{
let num_of_nodes = graph.node_count();
// |V|x|V| matrix
let mut dist = vec![vec![K::max(); num_of_nodes]; num_of_nodes];
// init distances of paths with no intermediate nodes
for edge in graph.edge_references() {
let i = graph.to_index(edge.source());
let j = graph.to_index(edge.target());
let cost = edge_cost(edge);
if dist[i][j] > cost {
dist[i][j] = cost;
if !graph.is_directed() {
dist[j][i] = cost;
}
}
}
// distance of each node to itself is 0(default value)
for node in graph.node_identifiers() {
dist[graph.to_index(node)][graph.to_index(node)] = K::default();
}
for k in 0..num_of_nodes {
for i in 0..num_of_nodes {
for j in 0..num_of_nodes {
let (result, overflow) = dist[i][k].overflowing_add(dist[k][j]);
if !overflow && dist[i][j] > result {
dist[i][j] = result;
}
}
}
}
// value less than 0(default value) indicates a negative cycle
for i in 0..num_of_nodes {
if dist[i][i] < K::default() {
return Err(NegativeCycle(()));
}
}
let mut distance_map: HashMap<(G::NodeId, G::NodeId), K> =
HashMap::with_capacity(num_of_nodes * num_of_nodes);
for i in 0..num_of_nodes {
for j in 0..num_of_nodes {
distance_map.insert((graph.from_index(i), graph.from_index(j)), dist[i][j]);
}
}
Ok(distance_map)
}

View File

@@ -0,0 +1,196 @@
use std::{collections::VecDeque, ops::Sub};
use crate::{
data::DataMap,
visit::{
EdgeCount, EdgeIndexable, IntoEdges, IntoEdgesDirected, NodeCount, NodeIndexable, VisitMap,
Visitable,
},
};
use super::{EdgeRef, PositiveMeasure};
use crate::prelude::Direction;
fn residual_capacity<N>(
network: N,
edge: N::EdgeRef,
vertex: N::NodeId,
flow: N::EdgeWeight,
) -> N::EdgeWeight
where
N: NodeIndexable + IntoEdges,
N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,
{
if vertex == edge.source() {
// backward edge
flow
} else if vertex == edge.target() {
// forward edge
return *edge.weight() - flow;
} else {
let end_point = NodeIndexable::to_index(&network, vertex);
panic!("Illegal endpoint {}", end_point);
}
}
/// Gets the other endpoint of graph edge, if any, otherwise panics.
fn other_endpoint<N>(network: N, edge: N::EdgeRef, vertex: N::NodeId) -> N::NodeId
where
N: NodeIndexable + IntoEdges,
{
if vertex == edge.source() {
edge.target()
} else if vertex == edge.target() {
edge.source()
} else {
let end_point = NodeIndexable::to_index(&network, vertex);
panic!("Illegal endpoint {}", end_point);
}
}
/// Tells whether there is an augmented path in the graph
fn has_augmented_path<N>(
network: N,
source: N::NodeId,
destination: N::NodeId,
edge_to: &mut [Option<N::EdgeRef>],
flows: &[N::EdgeWeight],
) -> bool
where
N: NodeCount + IntoEdgesDirected + NodeIndexable + EdgeIndexable + Visitable,
N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,
{
let mut visited = network.visit_map();
let mut queue = VecDeque::new();
visited.visit(source);
queue.push_back(source);
while let Some(vertex) = queue.pop_front() {
let out_edges = network.edges_directed(vertex, Direction::Outgoing);
let in_edges = network.edges_directed(vertex, Direction::Incoming);
for edge in out_edges.chain(in_edges) {
let next = other_endpoint(&network, edge, vertex);
let edge_index: usize = EdgeIndexable::to_index(&network, edge.id());
let residual_cap = residual_capacity(&network, edge, next, flows[edge_index]);
if !visited.is_visited(&next) && (residual_cap > N::EdgeWeight::zero()) {
visited.visit(next);
edge_to[NodeIndexable::to_index(&network, next)] = Some(edge);
if destination == next {
return true;
}
queue.push_back(next);
}
}
}
false
}
fn adjust_residual_flow<N>(
network: N,
edge: N::EdgeRef,
vertex: N::NodeId,
flow: N::EdgeWeight,
delta: N::EdgeWeight,
) -> N::EdgeWeight
where
N: NodeIndexable + IntoEdges,
N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,
{
if vertex == edge.source() {
// backward edge
flow - delta
} else if vertex == edge.target() {
// forward edge
flow + delta
} else {
let end_point = NodeIndexable::to_index(&network, vertex);
panic!("Illegal endpoint {}", end_point);
}
}
/// \[Generic\] Ford-Fulkerson algorithm.
///
/// Computes the [maximum flow][ff] of a weighted directed graph.
///
/// If it terminates, it returns the maximum flow and also the computed edge flows.
///
/// [ff]: https://en.wikipedia.org/wiki/Ford%E2%80%93Fulkerson_algorithm
///
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::algo::ford_fulkerson;
/// // Example from CLRS book
/// let mut graph = Graph::<u8, u8>::new();
/// let source = graph.add_node(0);
/// let _ = graph.add_node(1);
/// let _ = graph.add_node(2);
/// let _ = graph.add_node(3);
/// let _ = graph.add_node(4);
/// let destination = graph.add_node(5);
/// graph.extend_with_edges(&[
/// (0, 1, 16),
/// (0, 2, 13),
/// (1, 2, 10),
/// (1, 3, 12),
/// (2, 1, 4),
/// (2, 4, 14),
/// (3, 2, 9),
/// (3, 5, 20),
/// (4, 3, 7),
/// (4, 5, 4),
/// ]);
/// let (max_flow, _) = ford_fulkerson(&graph, source, destination);
/// assert_eq!(23, max_flow);
/// ```
pub fn ford_fulkerson<N>(
network: N,
source: N::NodeId,
destination: N::NodeId,
) -> (N::EdgeWeight, Vec<N::EdgeWeight>)
where
N: NodeCount
+ EdgeCount
+ IntoEdgesDirected
+ EdgeIndexable
+ NodeIndexable
+ DataMap
+ Visitable,
N::EdgeWeight: Sub<Output = N::EdgeWeight> + PositiveMeasure,
{
let mut edge_to = vec![None; network.node_count()];
let mut flows = vec![N::EdgeWeight::zero(); network.edge_count()];
let mut max_flow = N::EdgeWeight::zero();
while has_augmented_path(&network, source, destination, &mut edge_to, &flows) {
let mut path_flow = N::EdgeWeight::max();
// Find the bottleneck capacity of the path
let mut vertex = destination;
let mut vertex_index = NodeIndexable::to_index(&network, vertex);
while let Some(edge) = edge_to[vertex_index] {
let edge_index = EdgeIndexable::to_index(&network, edge.id());
let residual_capacity = residual_capacity(&network, edge, vertex, flows[edge_index]);
// Minimum between the current path flow and the residual capacity.
path_flow = if path_flow > residual_capacity {
residual_capacity
} else {
path_flow
};
vertex = other_endpoint(&network, edge, vertex);
vertex_index = NodeIndexable::to_index(&network, vertex);
}
// Update the flow of each edge along the path
let mut vertex = destination;
let mut vertex_index = NodeIndexable::to_index(&network, vertex);
while let Some(edge) = edge_to[vertex_index] {
let edge_index = EdgeIndexable::to_index(&network, edge.id());
flows[edge_index] =
adjust_residual_flow(&network, edge, vertex, flows[edge_index], path_flow);
vertex = other_endpoint(&network, edge, vertex);
vertex_index = NodeIndexable::to_index(&network, vertex);
}
max_flow = max_flow + path_flow;
}
(max_flow, flows)
}

994
vendor/petgraph/src/algo/isomorphism.rs vendored Normal file
View File

@@ -0,0 +1,994 @@
use std::convert::TryFrom;
use crate::data::DataMap;
use crate::visit::EdgeCount;
use crate::visit::EdgeRef;
use crate::visit::GetAdjacencyMatrix;
use crate::visit::GraphBase;
use crate::visit::GraphProp;
use crate::visit::IntoEdgesDirected;
use crate::visit::IntoNeighborsDirected;
use crate::visit::NodeCompactIndexable;
use crate::{Incoming, Outgoing};
use self::semantic::EdgeMatcher;
use self::semantic::NoSemanticMatch;
use self::semantic::NodeMatcher;
use self::state::Vf2State;
mod state {
use super::*;
#[derive(Debug)]
// TODO: make mapping generic over the index type of the other graph.
pub struct Vf2State<'a, G: GetAdjacencyMatrix> {
/// A reference to the graph this state was built from.
pub graph: &'a G,
/// The current mapping M(s) of nodes from G0 → G1 and G1 → G0,
/// `usize::MAX` for no mapping.
pub mapping: Vec<usize>,
/// out[i] is non-zero if i is in either M_0(s) or Tout_0(s)
/// These are all the next vertices that are not mapped yet, but
/// have an outgoing edge from the mapping.
out: Vec<usize>,
/// ins[i] is non-zero if i is in either M_0(s) or Tin_0(s)
/// These are all the incoming vertices, those not mapped yet, but
/// have an edge from them into the mapping.
/// Unused if graph is undirected -- it's identical with out in that case.
ins: Vec<usize>,
pub out_size: usize,
pub ins_size: usize,
pub adjacency_matrix: G::AdjMatrix,
generation: usize,
}
impl<'a, G> Vf2State<'a, G>
where
G: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
{
pub fn new(g: &'a G) -> Self {
let c0 = g.node_count();
Vf2State {
graph: g,
mapping: vec![std::usize::MAX; c0],
out: vec![0; c0],
ins: vec![0; c0 * (g.is_directed() as usize)],
out_size: 0,
ins_size: 0,
adjacency_matrix: g.adjacency_matrix(),
generation: 0,
}
}
/// Return **true** if we have a complete mapping
pub fn is_complete(&self) -> bool {
self.generation == self.mapping.len()
}
/// Add mapping **from** <-> **to** to the state.
pub fn push_mapping(&mut self, from: G::NodeId, to: usize) {
self.generation += 1;
self.mapping[self.graph.to_index(from)] = to;
// update T0 & T1 ins/outs
// T0out: Node in G0 not in M0 but successor of a node in M0.
// st.out[0]: Node either in M0 or successor of M0
for ix in self.graph.neighbors_directed(from, Outgoing) {
if self.out[self.graph.to_index(ix)] == 0 {
self.out[self.graph.to_index(ix)] = self.generation;
self.out_size += 1;
}
}
if self.graph.is_directed() {
for ix in self.graph.neighbors_directed(from, Incoming) {
if self.ins[self.graph.to_index(ix)] == 0 {
self.ins[self.graph.to_index(ix)] = self.generation;
self.ins_size += 1;
}
}
}
}
/// Restore the state to before the last added mapping
pub fn pop_mapping(&mut self, from: G::NodeId) {
// undo (n, m) mapping
self.mapping[self.graph.to_index(from)] = std::usize::MAX;
// unmark in ins and outs
for ix in self.graph.neighbors_directed(from, Outgoing) {
if self.out[self.graph.to_index(ix)] == self.generation {
self.out[self.graph.to_index(ix)] = 0;
self.out_size -= 1;
}
}
if self.graph.is_directed() {
for ix in self.graph.neighbors_directed(from, Incoming) {
if self.ins[self.graph.to_index(ix)] == self.generation {
self.ins[self.graph.to_index(ix)] = 0;
self.ins_size -= 1;
}
}
}
self.generation -= 1;
}
/// Find the next (least) node in the Tout set.
pub fn next_out_index(&self, from_index: usize) -> Option<usize> {
self.out[from_index..]
.iter()
.enumerate()
.find(move |&(index, &elt)| {
elt > 0 && self.mapping[from_index + index] == std::usize::MAX
})
.map(|(index, _)| index)
}
/// Find the next (least) node in the Tin set.
pub fn next_in_index(&self, from_index: usize) -> Option<usize> {
if !self.graph.is_directed() {
return None;
}
self.ins[from_index..]
.iter()
.enumerate()
.find(move |&(index, &elt)| {
elt > 0 && self.mapping[from_index + index] == std::usize::MAX
})
.map(|(index, _)| index)
}
/// Find the next (least) node in the N - M set.
pub fn next_rest_index(&self, from_index: usize) -> Option<usize> {
self.mapping[from_index..]
.iter()
.enumerate()
.find(|&(_, &elt)| elt == std::usize::MAX)
.map(|(index, _)| index)
}
}
}
mod semantic {
use super::*;
pub struct NoSemanticMatch;
pub trait NodeMatcher<G0: GraphBase, G1: GraphBase> {
fn enabled() -> bool;
fn eq(&mut self, _g0: &G0, _g1: &G1, _n0: G0::NodeId, _n1: G1::NodeId) -> bool;
}
impl<G0: GraphBase, G1: GraphBase> NodeMatcher<G0, G1> for NoSemanticMatch {
#[inline]
fn enabled() -> bool {
false
}
#[inline]
fn eq(&mut self, _g0: &G0, _g1: &G1, _n0: G0::NodeId, _n1: G1::NodeId) -> bool {
true
}
}
impl<G0, G1, F> NodeMatcher<G0, G1> for F
where
G0: GraphBase + DataMap,
G1: GraphBase + DataMap,
F: FnMut(&G0::NodeWeight, &G1::NodeWeight) -> bool,
{
#[inline]
fn enabled() -> bool {
true
}
#[inline]
fn eq(&mut self, g0: &G0, g1: &G1, n0: G0::NodeId, n1: G1::NodeId) -> bool {
if let (Some(x), Some(y)) = (g0.node_weight(n0), g1.node_weight(n1)) {
self(x, y)
} else {
false
}
}
}
pub trait EdgeMatcher<G0: GraphBase, G1: GraphBase> {
fn enabled() -> bool;
fn eq(
&mut self,
_g0: &G0,
_g1: &G1,
e0: (G0::NodeId, G0::NodeId),
e1: (G1::NodeId, G1::NodeId),
) -> bool;
}
impl<G0: GraphBase, G1: GraphBase> EdgeMatcher<G0, G1> for NoSemanticMatch {
#[inline]
fn enabled() -> bool {
false
}
#[inline]
fn eq(
&mut self,
_g0: &G0,
_g1: &G1,
_e0: (G0::NodeId, G0::NodeId),
_e1: (G1::NodeId, G1::NodeId),
) -> bool {
true
}
}
impl<G0, G1, F> EdgeMatcher<G0, G1> for F
where
G0: GraphBase + DataMap + IntoEdgesDirected,
G1: GraphBase + DataMap + IntoEdgesDirected,
F: FnMut(&G0::EdgeWeight, &G1::EdgeWeight) -> bool,
{
#[inline]
fn enabled() -> bool {
true
}
#[inline]
fn eq(
&mut self,
g0: &G0,
g1: &G1,
e0: (G0::NodeId, G0::NodeId),
e1: (G1::NodeId, G1::NodeId),
) -> bool {
let w0 = g0
.edges_directed(e0.0, Outgoing)
.find(|edge| edge.target() == e0.1)
.and_then(|edge| g0.edge_weight(edge.id()));
let w1 = g1
.edges_directed(e1.0, Outgoing)
.find(|edge| edge.target() == e1.1)
.and_then(|edge| g1.edge_weight(edge.id()));
if let (Some(x), Some(y)) = (w0, w1) {
self(x, y)
} else {
false
}
}
}
}
mod matching {
use super::*;
#[derive(Copy, Clone, PartialEq, Debug)]
enum OpenList {
Out,
In,
Other,
}
#[derive(Clone, PartialEq, Debug)]
enum Frame<G0, G1>
where
G0: GraphBase,
G1: GraphBase,
{
Outer,
Inner {
nodes: (G0::NodeId, G1::NodeId),
open_list: OpenList,
},
Unwind {
nodes: (G0::NodeId, G1::NodeId),
open_list: OpenList,
},
}
fn is_feasible<G0, G1, NM, EM>(
st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
nodes: (G0::NodeId, G1::NodeId),
node_match: &mut NM,
edge_match: &mut EM,
) -> bool
where
G0: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
G1: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
NM: NodeMatcher<G0, G1>,
EM: EdgeMatcher<G0, G1>,
{
macro_rules! field {
($x:ident, 0) => {
$x.0
};
($x:ident, 1) => {
$x.1
};
($x:ident, 1 - 0) => {
$x.1
};
($x:ident, 1 - 1) => {
$x.0
};
}
macro_rules! r_succ {
($j:tt) => {{
let mut succ_count = 0;
for n_neigh in field!(st, $j)
.graph
.neighbors_directed(field!(nodes, $j), Outgoing)
{
succ_count += 1;
// handle the self loop case; it's not in the mapping (yet)
let m_neigh = if field!(nodes, $j) != n_neigh {
field!(st, $j).mapping[field!(st, $j).graph.to_index(n_neigh)]
} else {
field!(st, 1 - $j).graph.to_index(field!(nodes, 1 - $j))
};
if m_neigh == std::usize::MAX {
continue;
}
let has_edge = field!(st, 1 - $j).graph.is_adjacent(
&field!(st, 1 - $j).adjacency_matrix,
field!(nodes, 1 - $j),
field!(st, 1 - $j).graph.from_index(m_neigh),
);
if !has_edge {
return false;
}
}
succ_count
}};
}
macro_rules! r_pred {
($j:tt) => {{
let mut pred_count = 0;
for n_neigh in field!(st, $j)
.graph
.neighbors_directed(field!(nodes, $j), Incoming)
{
pred_count += 1;
// the self loop case is handled in outgoing
let m_neigh = field!(st, $j).mapping[field!(st, $j).graph.to_index(n_neigh)];
if m_neigh == std::usize::MAX {
continue;
}
let has_edge = field!(st, 1 - $j).graph.is_adjacent(
&field!(st, 1 - $j).adjacency_matrix,
field!(st, 1 - $j).graph.from_index(m_neigh),
field!(nodes, 1 - $j),
);
if !has_edge {
return false;
}
}
pred_count
}};
}
// Check syntactic feasibility of mapping by ensuring adjacencies
// of nx map to adjacencies of mx.
//
// nx == map to => mx
//
// R_succ
//
// Check that every neighbor of nx is mapped to a neighbor of mx,
// then check the reverse, from mx to nx. Check that they have the same
// count of edges.
//
// Note: We want to check the lookahead measures here if we can,
// R_out: Equal for G0, G1: Card(Succ(G, n) ^ Tout); for both Succ and Pred
// R_in: Same with Tin
// R_new: Equal for G0, G1: Ñ n Pred(G, n); both Succ and Pred,
// Ñ is G0 - M - Tin - Tout
// last attempt to add these did not speed up any of the testcases
if r_succ!(0) > r_succ!(1) {
return false;
}
// R_pred
if st.0.graph.is_directed() && r_pred!(0) > r_pred!(1) {
return false;
}
// // semantic feasibility: compare associated data for nodes
if NM::enabled() && !node_match.eq(st.0.graph, st.1.graph, nodes.0, nodes.1) {
return false;
}
// semantic feasibility: compare associated data for edges
if EM::enabled() {
macro_rules! edge_feasibility {
($j:tt) => {{
for n_neigh in field!(st, $j)
.graph
.neighbors_directed(field!(nodes, $j), Outgoing)
{
let m_neigh = if field!(nodes, $j) != n_neigh {
field!(st, $j).mapping[field!(st, $j).graph.to_index(n_neigh)]
} else {
field!(st, 1 - $j).graph.to_index(field!(nodes, 1 - $j))
};
if m_neigh == std::usize::MAX {
continue;
}
let e0 = (field!(nodes, $j), n_neigh);
let e1 = (
field!(nodes, 1 - $j),
field!(st, 1 - $j).graph.from_index(m_neigh),
);
let edges = (e0, e1);
if !edge_match.eq(
st.0.graph,
st.1.graph,
field!(edges, $j),
field!(edges, 1 - $j),
) {
return false;
}
}
if field!(st, $j).graph.is_directed() {
for n_neigh in field!(st, $j)
.graph
.neighbors_directed(field!(nodes, $j), Incoming)
{
// the self loop case is handled in outgoing
let m_neigh =
field!(st, $j).mapping[field!(st, $j).graph.to_index(n_neigh)];
if m_neigh == std::usize::MAX {
continue;
}
let e0 = (n_neigh, field!(nodes, $j));
let e1 = (
field!(st, 1 - $j).graph.from_index(m_neigh),
field!(nodes, 1 - $j),
);
let edges = (e0, e1);
if !edge_match.eq(
st.0.graph,
st.1.graph,
field!(edges, $j),
field!(edges, 1 - $j),
) {
return false;
}
}
}
}};
}
edge_feasibility!(0);
edge_feasibility!(1);
}
true
}
fn next_candidate<G0, G1>(
st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
) -> Option<(G0::NodeId, G1::NodeId, OpenList)>
where
G0: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
G1: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
{
let mut from_index = None;
let mut open_list = OpenList::Out;
let mut to_index = st.1.next_out_index(0);
// Try the out list
if to_index.is_some() {
from_index = st.0.next_out_index(0);
open_list = OpenList::Out;
}
// Try the in list
if to_index.is_none() || from_index.is_none() {
to_index = st.1.next_in_index(0);
if to_index.is_some() {
from_index = st.0.next_in_index(0);
open_list = OpenList::In;
}
}
// Try the other list -- disconnected graph
if to_index.is_none() || from_index.is_none() {
to_index = st.1.next_rest_index(0);
if to_index.is_some() {
from_index = st.0.next_rest_index(0);
open_list = OpenList::Other;
}
}
match (from_index, to_index) {
(Some(n), Some(m)) => Some((
st.0.graph.from_index(n),
st.1.graph.from_index(m),
open_list,
)),
// No more candidates
_ => None,
}
}
fn next_from_ix<G0, G1>(
st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
nx: G1::NodeId,
open_list: OpenList,
) -> Option<G1::NodeId>
where
G0: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
G1: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
{
// Find the next node index to try on the `to` side of the mapping
let start = st.1.graph.to_index(nx) + 1;
let cand1 = match open_list {
OpenList::Out => st.1.next_out_index(start),
OpenList::In => st.1.next_in_index(start),
OpenList::Other => st.1.next_rest_index(start),
}
.map(|c| c + start); // compensate for start offset.
match cand1 {
None => None, // no more candidates
Some(ix) => {
debug_assert!(ix >= start);
Some(st.1.graph.from_index(ix))
}
}
}
fn pop_state<G0, G1>(
st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
nodes: (G0::NodeId, G1::NodeId),
) where
G0: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
G1: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
{
st.0.pop_mapping(nodes.0);
st.1.pop_mapping(nodes.1);
}
fn push_state<G0, G1>(
st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
nodes: (G0::NodeId, G1::NodeId),
) where
G0: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
G1: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
{
st.0.push_mapping(nodes.0, st.1.graph.to_index(nodes.1));
st.1.push_mapping(nodes.1, st.0.graph.to_index(nodes.0));
}
/// Return Some(bool) if isomorphism is decided, else None.
pub fn try_match<G0, G1, NM, EM>(
st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
node_match: &mut NM,
edge_match: &mut EM,
match_subgraph: bool,
) -> Option<bool>
where
G0: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
NM: NodeMatcher<G0, G1>,
EM: EdgeMatcher<G0, G1>,
{
let mut stack = vec![Frame::Outer];
if isomorphisms(st, node_match, edge_match, match_subgraph, &mut stack).is_some() {
Some(true)
} else {
None
}
}
fn isomorphisms<G0, G1, NM, EM>(
st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
node_match: &mut NM,
edge_match: &mut EM,
match_subgraph: bool,
stack: &mut Vec<Frame<G0, G1>>,
) -> Option<Vec<usize>>
where
G0: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
NM: NodeMatcher<G0, G1>,
EM: EdgeMatcher<G0, G1>,
{
if st.0.is_complete() {
return Some(st.0.mapping.clone());
}
// A "depth first" search of a valid mapping from graph 1 to graph 2
// F(s, n, m) -- evaluate state s and add mapping n <-> m
// Find least T1out node (in st.out[1] but not in M[1])
let mut result = None;
while let Some(frame) = stack.pop() {
match frame {
Frame::Unwind { nodes, open_list } => {
pop_state(st, nodes);
match next_from_ix(st, nodes.1, open_list) {
None => continue,
Some(nx) => {
let f = Frame::Inner {
nodes: (nodes.0, nx),
open_list,
};
stack.push(f);
}
}
}
Frame::Outer => match next_candidate(st) {
None => continue,
Some((nx, mx, open_list)) => {
let f = Frame::Inner {
nodes: (nx, mx),
open_list,
};
stack.push(f);
}
},
Frame::Inner { nodes, open_list } => {
if is_feasible(st, nodes, node_match, edge_match) {
push_state(st, nodes);
if st.0.is_complete() {
result = Some(st.0.mapping.clone());
}
// Check cardinalities of Tin, Tout sets
if (!match_subgraph
&& st.0.out_size == st.1.out_size
&& st.0.ins_size == st.1.ins_size)
|| (match_subgraph
&& st.0.out_size <= st.1.out_size
&& st.0.ins_size <= st.1.ins_size)
{
let f0 = Frame::Unwind { nodes, open_list };
stack.push(f0);
stack.push(Frame::Outer);
continue;
}
pop_state(st, nodes);
}
match next_from_ix(st, nodes.1, open_list) {
None => continue,
Some(nx) => {
let f = Frame::Inner {
nodes: (nodes.0, nx),
open_list,
};
stack.push(f);
}
}
}
}
if result.is_some() {
return result;
}
}
result
}
pub struct GraphMatcher<'a, 'b, 'c, G0, G1, NM, EM>
where
G0: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
NM: NodeMatcher<G0, G1>,
EM: EdgeMatcher<G0, G1>,
{
st: (Vf2State<'a, G0>, Vf2State<'b, G1>),
node_match: &'c mut NM,
edge_match: &'c mut EM,
match_subgraph: bool,
stack: Vec<Frame<G0, G1>>,
}
impl<'a, 'b, 'c, G0, G1, NM, EM> GraphMatcher<'a, 'b, 'c, G0, G1, NM, EM>
where
G0: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
NM: NodeMatcher<G0, G1>,
EM: EdgeMatcher<G0, G1>,
{
pub fn new(
g0: &'a G0,
g1: &'b G1,
node_match: &'c mut NM,
edge_match: &'c mut EM,
match_subgraph: bool,
) -> Self {
let stack = vec![Frame::Outer];
Self {
st: (Vf2State::new(g0), Vf2State::new(g1)),
node_match,
edge_match,
match_subgraph,
stack,
}
}
}
impl<G0, G1, NM, EM> Iterator for GraphMatcher<'_, '_, '_, G0, G1, NM, EM>
where
G0: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp
+ IntoNeighborsDirected,
NM: NodeMatcher<G0, G1>,
EM: EdgeMatcher<G0, G1>,
{
type Item = Vec<usize>;
fn next(&mut self) -> Option<Self::Item> {
isomorphisms(
&mut self.st,
self.node_match,
self.edge_match,
self.match_subgraph,
&mut self.stack,
)
}
fn size_hint(&self) -> (usize, Option<usize>) {
// To calculate the upper bound of results we use n! where n is the
// number of nodes in graph 1. n! values fit into a 64-bit usize up
// to n = 20, so we don't estimate an upper limit for n > 20.
let n = self.st.0.graph.node_count();
// We hardcode n! values into an array that accounts for architectures
// with smaller usizes to get our upper bound.
let upper_bounds: Vec<Option<usize>> = [
1u64,
1,
2,
6,
24,
120,
720,
5040,
40320,
362880,
3628800,
39916800,
479001600,
6227020800,
87178291200,
1307674368000,
20922789888000,
355687428096000,
6402373705728000,
121645100408832000,
2432902008176640000,
]
.iter()
.map(|n| usize::try_from(*n).ok())
.collect();
if n > upper_bounds.len() {
return (0, None);
}
(0, upper_bounds[n])
}
}
}
/// \[Generic\] Return `true` if the graphs `g0` and `g1` are isomorphic.
///
/// Using the VF2 algorithm, only matching graph syntactically (graph
/// structure).
///
/// The graphs should not be multigraphs.
///
/// **Reference**
///
/// * Luigi P. Cordella, Pasquale Foggia, Carlo Sansone, Mario Vento;
/// *A (Sub)Graph Isomorphism Algorithm for Matching Large Graphs*
pub fn is_isomorphic<G0, G1>(g0: G0, g1: G1) -> bool
where
G0: NodeCompactIndexable + EdgeCount + GetAdjacencyMatrix + GraphProp + IntoNeighborsDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp<EdgeType = G0::EdgeType>
+ IntoNeighborsDirected,
{
if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
return false;
}
let mut st = (Vf2State::new(&g0), Vf2State::new(&g1));
self::matching::try_match(&mut st, &mut NoSemanticMatch, &mut NoSemanticMatch, false)
.unwrap_or(false)
}
/// \[Generic\] Return `true` if the graphs `g0` and `g1` are isomorphic.
///
/// Using the VF2 algorithm, examining both syntactic and semantic
/// graph isomorphism (graph structure and matching node and edge weights).
///
/// The graphs should not be multigraphs.
pub fn is_isomorphic_matching<G0, G1, NM, EM>(
g0: G0,
g1: G1,
mut node_match: NM,
mut edge_match: EM,
) -> bool
where
G0: NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp
+ IntoEdgesDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp<EdgeType = G0::EdgeType>
+ IntoEdgesDirected,
NM: FnMut(&G0::NodeWeight, &G1::NodeWeight) -> bool,
EM: FnMut(&G0::EdgeWeight, &G1::EdgeWeight) -> bool,
{
if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
return false;
}
let mut st = (Vf2State::new(&g0), Vf2State::new(&g1));
self::matching::try_match(&mut st, &mut node_match, &mut edge_match, false).unwrap_or(false)
}
/// \[Generic\] Return `true` if `g0` is isomorphic to a subgraph of `g1`.
///
/// Using the VF2 algorithm, only matching graph syntactically (graph
/// structure).
///
/// The graphs should not be multigraphs.
///
/// # Subgraph isomorphism
///
/// (adapted from [`networkx` documentation](https://networkx.github.io/documentation/stable/reference/algorithms/isomorphism.vf2.html))
///
/// Graph theory literature can be ambiguous about the meaning of the above statement,
/// and we seek to clarify it now.
///
/// In the VF2 literature, a mapping **M** is said to be a *graph-subgraph isomorphism*
/// iff **M** is an isomorphism between **G2** and a subgraph of **G1**. Thus, to say
/// that **G1** and **G2** are graph-subgraph isomorphic is to say that a subgraph of
/// **G1** is isomorphic to **G2**.
///
/// Other literature uses the phrase subgraph isomorphic as in
/// **G1** does not have a subgraph isomorphic to **G2**. Another use is as an in adverb
/// for isomorphic. Thus, to say that **G1** and **G2** are subgraph isomorphic is to say
/// that a subgraph of **G1** is isomorphic to **G2**.
///
/// Finally, the term subgraph can have multiple meanings. In this context,
/// subgraph always means a node-induced subgraph. Edge-induced subgraph
/// isomorphisms are not directly supported. For subgraphs which are not
/// induced, the term monomorphism is preferred over isomorphism.
///
/// **Reference**
///
/// * Luigi P. Cordella, Pasquale Foggia, Carlo Sansone, Mario Vento;
/// *A (Sub)Graph Isomorphism Algorithm for Matching Large Graphs*
pub fn is_isomorphic_subgraph<G0, G1>(g0: G0, g1: G1) -> bool
where
G0: NodeCompactIndexable + EdgeCount + GetAdjacencyMatrix + GraphProp + IntoNeighborsDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ GetAdjacencyMatrix
+ GraphProp<EdgeType = G0::EdgeType>
+ IntoNeighborsDirected,
{
if g0.node_count() > g1.node_count() || g0.edge_count() > g1.edge_count() {
return false;
}
let mut st = (Vf2State::new(&g0), Vf2State::new(&g1));
self::matching::try_match(&mut st, &mut NoSemanticMatch, &mut NoSemanticMatch, true)
.unwrap_or(false)
}
/// \[Generic\] Return `true` if `g0` is isomorphic to a subgraph of `g1`.
///
/// Using the VF2 algorithm, examining both syntactic and semantic
/// graph isomorphism (graph structure and matching node and edge weights).
///
/// The graphs should not be multigraphs.
pub fn is_isomorphic_subgraph_matching<G0, G1, NM, EM>(
g0: G0,
g1: G1,
mut node_match: NM,
mut edge_match: EM,
) -> bool
where
G0: NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp
+ IntoEdgesDirected,
G1: NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp<EdgeType = G0::EdgeType>
+ IntoEdgesDirected,
NM: FnMut(&G0::NodeWeight, &G1::NodeWeight) -> bool,
EM: FnMut(&G0::EdgeWeight, &G1::EdgeWeight) -> bool,
{
if g0.node_count() > g1.node_count() || g0.edge_count() > g1.edge_count() {
return false;
}
let mut st = (Vf2State::new(&g0), Vf2State::new(&g1));
self::matching::try_match(&mut st, &mut node_match, &mut edge_match, true).unwrap_or(false)
}
/// Using the VF2 algorithm, examine both syntactic and semantic graph
/// isomorphism (graph structure and matching node and edge weights) and,
/// if `g0` is isomorphic to a subgraph of `g1`, return the mappings between
/// them.
///
/// The graphs should not be multigraphs.
pub fn subgraph_isomorphisms_iter<'a, G0, G1, NM, EM>(
g0: &'a G0,
g1: &'a G1,
node_match: &'a mut NM,
edge_match: &'a mut EM,
) -> Option<impl Iterator<Item = Vec<usize>> + 'a>
where
G0: 'a
+ NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp
+ IntoEdgesDirected,
G1: 'a
+ NodeCompactIndexable
+ EdgeCount
+ DataMap
+ GetAdjacencyMatrix
+ GraphProp<EdgeType = G0::EdgeType>
+ IntoEdgesDirected,
NM: 'a + FnMut(&G0::NodeWeight, &G1::NodeWeight) -> bool,
EM: 'a + FnMut(&G0::EdgeWeight, &G1::EdgeWeight) -> bool,
{
if g0.node_count() > g1.node_count() || g0.edge_count() > g1.edge_count() {
return None;
}
Some(self::matching::GraphMatcher::new(
g0, g1, node_match, edge_match, true,
))
}

View File

@@ -0,0 +1,115 @@
use std::collections::{BinaryHeap, HashMap};
use std::hash::Hash;
use crate::algo::Measure;
use crate::scored::MinScored;
use crate::visit::{EdgeRef, IntoEdges, NodeCount, NodeIndexable, Visitable};
/// \[Generic\] k'th shortest path algorithm.
///
/// Compute the length of the k'th shortest path from `start` to every reachable
/// node.
///
/// The graph should be `Visitable` and implement `IntoEdges`. The function
/// `edge_cost` should return the cost for a particular edge, which is used
/// to compute path costs. Edge costs must be non-negative.
///
/// If `goal` is not `None`, then the algorithm terminates once the `goal` node's
/// cost is calculated.
///
/// Computes in **O(k * (|E| + |V|*log(|V|)))** time (average).
///
/// Returns a `HashMap` that maps `NodeId` to path cost.
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::algo::k_shortest_path;
/// use petgraph::prelude::*;
/// use std::collections::HashMap;
///
/// let mut graph : Graph<(),(),Directed>= Graph::new();
/// let a = graph.add_node(()); // node with no weight
/// let b = graph.add_node(());
/// let c = graph.add_node(());
/// let d = graph.add_node(());
/// let e = graph.add_node(());
/// let f = graph.add_node(());
/// let g = graph.add_node(());
/// let h = graph.add_node(());
/// // z will be in another connected component
/// let z = graph.add_node(());
///
/// graph.extend_with_edges(&[
/// (a, b),
/// (b, c),
/// (c, d),
/// (d, a),
/// (e, f),
/// (b, e),
/// (f, g),
/// (g, h),
/// (h, e)
/// ]);
/// // a ----> b ----> e ----> f
/// // ^ | ^ |
/// // | v | v
/// // d <---- c h <---- g
///
/// let expected_res: HashMap<NodeIndex, usize> = [
/// (a, 7),
/// (b, 4),
/// (c, 5),
/// (d, 6),
/// (e, 5),
/// (f, 6),
/// (g, 7),
/// (h, 8)
/// ].iter().cloned().collect();
/// let res = k_shortest_path(&graph,b,None,2, |_| 1);
/// assert_eq!(res, expected_res);
/// // z is not inside res because there is not path from b to z.
/// ```
pub fn k_shortest_path<G, F, K>(
graph: G,
start: G::NodeId,
goal: Option<G::NodeId>,
k: usize,
mut edge_cost: F,
) -> HashMap<G::NodeId, K>
where
G: IntoEdges + Visitable + NodeCount + NodeIndexable,
G::NodeId: Eq + Hash,
F: FnMut(G::EdgeRef) -> K,
K: Measure + Copy,
{
let mut counter: Vec<usize> = vec![0; graph.node_count()];
let mut scores = HashMap::new();
let mut visit_next = BinaryHeap::new();
let zero_score = K::default();
visit_next.push(MinScored(zero_score, start));
while let Some(MinScored(node_score, node)) = visit_next.pop() {
counter[graph.to_index(node)] += 1;
let current_counter = counter[graph.to_index(node)];
if current_counter > k {
continue;
}
if current_counter == k {
scores.insert(node, node_score);
}
//Already reached goal k times
if goal.as_ref() == Some(&node) && current_counter == k {
break;
}
for edge in graph.edges(node) {
visit_next.push(MinScored(node_score + edge_cost(edge), edge.target()));
}
}
scores
}

606
vendor/petgraph/src/algo/matching.rs vendored Normal file
View File

@@ -0,0 +1,606 @@
use std::collections::VecDeque;
use std::hash::Hash;
use crate::visit::{
EdgeRef, GraphBase, IntoEdges, IntoNeighbors, IntoNodeIdentifiers, NodeCount, NodeIndexable,
VisitMap, Visitable,
};
/// Computed
/// [*matching*](https://en.wikipedia.org/wiki/Matching_(graph_theory)#Definitions)
/// of the graph.
pub struct Matching<G: GraphBase> {
graph: G,
mate: Vec<Option<G::NodeId>>,
n_edges: usize,
}
impl<G> Matching<G>
where
G: GraphBase,
{
fn new(graph: G, mate: Vec<Option<G::NodeId>>, n_edges: usize) -> Self {
Self {
graph,
mate,
n_edges,
}
}
}
impl<G> Matching<G>
where
G: NodeIndexable,
{
/// Gets the matched counterpart of given node, if there is any.
///
/// Returns `None` if the node is not matched or does not exist.
pub fn mate(&self, node: G::NodeId) -> Option<G::NodeId> {
self.mate.get(self.graph.to_index(node)).and_then(|&id| id)
}
/// Iterates over all edges from the matching.
///
/// An edge is represented by its endpoints. The graph is considered
/// undirected and every pair of matched nodes is reported only once.
pub fn edges(&self) -> MatchedEdges<'_, G> {
MatchedEdges {
graph: &self.graph,
mate: self.mate.as_slice(),
current: 0,
}
}
/// Iterates over all nodes from the matching.
pub fn nodes(&self) -> MatchedNodes<'_, G> {
MatchedNodes {
graph: &self.graph,
mate: self.mate.as_slice(),
current: 0,
}
}
/// Returns `true` if given edge is in the matching, or `false` otherwise.
///
/// If any of the nodes does not exist, `false` is returned.
pub fn contains_edge(&self, a: G::NodeId, b: G::NodeId) -> bool {
match self.mate(a) {
Some(mate) => mate == b,
None => false,
}
}
/// Returns `true` if given node is in the matching, or `false` otherwise.
///
/// If the node does not exist, `false` is returned.
pub fn contains_node(&self, node: G::NodeId) -> bool {
self.mate(node).is_some()
}
/// Gets the number of matched **edges**.
pub fn len(&self) -> usize {
self.n_edges
}
/// Returns `true` if the number of matched **edges** is 0.
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl<G> Matching<G>
where
G: NodeCount,
{
/// Returns `true` if the matching is perfect.
///
/// A matching is
/// [*perfect*](https://en.wikipedia.org/wiki/Matching_(graph_theory)#Definitions)
/// if every node in the graph is incident to an edge from the matching.
pub fn is_perfect(&self) -> bool {
let n_nodes = self.graph.node_count();
n_nodes % 2 == 0 && self.n_edges == n_nodes / 2
}
}
trait WithDummy: NodeIndexable {
fn dummy_idx(&self) -> usize;
/// Convert `i` to a node index, returns None for the dummy node
fn try_from_index(&self, i: usize) -> Option<Self::NodeId>;
}
impl<G: NodeIndexable> WithDummy for G {
fn dummy_idx(&self) -> usize {
// Gabow numbers the vertices from 1 to n, and uses 0 as the dummy
// vertex. Our vertex indices are zero-based and so we use the node
// bound as the dummy node.
self.node_bound()
}
fn try_from_index(&self, i: usize) -> Option<Self::NodeId> {
if i != self.dummy_idx() {
Some(self.from_index(i))
} else {
None
}
}
}
pub struct MatchedNodes<'a, G: GraphBase> {
graph: &'a G,
mate: &'a [Option<G::NodeId>],
current: usize,
}
impl<G> Iterator for MatchedNodes<'_, G>
where
G: NodeIndexable,
{
type Item = G::NodeId;
fn next(&mut self) -> Option<Self::Item> {
while self.current != self.mate.len() {
let current = self.current;
self.current += 1;
if self.mate[current].is_some() {
return Some(self.graph.from_index(current));
}
}
None
}
}
pub struct MatchedEdges<'a, G: GraphBase> {
graph: &'a G,
mate: &'a [Option<G::NodeId>],
current: usize,
}
impl<G> Iterator for MatchedEdges<'_, G>
where
G: NodeIndexable,
{
type Item = (G::NodeId, G::NodeId);
fn next(&mut self) -> Option<Self::Item> {
while self.current != self.mate.len() {
let current = self.current;
self.current += 1;
if let Some(mate) = self.mate[current] {
// Check if the mate is a node after the current one. If not, then
// do not report that edge since it has been already reported (the
// graph is considered undirected).
if self.graph.to_index(mate) > current {
let this = self.graph.from_index(current);
return Some((this, mate));
}
}
}
None
}
}
/// \[Generic\] Compute a
/// [*matching*](https://en.wikipedia.org/wiki/Matching_(graph_theory)) using a
/// greedy heuristic.
///
/// The input graph is treated as if undirected. The underlying heuristic is
/// unspecified, but is guaranteed to be bounded by *O(|V| + |E|)*. No
/// guarantees about the output are given other than that it is a valid
/// matching.
///
/// If you require a maximum matching, use [`maximum_matching`][1] function
/// instead.
///
/// [1]: fn.maximum_matching.html
pub fn greedy_matching<G>(graph: G) -> Matching<G>
where
G: Visitable + IntoNodeIdentifiers + NodeIndexable + IntoNeighbors,
G::NodeId: Eq + Hash,
G::EdgeId: Eq + Hash,
{
let (mates, n_edges) = greedy_matching_inner(&graph);
Matching::new(graph, mates, n_edges)
}
#[inline]
fn greedy_matching_inner<G>(graph: &G) -> (Vec<Option<G::NodeId>>, usize)
where
G: Visitable + IntoNodeIdentifiers + NodeIndexable + IntoNeighbors,
{
let mut mate = vec![None; graph.node_bound()];
let mut n_edges = 0;
let visited = &mut graph.visit_map();
for start in graph.node_identifiers() {
let mut last = Some(start);
// Function non_backtracking_dfs does not expand the node if it has been
// already visited.
non_backtracking_dfs(graph, start, visited, |next| {
// Alternate matched and unmatched edges.
if let Some(pred) = last.take() {
mate[graph.to_index(pred)] = Some(next);
mate[graph.to_index(next)] = Some(pred);
n_edges += 1;
} else {
last = Some(next);
}
});
}
(mate, n_edges)
}
fn non_backtracking_dfs<G, F>(graph: &G, source: G::NodeId, visited: &mut G::Map, mut visitor: F)
where
G: Visitable + IntoNeighbors,
F: FnMut(G::NodeId),
{
if visited.visit(source) {
for target in graph.neighbors(source) {
if !visited.is_visited(&target) {
visitor(target);
non_backtracking_dfs(graph, target, visited, visitor);
// Non-backtracking traversal, stop iterating over the
// neighbors.
break;
}
}
}
}
#[derive(Clone, Copy)]
enum Label<G: GraphBase> {
None,
Start,
// If node v is outer node, then label(v) = w is another outer node on path
// from v to start u.
Vertex(G::NodeId),
// If node v is outer node, then label(v) = (r, s) are two outer vertices
// (connected by an edge)
Edge(G::EdgeId, [G::NodeId; 2]),
// Flag is a special label used in searching for the join vertex of two
// paths.
Flag(G::EdgeId),
}
impl<G: GraphBase> Label<G> {
fn is_outer(&self) -> bool {
self != &Label::None
&& !match self {
Label::Flag(_) => true,
_ => false,
}
}
fn is_inner(&self) -> bool {
!self.is_outer()
}
fn to_vertex(&self) -> Option<G::NodeId> {
match *self {
Label::Vertex(v) => Some(v),
_ => None,
}
}
fn is_flagged(&self, edge: G::EdgeId) -> bool {
match self {
Label::Flag(flag) if flag == &edge => true,
_ => false,
}
}
}
impl<G: GraphBase> Default for Label<G> {
fn default() -> Self {
Label::None
}
}
impl<G: GraphBase> PartialEq for Label<G> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Label::None, Label::None) => true,
(Label::Start, Label::Start) => true,
(Label::Vertex(v1), Label::Vertex(v2)) => v1 == v2,
(Label::Edge(e1, _), Label::Edge(e2, _)) => e1 == e2,
(Label::Flag(e1), Label::Flag(e2)) => e1 == e2,
_ => false,
}
}
}
/// \[Generic\] Compute the [*maximum
/// matching*](https://en.wikipedia.org/wiki/Matching_(graph_theory)) using
/// [Gabow's algorithm][1].
///
/// [1]: https://dl.acm.org/doi/10.1145/321941.321942
///
/// The input graph is treated as if undirected. The algorithm runs in
/// *O(|V|³)*. An algorithm with a better time complexity might be used in the
/// future.
///
/// **Panics** if `g.node_bound()` is `std::usize::MAX`.
///
/// # Examples
///
/// ```
/// use petgraph::prelude::*;
/// use petgraph::algo::maximum_matching;
///
/// // The example graph:
/// //
/// // +-- b ---- d ---- f
/// // / | |
/// // a | |
/// // \ | |
/// // +-- c ---- e
/// //
/// // Maximum matching: { (a, b), (c, e), (d, f) }
///
/// let mut graph: UnGraph<(), ()> = UnGraph::new_undirected();
/// let a = graph.add_node(());
/// let b = graph.add_node(());
/// let c = graph.add_node(());
/// let d = graph.add_node(());
/// let e = graph.add_node(());
/// let f = graph.add_node(());
/// graph.extend_with_edges(&[(a, b), (a, c), (b, c), (b, d), (c, e), (d, e), (d, f)]);
///
/// let matching = maximum_matching(&graph);
/// assert!(matching.contains_edge(a, b));
/// assert!(matching.contains_edge(c, e));
/// assert_eq!(matching.mate(d), Some(f));
/// assert_eq!(matching.mate(f), Some(d));
/// ```
pub fn maximum_matching<G>(graph: G) -> Matching<G>
where
G: Visitable + NodeIndexable + IntoNodeIdentifiers + IntoEdges,
{
// The dummy identifier needs an unused index
assert_ne!(
graph.node_bound(),
std::usize::MAX,
"The input graph capacity should be strictly less than std::usize::MAX."
);
// Greedy algorithm should create a fairly good initial matching. The hope
// is that it speeds up the computation by doing les work in the complex
// algorithm.
let (mut mate, mut n_edges) = greedy_matching_inner(&graph);
// Gabow's algorithm uses a dummy node in the mate array.
mate.push(None);
let len = graph.node_bound() + 1;
debug_assert_eq!(mate.len(), len);
let mut label: Vec<Label<G>> = vec![Label::None; len];
let mut first_inner = vec![std::usize::MAX; len];
let visited = &mut graph.visit_map();
for start in 0..graph.node_bound() {
if mate[start].is_some() {
// The vertex is already matched. A start must be a free vertex.
continue;
}
// Begin search from the node.
label[start] = Label::Start;
first_inner[start] = graph.dummy_idx();
graph.reset_map(visited);
// start is never a dummy index
let start = graph.from_index(start);
// Queue will contain outer vertices that should be processed next. The
// start vertex is considered an outer vertex.
let mut queue = VecDeque::new();
queue.push_back(start);
// Mark the start vertex so it is not processed repeatedly.
visited.visit(start);
'search: while let Some(outer_vertex) = queue.pop_front() {
for edge in graph.edges(outer_vertex) {
if edge.source() == edge.target() {
// Ignore self-loops.
continue;
}
let other_vertex = edge.target();
let other_idx = graph.to_index(other_vertex);
if mate[other_idx].is_none() && other_vertex != start {
// An augmenting path was found. Augment the matching. If
// `other` is actually the start node, then the augmentation
// must not be performed, because the start vertex would be
// incident to two edges, which violates the matching
// property.
mate[other_idx] = Some(outer_vertex);
augment_path(&graph, outer_vertex, other_vertex, &mut mate, &label);
n_edges += 1;
// The path is augmented, so the start is no longer free
// vertex. We need to begin with a new start.
break 'search;
} else if label[other_idx].is_outer() {
// The `other` is an outer vertex (a label has been set to
// it). An odd cycle (blossom) was found. Assign this edge
// as a label to all inner vertices in paths P(outer) and
// P(other).
find_join(
&graph,
edge,
&mate,
&mut label,
&mut first_inner,
|labeled| {
if visited.visit(labeled) {
queue.push_back(labeled);
}
},
);
} else {
let mate_vertex = mate[other_idx];
let mate_idx = mate_vertex.map_or(graph.dummy_idx(), |id| graph.to_index(id));
if label[mate_idx].is_inner() {
// Mate of `other` vertex is inner (no label has been
// set to it so far). But it actually is an outer vertex
// (it is on a path to the start vertex that begins with
// a matched edge, since it is a mate of `other`).
// Assign the label of this mate to the `outer` vertex,
// so the path for it can be reconstructed using `mate`
// and this label.
label[mate_idx] = Label::Vertex(outer_vertex);
first_inner[mate_idx] = other_idx;
}
// Add the vertex to the queue only if it's not the dummy and this is its first
// discovery.
if let Some(mate_vertex) = mate_vertex {
if visited.visit(mate_vertex) {
queue.push_back(mate_vertex);
}
}
}
}
}
// Reset the labels. All vertices are inner for the next search.
for lbl in label.iter_mut() {
*lbl = Label::None;
}
}
// Discard the dummy node.
mate.pop();
Matching::new(graph, mate, n_edges)
}
fn find_join<G, F>(
graph: &G,
edge: G::EdgeRef,
mate: &[Option<G::NodeId>],
label: &mut [Label<G>],
first_inner: &mut [usize],
mut visitor: F,
) where
G: IntoEdges + NodeIndexable + Visitable,
F: FnMut(G::NodeId),
{
// Simultaneously traverse the inner vertices on paths P(source) and
// P(target) to find a join vertex - an inner vertex that is shared by these
// paths.
let source = graph.to_index(edge.source());
let target = graph.to_index(edge.target());
let mut left = first_inner[source];
let mut right = first_inner[target];
if left == right {
// No vertices can be labeled, since both paths already refer to a
// common vertex - the join.
return;
}
// Flag the (first) inner vertices. This ensures that they are assigned the
// join as their first inner vertex.
let flag = Label::Flag(edge.id());
label[left] = flag;
label[right] = flag;
// Find the join.
let join = loop {
// Swap the sides. Do not swap if the right side is already finished.
if right != graph.dummy_idx() {
std::mem::swap(&mut left, &mut right);
}
// Set left to the next inner vertex in P(source) or P(target).
// The unwraps are safe because left is not the dummy node.
let left_mate = graph.to_index(mate[left].unwrap());
let next_inner = label[left_mate].to_vertex().unwrap();
left = first_inner[graph.to_index(next_inner)];
if !label[left].is_flagged(edge.id()) {
// The inner vertex is not flagged yet, so flag it.
label[left] = flag;
} else {
// The inner vertex is already flagged. It means that the other side
// had to visit it already. Therefore it is the join vertex.
break left;
}
};
// Label all inner vertices on P(source) and P(target) with the found join.
for endpoint in [source, target].iter().copied() {
let mut inner = first_inner[endpoint];
while inner != join {
// Notify the caller about labeling a vertex.
if let Some(ix) = graph.try_from_index(inner) {
visitor(ix);
}
label[inner] = Label::Edge(edge.id(), [edge.source(), edge.target()]);
first_inner[inner] = join;
let inner_mate = graph.to_index(mate[inner].unwrap());
let next_inner = label[inner_mate].to_vertex().unwrap();
inner = first_inner[graph.to_index(next_inner)];
}
}
for (vertex_idx, vertex_label) in label.iter().enumerate() {
// To all outer vertices that are on paths P(source) and P(target) until
// the join, se the join as their first inner vertex.
if vertex_idx != graph.dummy_idx()
&& vertex_label.is_outer()
&& label[first_inner[vertex_idx]].is_outer()
{
first_inner[vertex_idx] = join;
}
}
}
fn augment_path<G>(
graph: &G,
outer: G::NodeId,
other: G::NodeId,
mate: &mut [Option<G::NodeId>],
label: &[Label<G>],
) where
G: NodeIndexable,
{
let outer_idx = graph.to_index(outer);
let temp = mate[outer_idx];
let temp_idx = temp.map_or(graph.dummy_idx(), |id| graph.to_index(id));
mate[outer_idx] = Some(other);
if mate[temp_idx] != Some(outer) {
// We are at the end of the path and so the entire path is completely
// rematched/augmented.
} else if let Label::Vertex(vertex) = label[outer_idx] {
// The outer vertex has a vertex label which refers to another outer
// vertex on the path. So we set this another outer node as the mate for
// the previous mate of the outer node.
mate[temp_idx] = Some(vertex);
if let Some(temp) = temp {
augment_path(graph, vertex, temp, mate, label);
}
} else if let Label::Edge(_, [source, target]) = label[outer_idx] {
// The outer vertex has an edge label which refers to an edge in a
// blossom. We need to augment both directions along the blossom.
augment_path(graph, source, target, mate, label);
augment_path(graph, target, source, mate, label);
} else {
panic!("Unexpected label when augmenting path");
}
}

View File

@@ -0,0 +1,117 @@
//! Minimum Spanning Tree algorithms.
use std::collections::{BinaryHeap, HashMap};
use crate::prelude::*;
use crate::data::Element;
use crate::scored::MinScored;
use crate::unionfind::UnionFind;
use crate::visit::{Data, IntoNodeReferences, NodeRef};
use crate::visit::{IntoEdgeReferences, NodeIndexable};
/// \[Generic\] Compute a *minimum spanning tree* of a graph.
///
/// The input graph is treated as if undirected.
///
/// Using Kruskal's algorithm with runtime **O(|E| log |E|)**. We actually
/// return a minimum spanning forest, i.e. a minimum spanning tree for each connected
/// component of the graph.
///
/// The resulting graph has all the vertices of the input graph (with identical node indices),
/// and **|V| - c** edges, where **c** is the number of connected components in `g`.
///
/// Use `from_elements` to create a graph from the resulting iterator.
pub fn min_spanning_tree<G>(g: G) -> MinSpanningTree<G>
where
G::NodeWeight: Clone,
G::EdgeWeight: Clone + PartialOrd,
G: IntoNodeReferences + IntoEdgeReferences + NodeIndexable,
{
// Initially each vertex is its own disjoint subgraph, track the connectedness
// of the pre-MST with a union & find datastructure.
let subgraphs = UnionFind::new(g.node_bound());
let edges = g.edge_references();
let mut sort_edges = BinaryHeap::with_capacity(edges.size_hint().0);
for edge in edges {
sort_edges.push(MinScored(
edge.weight().clone(),
(edge.source(), edge.target()),
));
}
MinSpanningTree {
graph: g,
node_ids: Some(g.node_references()),
subgraphs,
sort_edges,
node_map: HashMap::new(),
node_count: 0,
}
}
/// An iterator producing a minimum spanning forest of a graph.
#[derive(Debug, Clone)]
pub struct MinSpanningTree<G>
where
G: Data + IntoNodeReferences,
{
graph: G,
node_ids: Option<G::NodeReferences>,
subgraphs: UnionFind<usize>,
#[allow(clippy::type_complexity)]
sort_edges: BinaryHeap<MinScored<G::EdgeWeight, (G::NodeId, G::NodeId)>>,
node_map: HashMap<usize, usize>,
node_count: usize,
}
impl<G> Iterator for MinSpanningTree<G>
where
G: IntoNodeReferences + NodeIndexable,
G::NodeWeight: Clone,
G::EdgeWeight: PartialOrd,
{
type Item = Element<G::NodeWeight, G::EdgeWeight>;
fn next(&mut self) -> Option<Self::Item> {
let g = self.graph;
if let Some(ref mut iter) = self.node_ids {
if let Some(node) = iter.next() {
self.node_map.insert(g.to_index(node.id()), self.node_count);
self.node_count += 1;
return Some(Element::Node {
weight: node.weight().clone(),
});
}
}
self.node_ids = None;
// Kruskal's algorithm.
// Algorithm is this:
//
// 1. Create a pre-MST with all the vertices and no edges.
// 2. Repeat:
//
// a. Remove the shortest edge from the original graph.
// b. If the edge connects two disjoint trees in the pre-MST,
// add the edge.
while let Some(MinScored(score, (a, b))) = self.sort_edges.pop() {
// check if the edge would connect two disjoint parts
let (a_index, b_index) = (g.to_index(a), g.to_index(b));
if self.subgraphs.union(a_index, b_index) {
let (&a_order, &b_order) =
match (self.node_map.get(&a_index), self.node_map.get(&b_index)) {
(Some(a_id), Some(b_id)) => (a_id, b_id),
_ => panic!("Edge references unknown node"),
};
return Some(Element::Edge {
source: a_order,
target: b_order,
weight: score,
});
}
}
None
}
}

867
vendor/petgraph/src/algo/mod.rs vendored Normal file
View File

@@ -0,0 +1,867 @@
//! Graph algorithms.
//!
//! It is a goal to gradually migrate the algorithms to be based on graph traits
//! so that they are generally applicable. For now, some of these still require
//! the `Graph` type.
pub mod astar;
pub mod bellman_ford;
pub mod coloring;
pub mod dijkstra;
pub mod dominators;
pub mod feedback_arc_set;
pub mod floyd_warshall;
pub mod ford_fulkerson;
pub mod isomorphism;
pub mod k_shortest_path;
pub mod matching;
pub mod min_spanning_tree;
pub mod page_rank;
pub mod simple_paths;
pub mod tred;
use std::num::NonZeroUsize;
use crate::prelude::*;
use super::graph::IndexType;
use super::unionfind::UnionFind;
use super::visit::{
GraphBase, GraphRef, IntoEdgeReferences, IntoNeighbors, IntoNeighborsDirected,
IntoNodeIdentifiers, NodeCompactIndexable, NodeIndexable, Reversed, VisitMap, Visitable,
};
use super::EdgeType;
use crate::visit::Walker;
pub use astar::astar;
pub use bellman_ford::{bellman_ford, find_negative_cycle};
pub use coloring::dsatur_coloring;
pub use dijkstra::dijkstra;
pub use feedback_arc_set::greedy_feedback_arc_set;
pub use floyd_warshall::floyd_warshall;
pub use ford_fulkerson::ford_fulkerson;
pub use isomorphism::{
is_isomorphic, is_isomorphic_matching, is_isomorphic_subgraph, is_isomorphic_subgraph_matching,
subgraph_isomorphisms_iter,
};
pub use k_shortest_path::k_shortest_path;
pub use matching::{greedy_matching, maximum_matching, Matching};
pub use min_spanning_tree::min_spanning_tree;
pub use page_rank::page_rank;
pub use simple_paths::all_simple_paths;
/// \[Generic\] Return the number of connected components of the graph.
///
/// For a directed graph, this is the *weakly* connected components.
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::algo::connected_components;
/// use petgraph::prelude::*;
///
/// let mut graph : Graph<(),(),Directed>= Graph::new();
/// let a = graph.add_node(()); // node with no weight
/// let b = graph.add_node(());
/// let c = graph.add_node(());
/// let d = graph.add_node(());
/// let e = graph.add_node(());
/// let f = graph.add_node(());
/// let g = graph.add_node(());
/// let h = graph.add_node(());
///
/// graph.extend_with_edges(&[
/// (a, b),
/// (b, c),
/// (c, d),
/// (d, a),
/// (e, f),
/// (f, g),
/// (g, h),
/// (h, e)
/// ]);
/// // a ----> b e ----> f
/// // ^ | ^ |
/// // | v | v
/// // d <---- c h <---- g
///
/// assert_eq!(connected_components(&graph),2);
/// graph.add_edge(b,e,());
/// assert_eq!(connected_components(&graph),1);
/// ```
pub fn connected_components<G>(g: G) -> usize
where
G: NodeCompactIndexable + IntoEdgeReferences,
{
let mut vertex_sets = UnionFind::new(g.node_bound());
for edge in g.edge_references() {
let (a, b) = (edge.source(), edge.target());
// union the two vertices of the edge
vertex_sets.union(g.to_index(a), g.to_index(b));
}
let mut labels = vertex_sets.into_labeling();
labels.sort_unstable();
labels.dedup();
labels.len()
}
/// \[Generic\] Return `true` if the input graph contains a cycle.
///
/// Always treats the input graph as if undirected.
pub fn is_cyclic_undirected<G>(g: G) -> bool
where
G: NodeIndexable + IntoEdgeReferences,
{
let mut edge_sets = UnionFind::new(g.node_bound());
for edge in g.edge_references() {
let (a, b) = (edge.source(), edge.target());
// union the two vertices of the edge
// -- if they were already the same, then we have a cycle
if !edge_sets.union(g.to_index(a), g.to_index(b)) {
return true;
}
}
false
}
/// \[Generic\] Perform a topological sort of a directed graph.
///
/// If the graph was acyclic, return a vector of nodes in topological order:
/// each node is ordered before its successors.
/// Otherwise, it will return a `Cycle` error. Self loops are also cycles.
///
/// To handle graphs with cycles, use the scc algorithms or `DfsPostOrder`
/// instead of this function.
///
/// If `space` is not `None`, it is used instead of creating a new workspace for
/// graph traversal. The implementation is iterative.
pub fn toposort<G>(
g: G,
space: Option<&mut DfsSpace<G::NodeId, G::Map>>,
) -> Result<Vec<G::NodeId>, Cycle<G::NodeId>>
where
G: IntoNeighborsDirected + IntoNodeIdentifiers + Visitable,
{
// based on kosaraju scc
with_dfs(g, space, |dfs| {
dfs.reset(g);
let mut finished = g.visit_map();
let mut finish_stack = Vec::new();
for i in g.node_identifiers() {
if dfs.discovered.is_visited(&i) {
continue;
}
dfs.stack.push(i);
while let Some(&nx) = dfs.stack.last() {
if dfs.discovered.visit(nx) {
// First time visiting `nx`: Push neighbors, don't pop `nx`
for succ in g.neighbors(nx) {
if succ == nx {
// self cycle
return Err(Cycle(nx));
}
if !dfs.discovered.is_visited(&succ) {
dfs.stack.push(succ);
}
}
} else {
dfs.stack.pop();
if finished.visit(nx) {
// Second time: All reachable nodes must have been finished
finish_stack.push(nx);
}
}
}
}
finish_stack.reverse();
dfs.reset(g);
for &i in &finish_stack {
dfs.move_to(i);
let mut cycle = false;
while let Some(j) = dfs.next(Reversed(g)) {
if cycle {
return Err(Cycle(j));
}
cycle = true;
}
}
Ok(finish_stack)
})
}
/// \[Generic\] Return `true` if the input directed graph contains a cycle.
///
/// This implementation is recursive; use `toposort` if an alternative is
/// needed.
pub fn is_cyclic_directed<G>(g: G) -> bool
where
G: IntoNodeIdentifiers + IntoNeighbors + Visitable,
{
use crate::visit::{depth_first_search, DfsEvent};
depth_first_search(g, g.node_identifiers(), |event| match event {
DfsEvent::BackEdge(_, _) => Err(()),
_ => Ok(()),
})
.is_err()
}
type DfsSpaceType<G> = DfsSpace<<G as GraphBase>::NodeId, <G as Visitable>::Map>;
/// Workspace for a graph traversal.
#[derive(Clone, Debug)]
pub struct DfsSpace<N, VM> {
dfs: Dfs<N, VM>,
}
impl<N, VM> DfsSpace<N, VM>
where
N: Copy + PartialEq,
VM: VisitMap<N>,
{
pub fn new<G>(g: G) -> Self
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
DfsSpace { dfs: Dfs::empty(g) }
}
}
impl<N, VM> Default for DfsSpace<N, VM>
where
VM: VisitMap<N> + Default,
{
fn default() -> Self {
DfsSpace {
dfs: Dfs {
stack: <_>::default(),
discovered: <_>::default(),
},
}
}
}
/// Create a Dfs if it's needed
fn with_dfs<G, F, R>(g: G, space: Option<&mut DfsSpaceType<G>>, f: F) -> R
where
G: GraphRef + Visitable,
F: FnOnce(&mut Dfs<G::NodeId, G::Map>) -> R,
{
let mut local_visitor;
let dfs = if let Some(v) = space {
&mut v.dfs
} else {
local_visitor = Dfs::empty(g);
&mut local_visitor
};
f(dfs)
}
/// \[Generic\] Check if there exists a path starting at `from` and reaching `to`.
///
/// If `from` and `to` are equal, this function returns true.
///
/// If `space` is not `None`, it is used instead of creating a new workspace for
/// graph traversal.
pub fn has_path_connecting<G>(
g: G,
from: G::NodeId,
to: G::NodeId,
space: Option<&mut DfsSpace<G::NodeId, G::Map>>,
) -> bool
where
G: IntoNeighbors + Visitable,
{
with_dfs(g, space, |dfs| {
dfs.reset(g);
dfs.move_to(from);
dfs.iter(g).any(|x| x == to)
})
}
/// Renamed to `kosaraju_scc`.
#[deprecated(note = "renamed to kosaraju_scc")]
pub fn scc<G>(g: G) -> Vec<Vec<G::NodeId>>
where
G: IntoNeighborsDirected + Visitable + IntoNodeIdentifiers,
{
kosaraju_scc(g)
}
/// \[Generic\] Compute the *strongly connected components* using [Kosaraju's algorithm][1].
///
/// [1]: https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm
///
/// Return a vector where each element is a strongly connected component (scc).
/// The order of node ids within each scc is arbitrary, but the order of
/// the sccs is their postorder (reverse topological sort).
///
/// For an undirected graph, the sccs are simply the connected components.
///
/// This implementation is iterative and does two passes over the nodes.
pub fn kosaraju_scc<G>(g: G) -> Vec<Vec<G::NodeId>>
where
G: IntoNeighborsDirected + Visitable + IntoNodeIdentifiers,
{
let mut dfs = DfsPostOrder::empty(g);
// First phase, reverse dfs pass, compute finishing times.
// http://stackoverflow.com/a/26780899/161659
let mut finish_order = Vec::with_capacity(0);
for i in g.node_identifiers() {
if dfs.discovered.is_visited(&i) {
continue;
}
dfs.move_to(i);
while let Some(nx) = dfs.next(Reversed(g)) {
finish_order.push(nx);
}
}
let mut dfs = Dfs::from_parts(dfs.stack, dfs.discovered);
dfs.reset(g);
let mut sccs = Vec::new();
// Second phase
// Process in decreasing finishing time order
for i in finish_order.into_iter().rev() {
if dfs.discovered.is_visited(&i) {
continue;
}
// Move to the leader node `i`.
dfs.move_to(i);
let mut scc = Vec::new();
while let Some(nx) = dfs.next(g) {
scc.push(nx);
}
sccs.push(scc);
}
sccs
}
#[derive(Copy, Clone, Debug)]
struct NodeData {
rootindex: Option<NonZeroUsize>,
}
/// A reusable state for computing the *strongly connected components* using [Tarjan's algorithm][1].
///
/// [1]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
#[derive(Debug)]
pub struct TarjanScc<N> {
index: usize,
componentcount: usize,
nodes: Vec<NodeData>,
stack: Vec<N>,
}
impl<N> Default for TarjanScc<N> {
fn default() -> Self {
Self::new()
}
}
impl<N> TarjanScc<N> {
/// Creates a new `TarjanScc`
pub fn new() -> Self {
TarjanScc {
index: 1, // Invariant: index < componentcount at all times.
componentcount: std::usize::MAX, // Will hold if componentcount is initialized to number of nodes - 1 or higher.
nodes: Vec::new(),
stack: Vec::new(),
}
}
/// \[Generic\] Compute the *strongly connected components* using Algorithm 3 in
/// [A Space-Efficient Algorithm for Finding Strongly Connected Components][1] by David J. Pierce,
/// which is a memory-efficient variation of [Tarjan's algorithm][2].
///
///
/// [1]: https://homepages.ecs.vuw.ac.nz/~djp/files/P05.pdf
/// [2]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
///
/// Calls `f` for each strongly strongly connected component (scc).
/// The order of node ids within each scc is arbitrary, but the order of
/// the sccs is their postorder (reverse topological sort).
///
/// For an undirected graph, the sccs are simply the connected components.
///
/// This implementation is recursive and does one pass over the nodes.
pub fn run<G, F>(&mut self, g: G, mut f: F)
where
G: IntoNodeIdentifiers<NodeId = N> + IntoNeighbors<NodeId = N> + NodeIndexable<NodeId = N>,
F: FnMut(&[N]),
N: Copy + PartialEq,
{
self.nodes.clear();
self.nodes
.resize(g.node_bound(), NodeData { rootindex: None });
for n in g.node_identifiers() {
let visited = self.nodes[g.to_index(n)].rootindex.is_some();
if !visited {
self.visit(n, g, &mut f);
}
}
debug_assert!(self.stack.is_empty());
}
fn visit<G, F>(&mut self, v: G::NodeId, g: G, f: &mut F)
where
G: IntoNeighbors<NodeId = N> + NodeIndexable<NodeId = N>,
F: FnMut(&[N]),
N: Copy + PartialEq,
{
macro_rules! node {
($node:expr) => {
self.nodes[g.to_index($node)]
};
}
let node_v = &mut node![v];
debug_assert!(node_v.rootindex.is_none());
let mut v_is_local_root = true;
let v_index = self.index;
node_v.rootindex = NonZeroUsize::new(v_index);
self.index += 1;
for w in g.neighbors(v) {
if node![w].rootindex.is_none() {
self.visit(w, g, f);
}
if node![w].rootindex < node![v].rootindex {
node![v].rootindex = node![w].rootindex;
v_is_local_root = false
}
}
if v_is_local_root {
// Pop the stack and generate an SCC.
let mut indexadjustment = 1;
let c = NonZeroUsize::new(self.componentcount);
let nodes = &mut self.nodes;
let start = self
.stack
.iter()
.rposition(|&w| {
if nodes[g.to_index(v)].rootindex > nodes[g.to_index(w)].rootindex {
true
} else {
nodes[g.to_index(w)].rootindex = c;
indexadjustment += 1;
false
}
})
.map(|x| x + 1)
.unwrap_or_default();
nodes[g.to_index(v)].rootindex = c;
self.stack.push(v); // Pushing the component root to the back right before getting rid of it is somewhat ugly, but it lets it be included in f.
f(&self.stack[start..]);
self.stack.truncate(start);
self.index -= indexadjustment; // Backtrack index back to where it was before we ever encountered the component.
self.componentcount -= 1;
} else {
self.stack.push(v); // Stack is filled up when backtracking, unlike in Tarjans original algorithm.
}
}
/// Returns the index of the component in which v has been assigned. Allows for using self as a lookup table for an scc decomposition produced by self.run().
pub fn node_component_index<G>(&self, g: G, v: N) -> usize
where
G: IntoNeighbors<NodeId = N> + NodeIndexable<NodeId = N>,
N: Copy + PartialEq,
{
let rindex: usize = self.nodes[g.to_index(v)]
.rootindex
.map(NonZeroUsize::get)
.unwrap_or(0); // Compiles to no-op.
debug_assert!(
rindex != 0,
"Tried to get the component index of an unvisited node."
);
debug_assert!(
rindex > self.componentcount,
"Given node has been visited but not yet assigned to a component."
);
std::usize::MAX - rindex
}
}
/// \[Generic\] Compute the *strongly connected components* using [Tarjan's algorithm][1].
///
/// [1]: https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
/// [2]: https://homepages.ecs.vuw.ac.nz/~djp/files/P05.pdf
///
/// Return a vector where each element is a strongly connected component (scc).
/// The order of node ids within each scc is arbitrary, but the order of
/// the sccs is their postorder (reverse topological sort).
///
/// For an undirected graph, the sccs are simply the connected components.
///
/// This implementation is recursive and does one pass over the nodes. It is based on
/// [A Space-Efficient Algorithm for Finding Strongly Connected Components][2] by David J. Pierce,
/// to provide a memory-efficient implementation of [Tarjan's algorithm][1].
pub fn tarjan_scc<G>(g: G) -> Vec<Vec<G::NodeId>>
where
G: IntoNodeIdentifiers + IntoNeighbors + NodeIndexable,
{
let mut sccs = Vec::new();
{
let mut tarjan_scc = TarjanScc::new();
tarjan_scc.run(g, |scc| sccs.push(scc.to_vec()));
}
sccs
}
/// [Graph] Condense every strongly connected component into a single node and return the result.
///
/// If `make_acyclic` is true, self-loops and multi edges are ignored, guaranteeing that
/// the output is acyclic.
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::algo::condensation;
/// use petgraph::prelude::*;
///
/// let mut graph : Graph<(),(),Directed> = Graph::new();
/// let a = graph.add_node(()); // node with no weight
/// let b = graph.add_node(());
/// let c = graph.add_node(());
/// let d = graph.add_node(());
/// let e = graph.add_node(());
/// let f = graph.add_node(());
/// let g = graph.add_node(());
/// let h = graph.add_node(());
///
/// graph.extend_with_edges(&[
/// (a, b),
/// (b, c),
/// (c, d),
/// (d, a),
/// (b, e),
/// (e, f),
/// (f, g),
/// (g, h),
/// (h, e)
/// ]);
///
/// // a ----> b ----> e ----> f
/// // ^ | ^ |
/// // | v | v
/// // d <---- c h <---- g
///
/// let condensed_graph = condensation(graph,false);
/// let A = NodeIndex::new(0);
/// let B = NodeIndex::new(1);
/// assert_eq!(condensed_graph.node_count(), 2);
/// assert_eq!(condensed_graph.edge_count(), 9);
/// assert_eq!(condensed_graph.neighbors(A).collect::<Vec<_>>(), vec![A, A, A, A]);
/// assert_eq!(condensed_graph.neighbors(B).collect::<Vec<_>>(), vec![A, B, B, B, B]);
/// ```
/// If `make_acyclic` is true, self-loops and multi edges are ignored:
///
/// ```rust
/// # use petgraph::Graph;
/// # use petgraph::algo::condensation;
/// # use petgraph::prelude::*;
/// #
/// # let mut graph : Graph<(),(),Directed> = Graph::new();
/// # let a = graph.add_node(()); // node with no weight
/// # let b = graph.add_node(());
/// # let c = graph.add_node(());
/// # let d = graph.add_node(());
/// # let e = graph.add_node(());
/// # let f = graph.add_node(());
/// # let g = graph.add_node(());
/// # let h = graph.add_node(());
/// #
/// # graph.extend_with_edges(&[
/// # (a, b),
/// # (b, c),
/// # (c, d),
/// # (d, a),
/// # (b, e),
/// # (e, f),
/// # (f, g),
/// # (g, h),
/// # (h, e)
/// # ]);
/// let acyclic_condensed_graph = condensation(graph, true);
/// let A = NodeIndex::new(0);
/// let B = NodeIndex::new(1);
/// assert_eq!(acyclic_condensed_graph.node_count(), 2);
/// assert_eq!(acyclic_condensed_graph.edge_count(), 1);
/// assert_eq!(acyclic_condensed_graph.neighbors(B).collect::<Vec<_>>(), vec![A]);
/// ```
pub fn condensation<N, E, Ty, Ix>(
g: Graph<N, E, Ty, Ix>,
make_acyclic: bool,
) -> Graph<Vec<N>, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
let sccs = kosaraju_scc(&g);
let mut condensed: Graph<Vec<N>, E, Ty, Ix> = Graph::with_capacity(sccs.len(), g.edge_count());
// Build a map from old indices to new ones.
let mut node_map = vec![NodeIndex::end(); g.node_count()];
for comp in sccs {
let new_nix = condensed.add_node(Vec::new());
for nix in comp {
node_map[nix.index()] = new_nix;
}
}
// Consume nodes and edges of the old graph and insert them into the new one.
let (nodes, edges) = g.into_nodes_edges();
for (nix, node) in nodes.into_iter().enumerate() {
condensed[node_map[nix]].push(node.weight);
}
for edge in edges {
let source = node_map[edge.source().index()];
let target = node_map[edge.target().index()];
if make_acyclic {
if source != target {
condensed.update_edge(source, target, edge.weight);
}
} else {
condensed.add_edge(source, target, edge.weight);
}
}
condensed
}
/// An algorithm error: a cycle was found in the graph.
#[derive(Clone, Debug, PartialEq)]
pub struct Cycle<N>(pub(crate) N);
impl<N> Cycle<N> {
/// Return a node id that participates in the cycle
pub fn node_id(&self) -> N
where
N: Copy,
{
self.0
}
}
/// An algorithm error: a cycle of negative weights was found in the graph.
#[derive(Clone, Debug, PartialEq)]
pub struct NegativeCycle(pub ());
/// Return `true` if the graph is bipartite. A graph is bipartite if its nodes can be divided into
/// two disjoint and indepedent sets U and V such that every edge connects U to one in V. This
/// algorithm implements 2-coloring algorithm based on the BFS algorithm.
///
/// Always treats the input graph as if undirected.
pub fn is_bipartite_undirected<G, N, VM>(g: G, start: N) -> bool
where
G: GraphRef + Visitable<NodeId = N, Map = VM> + IntoNeighbors<NodeId = N>,
N: Copy + PartialEq + std::fmt::Debug,
VM: VisitMap<N>,
{
let mut red = g.visit_map();
red.visit(start);
let mut blue = g.visit_map();
let mut stack = ::std::collections::VecDeque::new();
stack.push_front(start);
while let Some(node) = stack.pop_front() {
let is_red = red.is_visited(&node);
let is_blue = blue.is_visited(&node);
assert!(is_red ^ is_blue);
for neighbour in g.neighbors(node) {
let is_neigbour_red = red.is_visited(&neighbour);
let is_neigbour_blue = blue.is_visited(&neighbour);
if (is_red && is_neigbour_red) || (is_blue && is_neigbour_blue) {
return false;
}
if !is_neigbour_red && !is_neigbour_blue {
//hasn't been visited yet
match (is_red, is_blue) {
(true, false) => {
blue.visit(neighbour);
}
(false, true) => {
red.visit(neighbour);
}
(_, _) => {
panic!("Invariant doesn't hold");
}
}
stack.push_back(neighbour);
}
}
}
true
}
use std::fmt::Debug;
use std::ops::Add;
/// Associated data that can be used for measures (such as length).
pub trait Measure: Debug + PartialOrd + Add<Self, Output = Self> + Default + Clone {}
impl<M> Measure for M where M: Debug + PartialOrd + Add<M, Output = M> + Default + Clone {}
/// A floating-point measure.
pub trait FloatMeasure: Measure + Copy {
fn zero() -> Self;
fn infinite() -> Self;
}
impl FloatMeasure for f32 {
fn zero() -> Self {
0.
}
fn infinite() -> Self {
1. / 0.
}
}
impl FloatMeasure for f64 {
fn zero() -> Self {
0.
}
fn infinite() -> Self {
1. / 0.
}
}
pub trait BoundedMeasure: Measure + std::ops::Sub<Self, Output = Self> {
fn min() -> Self;
fn max() -> Self;
fn overflowing_add(self, rhs: Self) -> (Self, bool);
}
macro_rules! impl_bounded_measure_integer(
( $( $t:ident ),* ) => {
$(
impl BoundedMeasure for $t {
fn min() -> Self {
std::$t::MIN
}
fn max() -> Self {
std::$t::MAX
}
fn overflowing_add(self, rhs: Self) -> (Self, bool) {
self.overflowing_add(rhs)
}
}
)*
};
);
impl_bounded_measure_integer!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
macro_rules! impl_bounded_measure_float(
( $( $t:ident ),* ) => {
$(
impl BoundedMeasure for $t {
fn min() -> Self {
std::$t::MIN
}
fn max() -> Self {
std::$t::MAX
}
fn overflowing_add(self, rhs: Self) -> (Self, bool) {
// for an overflow: a + b > max: both values need to be positive and a > max - b must be satisfied
let overflow = self > Self::default() && rhs > Self::default() && self > std::$t::MAX - rhs;
// for an underflow: a + b < min: overflow can not happen and both values must be negative and a < min - b must be satisfied
let underflow = !overflow && self < Self::default() && rhs < Self::default() && self < std::$t::MIN - rhs;
(self + rhs, overflow || underflow)
}
}
)*
};
);
impl_bounded_measure_float!(f32, f64);
/// A floating-point measure that can be computed from `usize`
/// and with a default measure of proximity.
pub trait UnitMeasure:
Measure
+ std::ops::Sub<Self, Output = Self>
+ std::ops::Mul<Self, Output = Self>
+ std::ops::Div<Self, Output = Self>
+ std::iter::Sum
{
fn zero() -> Self;
fn one() -> Self;
fn from_usize(nb: usize) -> Self;
fn default_tol() -> Self;
}
macro_rules! impl_unit_measure(
( $( $t:ident ),* )=> {
$(
impl UnitMeasure for $t {
fn zero() -> Self {
0 as $t
}
fn one() -> Self {
1 as $t
}
fn from_usize(nb: usize) -> Self {
nb as $t
}
fn default_tol() -> Self {
1e-6 as $t
}
}
)*
}
);
impl_unit_measure!(f32, f64);
/// Some measure of positive numbers, assuming positive
/// float-pointing numbers
pub trait PositiveMeasure: Measure + Copy {
fn zero() -> Self;
fn max() -> Self;
}
macro_rules! impl_positive_measure(
( $( $t:ident ),* )=> {
$(
impl PositiveMeasure for $t {
fn zero() -> Self {
0 as $t
}
fn max() -> Self {
std::$t::MAX
}
}
)*
}
);
impl_positive_measure!(u8, u16, u32, u64, u128, usize, f32, f64);

185
vendor/petgraph/src/algo/page_rank.rs vendored Normal file
View File

@@ -0,0 +1,185 @@
use crate::visit::{EdgeRef, IntoEdges, NodeCount, NodeIndexable};
#[cfg(feature = "rayon")]
use rayon::prelude::*;
use super::UnitMeasure;
/// \[Generic\] Page Rank algorithm.
///
/// Computes the ranks of every node in a graph using the [Page Rank algorithm][pr].
///
/// Returns a `Vec` container mapping each node index to its rank.
///
/// # Panics
/// The damping factor should be a number of type `f32` or `f64` between 0 and 1 (0 and 1 included). Otherwise, it panics.
///
/// # Complexity
/// Time complexity is **O(N|V|²|E|)**.
/// Space complexity is **O(|V| + |E|)**
/// where **N** is the number of iterations, **|V|** the number of vertices (i.e nodes) and **|E|** the number of edges.
///
/// [pr]: https://en.wikipedia.org/wiki/PageRank
///
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::algo::page_rank;
/// let mut g: Graph<(), usize> = Graph::new();
/// assert_eq!(page_rank(&g, 0.5_f64, 1), vec![]); // empty graphs have no node ranks.
/// let a = g.add_node(());
/// let b = g.add_node(());
/// let c = g.add_node(());
/// let d = g.add_node(());
/// let e = g.add_node(());
/// g.extend_with_edges(&[(0, 1), (0, 3), (1, 2), (1, 3)]);
/// // With the following dot representation.
/// //digraph {
/// // 0 [ label = "()" ]
/// // 1 [ label = "()" ]
/// // 2 [ label = "()" ]
/// // 3 [ label = "()" ]
/// // 4 [ label = "()" ]
/// // 0 -> 1 [ label = "0.0" ]
/// // 0 -> 3 [ label = "0.0" ]
/// // 1 -> 2 [ label = "0.0" ]
/// // 1 -> 3 [ label = "0.0" ]
/// //}
/// let damping_factor = 0.7_f32;
/// let number_iterations = 10;
/// let output_ranks = page_rank(&g, damping_factor, number_iterations);
/// let expected_ranks = vec![0.14685437, 0.20267677, 0.22389607, 0.27971846, 0.14685437];
/// assert_eq!(expected_ranks, output_ranks);
/// ```
pub fn page_rank<G, D>(graph: G, damping_factor: D, nb_iter: usize) -> Vec<D>
where
G: NodeCount + IntoEdges + NodeIndexable,
D: UnitMeasure + Copy,
{
let node_count = graph.node_count();
if node_count == 0 {
return vec![];
}
assert!(
D::zero() <= damping_factor && damping_factor <= D::one(),
"Damping factor should be between 0 et 1."
);
let nb = D::from_usize(node_count);
let mut ranks = vec![D::one() / nb; node_count];
let nodeix = |i| graph.from_index(i);
let out_degrees: Vec<D> = (0..node_count)
.map(|i| graph.edges(nodeix(i)).map(|_| D::one()).sum::<D>())
.collect();
for _ in 0..nb_iter {
let pi = (0..node_count)
.enumerate()
.map(|(v, _)| {
ranks
.iter()
.enumerate()
.map(|(w, r)| {
let mut w_out_edges = graph.edges(nodeix(w));
if w_out_edges.any(|e| e.target() == nodeix(v)) {
damping_factor * *r / out_degrees[w]
} else if out_degrees[w] == D::zero() {
damping_factor * *r / nb // stochastic matrix condition
} else {
(D::one() - damping_factor) * *r / nb // random jumps
}
})
.sum::<D>()
})
.collect::<Vec<D>>();
let sum = pi.iter().copied().sum::<D>();
ranks = pi.iter().map(|r| *r / sum).collect::<Vec<D>>();
}
ranks
}
#[allow(dead_code)]
fn out_edges_info<G, D>(graph: G, index_w: usize, index_v: usize) -> (D, bool)
where
G: NodeCount + IntoEdges + NodeIndexable + std::marker::Sync,
D: UnitMeasure + Copy + std::marker::Send + std::marker::Sync,
{
let node_w = graph.from_index(index_w);
let node_v = graph.from_index(index_v);
let mut out_edges = graph.edges(node_w);
let mut out_edge = out_edges.next();
let mut out_degree = D::zero();
let mut flag_points_to = false;
while let Some(edge) = out_edge {
out_degree = out_degree + D::one();
if edge.target() == node_v {
flag_points_to = true;
}
out_edge = out_edges.next();
}
(out_degree, flag_points_to)
}
/// \[Generic\] Parallel Page Rank algorithm.
///
/// See [`page_rank`].
#[cfg(feature = "rayon")]
pub fn parallel_page_rank<G, D>(
graph: G,
damping_factor: D,
nb_iter: usize,
tol: Option<D>,
) -> Vec<D>
where
G: NodeCount + IntoEdges + NodeIndexable + std::marker::Sync,
D: UnitMeasure + Copy + std::marker::Send + std::marker::Sync,
{
let node_count = graph.node_count();
if node_count == 0 {
return vec![];
}
assert!(
D::zero() <= damping_factor && damping_factor <= D::one(),
"Damping factor should be between 0 et 1."
);
let mut tolerance = D::default_tol();
if let Some(_tol) = tol {
tolerance = _tol;
}
let nb = D::from_usize(node_count);
let mut ranks: Vec<D> = (0..node_count)
.into_par_iter()
.map(|_| D::one() / nb)
.collect();
for _ in 0..nb_iter {
let pi = (0..node_count)
.into_par_iter()
.map(|v| {
ranks
.iter()
.enumerate()
.map(|(w, r)| {
let (out_deg, w_points_to_v) = out_edges_info(graph, w, v);
if w_points_to_v {
damping_factor * *r / out_deg
} else if out_deg == D::zero() {
damping_factor * *r / nb // stochastic matrix condition
} else {
(D::one() - damping_factor) * *r / nb // random jumps
}
})
.sum::<D>()
})
.collect::<Vec<D>>();
let sum = pi.par_iter().map(|score| *score).sum::<D>();
let new_ranks = pi.par_iter().map(|r| *r / sum).collect::<Vec<D>>();
let squared_norm_2 = new_ranks
.par_iter()
.zip(&ranks)
.map(|(new, old)| (*new - *old) * (*new - *old))
.sum::<D>();
if squared_norm_2 <= tolerance {
return ranks;
} else {
ranks = new_ranks;
}
}
ranks
}

199
vendor/petgraph/src/algo/simple_paths.rs vendored Normal file
View File

@@ -0,0 +1,199 @@
use std::{
hash::Hash,
iter::{from_fn, FromIterator},
};
use indexmap::IndexSet;
use crate::{
visit::{IntoNeighborsDirected, NodeCount},
Direction::Outgoing,
};
/// Returns an iterator that produces all simple paths from `from` node to `to`, which contains at least `min_intermediate_nodes` nodes
/// and at most `max_intermediate_nodes`, if given, or limited by the graph's order otherwise. The simple path is a path without repetitions.
///
/// This algorithm is adapted from <https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.simple_paths.all_simple_paths.html>.
///
/// # Example
/// ```
/// use petgraph::{algo, prelude::*};
///
/// let mut graph = DiGraph::<&str, i32>::new();
///
/// let a = graph.add_node("a");
/// let b = graph.add_node("b");
/// let c = graph.add_node("c");
/// let d = graph.add_node("d");
///
/// graph.extend_with_edges(&[(a, b, 1), (b, c, 1), (c, d, 1), (a, b, 1), (b, d, 1)]);
///
/// let paths = algo::all_simple_paths::<Vec<_>, _>(&graph, a, d, 0, None)
/// .collect::<Vec<_>>();
///
/// assert_eq!(paths.len(), 4);
///
///
/// // Take only 2 paths.
/// let paths = algo::all_simple_paths::<Vec<_>, _>(&graph, a, d, 0, None)
/// .take(2)
/// .collect::<Vec<_>>();
///
/// assert_eq!(paths.len(), 2);
///
/// ```
///
/// # Note
///
/// The number of simple paths between a given pair of vertices almost always grows exponentially,
/// reaching `O(V!)` on a dense graphs at `V` vertices.
///
/// So if you have a large enough graph, be prepared to wait for the results for years.
/// Or consider extracting only part of the simple paths using the adapter [`Iterator::take`].
pub fn all_simple_paths<TargetColl, G>(
graph: G,
from: G::NodeId,
to: G::NodeId,
min_intermediate_nodes: usize,
max_intermediate_nodes: Option<usize>,
) -> impl Iterator<Item = TargetColl>
where
G: NodeCount,
G: IntoNeighborsDirected,
G::NodeId: Eq + Hash,
TargetColl: FromIterator<G::NodeId>,
{
// how many nodes are allowed in simple path up to target node
// it is min/max allowed path length minus one, because it is more appropriate when implementing lookahead
// than constantly add 1 to length of current path
let max_length = if let Some(l) = max_intermediate_nodes {
l + 1
} else {
graph.node_count() - 1
};
let min_length = min_intermediate_nodes + 1;
// list of visited nodes
let mut visited: IndexSet<G::NodeId> = IndexSet::from_iter(Some(from));
// list of childs of currently exploring path nodes,
// last elem is list of childs of last visited node
let mut stack = vec![graph.neighbors_directed(from, Outgoing)];
from_fn(move || {
while let Some(children) = stack.last_mut() {
if let Some(child) = children.next() {
if visited.len() < max_length {
if child == to {
if visited.len() >= min_length {
let path = visited
.iter()
.cloned()
.chain(Some(to))
.collect::<TargetColl>();
return Some(path);
}
} else if !visited.contains(&child) {
visited.insert(child);
stack.push(graph.neighbors_directed(child, Outgoing));
}
} else {
if (child == to || children.any(|v| v == to)) && visited.len() >= min_length {
let path = visited
.iter()
.cloned()
.chain(Some(to))
.collect::<TargetColl>();
return Some(path);
}
stack.pop();
visited.pop();
}
} else {
stack.pop();
visited.pop();
}
}
None
})
}
#[cfg(test)]
mod test {
use std::{collections::HashSet, iter::FromIterator};
use itertools::assert_equal;
use crate::{dot::Dot, prelude::DiGraph};
use super::all_simple_paths;
#[test]
fn test_all_simple_paths() {
let graph = DiGraph::<i32, i32, _>::from_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),
]);
let expexted_simple_paths_0_to_5 = vec![
vec![0usize, 1, 2, 3, 4, 5],
vec![0, 1, 2, 4, 5],
vec![0, 1, 3, 2, 4, 5],
vec![0, 1, 3, 4, 5],
vec![0, 2, 3, 4, 5],
vec![0, 2, 4, 5],
vec![0, 3, 2, 4, 5],
vec![0, 3, 4, 5],
];
println!("{}", Dot::new(&graph));
let actual_simple_paths_0_to_5: HashSet<Vec<_>> =
all_simple_paths(&graph, 0u32.into(), 5u32.into(), 0, None)
.map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
.collect();
assert_eq!(actual_simple_paths_0_to_5.len(), 8);
assert_eq!(
HashSet::from_iter(expexted_simple_paths_0_to_5),
actual_simple_paths_0_to_5
);
}
#[test]
fn test_one_simple_path() {
let graph = DiGraph::<i32, i32, _>::from_edges(&[(0, 1), (2, 1)]);
let expexted_simple_paths_0_to_1 = &[vec![0usize, 1]];
println!("{}", Dot::new(&graph));
let actual_simple_paths_0_to_1: Vec<Vec<_>> =
all_simple_paths(&graph, 0u32.into(), 1u32.into(), 0, None)
.map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
.collect();
assert_eq!(actual_simple_paths_0_to_1.len(), 1);
assert_equal(expexted_simple_paths_0_to_1, &actual_simple_paths_0_to_1);
}
#[test]
fn test_no_simple_paths() {
let graph = DiGraph::<i32, i32, _>::from_edges(&[(0, 1), (2, 1)]);
println!("{}", Dot::new(&graph));
let actual_simple_paths_0_to_2: Vec<Vec<_>> =
all_simple_paths(&graph, 0u32.into(), 2u32.into(), 0, None)
.map(|v: Vec<_>| v.into_iter().map(|i| i.index()).collect())
.collect();
assert_eq!(actual_simple_paths_0_to_2.len(), 0);
}
}

162
vendor/petgraph/src/algo/tred.rs vendored Normal file
View File

@@ -0,0 +1,162 @@
//! Compute the transitive reduction and closure of a directed acyclic graph
//!
//! ## Transitive reduction and closure
//! The *transitive closure* of a graph **G = (V, E)** is the graph **Gc = (V, Ec)**
//! such that **(i, j)** belongs to **Ec** if and only if there is a path connecting
//! **i** to **j** in **G**. The *transitive reduction* of **G** is the graph **Gr
//! = (V, Er)** such that **Er** is minimal wrt. inclusion in **E** and the transitive
//! closure of **Gr** is the same as that of **G**.
//! The transitive reduction is well-defined for acyclic graphs only.
use crate::adj::{List, UnweightedList};
use crate::graph::IndexType;
use crate::visit::{
GraphBase, IntoNeighbors, IntoNeighborsDirected, NodeCompactIndexable, NodeCount,
};
use crate::Direction;
use fixedbitset::FixedBitSet;
/// Creates a representation of the same graph respecting topological order for use in `tred::dag_transitive_reduction_closure`.
///
/// `toposort` must be a topological order on the node indices of `g` (for example obtained
/// from [`toposort`]).
///
/// [`toposort`]: ../fn.toposort.html
///
/// Returns a pair of a graph `res` and the reciprocal of the topological sort `revmap`.
///
/// `res` is the same graph as `g` with the following differences:
/// * Node and edge weights are stripped,
/// * Node indices are replaced by the corresponding rank in `toposort`,
/// * Iterating on the neighbors of a node respects topological order.
///
/// `revmap` is handy to get back to map indices in `g` to indices in `res`.
/// ```
/// use petgraph::prelude::*;
/// use petgraph::graph::DefaultIx;
/// use petgraph::visit::IntoNeighbors;
/// use petgraph::algo::tred::dag_to_toposorted_adjacency_list;
///
/// let mut g = Graph::<&str, (), Directed, DefaultIx>::new();
/// let second = g.add_node("second child");
/// let top = g.add_node("top");
/// let first = g.add_node("first child");
/// g.extend_with_edges(&[(top, second), (top, first), (first, second)]);
///
/// let toposort = vec![top, first, second];
///
/// let (res, revmap) = dag_to_toposorted_adjacency_list(&g, &toposort);
///
/// // let's compute the children of top in topological order
/// let children: Vec<NodeIndex> = res
/// .neighbors(revmap[top.index()])
/// .map(|ix: NodeIndex| toposort[ix.index()])
/// .collect();
/// assert_eq!(children, vec![first, second])
/// ```
///
/// Runtime: **O(|V| + |E|)**.
///
/// Space complexity: **O(|V| + |E|)**.
pub fn dag_to_toposorted_adjacency_list<G, Ix: IndexType>(
g: G,
toposort: &[G::NodeId],
) -> (UnweightedList<Ix>, Vec<Ix>)
where
G: GraphBase + IntoNeighborsDirected + NodeCompactIndexable + NodeCount,
G::NodeId: IndexType,
{
let mut res = List::with_capacity(g.node_count());
// map from old node index to rank in toposort
let mut revmap = vec![Ix::default(); g.node_bound()];
for (ix, &old_ix) in toposort.iter().enumerate() {
let ix = Ix::new(ix);
revmap[old_ix.index()] = ix;
let iter = g.neighbors_directed(old_ix, Direction::Incoming);
let new_ix: Ix = res.add_node_with_capacity(iter.size_hint().0);
debug_assert_eq!(new_ix.index(), ix.index());
for old_pre in iter {
let pre: Ix = revmap[old_pre.index()];
res.add_edge(pre, ix, ());
}
}
(res, revmap)
}
/// Computes the transitive reduction and closure of a DAG.
///
/// The algorithm implemented here comes from [On the calculation of
/// transitive reduction-closure of
/// orders](https://www.sciencedirect.com/science/article/pii/0012365X9390164O) by Habib, Morvan
/// and Rampon.
///
/// The input graph must be in a very specific format: an adjacency
/// list such that:
/// * Node indices are a toposort, and
/// * The neighbors of all nodes are stored in topological order.
///
/// To get such a representation, use the function [`dag_to_toposorted_adjacency_list`].
///
/// [`dag_to_toposorted_adjacency_list`]: ./fn.dag_to_toposorted_adjacency_list.html
///
/// The output is the pair of the transitive reduction and the transitive closure.
///
/// Runtime complexity: **O(|V| + \sum_{(x, y) \in Er} d(y))** where **d(y)**
/// denotes the outgoing degree of **y** in the transitive closure of **G**.
/// This is still **O(|V|³)** in the worst case like the naive algorithm but
/// should perform better for some classes of graphs.
///
/// Space complexity: **O(|E|)**.
pub fn dag_transitive_reduction_closure<E, Ix: IndexType>(
g: &List<E, Ix>,
) -> (UnweightedList<Ix>, UnweightedList<Ix>) {
let mut tred = List::with_capacity(g.node_count());
let mut tclos = List::with_capacity(g.node_count());
let mut mark = FixedBitSet::with_capacity(g.node_count());
for i in g.node_indices() {
tred.add_node();
tclos.add_node_with_capacity(g.neighbors(i).len());
}
// the algorithm relies on this iterator being toposorted
for i in g.node_indices().rev() {
// the algorighm relies on this iterator being toposorted
for x in g.neighbors(i) {
if !mark[x.index()] {
tred.add_edge(i, x, ());
tclos.add_edge(i, x, ());
for e in tclos.edge_indices_from(x) {
let y = tclos.edge_endpoints(e).unwrap().1;
if !mark[y.index()] {
mark.insert(y.index());
tclos.add_edge(i, y, ());
}
}
}
}
for y in tclos.neighbors(i) {
mark.set(y.index(), false);
}
}
(tred, tclos)
}
#[cfg(test)]
#[test]
fn test_easy_tred() {
let mut input = List::new();
let a: u8 = input.add_node();
let b = input.add_node();
let c = input.add_node();
input.add_edge(a, b, ());
input.add_edge(a, c, ());
input.add_edge(b, c, ());
let (tred, tclos) = dag_transitive_reduction_closure(&input);
assert_eq!(tred.node_count(), 3);
assert_eq!(tclos.node_count(), 3);
assert!(tred.find_edge(a, b).is_some());
assert!(tred.find_edge(b, c).is_some());
assert!(tred.find_edge(a, c).is_none());
assert!(tclos.find_edge(a, b).is_some());
assert!(tclos.find_edge(b, c).is_some());
assert!(tclos.find_edge(a, c).is_some());
}

1151
vendor/petgraph/src/csr.rs vendored Normal file

File diff suppressed because it is too large Load Diff

478
vendor/petgraph/src/data.rs vendored Normal file
View File

@@ -0,0 +1,478 @@
//! Graph traits for associated data and graph construction.
use crate::graph::IndexType;
#[cfg(feature = "graphmap")]
use crate::graphmap::{GraphMap, NodeTrait};
#[cfg(feature = "stable_graph")]
use crate::stable_graph::StableGraph;
use crate::visit::{Data, NodeCount, NodeIndexable, Reversed};
use crate::EdgeType;
use crate::Graph;
trait_template! {
/// Access node and edge weights (associated data).
#[allow(clippy::needless_arbitrary_self_type)]
pub trait DataMap : Data {
@section self
fn node_weight(self: &Self, id: Self::NodeId) -> Option<&Self::NodeWeight>;
fn edge_weight(self: &Self, id: Self::EdgeId) -> Option<&Self::EdgeWeight>;
}
}
macro_rules! access0 {
($e:expr) => {
$e.0
};
}
DataMap! {delegate_impl []}
DataMap! {delegate_impl [['a, G], G, &'a mut G, deref_twice]}
DataMap! {delegate_impl [[G], G, Reversed<G>, access0]}
trait_template! {
/// Access node and edge weights mutably.
#[allow(clippy::needless_arbitrary_self_type)]
pub trait DataMapMut : DataMap {
@section self
fn node_weight_mut(self: &mut Self, id: Self::NodeId) -> Option<&mut Self::NodeWeight>;
fn edge_weight_mut(self: &mut Self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight>;
}
}
DataMapMut! {delegate_impl [['a, G], G, &'a mut G, deref_twice]}
DataMapMut! {delegate_impl [[G], G, Reversed<G>, access0]}
/// A graph that can be extended with further nodes and edges
pub trait Build: Data + NodeCount {
fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId;
/// Add a new edge. If parallel edges (duplicate) are not allowed and
/// the edge already exists, return `None`.
fn add_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Option<Self::EdgeId> {
Some(self.update_edge(a, b, weight))
}
/// Add or update the edge from `a` to `b`. Return the id of the affected
/// edge.
fn update_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Self::EdgeId;
}
/// A graph that can be created
pub trait Create: Build + Default {
fn with_capacity(nodes: usize, edges: usize) -> Self;
}
impl<N, E, Ty, Ix> Data for Graph<N, E, Ty, Ix>
where
Ix: IndexType,
{
type NodeWeight = N;
type EdgeWeight = E;
}
impl<N, E, Ty, Ix> DataMap for Graph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
self.node_weight(id)
}
fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
self.edge_weight(id)
}
}
impl<N, E, Ty, Ix> DataMapMut for Graph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight> {
self.node_weight_mut(id)
}
fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight> {
self.edge_weight_mut(id)
}
}
#[cfg(feature = "stable_graph")]
impl<N, E, Ty, Ix> DataMap for StableGraph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
self.node_weight(id)
}
fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
self.edge_weight(id)
}
}
#[cfg(feature = "stable_graph")]
impl<N, E, Ty, Ix> DataMapMut for StableGraph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn node_weight_mut(&mut self, id: Self::NodeId) -> Option<&mut Self::NodeWeight> {
self.node_weight_mut(id)
}
fn edge_weight_mut(&mut self, id: Self::EdgeId) -> Option<&mut Self::EdgeWeight> {
self.edge_weight_mut(id)
}
}
impl<N, E, Ty, Ix> Build for Graph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId {
self.add_node(weight)
}
fn add_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Option<Self::EdgeId> {
Some(self.add_edge(a, b, weight))
}
fn update_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Self::EdgeId {
self.update_edge(a, b, weight)
}
}
#[cfg(feature = "stable_graph")]
impl<N, E, Ty, Ix> Build for StableGraph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId {
self.add_node(weight)
}
fn add_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Option<Self::EdgeId> {
Some(self.add_edge(a, b, weight))
}
fn update_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Self::EdgeId {
self.update_edge(a, b, weight)
}
}
#[cfg(feature = "graphmap")]
impl<N, E, Ty> Build for GraphMap<N, E, Ty>
where
Ty: EdgeType,
N: NodeTrait,
{
fn add_node(&mut self, weight: Self::NodeWeight) -> Self::NodeId {
self.add_node(weight)
}
fn add_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Option<Self::EdgeId> {
if self.contains_edge(a, b) {
None
} else {
let r = self.add_edge(a, b, weight);
debug_assert!(r.is_none());
Some((a, b))
}
}
fn update_edge(
&mut self,
a: Self::NodeId,
b: Self::NodeId,
weight: Self::EdgeWeight,
) -> Self::EdgeId {
self.add_edge(a, b, weight);
(a, b)
}
}
impl<N, E, Ty, Ix> Create for Graph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn with_capacity(nodes: usize, edges: usize) -> Self {
Self::with_capacity(nodes, edges)
}
}
#[cfg(feature = "stable_graph")]
impl<N, E, Ty, Ix> Create for StableGraph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn with_capacity(nodes: usize, edges: usize) -> Self {
Self::with_capacity(nodes, edges)
}
}
#[cfg(feature = "graphmap")]
impl<N, E, Ty> Create for GraphMap<N, E, Ty>
where
Ty: EdgeType,
N: NodeTrait,
{
fn with_capacity(nodes: usize, edges: usize) -> Self {
Self::with_capacity(nodes, edges)
}
}
/// A graph element.
///
/// A sequence of Elements, for example an iterator, is laid out as follows:
/// Nodes are implicitly given the index of their appearance in the sequence.
/// The edges source and target fields refer to these indices.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Element<N, E> {
/// A graph node.
Node { weight: N },
/// A graph edge.
Edge {
source: usize,
target: usize,
weight: E,
},
}
/// Create a graph from an iterator of elements.
pub trait FromElements: Create {
fn from_elements<I>(iterable: I) -> Self
where
Self: Sized,
I: IntoIterator<Item = Element<Self::NodeWeight, Self::EdgeWeight>>,
{
let mut gr = Self::with_capacity(0, 0);
// usize -> NodeId map
let mut map = Vec::new();
for element in iterable {
match element {
Element::Node { weight } => {
map.push(gr.add_node(weight));
}
Element::Edge {
source,
target,
weight,
} => {
gr.add_edge(map[source], map[target], weight);
}
}
}
gr
}
}
fn from_elements_indexable<G, I>(iterable: I) -> G
where
G: Create + NodeIndexable,
I: IntoIterator<Item = Element<G::NodeWeight, G::EdgeWeight>>,
{
let mut gr = G::with_capacity(0, 0);
let map = |gr: &G, i| gr.from_index(i);
for element in iterable {
match element {
Element::Node { weight } => {
gr.add_node(weight);
}
Element::Edge {
source,
target,
weight,
} => {
let from = map(&gr, source);
let to = map(&gr, target);
gr.add_edge(from, to, weight);
}
}
}
gr
}
impl<N, E, Ty, Ix> FromElements for Graph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn from_elements<I>(iterable: I) -> Self
where
Self: Sized,
I: IntoIterator<Item = Element<Self::NodeWeight, Self::EdgeWeight>>,
{
from_elements_indexable(iterable)
}
}
#[cfg(feature = "stable_graph")]
impl<N, E, Ty, Ix> FromElements for StableGraph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
fn from_elements<I>(iterable: I) -> Self
where
Self: Sized,
I: IntoIterator<Item = Element<Self::NodeWeight, Self::EdgeWeight>>,
{
from_elements_indexable(iterable)
}
}
#[cfg(feature = "graphmap")]
impl<N, E, Ty> FromElements for GraphMap<N, E, Ty>
where
Ty: EdgeType,
N: NodeTrait,
{
fn from_elements<I>(iterable: I) -> Self
where
Self: Sized,
I: IntoIterator<Item = Element<Self::NodeWeight, Self::EdgeWeight>>,
{
from_elements_indexable(iterable)
}
}
/// Iterator adaptors for iterators of `Element`.
pub trait ElementIterator<N, E>: Iterator<Item = Element<N, E>> {
/// Create an iterator adaptor that filters graph elements.
///
/// The function `f` is called with each element and if its return value
/// is `true` the element is accepted and if `false` it is removed.
/// `f` is called with mutable references to the node and edge weights,
/// so that they can be mutated (but the edge endpoints can not).
///
/// This filter adapts the edge source and target indices in the
/// stream so that they are correct after the removals.
fn filter_elements<F>(self, f: F) -> FilterElements<Self, F>
where
Self: Sized,
F: FnMut(Element<&mut N, &mut E>) -> bool,
{
FilterElements {
iter: self,
node_index: 0,
map: Vec::new(),
f,
}
}
}
impl<N, E, I: ?Sized> ElementIterator<N, E> for I where I: Iterator<Item = Element<N, E>> {}
/// An iterator that filters graph elements.
///
/// See [`.filter_elements()`][1] for more information.
///
/// [1]: trait.ElementIterator.html#method.filter_elements
#[derive(Debug, Clone)]
pub struct FilterElements<I, F> {
iter: I,
node_index: usize,
map: Vec<usize>,
f: F,
}
impl<I, F, N, E> Iterator for FilterElements<I, F>
where
I: Iterator<Item = Element<N, E>>,
F: FnMut(Element<&mut N, &mut E>) -> bool,
{
type Item = Element<N, E>;
fn next(&mut self) -> Option<Self::Item> {
loop {
let mut elt = self.iter.next()?;
let keep = (self.f)(match elt {
Element::Node { ref mut weight } => Element::Node { weight },
Element::Edge {
source,
target,
ref mut weight,
} => Element::Edge {
source,
target,
weight,
},
});
let is_node = if let Element::Node { .. } = elt {
true
} else {
false
};
if !keep && is_node {
self.map.push(self.node_index);
}
if is_node {
self.node_index += 1;
}
if !keep {
continue;
}
// map edge parts
match elt {
Element::Edge {
ref mut source,
ref mut target,
..
} => {
// Find the node indices in the map of removed ones.
// If a node was removed, the edge is as well.
// Otherwise the counts are adjusted by the number of nodes
// removed.
// Example: map: [1, 3, 4, 6]
// binary search for 2, result is Err(1). One node has been
// removed before 2.
match self.map.binary_search(source) {
Ok(_) => continue,
Err(i) => *source -= i,
}
match self.map.binary_search(target) {
Ok(_) => continue,
Err(i) => *target -= i,
}
}
Element::Node { .. } => {}
}
return Some(elt);
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}

371
vendor/petgraph/src/dot.rs vendored Normal file
View File

@@ -0,0 +1,371 @@
//! Simple graphviz dot file format output.
use std::fmt::{self, Display, Write};
use crate::visit::{
EdgeRef, GraphProp, IntoEdgeReferences, IntoNodeReferences, NodeIndexable, NodeRef,
};
/// `Dot` implements output to graphviz .dot format for a graph.
///
/// Formatting and options are rather simple, this is mostly intended
/// for debugging. Exact output may change.
///
/// # Examples
///
/// ```
/// use petgraph::Graph;
/// use petgraph::dot::{Dot, Config};
///
/// let mut graph = Graph::<_, ()>::new();
/// graph.add_node("A");
/// graph.add_node("B");
/// graph.add_node("C");
/// graph.add_node("D");
/// graph.extend_with_edges(&[
/// (0, 1), (0, 2), (0, 3),
/// (1, 2), (1, 3),
/// (2, 3),
/// ]);
///
/// println!("{:?}", Dot::with_config(&graph, &[Config::EdgeNoLabel]));
///
/// // In this case the output looks like this:
/// //
/// // digraph {
/// // 0 [label="\"A\""]
/// // 1 [label="\"B\""]
/// // 2 [label="\"C\""]
/// // 3 [label="\"D\""]
/// // 0 -> 1
/// // 0 -> 2
/// // 0 -> 3
/// // 1 -> 2
/// // 1 -> 3
/// // 2 -> 3
/// // }
///
/// // If you need multiple config options, just list them all in the slice.
/// ```
pub struct Dot<'a, G>
where
G: IntoEdgeReferences + IntoNodeReferences,
{
graph: G,
get_edge_attributes: &'a dyn Fn(G, G::EdgeRef) -> String,
get_node_attributes: &'a dyn Fn(G, G::NodeRef) -> String,
config: Configs,
}
static TYPE: [&str; 2] = ["graph", "digraph"];
static EDGE: [&str; 2] = ["--", "->"];
static INDENT: &str = " ";
impl<'a, G> Dot<'a, G>
where
G: IntoNodeReferences + IntoEdgeReferences,
{
/// Create a `Dot` formatting wrapper with default configuration.
#[inline]
pub fn new(graph: G) -> Self {
Self::with_config(graph, &[])
}
/// Create a `Dot` formatting wrapper with custom configuration.
#[inline]
pub fn with_config(graph: G, config: &'a [Config]) -> Self {
Self::with_attr_getters(graph, config, &|_, _| String::new(), &|_, _| String::new())
}
#[inline]
pub fn with_attr_getters(
graph: G,
config: &'a [Config],
get_edge_attributes: &'a dyn Fn(G, G::EdgeRef) -> String,
get_node_attributes: &'a dyn Fn(G, G::NodeRef) -> String,
) -> Self {
let config = Configs::extract(config);
Dot {
graph,
get_edge_attributes,
get_node_attributes,
config,
}
}
}
/// `Dot` configuration.
///
/// This enum does not have an exhaustive definition (will be expanded)
// TODO: #[non_exhaustive] once MSRV >= 1.40,
// and/or for a breaking change make this something like an EnumSet: https://docs.rs/enumset
#[derive(Debug, PartialEq, Eq)]
pub enum Config {
/// Use indices for node labels.
NodeIndexLabel,
/// Use indices for edge labels.
EdgeIndexLabel,
/// Use no edge labels.
EdgeNoLabel,
/// Use no node labels.
NodeNoLabel,
/// Do not print the graph/digraph string.
GraphContentOnly,
#[doc(hidden)]
_Incomplete(()),
}
macro_rules! make_config_struct {
($($variant:ident,)*) => {
#[allow(non_snake_case)]
#[derive(Default)]
struct Configs {
$($variant: bool,)*
}
impl Configs {
#[inline]
fn extract(configs: &[Config]) -> Self {
let mut conf = Self::default();
for c in configs {
match *c {
$(Config::$variant => conf.$variant = true,)*
Config::_Incomplete(()) => {}
}
}
conf
}
}
}
}
make_config_struct!(
NodeIndexLabel,
EdgeIndexLabel,
EdgeNoLabel,
NodeNoLabel,
GraphContentOnly,
);
impl<G> Dot<'_, G>
where
G: IntoNodeReferences + IntoEdgeReferences + NodeIndexable + GraphProp,
{
fn graph_fmt<NF, EF>(&self, f: &mut fmt::Formatter, node_fmt: NF, edge_fmt: EF) -> fmt::Result
where
NF: Fn(&G::NodeWeight, &mut fmt::Formatter) -> fmt::Result,
EF: Fn(&G::EdgeWeight, &mut fmt::Formatter) -> fmt::Result,
{
let g = self.graph;
if !self.config.GraphContentOnly {
writeln!(f, "{} {{", TYPE[g.is_directed() as usize])?;
}
// output all labels
for node in g.node_references() {
write!(f, "{}{} [ ", INDENT, g.to_index(node.id()),)?;
if !self.config.NodeNoLabel {
write!(f, "label = \"")?;
if self.config.NodeIndexLabel {
write!(f, "{}", g.to_index(node.id()))?;
} else {
Escaped(FnFmt(node.weight(), &node_fmt)).fmt(f)?;
}
write!(f, "\" ")?;
}
writeln!(f, "{}]", (self.get_node_attributes)(g, node))?;
}
// output all edges
for (i, edge) in g.edge_references().enumerate() {
write!(
f,
"{}{} {} {} [ ",
INDENT,
g.to_index(edge.source()),
EDGE[g.is_directed() as usize],
g.to_index(edge.target()),
)?;
if !self.config.EdgeNoLabel {
write!(f, "label = \"")?;
if self.config.EdgeIndexLabel {
write!(f, "{}", i)?;
} else {
Escaped(FnFmt(edge.weight(), &edge_fmt)).fmt(f)?;
}
write!(f, "\" ")?;
}
writeln!(f, "{}]", (self.get_edge_attributes)(g, edge))?;
}
if !self.config.GraphContentOnly {
writeln!(f, "}}")?;
}
Ok(())
}
}
impl<G> fmt::Display for Dot<'_, G>
where
G: IntoEdgeReferences + IntoNodeReferences + NodeIndexable + GraphProp,
G::EdgeWeight: fmt::Display,
G::NodeWeight: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.graph_fmt(f, fmt::Display::fmt, fmt::Display::fmt)
}
}
impl<G> fmt::LowerHex for Dot<'_, G>
where
G: IntoEdgeReferences + IntoNodeReferences + NodeIndexable + GraphProp,
G::EdgeWeight: fmt::LowerHex,
G::NodeWeight: fmt::LowerHex,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.graph_fmt(f, fmt::LowerHex::fmt, fmt::LowerHex::fmt)
}
}
impl<G> fmt::UpperHex for Dot<'_, G>
where
G: IntoEdgeReferences + IntoNodeReferences + NodeIndexable + GraphProp,
G::EdgeWeight: fmt::UpperHex,
G::NodeWeight: fmt::UpperHex,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.graph_fmt(f, fmt::UpperHex::fmt, fmt::UpperHex::fmt)
}
}
impl<G> fmt::Debug for Dot<'_, G>
where
G: IntoEdgeReferences + IntoNodeReferences + NodeIndexable + GraphProp,
G::EdgeWeight: fmt::Debug,
G::NodeWeight: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.graph_fmt(f, fmt::Debug::fmt, fmt::Debug::fmt)
}
}
/// Escape for Graphviz
struct Escaper<W>(W);
impl<W> fmt::Write for Escaper<W>
where
W: fmt::Write,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
for c in s.chars() {
self.write_char(c)?;
}
Ok(())
}
fn write_char(&mut self, c: char) -> fmt::Result {
match c {
'"' | '\\' => self.0.write_char('\\')?,
// \l is for left justified linebreak
'\n' => return self.0.write_str("\\l"),
_ => {}
}
self.0.write_char(c)
}
}
/// Pass Display formatting through a simple escaping filter
struct Escaped<T>(T);
impl<T> fmt::Display for Escaped<T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if f.alternate() {
writeln!(&mut Escaper(f), "{:#}", &self.0)
} else {
write!(&mut Escaper(f), "{}", &self.0)
}
}
}
/// Format data using a specific format function
struct FnFmt<'a, T, F>(&'a T, F);
impl<'a, T, F> fmt::Display for FnFmt<'a, T, F>
where
F: Fn(&'a T, &mut fmt::Formatter<'_>) -> fmt::Result,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.1(self.0, f)
}
}
#[cfg(test)]
mod test {
use super::{Config, Dot, Escaper};
use crate::prelude::Graph;
use crate::visit::NodeRef;
use std::fmt::Write;
#[test]
fn test_escape() {
let mut buff = String::new();
{
let mut e = Escaper(&mut buff);
let _ = e.write_str("\" \\ \n");
}
assert_eq!(buff, "\\\" \\\\ \\l");
}
fn simple_graph() -> Graph<&'static str, &'static str> {
let mut graph = Graph::<&str, &str>::new();
let a = graph.add_node("A");
let b = graph.add_node("B");
graph.add_edge(a, b, "edge_label");
graph
}
#[test]
fn test_nodeindexlable_option() {
let graph = simple_graph();
let dot = format!("{:?}", Dot::with_config(&graph, &[Config::NodeIndexLabel]));
assert_eq!(dot, "digraph {\n 0 [ label = \"0\" ]\n 1 [ label = \"1\" ]\n 0 -> 1 [ label = \"\\\"edge_label\\\"\" ]\n}\n");
}
#[test]
fn test_edgeindexlable_option() {
let graph = simple_graph();
let dot = format!("{:?}", Dot::with_config(&graph, &[Config::EdgeIndexLabel]));
assert_eq!(dot, "digraph {\n 0 [ label = \"\\\"A\\\"\" ]\n 1 [ label = \"\\\"B\\\"\" ]\n 0 -> 1 [ label = \"0\" ]\n}\n");
}
#[test]
fn test_edgenolable_option() {
let graph = simple_graph();
let dot = format!("{:?}", Dot::with_config(&graph, &[Config::EdgeNoLabel]));
assert_eq!(dot, "digraph {\n 0 [ label = \"\\\"A\\\"\" ]\n 1 [ label = \"\\\"B\\\"\" ]\n 0 -> 1 [ ]\n}\n");
}
#[test]
fn test_nodenolable_option() {
let graph = simple_graph();
let dot = format!("{:?}", Dot::with_config(&graph, &[Config::NodeNoLabel]));
assert_eq!(
dot,
"digraph {\n 0 [ ]\n 1 [ ]\n 0 -> 1 [ label = \"\\\"edge_label\\\"\" ]\n}\n"
);
}
#[test]
fn test_with_attr_getters() {
let graph = simple_graph();
let dot = format!(
"{:?}",
Dot::with_attr_getters(
&graph,
&[Config::NodeNoLabel, Config::EdgeNoLabel],
&|_, er| format!("label = \"{}\"", er.weight().to_uppercase()),
&|_, nr| format!("label = \"{}\"", nr.weight().to_lowercase()),
),
);
assert_eq!(dot, "digraph {\n 0 [ label = \"a\"]\n 1 [ label = \"b\"]\n 0 -> 1 [ label = \"EDGE_LABEL\"]\n}\n");
}
}

133
vendor/petgraph/src/generate.rs vendored Normal file
View File

@@ -0,0 +1,133 @@
//! ***Unstable.*** Graph generation.
//!
//! ***Unstable: API may change at any time.*** Depends on `feature = "generate"`.
//!
use crate::graph::NodeIndex;
use crate::{Directed, EdgeType, Graph};
// A DAG has the property that the adjacency matrix is lower triangular,
// diagonal zero.
//
// This means we only allow edges i → j where i < j.
//
// The set of all DAG of a particular size is simply the power set of all
// possible edges.
//
// For a graph of n=3 nodes we have (n - 1) * n / 2 = 3 possible edges.
/// A graph generator of “all” graphs of a particular size.
///
/// ***Unstable: API may change at any time.*** Depends on `feature = "generate"`.
pub struct Generator<Ty> {
acyclic: bool,
selfloops: bool,
nodes: usize,
/// number of possible edges
nedges: usize,
/// current edge bitmap
bits: u64,
g: Graph<(), (), Ty>,
}
impl Generator<Directed> {
/// Generate all possible Directed acyclic graphs (DAGs) of a particular number of vertices.
///
/// These are only generated with one per isomorphism, so they use
/// one canonical node labeling where node *i* can only have edges to node *j* if *i < j*.
///
/// For a graph of *k* vertices there are *e = (k - 1) k / 2* possible edges and
/// *2<sup>e</sup>* DAGs.
pub fn directed_acyclic(nodes: usize) -> Self {
assert!(nodes != 0);
let nedges = (nodes - 1) * nodes / 2;
assert!(nedges < 64);
Generator {
acyclic: true,
selfloops: false,
nodes: nodes,
nedges: nedges,
bits: !0,
g: Graph::with_capacity(nodes, nedges),
}
}
}
impl<Ty: EdgeType> Generator<Ty> {
/// Generate all possible graphs of a particular number of vertices.
///
/// All permutations are generated, so the graphs are not unique down to isomorphism.
///
/// For a graph of *k* vertices there are *e = k²* possible edges and
/// *2<sup>k<sup>2</sup></sup>* graphs.
pub fn all(nodes: usize, allow_selfloops: bool) -> Self {
let scale = if Ty::is_directed() { 1 } else { 2 };
let nedges = if allow_selfloops {
(nodes * nodes - nodes) / scale + nodes
} else {
(nodes * nodes) / scale - nodes
};
assert!(nedges < 64);
Generator {
acyclic: false,
selfloops: allow_selfloops,
nodes: nodes,
nedges: nedges,
bits: !0,
g: Graph::with_capacity(nodes, nedges),
}
}
fn state_to_graph(&mut self) -> &Graph<(), (), Ty> {
self.g.clear();
for _ in 0..self.nodes {
self.g.add_node(());
}
// For a DAG:
// interpret the bits in order, it's a lower triangular matrix:
// a b c d
// a x x x x
// b 0 x x x
// c 1 2 x x
// d 3 4 5 x
let mut bit = 0;
for i in 0..self.nodes {
let start = if self.acyclic || !self.g.is_directed() {
i
} else {
0
};
for j in start..self.nodes {
if i == j && !self.selfloops {
continue;
}
if self.bits & (1u64 << bit) != 0 {
self.g.add_edge(NodeIndex::new(i), NodeIndex::new(j), ());
}
bit += 1;
}
}
&self.g
}
pub fn next_ref(&mut self) -> Option<&Graph<(), (), Ty>> {
if self.bits == !0 {
self.bits = 0;
} else {
self.bits += 1;
if self.bits >= 1u64 << self.nedges {
return None;
}
}
Some(self.state_to_graph())
}
}
impl<Ty: EdgeType> Iterator for Generator<Ty> {
type Item = Graph<(), (), Ty>;
fn next(&mut self) -> Option<Self::Item> {
self.next_ref().cloned()
}
}

View File

@@ -0,0 +1,200 @@
//! [graph6 format](https://users.cecs.anu.edu.au/~bdm/data/formats.txt) decoder for undirected graphs.
use crate::{csr::Csr, graph::IndexType, Graph, Undirected};
#[cfg(feature = "graphmap")]
use crate::graphmap::GraphMap;
#[cfg(feature = "graphmap")]
use std::hash::BuildHasher;
#[cfg(feature = "matrix_graph")]
use crate::matrix_graph::{MatrixGraph, Nullable};
#[cfg(feature = "stable_graph")]
use crate::stable_graph::{StableGraph, StableUnGraph};
const N: usize = 63;
/// A graph that can be converted from graph6 format string.
pub trait FromGraph6 {
fn from_graph6_string(graph6_string: String) -> Self;
}
/// Converts a graph6 format string into data can be used to construct an undirected graph.
/// Returns a tuple containing the graph order and its edges.
pub fn from_graph6_representation<Ix>(graph6_representation: String) -> (usize, Vec<(Ix, Ix)>)
where
Ix: IndexType,
{
let (order_bytes, adj_matrix_bytes) =
get_order_bytes_and_adj_matrix_bytes(graph6_representation);
let order_bits = bytes_vector_to_bits_vector(order_bytes);
let adj_matrix_bits = bytes_vector_to_bits_vector(adj_matrix_bytes);
let graph_order = get_bits_as_decimal(order_bits);
let edges = get_edges(graph_order, adj_matrix_bits);
(graph_order, edges)
}
// Converts a graph6 format string into a vector of bytes, converted from ASCII characters,
// split into two parts, the first representing the graph order, and the second its adjacency matrix.
fn get_order_bytes_and_adj_matrix_bytes(graph6_representation: String) -> (Vec<usize>, Vec<usize>) {
let bytes: Vec<usize> = graph6_representation
.chars()
.map(|c| (c as usize) - N)
.collect();
let mut order_bytes = vec![];
let mut adj_matrix_bytes = vec![];
let first_byte = *bytes.first().unwrap();
if first_byte == N {
order_bytes.extend_from_slice(&bytes[1..=3]);
adj_matrix_bytes.extend_from_slice(&bytes[4..]);
} else {
order_bytes.push(first_byte);
adj_matrix_bytes.extend_from_slice(&bytes[1..]);
};
(order_bytes, adj_matrix_bytes)
}
// Converts a bytes vector into a bits vector.
fn bytes_vector_to_bits_vector(bytes: Vec<usize>) -> Vec<u8> {
bytes
.iter()
.flat_map(|&byte| get_number_as_bits(byte, 6))
.collect()
}
// Get binary representation of `n` as a vector of bits with `bits_length` length.
fn get_number_as_bits(n: usize, bits_length: usize) -> Vec<u8> {
let mut bits = Vec::new();
for i in (0..bits_length).rev() {
bits.push(((n >> i) & 1) as u8);
}
bits
}
// Convert a bits vector into its decimal representation.
fn get_bits_as_decimal(bits: Vec<u8>) -> usize {
let bits_str = bits
.iter()
.map(|bit| bit.to_string())
.collect::<Vec<String>>()
.join("");
usize::from_str_radix(&bits_str, 2).unwrap()
}
// Get graph edges from its order and bits vector representation of its adjacency matrix.
fn get_edges<Ix>(order: usize, adj_matrix_bits: Vec<u8>) -> Vec<(Ix, Ix)>
where
Ix: IndexType,
{
let mut edges = vec![];
let mut i = 0;
for col in 1..order {
for lin in 0..col {
let is_adjacent = adj_matrix_bits[i] == 1;
if is_adjacent {
edges.push((Ix::new(lin), Ix::new(col)));
};
i += 1;
}
}
edges
}
impl<Ix: IndexType> FromGraph6 for Graph<(), (), Undirected, Ix> {
fn from_graph6_string(graph6_string: String) -> Self {
let (order, edges): (usize, Vec<(Ix, Ix)>) = from_graph6_representation(graph6_string);
let mut graph: Graph<(), (), Undirected, Ix> = Graph::with_capacity(order, edges.len());
for _ in 0..order {
graph.add_node(());
}
graph.extend_with_edges(edges);
graph
}
}
#[cfg(feature = "stable_graph")]
impl<Ix: IndexType> FromGraph6 for StableGraph<(), (), Undirected, Ix> {
fn from_graph6_string(graph6_string: String) -> Self {
let (order, edges): (usize, Vec<(Ix, Ix)>) = from_graph6_representation(graph6_string);
let mut graph: StableGraph<(), (), Undirected, Ix> =
StableUnGraph::with_capacity(order, edges.len());
for _ in 0..order {
graph.add_node(());
}
graph.extend_with_edges(edges);
graph
}
}
#[cfg(feature = "graphmap")]
impl<Ix: IndexType, S: BuildHasher + Default> FromGraph6 for GraphMap<Ix, (), Undirected, S> {
fn from_graph6_string(graph6_string: String) -> Self {
let (order, edges): (usize, Vec<(Ix, Ix)>) = from_graph6_representation(graph6_string);
let mut graph: GraphMap<Ix, (), Undirected, S> =
GraphMap::with_capacity(order, edges.len());
for i in 0..order {
graph.add_node(Ix::new(i));
}
for (a, b) in edges {
graph.add_edge(a, b, ());
}
graph
}
}
#[cfg(feature = "matrix_graph")]
impl<Null, Ix> FromGraph6 for MatrixGraph<(), (), Undirected, Null, Ix>
where
Null: Nullable<Wrapped = ()>,
Ix: IndexType,
{
fn from_graph6_string(graph6_string: String) -> Self {
let (order, edges): (usize, Vec<(Ix, Ix)>) = from_graph6_representation(graph6_string);
let mut graph: MatrixGraph<(), (), Undirected, Null, Ix> =
MatrixGraph::with_capacity(order);
for _ in 0..order {
graph.add_node(());
}
graph.extend_with_edges(edges.iter());
graph
}
}
impl<Ix: IndexType> FromGraph6 for Csr<(), (), Undirected, Ix> {
fn from_graph6_string(graph6_string: String) -> Self {
let (order, edges): (usize, Vec<(Ix, Ix)>) = from_graph6_representation(graph6_string);
let mut graph: Csr<(), (), Undirected, Ix> = Csr::new();
let mut nodes = Vec::new();
for _ in 0..order {
let i = graph.add_node(());
nodes.push(i);
}
for (a, b) in edges {
graph.add_edge(a, b, ());
}
graph
}
}

View File

@@ -0,0 +1,154 @@
//! [graph6 format](https://users.cecs.anu.edu.au/~bdm/data/formats.txt) encoder for undirected graphs.
use crate::{
csr::Csr,
graph::IndexType,
visit::{GetAdjacencyMatrix, IntoNodeIdentifiers},
Graph, Undirected,
};
#[cfg(feature = "graphmap")]
use crate::graphmap::{GraphMap, NodeTrait};
#[cfg(feature = "graphmap")]
use std::hash::BuildHasher;
#[cfg(feature = "matrix_graph")]
use crate::matrix_graph::{MatrixGraph, Nullable};
#[cfg(feature = "stable_graph")]
use crate::stable_graph::StableGraph;
const N: usize = 63;
/// A graph that can be converted to graph6 format string.
pub trait ToGraph6 {
fn graph6_string(&self) -> String;
}
/// Converts a graph that implements GetAdjacencyMatrix and IntoNodeIdentifers
/// into a graph6 format string.
pub fn get_graph6_representation<G>(graph: G) -> String
where
G: GetAdjacencyMatrix + IntoNodeIdentifiers,
{
let (graph_order, mut upper_diagonal_as_bits) = get_adj_matrix_upper_diagonal_as_bits(graph);
let mut graph_order_as_bits = get_graph_order_as_bits(graph_order);
let mut graph_as_bits = vec![];
graph_as_bits.append(&mut graph_order_as_bits);
graph_as_bits.append(&mut upper_diagonal_as_bits);
bits_to_ascii(graph_as_bits)
}
// Traverse graph nodes and construct the upper diagonal of its adjacency matrix as a vector of bits.
// Returns a tuple containing:
// - `n`: graph order (number of nodes in graph)
// - `bits`: a vector of 0s and 1s encoding the upper diagonal of the graphs adjacency matrix.
fn get_adj_matrix_upper_diagonal_as_bits<G>(graph: G) -> (usize, Vec<usize>)
where
G: GetAdjacencyMatrix + IntoNodeIdentifiers,
{
let node_ids_iter = graph.node_identifiers();
let mut node_ids_vec = vec![];
let adj_matrix = graph.adjacency_matrix();
let mut bits = vec![];
let mut n = 0;
for node_id in node_ids_iter {
node_ids_vec.push(node_id);
for i in 1..=n {
let is_adjacent: bool =
graph.is_adjacent(&adj_matrix, node_ids_vec[i - 1], node_ids_vec[n]);
bits.push(if is_adjacent { 1 } else { 0 });
}
n += 1;
}
(n, bits)
}
// Converts graph order to a bits vector.
fn get_graph_order_as_bits(order: usize) -> Vec<usize> {
let to_convert_to_bits = if order < N {
vec![(order, 6)]
} else if order <= 258047 {
vec![(N, 6), (order, 18)]
} else {
panic!("Graph order not supported.")
};
to_convert_to_bits
.iter()
.flat_map(|&(n, n_of_bits)| get_number_as_bits(n, n_of_bits))
.collect()
}
// Get binary representation of `n` as a vector of bits with `bits_length` length.
fn get_number_as_bits(n: usize, bits_length: usize) -> Vec<usize> {
let mut bits = Vec::new();
for i in (0..bits_length).rev() {
bits.push((n >> i) & 1);
}
bits
}
// Convert a vector of bits to a String using ASCII encoding.
// Each 6 bits will be converted to a single ASCII character.
fn bits_to_ascii(mut bits: Vec<usize>) -> String {
while bits.len() % 6 != 0 {
bits.push(0);
}
let bits_strs = bits.iter().map(|bit| bit.to_string()).collect::<Vec<_>>();
let bytes = bits_strs
.chunks(6)
.map(|bits_chunk| bits_chunk.join(""))
.map(|bits_str| usize::from_str_radix(&bits_str, 2));
bytes
.map(|byte| char::from((N + byte.unwrap()) as u8))
.collect()
}
impl<N, E, Ix: IndexType> ToGraph6 for Graph<N, E, Undirected, Ix> {
fn graph6_string(&self) -> String {
get_graph6_representation(self)
}
}
#[cfg(feature = "stable_graph")]
impl<N, E, Ix: IndexType> ToGraph6 for StableGraph<N, E, Undirected, Ix> {
fn graph6_string(&self) -> String {
get_graph6_representation(self)
}
}
#[cfg(feature = "graphmap")]
impl<N: NodeTrait, E, S: BuildHasher> ToGraph6 for GraphMap<N, E, Undirected, S> {
fn graph6_string(&self) -> String {
get_graph6_representation(self)
}
}
#[cfg(feature = "matrix_graph")]
impl<N, E, Null, Ix> ToGraph6 for MatrixGraph<N, E, Undirected, Null, Ix>
where
N: NodeTrait,
Null: Nullable<Wrapped = E>,
Ix: IndexType,
{
fn graph6_string(&self) -> String {
get_graph6_representation(self)
}
}
impl<N, E, Ix: IndexType> ToGraph6 for Csr<N, E, Undirected, Ix> {
fn graph6_string(&self) -> String {
get_graph6_representation(self)
}
}

7
vendor/petgraph/src/graph6/mod.rs vendored Normal file
View File

@@ -0,0 +1,7 @@
//! Traits related to [graph6 format](https://users.cecs.anu.edu.au/~bdm/data/formats.txt) for undirected graphs.
pub use self::graph6_decoder::*;
pub use self::graph6_encoder::*;
mod graph6_decoder;
mod graph6_encoder;

108
vendor/petgraph/src/graph_impl/frozen.rs vendored Normal file
View File

@@ -0,0 +1,108 @@
use std::ops::{Deref, Index, IndexMut};
use super::Frozen;
use crate::data::{DataMap, DataMapMut};
use crate::graph::Graph;
use crate::graph::{GraphIndex, IndexType};
use crate::visit::{
Data, EdgeCount, EdgeIndexable, GetAdjacencyMatrix, GraphBase, GraphProp, IntoEdges,
IntoEdgesDirected, IntoNeighborsDirected, IntoNodeIdentifiers, NodeCompactIndexable, NodeCount,
NodeIndexable,
};
use crate::visit::{IntoEdgeReferences, IntoNeighbors, IntoNodeReferences, Visitable};
use crate::{Direction, EdgeType};
impl<'a, G> Frozen<'a, G> {
/// Create a new `Frozen` from a mutable reference to a graph.
pub fn new(gr: &'a mut G) -> Self {
Frozen(gr)
}
}
/// Deref allows transparent access to all shared reference (read-only)
/// functionality in the underlying graph.
impl<G> Deref for Frozen<'_, G> {
type Target = G;
fn deref(&self) -> &G {
self.0
}
}
impl<G, I> Index<I> for Frozen<'_, G>
where
G: Index<I>,
{
type Output = G::Output;
fn index(&self, i: I) -> &G::Output {
self.0.index(i)
}
}
impl<G, I> IndexMut<I> for Frozen<'_, G>
where
G: IndexMut<I>,
{
fn index_mut(&mut self, i: I) -> &mut G::Output {
self.0.index_mut(i)
}
}
impl<N, E, Ty, Ix> Frozen<'_, Graph<N, E, Ty, Ix>>
where
Ty: EdgeType,
Ix: IndexType,
{
#[allow(clippy::type_complexity)]
/// Index the `Graph` by two indices, any combination of
/// node or edge indices is fine.
///
/// **Panics** if the indices are equal or if they are out of bounds.
pub fn index_twice_mut<T, U>(
&mut self,
i: T,
j: U,
) -> (
&mut <Graph<N, E, Ty, Ix> as Index<T>>::Output,
&mut <Graph<N, E, Ty, Ix> as Index<U>>::Output,
)
where
Graph<N, E, Ty, Ix>: IndexMut<T> + IndexMut<U>,
T: GraphIndex,
U: GraphIndex,
{
self.0.index_twice_mut(i, j)
}
}
macro_rules! access0 {
($e:expr) => {
$e.0
};
}
impl<G> GraphBase for Frozen<'_, G>
where
G: GraphBase,
{
type NodeId = G::NodeId;
type EdgeId = G::EdgeId;
}
Data! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
DataMap! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
DataMapMut! {delegate_impl [['a, G], G, Frozen<'a, G>, access0]}
GetAdjacencyMatrix! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
IntoEdgeReferences! {delegate_impl [['a, 'b, G], G, &'b Frozen<'a, G>, deref_twice]}
IntoEdges! {delegate_impl [['a, 'b, G], G, &'b Frozen<'a, G>, deref_twice]}
IntoEdgesDirected! {delegate_impl [['a, 'b, G], G, &'b Frozen<'a, G>, deref_twice]}
IntoNeighbors! {delegate_impl [['a, 'b, G], G, &'b Frozen<'a, G>, deref_twice]}
IntoNeighborsDirected! {delegate_impl [['a, 'b, G], G, &'b Frozen<'a, G>, deref_twice]}
IntoNodeIdentifiers! {delegate_impl [['a, 'b, G], G, &'b Frozen<'a, G>, deref_twice]}
IntoNodeReferences! {delegate_impl [['a, 'b, G], G, &'b Frozen<'a, G>, deref_twice]}
NodeCompactIndexable! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
NodeCount! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
NodeIndexable! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
EdgeCount! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
EdgeIndexable! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
GraphProp! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}
Visitable! {delegate_impl [['a, G], G, Frozen<'a, G>, deref_twice]}

2411
vendor/petgraph/src/graph_impl/mod.rs vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,355 @@
use serde::de::Error;
use std::marker::PhantomData;
use crate::prelude::*;
use crate::graph::Node;
use crate::graph::{Edge, IndexType};
use crate::serde_utils::CollectSeqWithLength;
use crate::serde_utils::MappedSequenceVisitor;
use crate::serde_utils::{FromDeserialized, IntoSerializable};
use crate::EdgeType;
use super::{EdgeIndex, NodeIndex};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
/// Serialization representation for Graph
/// Keep in sync with deserialization and StableGraph
///
/// The serialization format is as follows, in Pseudorust:
///
/// Graph {
/// nodes: [N],
/// node_holes: [NodeIndex<Ix>],
/// edge_property: EdgeProperty,
/// edges: [Option<(NodeIndex<Ix>, NodeIndex<Ix>, E)>]
/// }
///
/// The same format is used by both Graph and StableGraph.
///
/// For graph there are restrictions:
/// node_holes is always empty and edges are always Some
///
/// A stable graph serialization that obeys these restrictions
/// (effectively, it has no interior vacancies) can de deserialized
/// as a graph.
///
/// Node indices are serialized as integers and are fixed size for
/// binary formats, so the Ix parameter matters there.
#[derive(Serialize)]
#[serde(rename = "Graph")]
#[serde(bound(serialize = "N: Serialize, E: Serialize, Ix: IndexType + Serialize"))]
pub struct SerGraph<'a, N: 'a, E: 'a, Ix: 'a + IndexType> {
#[serde(serialize_with = "ser_graph_nodes")]
nodes: &'a [Node<N, Ix>],
node_holes: &'a [NodeIndex<Ix>],
edge_property: EdgeProperty,
#[serde(serialize_with = "ser_graph_edges")]
edges: &'a [Edge<E, Ix>],
}
// Deserialization representation for Graph
// Keep in sync with serialization and StableGraph
#[derive(Deserialize)]
#[serde(rename = "Graph")]
#[serde(bound(
deserialize = "N: Deserialize<'de>, E: Deserialize<'de>, Ix: IndexType + Deserialize<'de>"
))]
pub struct DeserGraph<N, E, Ix> {
#[serde(deserialize_with = "deser_graph_nodes")]
nodes: Vec<Node<N, Ix>>,
#[serde(deserialize_with = "deser_graph_node_holes")]
#[allow(unused)]
#[serde(default = "Vec::new")]
node_holes: Vec<NodeIndex<Ix>>,
edge_property: EdgeProperty,
#[serde(deserialize_with = "deser_graph_edges")]
edges: Vec<Edge<E, Ix>>,
}
impl<Ix> Serialize for NodeIndex<Ix>
where
Ix: IndexType + Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(serializer)
}
}
impl<'de, Ix> Deserialize<'de> for NodeIndex<Ix>
where
Ix: IndexType + Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(NodeIndex(Ix::deserialize(deserializer)?))
}
}
impl<Ix> Serialize for EdgeIndex<Ix>
where
Ix: IndexType + Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.serialize(serializer)
}
}
impl<'de, Ix> Deserialize<'de> for EdgeIndex<Ix>
where
Ix: IndexType + Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(EdgeIndex(Ix::deserialize(deserializer)?))
}
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[derive(Debug)]
pub enum EdgeProperty {
Undirected,
Directed,
}
impl EdgeProperty {
pub fn is_directed(&self) -> bool {
match *self {
EdgeProperty::Directed => true,
EdgeProperty::Undirected => false,
}
}
}
impl<Ty> From<PhantomData<Ty>> for EdgeProperty
where
Ty: EdgeType,
{
fn from(_: PhantomData<Ty>) -> Self {
if Ty::is_directed() {
EdgeProperty::Directed
} else {
EdgeProperty::Undirected
}
}
}
impl<Ty> FromDeserialized for PhantomData<Ty>
where
Ty: EdgeType,
{
type Input = EdgeProperty;
fn from_deserialized<E2>(input: Self::Input) -> Result<Self, E2>
where
E2: Error,
{
if input.is_directed() != Ty::is_directed() {
Err(E2::custom(format_args!(
"graph edge property mismatch, \
expected {:?}, found {:?}",
EdgeProperty::from(PhantomData::<Ty>),
input
)))
} else {
Ok(PhantomData)
}
}
}
fn ser_graph_nodes<S, N, Ix>(nodes: &&[Node<N, Ix>], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
N: Serialize,
Ix: Serialize + IndexType,
{
serializer.collect_seq_exact(nodes.iter().map(|node| &node.weight))
}
fn ser_graph_edges<S, E, Ix>(edges: &&[Edge<E, Ix>], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
E: Serialize,
Ix: Serialize + IndexType,
{
serializer.collect_seq_exact(
edges
.iter()
.map(|edge| Some((edge.source(), edge.target(), &edge.weight))),
)
}
fn deser_graph_nodes<'de, D, N, Ix>(deserializer: D) -> Result<Vec<Node<N, Ix>>, D::Error>
where
D: Deserializer<'de>,
N: Deserialize<'de>,
Ix: IndexType + Deserialize<'de>,
{
deserializer.deserialize_seq(MappedSequenceVisitor::new(|n| {
Ok(Node {
weight: n,
next: [EdgeIndex::end(); 2],
})
}))
}
fn deser_graph_node_holes<'de, D, Ix>(deserializer: D) -> Result<Vec<NodeIndex<Ix>>, D::Error>
where
D: Deserializer<'de>,
Ix: IndexType + Deserialize<'de>,
{
deserializer.deserialize_seq(
MappedSequenceVisitor::<NodeIndex<Ix>, NodeIndex<Ix>, _>::new(|_| {
Err("Graph can not have holes in the node set, found non-empty node_holes")
}),
)
}
fn deser_graph_edges<'de, D, N, Ix>(deserializer: D) -> Result<Vec<Edge<N, Ix>>, D::Error>
where
D: Deserializer<'de>,
N: Deserialize<'de>,
Ix: IndexType + Deserialize<'de>,
{
deserializer.deserialize_seq(MappedSequenceVisitor::<
Option<(NodeIndex<Ix>, NodeIndex<Ix>, N)>,
_,
_,
>::new(|x| {
if let Some((i, j, w)) = x {
Ok(Edge {
weight: w,
node: [i, j],
next: [EdgeIndex::end(); 2],
})
} else {
Err("Graph can not have holes in the edge set, found None, expected edge")
}
}))
}
impl<'a, N, E, Ty, Ix> IntoSerializable for &'a Graph<N, E, Ty, Ix>
where
Ix: IndexType,
Ty: EdgeType,
{
type Output = SerGraph<'a, N, E, Ix>;
fn into_serializable(self) -> Self::Output {
SerGraph {
nodes: &self.nodes,
node_holes: &[],
edges: &self.edges,
edge_property: EdgeProperty::from(PhantomData::<Ty>),
}
}
}
/// Requires crate feature `"serde-1"`
impl<N, E, Ty, Ix> Serialize for Graph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType + Serialize,
N: Serialize,
E: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.into_serializable().serialize(serializer)
}
}
pub fn invalid_node_err<E>(node_index: usize, len: usize) -> E
where
E: Error,
{
E::custom(format_args!(
"invalid value: node index `{}` does not exist in graph \
with node bound {}",
node_index, len
))
}
pub fn invalid_hole_err<E>(node_index: usize) -> E
where
E: Error,
{
E::custom(format_args!(
"invalid value: node hole `{}` is not allowed.",
node_index
))
}
pub fn invalid_length_err<Ix, E>(node_or_edge: &str, len: usize) -> E
where
E: Error,
Ix: IndexType,
{
E::custom(format_args!(
"invalid size: graph {} count {} exceeds index type maximum {}",
node_or_edge,
len,
<Ix as IndexType>::max().index()
))
}
impl<'a, N, E, Ty, Ix> FromDeserialized for Graph<N, E, Ty, Ix>
where
Ix: IndexType,
Ty: EdgeType,
{
type Input = DeserGraph<N, E, Ix>;
fn from_deserialized<E2>(input: Self::Input) -> Result<Self, E2>
where
E2: Error,
{
let ty = PhantomData::<Ty>::from_deserialized(input.edge_property)?;
let nodes = input.nodes;
let edges = input.edges;
if nodes.len() >= <Ix as IndexType>::max().index() {
Err(invalid_length_err::<Ix, _>("node", nodes.len()))?
}
if edges.len() >= <Ix as IndexType>::max().index() {
Err(invalid_length_err::<Ix, _>("edge", edges.len()))?
}
let mut gr = Graph {
nodes: nodes,
edges: edges,
ty: ty,
};
let nc = gr.node_count();
gr.link_edges()
.map_err(|i| invalid_node_err(i.index(), nc))?;
Ok(gr)
}
}
/// Requires crate feature `"serde-1"`
impl<'de, N, E, Ty, Ix> Deserialize<'de> for Graph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType + Deserialize<'de>,
N: Deserialize<'de>,
E: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Self::from_deserialized(DeserGraph::deserialize(deserializer)?)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,298 @@
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::marker::PhantomData;
use crate::prelude::*;
use crate::graph::Node;
use crate::graph::{Edge, IndexType};
use crate::serde_utils::CollectSeqWithLength;
use crate::serde_utils::MappedSequenceVisitor;
use crate::serde_utils::{FromDeserialized, IntoSerializable};
use crate::stable_graph::StableGraph;
use crate::visit::{EdgeIndexable, NodeIndexable};
use crate::EdgeType;
use super::super::serialization::{
invalid_hole_err, invalid_length_err, invalid_node_err, EdgeProperty,
};
// Serialization representation for StableGraph
// Keep in sync with deserialization and Graph
#[derive(Serialize)]
#[serde(rename = "Graph")]
#[serde(bound(serialize = "N: Serialize, E: Serialize, Ix: IndexType + Serialize"))]
pub struct SerStableGraph<'a, N: 'a, E: 'a, Ix: 'a + IndexType> {
nodes: Somes<&'a [Node<Option<N>, Ix>]>,
node_holes: Holes<&'a [Node<Option<N>, Ix>]>,
edge_property: EdgeProperty,
#[serde(serialize_with = "ser_stable_graph_edges")]
edges: &'a [Edge<Option<E>, Ix>],
}
// Deserialization representation for StableGraph
// Keep in sync with serialization and Graph
#[derive(Deserialize)]
#[serde(rename = "Graph")]
#[serde(bound(
deserialize = "N: Deserialize<'de>, E: Deserialize<'de>, Ix: IndexType + Deserialize<'de>"
))]
pub struct DeserStableGraph<N, E, Ix> {
#[serde(deserialize_with = "deser_stable_graph_nodes")]
nodes: Vec<Node<Option<N>, Ix>>,
#[serde(default = "Vec::new")]
node_holes: Vec<NodeIndex<Ix>>,
edge_property: EdgeProperty,
#[serde(deserialize_with = "deser_stable_graph_edges")]
edges: Vec<Edge<Option<E>, Ix>>,
}
/// `Somes` are the present node weights N, with known length.
struct Somes<T>(usize, T);
impl<'a, N, Ix> Serialize for Somes<&'a [Node<Option<N>, Ix>]>
where
N: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_seq_with_length(
self.0,
self.1.iter().filter_map(|node| node.weight.as_ref()),
)
}
}
/// Holes are the node indices of vacancies, with known length
struct Holes<T>(usize, T);
impl<'a, N, Ix> Serialize for Holes<&'a [Node<Option<N>, Ix>]>
where
Ix: Serialize + IndexType,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_seq_with_length(
self.0,
self.1.iter().enumerate().filter_map(|(i, node)| {
if node.weight.is_none() {
Some(NodeIndex::<Ix>::new(i))
} else {
None
}
}),
)
}
}
fn ser_stable_graph_edges<S, E, Ix>(
edges: &&[Edge<Option<E>, Ix>],
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
E: Serialize,
Ix: Serialize + IndexType,
{
serializer.collect_seq_exact(edges.iter().map(|edge| {
edge.weight
.as_ref()
.map(|w| (edge.source(), edge.target(), w))
}))
}
fn deser_stable_graph_nodes<'de, D, N, Ix>(
deserializer: D,
) -> Result<Vec<Node<Option<N>, Ix>>, D::Error>
where
D: Deserializer<'de>,
N: Deserialize<'de>,
Ix: IndexType + Deserialize<'de>,
{
deserializer.deserialize_seq(MappedSequenceVisitor::new(|n| {
Ok(Node {
weight: Some(n),
next: [EdgeIndex::end(); 2],
})
}))
}
fn deser_stable_graph_edges<'de, D, N, Ix>(
deserializer: D,
) -> Result<Vec<Edge<Option<N>, Ix>>, D::Error>
where
D: Deserializer<'de>,
N: Deserialize<'de>,
Ix: IndexType + Deserialize<'de>,
{
deserializer.deserialize_seq(MappedSequenceVisitor::<
Option<(NodeIndex<Ix>, NodeIndex<Ix>, N)>,
_,
_,
>::new(|x| {
if let Some((i, j, w)) = x {
Ok(Edge {
weight: Some(w),
node: [i, j],
next: [EdgeIndex::end(); 2],
})
} else {
Ok(Edge {
weight: None,
node: [NodeIndex::end(); 2],
next: [EdgeIndex::end(); 2],
})
}
}))
}
impl<'a, N, E, Ty, Ix> IntoSerializable for &'a StableGraph<N, E, Ty, Ix>
where
Ix: IndexType,
Ty: EdgeType,
{
type Output = SerStableGraph<'a, N, E, Ix>;
fn into_serializable(self) -> Self::Output {
let nodes = &self.raw_nodes()[..self.node_bound()];
let node_count = self.node_count();
let hole_count = nodes.len() - node_count;
let edges = &self.raw_edges()[..self.edge_bound()];
SerStableGraph {
nodes: Somes(node_count, nodes),
node_holes: Holes(hole_count, nodes),
edges: edges,
edge_property: EdgeProperty::from(PhantomData::<Ty>),
}
}
}
/// Requires crate feature `"serde-1"`
impl<N, E, Ty, Ix> Serialize for StableGraph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType + Serialize,
N: Serialize,
E: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.into_serializable().serialize(serializer)
}
}
impl<'a, N, E, Ty, Ix> FromDeserialized for StableGraph<N, E, Ty, Ix>
where
Ix: IndexType,
Ty: EdgeType,
{
type Input = DeserStableGraph<N, E, Ix>;
fn from_deserialized<E2>(input: Self::Input) -> Result<Self, E2>
where
E2: Error,
{
let ty = PhantomData::<Ty>::from_deserialized(input.edge_property)?;
let node_holes = input.node_holes;
let edges = input.edges;
if edges.len() >= <Ix as IndexType>::max().index() {
Err(invalid_length_err::<Ix, _>("edge", edges.len()))?
}
let total_nodes = input.nodes.len() + node_holes.len();
let mut nodes = Vec::with_capacity(total_nodes);
let mut compact_nodes = input.nodes.into_iter();
let mut node_pos = 0;
for hole_pos in node_holes.iter() {
let hole_pos = hole_pos.index();
if !(node_pos..total_nodes).contains(&hole_pos) {
return Err(invalid_hole_err(hole_pos));
}
nodes.extend(compact_nodes.by_ref().take(hole_pos - node_pos));
nodes.push(Node {
weight: None,
next: [EdgeIndex::end(); 2],
});
node_pos = hole_pos + 1;
debug_assert_eq!(nodes.len(), node_pos);
}
nodes.extend(compact_nodes);
if nodes.len() >= <Ix as IndexType>::max().index() {
Err(invalid_length_err::<Ix, _>("node", nodes.len()))?
}
let node_bound = nodes.len();
let mut sgr = StableGraph {
g: Graph {
nodes: nodes,
edges: edges,
ty: ty,
},
node_count: 0,
edge_count: 0,
free_edge: EdgeIndex::end(),
free_node: NodeIndex::end(),
};
sgr.link_edges()
.map_err(|i| invalid_node_err(i.index(), node_bound))?;
Ok(sgr)
}
}
/// Requires crate feature `"serde-1"`
impl<'de, N, E, Ty, Ix> Deserialize<'de> for StableGraph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType + Deserialize<'de>,
N: Deserialize<'de>,
E: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Self::from_deserialized(DeserStableGraph::deserialize(deserializer)?)
}
}
#[test]
fn test_from_deserialized_with_holes() {
use crate::graph::node_index;
use crate::stable_graph::StableUnGraph;
use itertools::assert_equal;
use serde::de::value::Error as SerdeError;
let input = DeserStableGraph::<_, (), u32> {
nodes: vec![
Node {
weight: Some(1),
next: [EdgeIndex::end(); 2],
},
Node {
weight: Some(4),
next: [EdgeIndex::end(); 2],
},
Node {
weight: Some(5),
next: [EdgeIndex::end(); 2],
},
],
node_holes: vec![node_index(0), node_index(2), node_index(3), node_index(6)],
edges: vec![],
edge_property: EdgeProperty::Undirected,
};
let graph = StableUnGraph::from_deserialized::<SerdeError>(input).unwrap();
assert_eq!(graph.node_count(), 3);
assert_equal(
graph.raw_nodes().iter().map(|n| n.weight.as_ref().cloned()),
vec![None, Some(1), None, None, Some(4), Some(5), None],
);
}

1504
vendor/petgraph/src/graphmap.rs vendored Normal file

File diff suppressed because it is too large Load Diff

102
vendor/petgraph/src/iter_format.rs vendored Normal file
View File

@@ -0,0 +1,102 @@
//! Formatting utils
use std::cell::RefCell;
use std::fmt;
/// Format the iterator like a map
pub struct DebugMap<F>(pub F);
impl<F, I, K, V> fmt::Debug for DebugMap<F>
where
F: Fn() -> I,
I: IntoIterator<Item = (K, V)>,
K: fmt::Debug,
V: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_map().entries((self.0)()).finish()
}
}
/// Avoid "pretty" debug
pub struct NoPretty<T>(pub T);
impl<T> fmt::Debug for NoPretty<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.0)
}
}
/// Format all iterator elements lazily, separated by `sep`.
///
/// The format value can only be formatted once, after that the iterator is
/// exhausted.
///
/// See [`.format()`](../trait.Itertools.html#method.format)
/// for more information.
#[derive(Clone)]
pub struct Format<'a, I> {
sep: &'a str,
/// Format uses interior mutability because Display::fmt takes &self.
inner: RefCell<Option<I>>,
}
pub trait IterFormatExt: Iterator {
fn format(self, separator: &str) -> Format<Self>
where
Self: Sized,
{
Format {
sep: separator,
inner: RefCell::new(Some(self)),
}
}
}
impl<I> IterFormatExt for I where I: Iterator {}
impl<I> Format<'_, I>
where
I: Iterator,
{
fn format<F>(&self, f: &mut fmt::Formatter, mut cb: F) -> fmt::Result
where
F: FnMut(&I::Item, &mut fmt::Formatter) -> fmt::Result,
{
let mut iter = match self.inner.borrow_mut().take() {
Some(t) => t,
None => panic!("Format: was already formatted once"),
};
if let Some(fst) = iter.next() {
cb(&fst, f)?;
for elt in iter {
if !self.sep.is_empty() {
f.write_str(self.sep)?;
}
cb(&elt, f)?;
}
}
Ok(())
}
}
macro_rules! impl_format {
($($fmt_trait:ident)*) => {
$(
impl<'a, I> fmt::$fmt_trait for Format<'a, I>
where I: Iterator,
I::Item: fmt::$fmt_trait,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.format(f, fmt::$fmt_trait::fmt)
}
}
)*
}
}
impl_format!(Debug);

32
vendor/petgraph/src/iter_utils.rs vendored Normal file
View File

@@ -0,0 +1,32 @@
pub trait IterUtilsExt: Iterator {
/// Return the first element that maps to `Some(_)`, or None if the iterator
/// was exhausted.
fn ex_find_map<F, R>(&mut self, mut f: F) -> Option<R>
where
F: FnMut(Self::Item) -> Option<R>,
{
for elt in self {
if let result @ Some(_) = f(elt) {
return result;
}
}
None
}
/// Return the last element from the back that maps to `Some(_)`, or
/// None if the iterator was exhausted.
fn ex_rfind_map<F, R>(&mut self, mut f: F) -> Option<R>
where
F: FnMut(Self::Item) -> Option<R>,
Self: DoubleEndedIterator,
{
while let Some(elt) = self.next_back() {
if let result @ Some(_) = f(elt) {
return result;
}
}
None
}
}
impl<I> IterUtilsExt for I where I: Iterator {}

305
vendor/petgraph/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,305 @@
//! `petgraph` is a graph data structure library.
//!
//! Graphs are collections of nodes, and edges between nodes. `petgraph`
//! provides several [graph types](index.html#graph-types) (each differing in the
//! tradeoffs taken in their internal representation),
//! [algorithms](./algo/index.html#functions) on those graphs, and functionality to
//! [output graphs](./dot/struct.Dot.html) in
//! [`graphviz`](https://www.graphviz.org/) format. Both nodes and edges
//! can have arbitrary associated data, and edges may be either directed or undirected.
//!
//! # Example
//!
//! ```rust
//! use petgraph::graph::{NodeIndex, UnGraph};
//! use petgraph::algo::{dijkstra, min_spanning_tree};
//! use petgraph::data::FromElements;
//! use petgraph::dot::{Dot, Config};
//!
//! // Create an undirected graph with `i32` nodes and edges with `()` associated data.
//! let g = UnGraph::<i32, ()>::from_edges(&[
//! (1, 2), (2, 3), (3, 4),
//! (1, 4)]);
//!
//! // Find the shortest path from `1` to `4` using `1` as the cost for every edge.
//! let node_map = dijkstra(&g, 1.into(), Some(4.into()), |_| 1);
//! assert_eq!(&1i32, node_map.get(&NodeIndex::new(4)).unwrap());
//!
//! // Get the minimum spanning tree of the graph as a new graph, and check that
//! // one edge was trimmed.
//! let mst = UnGraph::<_, _>::from_elements(min_spanning_tree(&g));
//! assert_eq!(g.raw_edges().len() - 1, mst.raw_edges().len());
//!
//! // Output the tree to `graphviz` `DOT` format
//! println!("{:?}", Dot::with_config(&mst, &[Config::EdgeNoLabel]));
//! // graph {
//! // 0 [label="\"0\""]
//! // 1 [label="\"0\""]
//! // 2 [label="\"0\""]
//! // 3 [label="\"0\""]
//! // 1 -- 2
//! // 3 -- 4
//! // 2 -- 3
//! // }
//! ```
//!
//! # Graph types
//!
//! * [`Graph`](./graph/struct.Graph.html) -
//! An adjacency list graph with arbitrary associated data.
//! * [`StableGraph`](./stable_graph/struct.StableGraph.html) -
//! Similar to `Graph`, but it keeps indices stable across removals.
//! * [`GraphMap`](./graphmap/struct.GraphMap.html) -
//! An adjacency list graph backed by a hash table. The node identifiers are the keys
//! into the table.
//! * [`MatrixGraph`](./matrix_graph/struct.MatrixGraph.html) -
//! An adjacency matrix graph.
//! * [`CSR`](./csr/struct.Csr.html) -
//! A sparse adjacency matrix graph with arbitrary associated data.
//!
//! ### Generic parameters
//!
//! Each graph type is generic over a handful of parameters. All graphs share 3 common
//! parameters, `N`, `E`, and `Ty`. This is a broad overview of what those are. Each
//! type's documentation will have finer detail on these parameters.
//!
//! `N` & `E` are called *weights* in this implementation, and are associated with
//! nodes and edges respectively. They can generally be of arbitrary type, and don't have to
//! be what you might conventionally consider weight-like. For example, using `&str` for `N`
//! will work. Many algorithms that require costs let you provide a cost function that
//! translates your `N` and `E` weights into costs appropriate to the algorithm. Some graph
//! types and choices do impose bounds on `N` or `E`.
//! [`min_spanning_tree`](./algo/fn.min_spanning_tree.html) for example requires edge weights that
//! implement [`PartialOrd`](https://doc.rust-lang.org/stable/core/cmp/trait.PartialOrd.html).
//! [`GraphMap`](./graphmap/struct.GraphMap.html) requires node weights that can serve as hash
//! map keys, since that graph type does not create standalone node indices.
//!
//! `Ty` controls whether edges are [`Directed`](./enum.Directed.html) or
//! [`Undirected`](./enum.Undirected.html).
//!
//! `Ix` appears on graph types that use indices. It is exposed so you can control
//! the size of node and edge indices, and therefore the memory footprint of your graphs.
//! Allowed values are `u8`, `u16`, `u32`, and `usize`, with `u32` being the default.
//!
//! ### Shorthand types
//!
//! Each graph type vends a few shorthand type definitions that name some specific
//! generic choices. For example, [`DiGraph<_, _>`](./graph/type.DiGraph.html) is shorthand
//! for [`Graph<_, _, Directed>`](graph/struct.Graph.html).
//! [`UnMatrix<_, _>`](./matrix_graph/type.UnMatrix.html) is shorthand for
//! [`MatrixGraph<_, _, Undirected>`](./matrix_graph/struct.MatrixGraph.html). Each graph type's
//! module documentation lists the available shorthand types.
//!
//! # Crate features
//!
//! * **serde-1** -
//! Defaults off. Enables serialization for ``Graph, StableGraph, GraphMap`` using
//! [`serde 1.0`](https://crates.io/crates/serde). May require a more recent version
//! of Rust than petgraph alone.
//! * **graphmap** -
//! Defaults on. Enables [`GraphMap`](./graphmap/struct.GraphMap.html).
//! * **stable_graph** -
//! Defaults on. Enables [`StableGraph`](./stable_graph/struct.StableGraph.html).
//! * **matrix_graph** -
//! Defaults on. Enables [`MatrixGraph`](./matrix_graph/struct.MatrixGraph.html).
//!
#![doc(html_root_url = "https://docs.rs/petgraph/0.4/")]
extern crate fixedbitset;
#[cfg(feature = "graphmap")]
extern crate indexmap;
#[cfg(feature = "serde-1")]
extern crate serde;
#[cfg(feature = "serde-1")]
#[macro_use]
extern crate serde_derive;
#[cfg(all(feature = "serde-1", test))]
extern crate itertools;
#[doc(no_inline)]
pub use crate::graph::Graph;
pub use crate::Direction::{Incoming, Outgoing};
#[macro_use]
mod macros;
mod scored;
// these modules define trait-implementing macros
#[macro_use]
pub mod visit;
#[macro_use]
pub mod data;
pub mod acyclic;
pub mod adj;
pub mod algo;
pub mod csr;
pub mod dot;
#[cfg(feature = "generate")]
pub mod generate;
pub mod graph6;
mod graph_impl;
#[cfg(feature = "graphmap")]
pub mod graphmap;
mod iter_format;
mod iter_utils;
#[cfg(feature = "matrix_graph")]
pub mod matrix_graph;
#[cfg(feature = "quickcheck")]
mod quickcheck;
#[cfg(feature = "serde-1")]
mod serde_utils;
mod traits_graph;
pub mod unionfind;
mod util;
pub mod operator;
pub mod prelude;
/// `Graph<N, E, Ty, Ix>` is a graph datastructure using an adjacency list representation.
pub mod graph {
pub use crate::graph_impl::{
edge_index, node_index, DefaultIx, DiGraph, Edge, EdgeIndex, EdgeIndices, EdgeReference,
EdgeReferences, EdgeWeightsMut, Edges, EdgesConnecting, Externals, Frozen, Graph,
GraphIndex, IndexType, Neighbors, Node, NodeIndex, NodeIndices, NodeReferences,
NodeWeightsMut, UnGraph, WalkNeighbors,
};
}
#[cfg(feature = "stable_graph")]
pub use crate::graph_impl::stable_graph;
// Index into the NodeIndex and EdgeIndex arrays
/// Edge direction.
#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
#[repr(usize)]
#[cfg_attr(
feature = "serde-1",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub enum Direction {
/// An `Outgoing` edge is an outward edge *from* the current node.
Outgoing = 0,
/// An `Incoming` edge is an inbound edge *to* the current node.
Incoming = 1,
}
impl Direction {
/// Return the opposite `Direction`.
#[inline]
pub fn opposite(self) -> Direction {
match self {
Outgoing => Incoming,
Incoming => Outgoing,
}
}
/// Return `0` for `Outgoing` and `1` for `Incoming`.
#[inline]
pub fn index(self) -> usize {
(self as usize) & 0x1
}
}
#[doc(hidden)]
pub use crate::Direction as EdgeDirection;
/// Marker type for a directed graph.
#[derive(Clone, Copy, Debug)]
#[cfg_attr(
feature = "serde-1",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub enum Directed {}
/// Marker type for an undirected graph.
#[derive(Clone, Copy, Debug)]
#[cfg_attr(
feature = "serde-1",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub enum Undirected {}
/// A graph's edge type determines whether it has directed edges or not.
pub trait EdgeType {
fn is_directed() -> bool;
}
impl EdgeType for Directed {
#[inline]
fn is_directed() -> bool {
true
}
}
impl EdgeType for Undirected {
#[inline]
fn is_directed() -> bool {
false
}
}
/// Convert an element like `(i, j)` or `(i, j, w)` into
/// a triple of source, target, edge weight.
///
/// For `Graph::from_edges` and `GraphMap::from_edges`.
pub trait IntoWeightedEdge<E> {
type NodeId;
fn into_weighted_edge(self) -> (Self::NodeId, Self::NodeId, E);
}
impl<Ix, E> IntoWeightedEdge<E> for (Ix, Ix)
where
E: Default,
{
type NodeId = Ix;
fn into_weighted_edge(self) -> (Ix, Ix, E) {
let (s, t) = self;
(s, t, E::default())
}
}
impl<Ix, E> IntoWeightedEdge<E> for (Ix, Ix, E) {
type NodeId = Ix;
fn into_weighted_edge(self) -> (Ix, Ix, E) {
self
}
}
impl<Ix, E> IntoWeightedEdge<E> for (Ix, Ix, &E)
where
E: Clone,
{
type NodeId = Ix;
fn into_weighted_edge(self) -> (Ix, Ix, E) {
let (a, b, c) = self;
(a, b, c.clone())
}
}
impl<Ix, E> IntoWeightedEdge<E> for &(Ix, Ix)
where
Ix: Copy,
E: Default,
{
type NodeId = Ix;
fn into_weighted_edge(self) -> (Ix, Ix, E) {
let (s, t) = *self;
(s, t, E::default())
}
}
impl<Ix, E> IntoWeightedEdge<E> for &(Ix, Ix, E)
where
Ix: Copy,
E: Clone,
{
type NodeId = Ix;
fn into_weighted_edge(self) -> (Ix, Ix, E) {
self.clone()
}
}

108
vendor/petgraph/src/macros.rs vendored Normal file
View File

@@ -0,0 +1,108 @@
macro_rules! clone_fields {
($name:ident, $($field:ident),+ $(,)*) => (
fn clone(&self) -> Self {
$name {
$(
$field : self . $field .clone()
),*
}
}
);
}
macro_rules! iterator_wrap {
(impl () for
struct $name: ident <$($typarm:tt),*> where { $($bounds: tt)* }
item: $item: ty,
iter: $iter: ty,
) => ();
(
impl (Iterator $($rest:tt)*) for
$(#[$derive:meta])*
struct $name: ident <$($typarm:tt),*> where { $($bounds: tt)* }
item: $item: ty,
iter: $iter: ty,
) => (
// having complex iterator types is kind of the point of this macro
#[allow(clippy::type_complexity)]
$(#[$derive])*
pub struct $name <$($typarm),*> where $($bounds)* {
iter: $iter,
}
impl<$($typarm),*> Iterator for $name <$($typarm),*>
where $($bounds)*
{
type Item = $item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
iterator_wrap!(
impl ($($rest)*) for
struct $name <$($typarm),*> where { $($bounds)* }
item: $item,
iter: $iter,
);
);
(
impl (ExactSizeIterator $($rest:tt)*) for
$(#[$derive:meta])*
struct $name: ident <$($typarm:tt),*> where { $($bounds: tt)* }
item: $item: ty,
iter: $iter: ty,
) => (
impl<$($typarm),*> ExactSizeIterator for $name <$($typarm),*>
where $($bounds)*
{
#[inline]
fn len(&self) -> usize {
self.iter.len()
}
}
iterator_wrap!(
impl ($($rest)*) for
$(#[$derive])*
struct $name <$($typarm),*> where { $($bounds)* }
item: $item,
iter: $iter,
);
);
(
impl (DoubleEndedIterator $($rest:tt)*) for
$(#[$derive:meta])*
struct $name: ident <$($typarm:tt),*> where { $($bounds: tt)* }
item: $item: ty,
iter: $iter: ty,
) => (
impl<$($typarm),*> DoubleEndedIterator for $name <$($typarm),*>
where $($bounds)*
{
fn next_back(&mut self) -> Option<Self::Item> {
self.iter.next_back()
}
fn rfold<B, F>(self, accum: B, f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{ self.iter.rfold(accum, f) }
fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
where
P: FnMut(&Self::Item) -> bool,
{ self.iter.rfind(predicate) }
}
iterator_wrap!(
impl ($($rest)*) for
$(#[$derive])*
struct $name <$($typarm),*> where { $($bounds)* }
item: $item,
iter: $iter,
);
);
}

1814
vendor/petgraph/src/matrix_graph.rs vendored Normal file

File diff suppressed because it is too large Load Diff

83
vendor/petgraph/src/operator.rs vendored Normal file
View File

@@ -0,0 +1,83 @@
//! Operators for creating new graphs from existings ones.
use super::graph::{Graph, IndexType};
use super::EdgeType;
use crate::visit::IntoNodeReferences;
/// \[Generic\] complement of the graph
///
/// Computes the graph complement of the input Graph and stores it
/// in the provided empty output Graph.
///
/// The function does not create self-loops.
///
/// Computes in **O(|V|^2*log(|V|))** time (average).
///
/// Returns the complement.
///
/// # Example
/// ```rust
/// use petgraph::Graph;
/// use petgraph::operator::complement;
/// use petgraph::prelude::*;
///
/// let mut graph: Graph<(),(),Directed> = Graph::new();
/// let a = graph.add_node(()); // node with no weight
/// let b = graph.add_node(());
/// let c = graph.add_node(());
/// let d = graph.add_node(());
///
/// graph.extend_with_edges(&[
/// (a, b),
/// (b, c),
/// (c, d),
/// ]);
/// // a ----> b ----> c ----> d
///
/// let mut output: Graph<(), (), Directed> = Graph::new();
///
/// complement(&graph, &mut output, ());
///
/// let mut expected_res: Graph<(), (), Directed> = Graph::new();
/// let a = expected_res.add_node(());
/// let b = expected_res.add_node(());
/// let c = expected_res.add_node(());
/// let d = expected_res.add_node(());
/// expected_res.extend_with_edges(&[
/// (a, c),
/// (a, d),
/// (b, a),
/// (b, d),
/// (c, a),
/// (c, b),
/// (d, a),
/// (d, b),
/// (d, c),
/// ]);
///
/// for x in graph.node_indices() {
/// for y in graph.node_indices() {
/// assert_eq!(output.contains_edge(x, y), expected_res.contains_edge(x, y));
/// }
/// }
/// ```
pub fn complement<N, E, Ty, Ix>(
input: &Graph<N, E, Ty, Ix>,
output: &mut Graph<N, E, Ty, Ix>,
weight: E,
) where
Ty: EdgeType,
Ix: IndexType,
E: Clone,
N: Clone,
{
for (_node, weight) in input.node_references() {
output.add_node(weight.clone());
}
for x in input.node_indices() {
for y in input.node_indices() {
if x != y && !input.contains_edge(x, y) {
output.add_edge(x, y, weight.clone());
}
}
}
}

21
vendor/petgraph/src/prelude.rs vendored Normal file
View File

@@ -0,0 +1,21 @@
//! Commonly used items.
//!
//! ```
//! use petgraph::prelude::*;
//! ```
#[doc(no_inline)]
pub use crate::graph::{DiGraph, EdgeIndex, Graph, NodeIndex, UnGraph};
#[cfg(feature = "graphmap")]
#[doc(no_inline)]
pub use crate::graphmap::{DiGraphMap, GraphMap, UnGraphMap};
#[doc(no_inline)]
#[cfg(feature = "stable_graph")]
pub use crate::stable_graph::{StableDiGraph, StableGraph, StableUnGraph};
#[doc(no_inline)]
pub use crate::visit::{Bfs, Dfs, DfsPostOrder};
#[doc(no_inline)]
pub use crate::{Directed, Direction, Incoming, Outgoing, Undirected};
#[doc(no_inline)]
pub use crate::visit::EdgeRef;

216
vendor/petgraph/src/quickcheck.rs vendored Normal file
View File

@@ -0,0 +1,216 @@
extern crate quickcheck;
use self::quickcheck::{Arbitrary, Gen};
use crate::graph::{node_index, IndexType};
#[cfg(feature = "stable_graph")]
use crate::stable_graph::StableGraph;
use crate::{EdgeType, Graph};
#[cfg(feature = "graphmap")]
use crate::graphmap::{GraphMap, NodeTrait};
use crate::visit::NodeIndexable;
/// Return a random float in the range [0, 1.)
fn random_01<G: Gen>(g: &mut G) -> f64 {
// from rand
let bits = 53;
let scale = 1. / ((1u64 << bits) as f64);
let x: u64 = Arbitrary::arbitrary(g);
(x >> (64 - bits)) as f64 * scale
}
/// `Arbitrary` for `Graph` creates a graph by selecting a node count
/// and a probability for each possible edge to exist.
///
/// The result will be simple graph or digraph, self loops
/// possible, no parallel edges.
///
/// The exact properties of the produced graph is subject to change.
///
/// Requires crate feature `"quickcheck"`
impl<N, E, Ty, Ix> Arbitrary for Graph<N, E, Ty, Ix>
where
N: Arbitrary,
E: Arbitrary,
Ty: EdgeType + Send + 'static,
Ix: IndexType + Send,
{
fn arbitrary<G: Gen>(g: &mut G) -> Self {
let nodes = usize::arbitrary(g);
if nodes == 0 {
return Graph::with_capacity(0, 0);
}
// use X² for edge probability (bias towards lower)
let edge_prob = random_01(g) * random_01(g);
let edges = ((nodes as f64).powi(2) * edge_prob) as usize;
let mut gr = Graph::with_capacity(nodes, edges);
for _ in 0..nodes {
gr.add_node(N::arbitrary(g));
}
for i in gr.node_indices() {
for j in gr.node_indices() {
if !gr.is_directed() && i > j {
continue;
}
let p: f64 = random_01(g);
if p <= edge_prob {
gr.add_edge(i, j, E::arbitrary(g));
}
}
}
gr
}
// shrink the graph by splitting it in two by a very
// simple algorithm, just even and odd node indices
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
let self_ = self.clone();
Box::new((0..2).filter_map(move |x| {
let gr = self_.filter_map(
|i, w| {
if i.index() % 2 == x {
Some(w.clone())
} else {
None
}
},
|_, w| Some(w.clone()),
);
// make sure we shrink
if gr.node_count() < self_.node_count() {
Some(gr)
} else {
None
}
}))
}
}
#[cfg(feature = "stable_graph")]
/// `Arbitrary` for `StableGraph` creates a graph by selecting a node count
/// and a probability for each possible edge to exist.
///
/// The result will be simple graph or digraph, with possible
/// self loops, no parallel edges.
///
/// The exact properties of the produced graph is subject to change.
///
/// Requires crate features `"quickcheck"` and `"stable_graph"`
impl<N, E, Ty, Ix> Arbitrary for StableGraph<N, E, Ty, Ix>
where
N: Arbitrary,
E: Arbitrary,
Ty: EdgeType + Send + 'static,
Ix: IndexType + Send,
{
fn arbitrary<G: Gen>(g: &mut G) -> Self {
let nodes = usize::arbitrary(g);
if nodes == 0 {
return StableGraph::with_capacity(0, 0);
}
// use X² for edge probability (bias towards lower)
let edge_prob = random_01(g) * random_01(g);
let edges = ((nodes as f64).powi(2) * edge_prob) as usize;
let mut gr = StableGraph::with_capacity(nodes, edges);
for _ in 0..nodes {
gr.add_node(N::arbitrary(g));
}
for i in 0..gr.node_count() {
for j in 0..gr.node_count() {
let i = node_index(i);
let j = node_index(j);
if !gr.is_directed() && i > j {
continue;
}
let p: f64 = random_01(g);
if p <= edge_prob {
gr.add_edge(i, j, E::arbitrary(g));
}
}
}
if bool::arbitrary(g) {
// potentially remove nodes to make holes in nodes & edge sets
let n = u8::arbitrary(g) % (gr.node_count() as u8);
for _ in 0..n {
let ni = node_index(usize::arbitrary(g) % gr.node_bound());
if gr.node_weight(ni).is_some() {
gr.remove_node(ni);
}
}
}
gr
}
// shrink the graph by splitting it in two by a very
// simple algorithm, just even and odd node indices
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
let self_ = self.clone();
Box::new((0..2).filter_map(move |x| {
let gr = self_.filter_map(
|i, w| {
if i.index() % 2 == x {
Some(w.clone())
} else {
None
}
},
|_, w| Some(w.clone()),
);
// make sure we shrink
if gr.node_count() < self_.node_count() {
Some(gr)
} else {
None
}
}))
}
}
/// `Arbitrary` for `GraphMap` creates a graph by selecting a node count
/// and a probability for each possible edge to exist.
///
/// The result will be simple graph or digraph, self loops
/// possible, no parallel edges.
///
/// The exact properties of the produced graph is subject to change.
///
/// Requires crate features `"quickcheck"` and `"graphmap"`
#[cfg(feature = "graphmap")]
impl<N, E, Ty> Arbitrary for GraphMap<N, E, Ty>
where
N: NodeTrait + Arbitrary,
E: Arbitrary,
Ty: EdgeType + Clone + Send + 'static,
{
fn arbitrary<G: Gen>(g: &mut G) -> Self {
let nodes = usize::arbitrary(g);
if nodes == 0 {
return GraphMap::with_capacity(0, 0);
}
let mut nodes = (0..nodes).map(|_| N::arbitrary(g)).collect::<Vec<_>>();
nodes.sort();
nodes.dedup();
// use X² for edge probability (bias towards lower)
let edge_prob = random_01(g) * random_01(g);
let edges = ((nodes.len() as f64).powi(2) * edge_prob) as usize;
let mut gr = GraphMap::with_capacity(nodes.len(), edges);
for &node in &nodes {
gr.add_node(node);
}
for (index, &i) in nodes.iter().enumerate() {
let js = if Ty::is_directed() {
&nodes[..]
} else {
&nodes[index..]
};
for &j in js {
let p: f64 = random_01(g);
if p <= edge_prob {
gr.add_edge(i, j, E::arbitrary(g));
}
}
}
gr
}
}

93
vendor/petgraph/src/scored.rs vendored Normal file
View File

@@ -0,0 +1,93 @@
use std::cmp::Ordering;
/// `MinScored<K, T>` holds a score `K` and a scored object `T` in
/// a pair for use with a `BinaryHeap`.
///
/// `MinScored` compares in reverse order by the score, so that we can
/// use `BinaryHeap` as a min-heap to extract the score-value pair with the
/// least score.
///
/// **Note:** `MinScored` implements a total order (`Ord`), so that it is
/// possible to use float types as scores.
#[derive(Copy, Clone, Debug)]
pub struct MinScored<K, T>(pub K, pub T);
impl<K: PartialOrd, T> PartialEq for MinScored<K, T> {
#[inline]
fn eq(&self, other: &MinScored<K, T>) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl<K: PartialOrd, T> Eq for MinScored<K, T> {}
impl<K: PartialOrd, T> PartialOrd for MinScored<K, T> {
#[inline]
fn partial_cmp(&self, other: &MinScored<K, T>) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<K: PartialOrd, T> Ord for MinScored<K, T> {
#[inline]
fn cmp(&self, other: &MinScored<K, T>) -> Ordering {
let a = &self.0;
let b = &other.0;
if a == b {
Ordering::Equal
} else if a < b {
Ordering::Greater
} else if a > b {
Ordering::Less
} else if a.ne(a) && b.ne(b) {
// these are the NaN cases
Ordering::Equal
} else if a.ne(a) {
// Order NaN less, so that it is last in the MinScore order
Ordering::Less
} else {
Ordering::Greater
}
}
}
#[derive(Copy, Clone, Debug)]
pub struct MaxScored<K, T>(pub K, pub T);
impl<K: PartialOrd, T> PartialEq for MaxScored<K, T> {
#[inline]
fn eq(&self, other: &MaxScored<K, T>) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl<K: PartialOrd, T> Eq for MaxScored<K, T> {}
impl<K: PartialOrd, T> PartialOrd for MaxScored<K, T> {
#[inline]
fn partial_cmp(&self, other: &MaxScored<K, T>) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<K: PartialOrd, T> Ord for MaxScored<K, T> {
#[inline]
fn cmp(&self, other: &MaxScored<K, T>) -> Ordering {
let a = &self.0;
let b = &other.0;
if a == b {
Ordering::Equal
} else if a < b {
Ordering::Less
} else if a > b {
Ordering::Greater
} else if a.ne(a) && b.ne(b) {
// these are the NaN cases
Ordering::Equal
} else if a.ne(a) {
Ordering::Less
} else {
Ordering::Greater
}
}
}

95
vendor/petgraph/src/serde_utils.rs vendored Normal file
View File

@@ -0,0 +1,95 @@
use serde::de::{Deserialize, Error, SeqAccess, Visitor};
use serde::ser::{Serialize, SerializeSeq, Serializer};
use std::fmt;
use std::marker::PhantomData;
/// Map to serializeable representation
pub trait IntoSerializable {
type Output;
fn into_serializable(self) -> Self::Output;
}
/// Map from deserialized representation
pub trait FromDeserialized: Sized {
type Input;
fn from_deserialized<E>(input: Self::Input) -> Result<Self, E>
where
E: Error;
}
/// Serde combinator. A sequence visitor that maps deserialized elements
/// lazily; the visitor can also emit new errors if the elements have errors.
pub struct MappedSequenceVisitor<T, R, F>
where
F: Fn(T) -> Result<R, &'static str>,
{
f: F,
marker: PhantomData<fn() -> T>,
}
impl<'de, F, T, R> MappedSequenceVisitor<T, R, F>
where
T: Deserialize<'de>,
F: Fn(T) -> Result<R, &'static str>,
{
pub fn new(f: F) -> Self {
MappedSequenceVisitor {
f: f,
marker: PhantomData,
}
}
}
impl<'de, F, T, R> Visitor<'de> for MappedSequenceVisitor<T, R, F>
where
T: Deserialize<'de>,
F: Fn(T) -> Result<R, &'static str>,
{
type Value = Vec<R>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a sequence")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut v = Vec::new();
while let Some(elem) = seq.next_element()? {
match (self.f)(elem) {
Err(s) => Err(<A::Error>::custom(s))?,
Ok(x) => v.push(x),
}
}
Ok(v)
}
}
pub trait CollectSeqWithLength: Serializer {
fn collect_seq_with_length<I>(self, length: usize, iterable: I) -> Result<Self::Ok, Self::Error>
where
I: IntoIterator,
I::Item: Serialize,
{
let mut count = 0;
let mut seq = self.serialize_seq(Some(length))?;
for element in iterable {
seq.serialize_element(&element)?;
count += 1;
}
debug_assert_eq!(length, count, "collect_seq_with_length: length mismatch!");
seq.end()
}
fn collect_seq_exact<I>(self, iterable: I) -> Result<Self::Ok, Self::Error>
where
I: IntoIterator,
I::Item: Serialize,
I::IntoIter: ExactSizeIterator,
{
let iter = iterable.into_iter();
self.collect_seq_with_length(iter.len(), iter)
}
}
impl<S> CollectSeqWithLength for S where S: Serializer {}

73
vendor/petgraph/src/traits_graph.rs vendored Normal file
View File

@@ -0,0 +1,73 @@
use fixedbitset::FixedBitSet;
use super::EdgeType;
use super::graph::{Graph, IndexType, NodeIndex};
#[cfg(feature = "stable_graph")]
use crate::stable_graph::StableGraph;
use crate::visit::EdgeRef;
#[cfg(feature = "stable_graph")]
use crate::visit::{IntoEdgeReferences, NodeIndexable};
use super::visit::GetAdjacencyMatrix;
/// The adjacency matrix for **Graph** is a bitmap that's computed by
/// `.adjacency_matrix()`.
impl<N, E, Ty, Ix> GetAdjacencyMatrix for Graph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
type AdjMatrix = FixedBitSet;
fn adjacency_matrix(&self) -> FixedBitSet {
let n = self.node_count();
let mut matrix = FixedBitSet::with_capacity(n * n);
for edge in self.edge_references() {
let i = edge.source().index() * n + edge.target().index();
matrix.put(i);
if !self.is_directed() {
let j = edge.source().index() + n * edge.target().index();
matrix.put(j);
}
}
matrix
}
fn is_adjacent(&self, matrix: &FixedBitSet, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> bool {
let n = self.node_count();
let index = n * a.index() + b.index();
matrix.contains(index)
}
}
#[cfg(feature = "stable_graph")]
/// The adjacency matrix for **Graph** is a bitmap that's computed by
/// `.adjacency_matrix()`.
impl<N, E, Ty, Ix> GetAdjacencyMatrix for StableGraph<N, E, Ty, Ix>
where
Ty: EdgeType,
Ix: IndexType,
{
type AdjMatrix = FixedBitSet;
fn adjacency_matrix(&self) -> FixedBitSet {
let n = self.node_bound();
let mut matrix = FixedBitSet::with_capacity(n * n);
for edge in self.edge_references() {
let i = edge.source().index() * n + edge.target().index();
matrix.put(i);
if !self.is_directed() {
let j = edge.source().index() + n * edge.target().index();
matrix.put(j);
}
}
matrix
}
fn is_adjacent(&self, matrix: &FixedBitSet, a: NodeIndex<Ix>, b: NodeIndex<Ix>) -> bool {
let n = self.node_count();
let index = n * a.index() + b.index();
matrix.contains(index)
}
}

146
vendor/petgraph/src/unionfind.rs vendored Normal file
View File

@@ -0,0 +1,146 @@
//! `UnionFind<K>` is a disjoint-set data structure.
use super::graph::IndexType;
use std::cmp::Ordering;
/// `UnionFind<K>` is a disjoint-set data structure. It tracks set membership of *n* elements
/// indexed from *0* to *n - 1*. The scalar type is `K` which must be an unsigned integer type.
///
/// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>
///
/// Too awesome not to quote:
///
/// “The amortized time per operation is **O(α(n))** where **α(n)** is the
/// inverse of **f(x) = A(x, x)** with **A** being the extremely fast-growing Ackermann function.”
#[derive(Debug, Clone)]
pub struct UnionFind<K> {
// For element at index *i*, store the index of its parent; the representative itself
// stores its own index. This forms equivalence classes which are the disjoint sets, each
// with a unique representative.
parent: Vec<K>,
// It is a balancing tree structure,
// so the ranks are logarithmic in the size of the container -- a byte is more than enough.
//
// Rank is separated out both to save space and to save cache in when searching in the parent
// vector.
rank: Vec<u8>,
}
#[inline]
unsafe fn get_unchecked<K>(xs: &[K], index: usize) -> &K {
debug_assert!(index < xs.len());
xs.get_unchecked(index)
}
#[inline]
unsafe fn get_unchecked_mut<K>(xs: &mut [K], index: usize) -> &mut K {
debug_assert!(index < xs.len());
xs.get_unchecked_mut(index)
}
impl<K> UnionFind<K>
where
K: IndexType,
{
/// Create a new `UnionFind` of `n` disjoint sets.
pub fn new(n: usize) -> Self {
let rank = vec![0; n];
let parent = (0..n).map(K::new).collect::<Vec<K>>();
UnionFind { parent, rank }
}
/// Return the representative for `x`.
///
/// **Panics** if `x` is out of bounds.
pub fn find(&self, x: K) -> K {
assert!(x.index() < self.parent.len());
unsafe {
let mut x = x;
loop {
// Use unchecked indexing because we can trust the internal set ids.
let xparent = *get_unchecked(&self.parent, x.index());
if xparent == x {
break;
}
x = xparent;
}
x
}
}
/// Return the representative for `x`.
///
/// Write back the found representative, flattening the internal
/// datastructure in the process and quicken future lookups.
///
/// **Panics** if `x` is out of bounds.
pub fn find_mut(&mut self, x: K) -> K {
assert!(x.index() < self.parent.len());
unsafe { self.find_mut_recursive(x) }
}
unsafe fn find_mut_recursive(&mut self, mut x: K) -> K {
let mut parent = *get_unchecked(&self.parent, x.index());
while parent != x {
let grandparent = *get_unchecked(&self.parent, parent.index());
*get_unchecked_mut(&mut self.parent, x.index()) = grandparent;
x = parent;
parent = grandparent;
}
x
}
/// Returns `true` if the given elements belong to the same set, and returns
/// `false` otherwise.
pub fn equiv(&self, x: K, y: K) -> bool {
self.find(x) == self.find(y)
}
/// Unify the two sets containing `x` and `y`.
///
/// Return `false` if the sets were already the same, `true` if they were unified.
///
/// **Panics** if `x` or `y` is out of bounds.
pub fn union(&mut self, x: K, y: K) -> bool {
if x == y {
return false;
}
let xrep = self.find_mut(x);
let yrep = self.find_mut(y);
if xrep == yrep {
return false;
}
let xrepu = xrep.index();
let yrepu = yrep.index();
let xrank = self.rank[xrepu];
let yrank = self.rank[yrepu];
// The rank corresponds roughly to the depth of the treeset, so put the
// smaller set below the larger
match xrank.cmp(&yrank) {
Ordering::Less => self.parent[xrepu] = yrep,
Ordering::Greater => self.parent[yrepu] = xrep,
Ordering::Equal => {
self.parent[yrepu] = xrep;
self.rank[xrepu] += 1;
}
}
true
}
/// Return a vector mapping each element to its representative.
pub fn into_labeling(mut self) -> Vec<K> {
// write in the labeling of each element
unsafe {
for ix in 0..self.parent.len() {
let k = *get_unchecked(&self.parent, ix);
let xrep = self.find_mut_recursive(k);
*self.parent.get_unchecked_mut(ix) = xrep;
}
}
self.parent
}
}

16
vendor/petgraph/src/util.rs vendored Normal file
View File

@@ -0,0 +1,16 @@
use std::iter;
pub fn enumerate<I>(iterable: I) -> iter::Enumerate<I::IntoIter>
where
I: IntoIterator,
{
iterable.into_iter().enumerate()
}
pub fn zip<I, J>(i: I, j: J) -> iter::Zip<I::IntoIter, J::IntoIter>
where
I: IntoIterator,
J: IntoIterator,
{
i.into_iter().zip(j)
}

314
vendor/petgraph/src/visit/dfsvisit.rs vendored Normal file
View File

@@ -0,0 +1,314 @@
use crate::visit::IntoNeighbors;
use crate::visit::{VisitMap, Visitable};
/// Strictly monotonically increasing event time for a depth first search.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord, Default, Hash)]
pub struct Time(pub usize);
/// A depth first search (DFS) visitor event.
#[derive(Copy, Clone, Debug)]
pub enum DfsEvent<N> {
Discover(N, Time),
/// An edge of the tree formed by the traversal.
TreeEdge(N, N),
/// An edge to an already visited node.
BackEdge(N, N),
/// A cross or forward edge.
///
/// For an edge *(u, v)*, if the discover time of *v* is greater than *u*,
/// then it is a forward edge, else a cross edge.
CrossForwardEdge(N, N),
/// All edges from a node have been reported.
Finish(N, Time),
}
/// Return if the expression is a break value, execute the provided statement
/// if it is a prune value.
macro_rules! try_control {
($e:expr, $p:stmt) => {
try_control!($e, $p, ());
};
($e:expr, $p:stmt, $q:stmt) => {
match $e {
x => {
if x.should_break() {
return x;
} else if x.should_prune() {
$p
} else {
$q
}
}
}
};
}
/// Control flow for `depth_first_search` callbacks.
#[derive(Copy, Clone, Debug)]
pub enum Control<B> {
/// Continue the DFS traversal as normal.
Continue,
/// Prune the current node from the DFS traversal. No more edges from this
/// node will be reported to the callback. A `DfsEvent::Finish` for this
/// node will still be reported. This can be returned in response to any
/// `DfsEvent`, except `Finish`, which will panic.
Prune,
/// Stop the DFS traversal and return the provided value.
Break(B),
}
impl<B> Control<B> {
pub fn breaking() -> Control<()> {
Control::Break(())
}
/// Get the value in `Control::Break(_)`, if present.
pub fn break_value(self) -> Option<B> {
match self {
Control::Continue | Control::Prune => None,
Control::Break(b) => Some(b),
}
}
}
/// Control flow for callbacks.
///
/// The empty return value `()` is equivalent to continue.
pub trait ControlFlow {
fn continuing() -> Self;
fn should_break(&self) -> bool;
fn should_prune(&self) -> bool;
}
impl ControlFlow for () {
fn continuing() {}
#[inline]
fn should_break(&self) -> bool {
false
}
#[inline]
fn should_prune(&self) -> bool {
false
}
}
impl<B> ControlFlow for Control<B> {
fn continuing() -> Self {
Control::Continue
}
fn should_break(&self) -> bool {
if let Control::Break(_) = *self {
true
} else {
false
}
}
fn should_prune(&self) -> bool {
match *self {
Control::Prune => true,
Control::Continue | Control::Break(_) => false,
}
}
}
impl<C: ControlFlow, E> ControlFlow for Result<C, E> {
fn continuing() -> Self {
Ok(C::continuing())
}
fn should_break(&self) -> bool {
if let Ok(ref c) = *self {
c.should_break()
} else {
true
}
}
fn should_prune(&self) -> bool {
if let Ok(ref c) = *self {
c.should_prune()
} else {
false
}
}
}
/// The default is `Continue`.
impl<B> Default for Control<B> {
fn default() -> Self {
Control::Continue
}
}
/// A recursive depth first search.
///
/// Starting points are the nodes in the iterator `starts` (specify just one
/// start vertex *x* by using `Some(x)`).
///
/// The traversal emits discovery and finish events for each reachable vertex,
/// and edge classification of each reachable edge. `visitor` is called for each
/// event, see [`DfsEvent`][de] for possible values.
///
/// The return value should implement the trait `ControlFlow`, and can be used to change
/// the control flow of the search.
///
/// `Control` Implements `ControlFlow` such that `Control::Continue` resumes the search.
/// `Control::Break` will stop the visit early, returning the contained value.
/// `Control::Prune` will stop traversing any additional edges from the current
/// node and proceed immediately to the `Finish` event.
///
/// There are implementations of `ControlFlow` for `()`, and `Result<C, E>` where
/// `C: ControlFlow`. The implementation for `()` will continue until finished.
/// For `Result`, upon encountering an `E` it will break, otherwise acting the same as `C`.
///
/// ***Panics** if you attempt to prune a node from its `Finish` event.
///
/// [de]: enum.DfsEvent.html
///
/// # Example returning `Control`.
///
/// Find a path from vertex 0 to 5, and exit the visit as soon as we reach
/// the goal vertex.
///
/// ```
/// use petgraph::prelude::*;
/// use petgraph::graph::node_index as n;
/// use petgraph::visit::depth_first_search;
/// use petgraph::visit::{DfsEvent, Control};
///
/// let gr: Graph<(), ()> = Graph::from_edges(&[
/// (0, 1), (0, 2), (0, 3),
/// (1, 3),
/// (2, 3), (2, 4),
/// (4, 0), (4, 5),
/// ]);
///
/// // record each predecessor, mapping node → node
/// let mut predecessor = vec![NodeIndex::end(); gr.node_count()];
/// let start = n(0);
/// let goal = n(5);
/// depth_first_search(&gr, Some(start), |event| {
/// if let DfsEvent::TreeEdge(u, v) = event {
/// predecessor[v.index()] = u;
/// if v == goal {
/// return Control::Break(v);
/// }
/// }
/// Control::Continue
/// });
///
/// let mut next = goal;
/// let mut path = vec![next];
/// while next != start {
/// let pred = predecessor[next.index()];
/// path.push(pred);
/// next = pred;
/// }
/// path.reverse();
/// assert_eq!(&path, &[n(0), n(2), n(4), n(5)]);
/// ```
///
/// # Example returning a `Result`.
/// ```
/// use petgraph::graph::node_index as n;
/// use petgraph::prelude::*;
/// use petgraph::visit::depth_first_search;
/// use petgraph::visit::{DfsEvent, Time};
///
/// let gr: Graph<(), ()> = Graph::from_edges(&[(0, 1), (1, 2), (1, 1), (2, 1)]);
/// let start = n(0);
/// let mut back_edges = 0;
/// let mut discover_time = 0;
/// // Stop the search, the first time a BackEdge is encountered.
/// let result = depth_first_search(&gr, Some(start), |event| {
/// match event {
/// // In the cases where Ok(()) is returned,
/// // Result falls back to the implementation of Control on the value ().
/// // In the case of (), this is to always return Control::Continue.
/// // continuing the search.
/// DfsEvent::Discover(_, Time(t)) => {
/// discover_time = t;
/// Ok(())
/// }
/// DfsEvent::BackEdge(_, _) => {
/// back_edges += 1;
/// // the implementation of ControlFlow for Result,
/// // treats this Err value as Continue::Break
/// Err(event)
/// }
/// _ => Ok(()),
/// }
/// });
///
/// // Even though the graph has more than one cycle,
/// // The number of back_edges visited by the search should always be 1.
/// assert_eq!(back_edges, 1);
/// println!("discover time:{:?}", discover_time);
/// println!("number of backedges encountered: {}", back_edges);
/// println!("back edge: {:?}", result);
/// ```
pub fn depth_first_search<G, I, F, C>(graph: G, starts: I, mut visitor: F) -> C
where
G: IntoNeighbors + Visitable,
I: IntoIterator<Item = G::NodeId>,
F: FnMut(DfsEvent<G::NodeId>) -> C,
C: ControlFlow,
{
let time = &mut Time(0);
let discovered = &mut graph.visit_map();
let finished = &mut graph.visit_map();
for start in starts {
try_control!(
dfs_visitor(graph, start, &mut visitor, discovered, finished, time),
unreachable!()
);
}
C::continuing()
}
pub(crate) fn dfs_visitor<G, F, C>(
graph: G,
u: G::NodeId,
visitor: &mut F,
discovered: &mut impl VisitMap<G::NodeId>,
finished: &mut impl VisitMap<G::NodeId>,
time: &mut Time,
) -> C
where
G: IntoNeighbors + Visitable,
F: FnMut(DfsEvent<G::NodeId>) -> C,
C: ControlFlow,
{
if !discovered.visit(u) {
return C::continuing();
}
try_control!(
visitor(DfsEvent::Discover(u, time_post_inc(time))),
{},
for v in graph.neighbors(u) {
if !discovered.is_visited(&v) {
try_control!(visitor(DfsEvent::TreeEdge(u, v)), continue);
try_control!(
dfs_visitor(graph, v, visitor, discovered, finished, time),
unreachable!()
);
} else if !finished.is_visited(&v) {
try_control!(visitor(DfsEvent::BackEdge(u, v)), continue);
} else {
try_control!(visitor(DfsEvent::CrossForwardEdge(u, v)), continue);
}
}
);
let first_finish = finished.visit(u);
debug_assert!(first_finish);
try_control!(
visitor(DfsEvent::Finish(u, time_post_inc(time))),
panic!("Pruning on the `DfsEvent::Finish` is not supported!")
);
C::continuing()
}
fn time_post_inc(x: &mut Time) -> Time {
let v = *x;
x.0 += 1;
v
}

583
vendor/petgraph/src/visit/filter.rs vendored Normal file
View File

@@ -0,0 +1,583 @@
use crate::prelude::*;
use fixedbitset::FixedBitSet;
use std::collections::HashSet;
use std::marker::PhantomData;
use crate::data::DataMap;
use crate::visit::{Data, NodeCompactIndexable, NodeCount};
use crate::visit::{
EdgeIndexable, GraphBase, GraphProp, IntoEdgeReferences, IntoEdges, IntoEdgesDirected,
IntoNeighbors, IntoNeighborsDirected, IntoNodeIdentifiers, IntoNodeReferences, NodeIndexable,
NodeRef, VisitMap, Visitable,
};
/// A graph filter for nodes.
pub trait FilterNode<N> {
/// Return true to have the node be part of the graph
fn include_node(&self, node: N) -> bool;
}
impl<F, N> FilterNode<N> for F
where
F: Fn(N) -> bool,
{
fn include_node(&self, n: N) -> bool {
(*self)(n)
}
}
/// This filter includes the nodes that are contained in the set.
impl<N> FilterNode<N> for FixedBitSet
where
FixedBitSet: VisitMap<N>,
{
fn include_node(&self, n: N) -> bool {
self.is_visited(&n)
}
}
/// This filter includes the nodes that are contained in the set.
impl<N, S> FilterNode<N> for HashSet<N, S>
where
HashSet<N, S>: VisitMap<N>,
{
fn include_node(&self, n: N) -> bool {
self.is_visited(&n)
}
}
// Can't express these as a generic impl over all references since that would conflict with the
// impl for Fn.
impl<N> FilterNode<N> for &FixedBitSet
where
FixedBitSet: VisitMap<N>,
{
fn include_node(&self, n: N) -> bool {
self.is_visited(&n)
}
}
impl<N, S> FilterNode<N> for &HashSet<N, S>
where
HashSet<N, S>: VisitMap<N>,
{
fn include_node(&self, n: N) -> bool {
self.is_visited(&n)
}
}
/// A node-filtering graph adaptor.
#[derive(Copy, Clone, Debug)]
pub struct NodeFiltered<G, F>(pub G, pub F);
impl<F, G> NodeFiltered<G, F>
where
G: GraphBase,
F: Fn(G::NodeId) -> bool,
{
/// Create an `NodeFiltered` adaptor from the closure `filter`.
pub fn from_fn(graph: G, filter: F) -> Self {
NodeFiltered(graph, filter)
}
}
impl<G, F> GraphBase for NodeFiltered<G, F>
where
G: GraphBase,
{
type NodeId = G::NodeId;
type EdgeId = G::EdgeId;
}
impl<'a, G, F> IntoNeighbors for &'a NodeFiltered<G, F>
where
G: IntoNeighbors,
F: FilterNode<G::NodeId>,
{
type Neighbors = NodeFilteredNeighbors<'a, G::Neighbors, F>;
fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
NodeFilteredNeighbors {
include_source: self.1.include_node(n),
iter: self.0.neighbors(n),
f: &self.1,
}
}
}
/// A filtered neighbors iterator.
#[derive(Debug, Clone)]
pub struct NodeFilteredNeighbors<'a, I, F: 'a> {
include_source: bool,
iter: I,
f: &'a F,
}
impl<I, F> Iterator for NodeFilteredNeighbors<'_, I, F>
where
I: Iterator,
I::Item: Copy,
F: FilterNode<I::Item>,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
let f = self.f;
if !self.include_source {
None
} else {
self.iter.find(move |&target| f.include_node(target))
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}
impl<'a, G, F> IntoNeighborsDirected for &'a NodeFiltered<G, F>
where
G: IntoNeighborsDirected,
F: FilterNode<G::NodeId>,
{
type NeighborsDirected = NodeFilteredNeighbors<'a, G::NeighborsDirected, F>;
fn neighbors_directed(self, n: G::NodeId, dir: Direction) -> Self::NeighborsDirected {
NodeFilteredNeighbors {
include_source: self.1.include_node(n),
iter: self.0.neighbors_directed(n, dir),
f: &self.1,
}
}
}
impl<'a, G, F> IntoNodeIdentifiers for &'a NodeFiltered<G, F>
where
G: IntoNodeIdentifiers,
F: FilterNode<G::NodeId>,
{
type NodeIdentifiers = NodeFilteredNeighbors<'a, G::NodeIdentifiers, F>;
fn node_identifiers(self) -> Self::NodeIdentifiers {
NodeFilteredNeighbors {
include_source: true,
iter: self.0.node_identifiers(),
f: &self.1,
}
}
}
impl<'a, G, F> IntoNodeReferences for &'a NodeFiltered<G, F>
where
G: IntoNodeReferences,
F: FilterNode<G::NodeId>,
{
type NodeRef = G::NodeRef;
type NodeReferences = NodeFilteredNodes<'a, G::NodeReferences, F>;
fn node_references(self) -> Self::NodeReferences {
NodeFilteredNodes {
include_source: true,
iter: self.0.node_references(),
f: &self.1,
}
}
}
/// A filtered node references iterator.
#[derive(Debug, Clone)]
pub struct NodeFilteredNodes<'a, I, F: 'a> {
include_source: bool,
iter: I,
f: &'a F,
}
impl<I, F> Iterator for NodeFilteredNodes<'_, I, F>
where
I: Iterator,
I::Item: Copy + NodeRef,
F: FilterNode<<I::Item as NodeRef>::NodeId>,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
let f = self.f;
if !self.include_source {
None
} else {
self.iter.find(move |&target| f.include_node(target.id()))
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}
impl<'a, G, F> IntoEdgeReferences for &'a NodeFiltered<G, F>
where
G: IntoEdgeReferences,
F: FilterNode<G::NodeId>,
{
type EdgeRef = G::EdgeRef;
type EdgeReferences = NodeFilteredEdgeReferences<'a, G, G::EdgeReferences, F>;
fn edge_references(self) -> Self::EdgeReferences {
NodeFilteredEdgeReferences {
graph: PhantomData,
iter: self.0.edge_references(),
f: &self.1,
}
}
}
/// A filtered edges iterator.
#[derive(Debug, Clone)]
pub struct NodeFilteredEdgeReferences<'a, G, I, F: 'a> {
graph: PhantomData<G>,
iter: I,
f: &'a F,
}
impl<G, I, F> Iterator for NodeFilteredEdgeReferences<'_, G, I, F>
where
F: FilterNode<G::NodeId>,
G: IntoEdgeReferences,
I: Iterator<Item = G::EdgeRef>,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
let f = self.f;
self.iter
.find(move |&edge| f.include_node(edge.source()) && f.include_node(edge.target()))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}
impl<'a, G, F> IntoEdges for &'a NodeFiltered<G, F>
where
G: IntoEdges,
F: FilterNode<G::NodeId>,
{
type Edges = NodeFilteredEdges<'a, G, G::Edges, F>;
fn edges(self, a: G::NodeId) -> Self::Edges {
NodeFilteredEdges {
graph: PhantomData,
include_source: self.1.include_node(a),
iter: self.0.edges(a),
f: &self.1,
dir: Direction::Outgoing,
}
}
}
impl<'a, G, F> IntoEdgesDirected for &'a NodeFiltered<G, F>
where
G: IntoEdgesDirected,
F: FilterNode<G::NodeId>,
{
type EdgesDirected = NodeFilteredEdges<'a, G, G::EdgesDirected, F>;
fn edges_directed(self, a: G::NodeId, dir: Direction) -> Self::EdgesDirected {
NodeFilteredEdges {
graph: PhantomData,
include_source: self.1.include_node(a),
iter: self.0.edges_directed(a, dir),
f: &self.1,
dir,
}
}
}
/// A filtered edges iterator.
#[derive(Debug, Clone)]
pub struct NodeFilteredEdges<'a, G, I, F: 'a> {
graph: PhantomData<G>,
include_source: bool,
iter: I,
f: &'a F,
dir: Direction,
}
impl<G, I, F> Iterator for NodeFilteredEdges<'_, G, I, F>
where
F: FilterNode<G::NodeId>,
G: IntoEdges,
I: Iterator<Item = G::EdgeRef>,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
if !self.include_source {
None
} else {
let dir = self.dir;
let f = self.f;
self.iter.find(move |&edge| {
f.include_node(match dir {
Direction::Outgoing => edge.target(),
Direction::Incoming => edge.source(),
})
})
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}
impl<G, F> DataMap for NodeFiltered<G, F>
where
G: DataMap,
F: FilterNode<G::NodeId>,
{
fn node_weight(&self, id: Self::NodeId) -> Option<&Self::NodeWeight> {
if self.1.include_node(id) {
self.0.node_weight(id)
} else {
None
}
}
fn edge_weight(&self, id: Self::EdgeId) -> Option<&Self::EdgeWeight> {
self.0.edge_weight(id)
}
}
macro_rules! access0 {
($e:expr) => {
$e.0
};
}
Data! {delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
NodeIndexable! {delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
EdgeIndexable! {delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
GraphProp! {delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
Visitable! {delegate_impl [[G, F], G, NodeFiltered<G, F>, access0]}
/// A graph filter for edges
pub trait FilterEdge<Edge> {
/// Return true to have the edge be part of the graph
fn include_edge(&self, edge: Edge) -> bool;
}
impl<F, N> FilterEdge<N> for F
where
F: Fn(N) -> bool,
{
fn include_edge(&self, n: N) -> bool {
(*self)(n)
}
}
/// An edge-filtering graph adaptor.
///
/// The adaptor may filter out edges. The filter implements the trait
/// `FilterEdge`. Closures of type `Fn(G::EdgeRef) -> bool` already
/// implement this trait.
///
/// The filter may use edge source, target, id, and weight to select whether to
/// include the edge or not.
#[derive(Copy, Clone, Debug)]
pub struct EdgeFiltered<G, F>(pub G, pub F);
impl<F, G> EdgeFiltered<G, F>
where
G: IntoEdgeReferences,
F: Fn(G::EdgeRef) -> bool,
{
/// Create an `EdgeFiltered` adaptor from the closure `filter`.
pub fn from_fn(graph: G, filter: F) -> Self {
EdgeFiltered(graph, filter)
}
}
impl<G, F> GraphBase for EdgeFiltered<G, F>
where
G: GraphBase,
{
type NodeId = G::NodeId;
type EdgeId = G::EdgeId;
}
impl<'a, G, F> IntoNeighbors for &'a EdgeFiltered<G, F>
where
G: IntoEdges,
F: FilterEdge<G::EdgeRef>,
{
type Neighbors = EdgeFilteredNeighbors<'a, G, F>;
fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
EdgeFilteredNeighbors {
iter: self.0.edges(n),
f: &self.1,
}
}
}
impl<'a, G, F> IntoNeighborsDirected for &'a EdgeFiltered<G, F>
where
G: IntoEdgesDirected,
F: FilterEdge<G::EdgeRef>,
{
type NeighborsDirected = EdgeFilteredNeighborsDirected<'a, G, F>;
fn neighbors_directed(self, n: G::NodeId, dir: Direction) -> Self::NeighborsDirected {
EdgeFilteredNeighborsDirected {
iter: self.0.edges_directed(n, dir),
f: &self.1,
from: n,
}
}
}
/// A filtered neighbors iterator.
#[derive(Debug, Clone)]
pub struct EdgeFilteredNeighbors<'a, G, F: 'a>
where
G: IntoEdges,
{
iter: G::Edges,
f: &'a F,
}
impl<G, F> Iterator for EdgeFilteredNeighbors<'_, G, F>
where
F: FilterEdge<G::EdgeRef>,
G: IntoEdges,
{
type Item = G::NodeId;
fn next(&mut self) -> Option<Self::Item> {
let f = self.f;
(&mut self.iter)
.filter_map(move |edge| {
if f.include_edge(edge) {
Some(edge.target())
} else {
None
}
})
.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}
impl<'a, G, F> IntoEdgeReferences for &'a EdgeFiltered<G, F>
where
G: IntoEdgeReferences,
F: FilterEdge<G::EdgeRef>,
{
type EdgeRef = G::EdgeRef;
type EdgeReferences = EdgeFilteredEdges<'a, G, G::EdgeReferences, F>;
fn edge_references(self) -> Self::EdgeReferences {
EdgeFilteredEdges {
graph: PhantomData,
iter: self.0.edge_references(),
f: &self.1,
}
}
}
impl<'a, G, F> IntoEdges for &'a EdgeFiltered<G, F>
where
G: IntoEdges,
F: FilterEdge<G::EdgeRef>,
{
type Edges = EdgeFilteredEdges<'a, G, G::Edges, F>;
fn edges(self, n: G::NodeId) -> Self::Edges {
EdgeFilteredEdges {
graph: PhantomData,
iter: self.0.edges(n),
f: &self.1,
}
}
}
impl<'a, G, F> IntoEdgesDirected for &'a EdgeFiltered<G, F>
where
G: IntoEdgesDirected,
F: FilterEdge<G::EdgeRef>,
{
type EdgesDirected = EdgeFilteredEdges<'a, G, G::EdgesDirected, F>;
fn edges_directed(self, n: G::NodeId, dir: Direction) -> Self::EdgesDirected {
EdgeFilteredEdges {
graph: PhantomData,
iter: self.0.edges_directed(n, dir),
f: &self.1,
}
}
}
/// A filtered edges iterator.
#[derive(Debug, Clone)]
pub struct EdgeFilteredEdges<'a, G, I, F: 'a> {
graph: PhantomData<G>,
iter: I,
f: &'a F,
}
impl<G, I, F> Iterator for EdgeFilteredEdges<'_, G, I, F>
where
F: FilterEdge<G::EdgeRef>,
G: IntoEdgeReferences,
I: Iterator<Item = G::EdgeRef>,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
let f = self.f;
self.iter.find(move |&edge| f.include_edge(edge))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}
/// A filtered neighbors-directed iterator.
#[derive(Debug, Clone)]
pub struct EdgeFilteredNeighborsDirected<'a, G, F: 'a>
where
G: IntoEdgesDirected,
{
iter: G::EdgesDirected,
f: &'a F,
from: G::NodeId,
}
impl<G, F> Iterator for EdgeFilteredNeighborsDirected<'_, G, F>
where
F: FilterEdge<G::EdgeRef>,
G: IntoEdgesDirected,
{
type Item = G::NodeId;
fn next(&mut self) -> Option<Self::Item> {
let f = self.f;
let from = self.from;
(&mut self.iter)
.filter_map(move |edge| {
if f.include_edge(edge) {
if edge.source() != from {
Some(edge.source())
} else {
Some(edge.target()) // includes case where from == source == target
}
} else {
None
}
})
.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, upper) = self.iter.size_hint();
(0, upper)
}
}
Data! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
GraphProp! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
IntoNodeIdentifiers! {delegate_impl [['a, G, F], G, &'a EdgeFiltered<G, F>, access0]}
IntoNodeReferences! {delegate_impl [['a, G, F], G, &'a EdgeFiltered<G, F>, access0]}
NodeCompactIndexable! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
NodeCount! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
NodeIndexable! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
EdgeIndexable! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}
Visitable! {delegate_impl [[G, F], G, EdgeFiltered<G, F>, access0]}

135
vendor/petgraph/src/visit/macros.rs vendored Normal file
View File

@@ -0,0 +1,135 @@
/// Define a trait as usual, and a macro that can be used to instantiate
/// implementations of it.
///
/// There *must* be section markers in the trait definition:
/// @section type for associated types
/// @section self for methods
/// @section nodelegate for arbitrary tail that is not forwarded.
macro_rules! trait_template {
($(#[$doc:meta])* pub trait $name:ident $($methods:tt)*) => {
macro_rules! $name {
($m:ident $extra:tt) => {
$m! {
$extra
pub trait $name $($methods)*
}
}
}
remove_sections! { []
$(#[$doc])*
pub trait $name $($methods)*
// This is where the trait definition is reproduced by the macro.
// It makes the source links point to this place!
//
// I'm sorry, you'll have to find the source by looking at the
// source of the module the trait is defined in.
//
// We use this nifty macro so that we can automatically generate
// delegation trait impls and implement the graph traits for more
// types and combinators.
}
}
}
macro_rules! remove_sections_inner {
([$($stack:tt)*]) => {
$($stack)*
};
// escape the following tt
([$($stack:tt)*] @escape $_x:tt $($t:tt)*) => {
remove_sections_inner!([$($stack)*] $($t)*);
};
([$($stack:tt)*] @section $x:ident $($t:tt)*) => {
remove_sections_inner!([$($stack)*] $($t)*);
};
([$($stack:tt)*] $t:tt $($tail:tt)*) => {
remove_sections_inner!([$($stack)* $t] $($tail)*);
};
}
// This is the outer layer, just find the { } of the actual trait definition
// recurse once into { }, but not more.
macro_rules! remove_sections {
([$($stack:tt)*]) => {
$($stack)*
};
([$($stack:tt)*] { $($tail:tt)* }) => {
$($stack)* {
remove_sections_inner!([] $($tail)*);
}
};
([$($stack:tt)*] $t:tt $($tail:tt)*) => {
remove_sections!([$($stack)* $t] $($tail)*);
};
}
macro_rules! deref {
($e:expr) => {
*$e
};
}
macro_rules! deref_twice {
($e:expr) => {
**$e
};
}
/// Implement a trait by delegation. By default as if we are delegating
/// from &G to G.
macro_rules! delegate_impl {
([] $($rest:tt)*) => {
delegate_impl! { [['a, G], G, &'a G, deref] $($rest)* }
};
([[$($param:tt)*], $self_type:ident, $self_wrap:ty, $self_map:ident]
pub trait $name:ident $(: $sup:ident)* $(+ $more_sup:ident)* {
// "Escaped" associated types. Stripped before making the `trait`
// itself, but forwarded when delegating impls.
$(
@escape [type $assoc_name_ext:ident]
// Associated types. Forwarded.
)*
$(
@section type
$(
$(#[$_assoc_attr:meta])*
type $assoc_name:ident $(: $assoc_bound:ty)*;
)+
)*
// Methods. Forwarded. Using $self_map!(self) around the self argument.
// Methods must use receiver `self` or explicit type like `self: &Self`
// &self and &mut self are _not_ supported.
$(
@section self
$(
$(#[$_method_attr:meta])*
fn $method_name:ident(self $(: $self_selftype:ty)* $(,$marg:ident : $marg_ty:ty)*) $(-> $mret:ty)?;
)+
)*
// Arbitrary tail that is ignored when forwarding.
$(
@section nodelegate
$($tail:tt)*
)*
}) => {
impl<$($param)*> $name for $self_wrap where $self_type: $name {
$(
$(
type $assoc_name = $self_type::$assoc_name;
)*
)*
$(
type $assoc_name_ext = $self_type::$assoc_name_ext;
)*
$(
$(
fn $method_name(self $(: $self_selftype)* $(,$marg: $marg_ty)*) $(-> $mret)? {
$self_map!(self).$method_name($($marg),*)
}
)*
)*
}
}
}

481
vendor/petgraph/src/visit/mod.rs vendored Normal file
View File

@@ -0,0 +1,481 @@
//! Graph traits and graph traversals.
//!
//! ### The `Into-` Traits
//!
//! Graph traits like [`IntoNeighbors`][in] create iterators and use the same
//! pattern that `IntoIterator` does: the trait takes a reference to a graph,
//! and produces an iterator. These traits are quite composable, but with the
//! limitation that they only use shared references to graphs.
//!
//! ### Graph Traversal
//!
//! [`Dfs`](struct.Dfs.html), [`Bfs`][bfs], [`DfsPostOrder`][dfspo] and
//! [`Topo`][topo] are basic visitors and they use “walker” methods: the
//! visitors don't hold the graph as borrowed during traversal, only for the
//! `.next()` call on the walker. They can be converted to iterators
//! through the [`Walker`][w] trait.
//!
//! There is also the callback based traversal [`depth_first_search`][dfs].
//!
//! [bfs]: struct.Bfs.html
//! [dfspo]: struct.DfsPostOrder.html
//! [topo]: struct.Topo.html
//! [dfs]: fn.depth_first_search.html
//! [w]: trait.Walker.html
//!
//! ### Other Graph Traits
//!
//! The traits are rather loosely coupled at the moment (which is intentional,
//! but will develop a bit), and there are traits missing that could be added.
//!
//! Not much is needed to be able to use the visitors on a graph. A graph
//! needs to define [`GraphBase`][gb], [`IntoNeighbors`][in] and
//! [`Visitable`][vis] as a minimum.
//!
//! [gb]: trait.GraphBase.html
//! [in]: trait.IntoNeighbors.html
//! [vis]: trait.Visitable.html
//!
//! ### Graph Trait Implementations
//!
//! The following table lists the traits that are implemented for each graph type:
//!
//! | | Graph | StableGraph | GraphMap | MatrixGraph | Csr | List |
//! | --------------------- | :---: | :---------: | :------: | :---------: | :---: | :---: |
//! | GraphBase | x | x | x | x | x | x |
//! | GraphProp | x | x | x | x | x | x |
//! | NodeCount | x | x | x | x | x | x |
//! | NodeIndexable | x | x | x | x | x | x |
//! | NodeCompactIndexable | x | | x | | x | x |
//! | EdgeCount | x | x | x | x | x | x |
//! | EdgeIndexable | x | x | x | | | |
//! | Data | x | x | x | x | x | x |
//! | IntoNodeIdentifiers | x | x | x | x | x | x |
//! | IntoNodeReferences | x | x | x | x | x | x |
//! | IntoEdgeReferences | x | x | x | x | x | x |
//! | IntoNeighbors | x | x | x | x | x | x |
//! | IntoNeighborsDirected | x | x | x | x | | |
//! | IntoEdges | x | x | x | x | x | x |
//! | IntoEdgesDirected | x | x | x | x | | |
//! | Visitable | x | x | x | x | x | x |
//! | GetAdjacencyMatrix | x | x | x | x | x | x |
// filter, reversed have their `mod` lines at the end,
// so that they can use the trait template macros
pub use self::filter::*;
pub use self::reversed::*;
pub use self::undirected_adaptor::*;
#[macro_use]
mod macros;
mod dfsvisit;
mod traversal;
pub use self::dfsvisit::*;
pub use self::traversal::*;
use fixedbitset::FixedBitSet;
use std::collections::HashSet;
use std::hash::{BuildHasher, Hash};
use super::EdgeType;
use crate::prelude::Direction;
use crate::graph::IndexType;
trait_template! {
/// Base graph trait: defines the associated node identifier and
/// edge identifier types.
pub trait GraphBase {
// FIXME: We can drop this escape/nodelegate stuff in Rust 1.18
@escape [type NodeId]
@escape [type EdgeId]
@section nodelegate
/// edge identifier
type EdgeId: Copy + PartialEq;
/// node identifier
type NodeId: Copy + PartialEq;
}
}
GraphBase! {delegate_impl []}
GraphBase! {delegate_impl [['a, G], G, &'a mut G, deref]}
/// A copyable reference to a graph.
pub trait GraphRef: Copy + GraphBase {}
impl<G> GraphRef for &G where G: GraphBase {}
trait_template! {
/// Access to the neighbors of each node
///
/// The neighbors are, depending on the graphs edge type:
///
/// - `Directed`: All targets of edges from `a`.
/// - `Undirected`: All other endpoints of edges connected to `a`.
pub trait IntoNeighbors : GraphRef {
@section type
type Neighbors: Iterator<Item=Self::NodeId>;
@section self
/// Return an iterator of the neighbors of node `a`.
fn neighbors(self, a: Self::NodeId) -> Self::Neighbors;
}
}
IntoNeighbors! {delegate_impl []}
trait_template! {
/// Access to the neighbors of each node, through incoming or outgoing edges.
///
/// Depending on the graphs edge type, the neighbors of a given directionality
/// are:
///
/// - `Directed`, `Outgoing`: All targets of edges from `a`.
/// - `Directed`, `Incoming`: All sources of edges to `a`.
/// - `Undirected`: All other endpoints of edges connected to `a`.
pub trait IntoNeighborsDirected : IntoNeighbors {
@section type
type NeighborsDirected: Iterator<Item=Self::NodeId>;
@section self
fn neighbors_directed(self, n: Self::NodeId, d: Direction)
-> Self::NeighborsDirected;
}
}
trait_template! {
/// Access to the edges of each node.
///
/// The edges are, depending on the graphs edge type:
///
/// - `Directed`: All edges from `a`.
/// - `Undirected`: All edges connected to `a`, with `a` being the source of each edge.
///
/// This is an extended version of the trait `IntoNeighbors`; the former
/// only iterates over the target node identifiers, while this trait
/// yields edge references (trait [`EdgeRef`][er]).
///
/// [er]: trait.EdgeRef.html
pub trait IntoEdges : IntoEdgeReferences + IntoNeighbors {
@section type
type Edges: Iterator<Item=Self::EdgeRef>;
@section self
fn edges(self, a: Self::NodeId) -> Self::Edges;
}
}
IntoEdges! {delegate_impl []}
trait_template! {
/// Access to all edges of each node, in the specified direction.
///
/// The edges are, depending on the direction and the graphs edge type:
///
///
/// - `Directed`, `Outgoing`: All edges from `a`.
/// - `Directed`, `Incoming`: All edges to `a`.
/// - `Undirected`, `Outgoing`: All edges connected to `a`, with `a` being the source of each edge.
/// - `Undirected`, `Incoming`: All edges connected to `a`, with `a` being the target of each edge.
///
/// This is an extended version of the trait `IntoNeighborsDirected`; the former
/// only iterates over the target node identifiers, while this trait
/// yields edge references (trait [`EdgeRef`][er]).
///
/// [er]: trait.EdgeRef.html
pub trait IntoEdgesDirected : IntoEdges + IntoNeighborsDirected {
@section type
type EdgesDirected: Iterator<Item=Self::EdgeRef>;
@section self
fn edges_directed(self, a: Self::NodeId, dir: Direction) -> Self::EdgesDirected;
}
}
IntoEdgesDirected! {delegate_impl []}
trait_template! {
/// Access to the sequence of the graphs `NodeId`s.
pub trait IntoNodeIdentifiers : GraphRef {
@section type
type NodeIdentifiers: Iterator<Item=Self::NodeId>;
@section self
fn node_identifiers(self) -> Self::NodeIdentifiers;
}
}
IntoNodeIdentifiers! {delegate_impl []}
IntoNeighborsDirected! {delegate_impl []}
trait_template! {
/// Define associated data for nodes and edges
pub trait Data : GraphBase {
@section type
type NodeWeight;
type EdgeWeight;
}
}
Data! {delegate_impl []}
Data! {delegate_impl [['a, G], G, &'a mut G, deref]}
/// An edge reference.
///
/// Edge references are used by traits `IntoEdges` and `IntoEdgeReferences`.
pub trait EdgeRef: Copy {
type NodeId;
type EdgeId;
type Weight;
/// The source node of the edge.
fn source(&self) -> Self::NodeId;
/// The target node of the edge.
fn target(&self) -> Self::NodeId;
/// A reference to the weight of the edge.
fn weight(&self) -> &Self::Weight;
/// The edges identifier.
fn id(&self) -> Self::EdgeId;
}
impl<N, E> EdgeRef for (N, N, &E)
where
N: Copy,
{
type NodeId = N;
type EdgeId = (N, N);
type Weight = E;
fn source(&self) -> N {
self.0
}
fn target(&self) -> N {
self.1
}
fn weight(&self) -> &E {
self.2
}
fn id(&self) -> (N, N) {
(self.0, self.1)
}
}
/// A node reference.
pub trait NodeRef: Copy {
type NodeId;
type Weight;
fn id(&self) -> Self::NodeId;
fn weight(&self) -> &Self::Weight;
}
trait_template! {
/// Access to the sequence of the graphs nodes
pub trait IntoNodeReferences : Data + IntoNodeIdentifiers {
@section type
type NodeRef: NodeRef<NodeId=Self::NodeId, Weight=Self::NodeWeight>;
type NodeReferences: Iterator<Item=Self::NodeRef>;
@section self
fn node_references(self) -> Self::NodeReferences;
}
}
IntoNodeReferences! {delegate_impl []}
impl<Id> NodeRef for (Id, ())
where
Id: Copy,
{
type NodeId = Id;
type Weight = ();
fn id(&self) -> Self::NodeId {
self.0
}
fn weight(&self) -> &Self::Weight {
static DUMMY: () = ();
&DUMMY
}
}
impl<Id, W> NodeRef for (Id, &W)
where
Id: Copy,
{
type NodeId = Id;
type Weight = W;
fn id(&self) -> Self::NodeId {
self.0
}
fn weight(&self) -> &Self::Weight {
self.1
}
}
trait_template! {
/// Access to the sequence of the graphs edges
pub trait IntoEdgeReferences : Data + GraphRef {
@section type
type EdgeRef: EdgeRef<NodeId=Self::NodeId, EdgeId=Self::EdgeId,
Weight=Self::EdgeWeight>;
type EdgeReferences: Iterator<Item=Self::EdgeRef>;
@section self
fn edge_references(self) -> Self::EdgeReferences;
}
}
IntoEdgeReferences! {delegate_impl [] }
trait_template! {
/// Edge kind property (directed or undirected edges)
pub trait GraphProp : GraphBase {
@section type
/// The kind of edges in the graph.
type EdgeType: EdgeType;
@section nodelegate
fn is_directed(&self) -> bool {
<Self::EdgeType>::is_directed()
}
}
}
GraphProp! {delegate_impl []}
trait_template! {
/// The graphs `NodeId`s map to indices
#[allow(clippy::needless_arbitrary_self_type)]
pub trait NodeIndexable : GraphBase {
@section self
/// Return an upper bound of the node indices in the graph
/// (suitable for the size of a bitmap).
fn node_bound(self: &Self) -> usize;
/// Convert `a` to an integer index.
fn to_index(self: &Self, a: Self::NodeId) -> usize;
/// Convert `i` to a node index. `i` must be a valid value in the graph.
fn from_index(self: &Self, i: usize) -> Self::NodeId;
}
}
NodeIndexable! {delegate_impl []}
trait_template! {
/// The graphs `NodeId`s map to indices
#[allow(clippy::needless_arbitrary_self_type)]
pub trait EdgeIndexable : GraphBase {
@section self
/// Return an upper bound of the edge indices in the graph
/// (suitable for the size of a bitmap).
fn edge_bound(self: &Self) -> usize;
/// Convert `a` to an integer index.
fn to_index(self: &Self, a: Self::EdgeId) -> usize;
/// Convert `i` to an edge index. `i` must be a valid value in the graph.
fn from_index(self: &Self, i: usize) -> Self::EdgeId;
}
}
EdgeIndexable! {delegate_impl []}
trait_template! {
/// A graph with a known node count.
#[allow(clippy::needless_arbitrary_self_type)]
pub trait NodeCount : GraphBase {
@section self
fn node_count(self: &Self) -> usize;
}
}
NodeCount! {delegate_impl []}
trait_template! {
/// The graphs `NodeId`s map to indices, in a range without holes.
///
/// The graph's node identifiers correspond to exactly the indices
/// `0..self.node_bound()`.
pub trait NodeCompactIndexable : NodeIndexable + NodeCount { }
}
NodeCompactIndexable! {delegate_impl []}
/// A mapping for storing the visited status for NodeId `N`.
pub trait VisitMap<N> {
/// Mark `a` as visited.
///
/// Return **true** if this is the first visit, false otherwise.
fn visit(&mut self, a: N) -> bool;
/// Return whether `a` has been visited before.
fn is_visited(&self, a: &N) -> bool;
}
impl<Ix> VisitMap<Ix> for FixedBitSet
where
Ix: IndexType,
{
fn visit(&mut self, x: Ix) -> bool {
!self.put(x.index())
}
fn is_visited(&self, x: &Ix) -> bool {
self.contains(x.index())
}
}
impl<N, S> VisitMap<N> for HashSet<N, S>
where
N: Hash + Eq,
S: BuildHasher,
{
fn visit(&mut self, x: N) -> bool {
self.insert(x)
}
fn is_visited(&self, x: &N) -> bool {
self.contains(x)
}
}
trait_template! {
/// A graph that can create a map that tracks the visited status of its nodes.
#[allow(clippy::needless_arbitrary_self_type)]
pub trait Visitable : GraphBase {
@section type
/// The associated map type
type Map: VisitMap<Self::NodeId>;
@section self
/// Create a new visitor map
fn visit_map(self: &Self) -> Self::Map;
/// Reset the visitor map (and resize to new size of graph if needed)
fn reset_map(self: &Self, map: &mut Self::Map);
}
}
Visitable! {delegate_impl []}
trait_template! {
/// Create or access the adjacency matrix of a graph.
///
/// The implementor can either create an adjacency matrix, or it can return
/// a placeholder if it has the needed representation internally.
#[allow(clippy::needless_arbitrary_self_type)]
pub trait GetAdjacencyMatrix : GraphBase {
@section type
/// The associated adjacency matrix type
type AdjMatrix;
@section self
/// Create the adjacency matrix
fn adjacency_matrix(self: &Self) -> Self::AdjMatrix;
/// Return true if there is an edge from `a` to `b`, false otherwise.
///
/// Computes in O(1) time.
fn is_adjacent(self: &Self, matrix: &Self::AdjMatrix, a: Self::NodeId, b: Self::NodeId) -> bool;
}
}
GetAdjacencyMatrix! {delegate_impl []}
trait_template! {
/// A graph with a known edge count.
#[allow(clippy::needless_arbitrary_self_type)]
pub trait EdgeCount : GraphBase {
@section self
/// Return the number of edges in the graph.
fn edge_count(self: &Self) -> usize;
}
}
EdgeCount! {delegate_impl []}
mod filter;
mod reversed;
mod undirected_adaptor;

184
vendor/petgraph/src/visit/reversed.rs vendored Normal file
View File

@@ -0,0 +1,184 @@
use crate::{Direction, Incoming};
use crate::visit::{
Data, EdgeCount, EdgeIndexable, EdgeRef, GetAdjacencyMatrix, GraphBase, GraphProp, GraphRef,
IntoEdgeReferences, IntoEdges, IntoEdgesDirected, IntoNeighbors, IntoNeighborsDirected,
IntoNodeIdentifiers, IntoNodeReferences, NodeCompactIndexable, NodeCount, NodeIndexable,
Visitable,
};
/// An edge-reversing graph adaptor.
///
/// All edges have the opposite direction with `Reversed`.
#[derive(Copy, Clone, Debug)]
pub struct Reversed<G>(pub G);
impl<G: GraphBase> GraphBase for Reversed<G> {
type NodeId = G::NodeId;
type EdgeId = G::EdgeId;
}
impl<G: GraphRef> GraphRef for Reversed<G> {}
Data! {delegate_impl [[G], G, Reversed<G>, access0]}
impl<G> IntoNeighbors for Reversed<G>
where
G: IntoNeighborsDirected,
{
type Neighbors = G::NeighborsDirected;
fn neighbors(self, n: G::NodeId) -> G::NeighborsDirected {
self.0.neighbors_directed(n, Incoming)
}
}
impl<G> IntoNeighborsDirected for Reversed<G>
where
G: IntoNeighborsDirected,
{
type NeighborsDirected = G::NeighborsDirected;
fn neighbors_directed(self, n: G::NodeId, d: Direction) -> G::NeighborsDirected {
self.0.neighbors_directed(n, d.opposite())
}
}
impl<G> IntoEdges for Reversed<G>
where
G: IntoEdgesDirected,
{
type Edges = ReversedEdges<G::EdgesDirected>;
fn edges(self, a: Self::NodeId) -> Self::Edges {
ReversedEdges {
iter: self.0.edges_directed(a, Incoming),
}
}
}
impl<G> IntoEdgesDirected for Reversed<G>
where
G: IntoEdgesDirected,
{
type EdgesDirected = ReversedEdges<G::EdgesDirected>;
fn edges_directed(self, a: Self::NodeId, dir: Direction) -> Self::Edges {
ReversedEdges {
iter: self.0.edges_directed(a, dir.opposite()),
}
}
}
impl<G: Visitable> Visitable for Reversed<G> {
type Map = G::Map;
fn visit_map(&self) -> G::Map {
self.0.visit_map()
}
fn reset_map(&self, map: &mut Self::Map) {
self.0.reset_map(map);
}
}
/// A reversed edges iterator.
#[derive(Debug, Clone)]
pub struct ReversedEdges<I> {
iter: I,
}
impl<I> Iterator for ReversedEdges<I>
where
I: Iterator,
I::Item: EdgeRef,
{
type Item = ReversedEdgeReference<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(ReversedEdgeReference)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
/// A reversed edge reference
#[derive(Copy, Clone, Debug)]
pub struct ReversedEdgeReference<R>(R);
impl<R> ReversedEdgeReference<R> {
/// Return the original, unreversed edge reference.
pub fn as_unreversed(&self) -> &R {
&self.0
}
/// Consume `self` and return the original, unreversed edge reference.
pub fn into_unreversed(self) -> R {
self.0
}
}
/// An edge reference
impl<R> EdgeRef for ReversedEdgeReference<R>
where
R: EdgeRef,
{
type NodeId = R::NodeId;
type EdgeId = R::EdgeId;
type Weight = R::Weight;
fn source(&self) -> Self::NodeId {
self.0.target()
}
fn target(&self) -> Self::NodeId {
self.0.source()
}
fn weight(&self) -> &Self::Weight {
self.0.weight()
}
fn id(&self) -> Self::EdgeId {
self.0.id()
}
}
impl<G> IntoEdgeReferences for Reversed<G>
where
G: IntoEdgeReferences,
{
type EdgeRef = ReversedEdgeReference<G::EdgeRef>;
type EdgeReferences = ReversedEdgeReferences<G::EdgeReferences>;
fn edge_references(self) -> Self::EdgeReferences {
ReversedEdgeReferences {
iter: self.0.edge_references(),
}
}
}
/// A reversed edge references iterator.
#[derive(Debug, Clone)]
pub struct ReversedEdgeReferences<I> {
iter: I,
}
impl<I> Iterator for ReversedEdgeReferences<I>
where
I: Iterator,
I::Item: EdgeRef,
{
type Item = ReversedEdgeReference<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(ReversedEdgeReference)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
macro_rules! access0 {
($e:expr) => {
$e.0
};
}
NodeIndexable! {delegate_impl [[G], G, Reversed<G>, access0]}
NodeCompactIndexable! {delegate_impl [[G], G, Reversed<G>, access0]}
IntoNodeIdentifiers! {delegate_impl [[G], G, Reversed<G>, access0]}
IntoNodeReferences! {delegate_impl [[G], G, Reversed<G>, access0]}
GraphProp! {delegate_impl [[G], G, Reversed<G>, access0]}
NodeCount! {delegate_impl [[G], G, Reversed<G>, access0]}
EdgeCount! {delegate_impl [[G], G, Reversed<G>, access0]}
EdgeIndexable! {delegate_impl [[G], G, Reversed<G>, access0]}
GetAdjacencyMatrix! {delegate_impl [[G], G, Reversed<G>, access0]}

536
vendor/petgraph/src/visit/traversal.rs vendored Normal file
View File

@@ -0,0 +1,536 @@
use super::{GraphRef, IntoNodeIdentifiers, Reversed};
use super::{IntoNeighbors, IntoNeighborsDirected, VisitMap, Visitable};
use crate::Incoming;
use std::collections::VecDeque;
/// Visit nodes of a graph in a depth-first-search (DFS) emitting nodes in
/// preorder (when they are first discovered).
///
/// The traversal starts at a given node and only traverses nodes reachable
/// from it.
///
/// `Dfs` is not recursive.
///
/// `Dfs` does not itself borrow the graph, and because of this you can run
/// a traversal over a graph while still retaining mutable access to it, if you
/// use it like the following example:
///
/// ```
/// use petgraph::Graph;
/// use petgraph::visit::Dfs;
///
/// let mut graph = Graph::<_,()>::new();
/// let a = graph.add_node(0);
///
/// let mut dfs = Dfs::new(&graph, a);
/// while let Some(nx) = dfs.next(&graph) {
/// // we can access `graph` mutably here still
/// graph[nx] += 1;
/// }
///
/// assert_eq!(graph[a], 1);
/// ```
///
/// **Note:** The algorithm may not behave correctly if nodes are removed
/// during iteration. It may not necessarily visit added nodes or edges.
#[derive(Clone, Debug)]
pub struct Dfs<N, VM> {
/// The stack of nodes to visit
pub stack: Vec<N>,
/// The map of discovered nodes
pub discovered: VM,
}
impl<N, VM> Default for Dfs<N, VM>
where
VM: Default,
{
fn default() -> Self {
Dfs {
stack: Vec::new(),
discovered: VM::default(),
}
}
}
impl<N, VM> Dfs<N, VM>
where
N: Copy + PartialEq,
VM: VisitMap<N>,
{
/// Create a new **Dfs**, using the graph's visitor map, and put **start**
/// in the stack of nodes to visit.
pub fn new<G>(graph: G, start: N) -> Self
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
let mut dfs = Dfs::empty(graph);
dfs.move_to(start);
dfs
}
/// Create a `Dfs` from a vector and a visit map
pub fn from_parts(stack: Vec<N>, discovered: VM) -> Self {
Dfs { stack, discovered }
}
/// Clear the visit state
pub fn reset<G>(&mut self, graph: G)
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
graph.reset_map(&mut self.discovered);
self.stack.clear();
}
/// Create a new **Dfs** using the graph's visitor map, and no stack.
pub fn empty<G>(graph: G) -> Self
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
Dfs {
stack: Vec::new(),
discovered: graph.visit_map(),
}
}
/// Keep the discovered map, but clear the visit stack and restart
/// the dfs from a particular node.
pub fn move_to(&mut self, start: N) {
self.stack.clear();
self.stack.push(start);
}
/// Return the next node in the dfs, or **None** if the traversal is done.
pub fn next<G>(&mut self, graph: G) -> Option<N>
where
G: IntoNeighbors<NodeId = N>,
{
while let Some(node) = self.stack.pop() {
if self.discovered.visit(node) {
for succ in graph.neighbors(node) {
if !self.discovered.is_visited(&succ) {
self.stack.push(succ);
}
}
return Some(node);
}
}
None
}
}
/// Visit nodes in a depth-first-search (DFS) emitting nodes in postorder
/// (each node after all its descendants have been emitted).
///
/// `DfsPostOrder` is not recursive.
///
/// The traversal starts at a given node and only traverses nodes reachable
/// from it.
#[derive(Clone, Debug)]
pub struct DfsPostOrder<N, VM> {
/// The stack of nodes to visit
pub stack: Vec<N>,
/// The map of discovered nodes
pub discovered: VM,
/// The map of finished nodes
pub finished: VM,
}
impl<N, VM> Default for DfsPostOrder<N, VM>
where
VM: Default,
{
fn default() -> Self {
DfsPostOrder {
stack: Vec::new(),
discovered: VM::default(),
finished: VM::default(),
}
}
}
impl<N, VM> DfsPostOrder<N, VM>
where
N: Copy + PartialEq,
VM: VisitMap<N>,
{
/// Create a new `DfsPostOrder` using the graph's visitor map, and put
/// `start` in the stack of nodes to visit.
pub fn new<G>(graph: G, start: N) -> Self
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
let mut dfs = Self::empty(graph);
dfs.move_to(start);
dfs
}
/// Create a new `DfsPostOrder` using the graph's visitor map, and no stack.
pub fn empty<G>(graph: G) -> Self
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
DfsPostOrder {
stack: Vec::new(),
discovered: graph.visit_map(),
finished: graph.visit_map(),
}
}
/// Clear the visit state
pub fn reset<G>(&mut self, graph: G)
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
graph.reset_map(&mut self.discovered);
graph.reset_map(&mut self.finished);
self.stack.clear();
}
/// Keep the discovered and finished map, but clear the visit stack and restart
/// the dfs from a particular node.
pub fn move_to(&mut self, start: N) {
self.stack.clear();
self.stack.push(start);
}
/// Return the next node in the traversal, or `None` if the traversal is done.
pub fn next<G>(&mut self, graph: G) -> Option<N>
where
G: IntoNeighbors<NodeId = N>,
{
while let Some(&nx) = self.stack.last() {
if self.discovered.visit(nx) {
// First time visiting `nx`: Push neighbors, don't pop `nx`
for succ in graph.neighbors(nx) {
if !self.discovered.is_visited(&succ) {
self.stack.push(succ);
}
}
} else {
self.stack.pop();
if self.finished.visit(nx) {
// Second time: All reachable nodes must have been finished
return Some(nx);
}
}
}
None
}
}
/// A breadth first search (BFS) of a graph.
///
/// The traversal starts at a given node and only traverses nodes reachable
/// from it.
///
/// `Bfs` is not recursive.
///
/// `Bfs` does not itself borrow the graph, and because of this you can run
/// a traversal over a graph while still retaining mutable access to it, if you
/// use it like the following example:
///
/// ```
/// use petgraph::Graph;
/// use petgraph::visit::Bfs;
///
/// let mut graph = Graph::<_,()>::new();
/// let a = graph.add_node(0);
///
/// let mut bfs = Bfs::new(&graph, a);
/// while let Some(nx) = bfs.next(&graph) {
/// // we can access `graph` mutably here still
/// graph[nx] += 1;
/// }
///
/// assert_eq!(graph[a], 1);
/// ```
///
/// **Note:** The algorithm may not behave correctly if nodes are removed
/// during iteration. It may not necessarily visit added nodes or edges.
#[derive(Clone)]
pub struct Bfs<N, VM> {
/// The queue of nodes to visit
pub stack: VecDeque<N>,
/// The map of discovered nodes
pub discovered: VM,
}
impl<N, VM> Default for Bfs<N, VM>
where
VM: Default,
{
fn default() -> Self {
Bfs {
stack: VecDeque::new(),
discovered: VM::default(),
}
}
}
impl<N, VM> Bfs<N, VM>
where
N: Copy + PartialEq,
VM: VisitMap<N>,
{
/// Create a new **Bfs**, using the graph's visitor map, and put **start**
/// in the stack of nodes to visit.
pub fn new<G>(graph: G, start: N) -> Self
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
let mut discovered = graph.visit_map();
discovered.visit(start);
let mut stack = VecDeque::new();
stack.push_front(start);
Bfs { stack, discovered }
}
/// Return the next node in the bfs, or **None** if the traversal is done.
pub fn next<G>(&mut self, graph: G) -> Option<N>
where
G: IntoNeighbors<NodeId = N>,
{
if let Some(node) = self.stack.pop_front() {
for succ in graph.neighbors(node) {
if self.discovered.visit(succ) {
self.stack.push_back(succ);
}
}
return Some(node);
}
None
}
}
/// A topological order traversal for a graph.
///
/// **Note** that `Topo` only visits nodes that are not part of cycles,
/// i.e. nodes in a true DAG. Use other visitors like `DfsPostOrder` or
/// algorithms like kosaraju_scc to handle graphs with possible cycles.
#[derive(Clone)]
pub struct Topo<N, VM> {
tovisit: Vec<N>,
ordered: VM,
}
impl<N, VM> Default for Topo<N, VM>
where
VM: Default,
{
fn default() -> Self {
Topo {
tovisit: Vec::new(),
ordered: VM::default(),
}
}
}
impl<N, VM> Topo<N, VM>
where
N: Copy + PartialEq,
VM: VisitMap<N>,
{
/// Create a new `Topo`, using the graph's visitor map, and put all
/// initial nodes in the to visit list.
pub fn new<G>(graph: G) -> Self
where
G: IntoNodeIdentifiers + IntoNeighborsDirected + Visitable<NodeId = N, Map = VM>,
{
let mut topo = Self::empty(graph);
topo.extend_with_initials(graph);
topo
}
/// Create a new `Topo` with initial nodes.
///
/// Nodes with incoming edges are ignored.
pub fn with_initials<G, I>(graph: G, initials: I) -> Self
where
G: IntoNeighborsDirected + Visitable<NodeId = N, Map = VM>,
I: IntoIterator<Item = N>,
{
Topo {
tovisit: initials
.into_iter()
.filter(|&n| graph.neighbors_directed(n, Incoming).next().is_none())
.collect(),
ordered: graph.visit_map(),
}
}
fn extend_with_initials<G>(&mut self, g: G)
where
G: IntoNodeIdentifiers + IntoNeighborsDirected<NodeId = N>,
{
// find all initial nodes (nodes without incoming edges)
self.tovisit.extend(
g.node_identifiers()
.filter(move |&a| g.neighbors_directed(a, Incoming).next().is_none()),
);
}
/* Private until it has a use */
/// Create a new `Topo`, using the graph's visitor map with *no* starting
/// index specified.
fn empty<G>(graph: G) -> Self
where
G: GraphRef + Visitable<NodeId = N, Map = VM>,
{
Topo {
ordered: graph.visit_map(),
tovisit: Vec::new(),
}
}
/// Clear visited state, and put all initial nodes in the to visit list.
pub fn reset<G>(&mut self, graph: G)
where
G: IntoNodeIdentifiers + IntoNeighborsDirected + Visitable<NodeId = N, Map = VM>,
{
graph.reset_map(&mut self.ordered);
self.tovisit.clear();
self.extend_with_initials(graph);
}
/// Return the next node in the current topological order traversal, or
/// `None` if the traversal is at the end.
///
/// *Note:* The graph may not have a complete topological order, and the only
/// way to know is to run the whole traversal and make sure it visits every node.
pub fn next<G>(&mut self, g: G) -> Option<N>
where
G: IntoNeighborsDirected + Visitable<NodeId = N, Map = VM>,
{
// Take an unvisited element and find which of its neighbors are next
while let Some(nix) = self.tovisit.pop() {
if self.ordered.is_visited(&nix) {
continue;
}
self.ordered.visit(nix);
for neigh in g.neighbors(nix) {
// Look at each neighbor, and those that only have incoming edges
// from the already ordered list, they are the next to visit.
if Reversed(g)
.neighbors(neigh)
.all(|b| self.ordered.is_visited(&b))
{
self.tovisit.push(neigh);
}
}
return Some(nix);
}
None
}
}
/// A walker is a traversal state, but where part of the traversal
/// information is supplied manually to each next call.
///
/// This for example allows graph traversals that don't hold a borrow of the
/// graph they are traversing.
pub trait Walker<Context> {
type Item;
/// Advance to the next item
fn walk_next(&mut self, context: Context) -> Option<Self::Item>;
/// Create an iterator out of the walker and given `context`.
fn iter(self, context: Context) -> WalkerIter<Self, Context>
where
Self: Sized,
Context: Clone,
{
WalkerIter {
walker: self,
context,
}
}
}
/// A walker and its context wrapped into an iterator.
#[derive(Clone, Debug)]
pub struct WalkerIter<W, C> {
walker: W,
context: C,
}
impl<W, C> WalkerIter<W, C>
where
W: Walker<C>,
C: Clone,
{
pub fn context(&self) -> C {
self.context.clone()
}
pub fn inner_ref(&self) -> &W {
&self.walker
}
pub fn inner_mut(&mut self) -> &mut W {
&mut self.walker
}
}
impl<W, C> Iterator for WalkerIter<W, C>
where
W: Walker<C>,
C: Clone,
{
type Item = W::Item;
fn next(&mut self) -> Option<Self::Item> {
self.walker.walk_next(self.context.clone())
}
}
impl<C, W: ?Sized> Walker<C> for &mut W
where
W: Walker<C>,
{
type Item = W::Item;
fn walk_next(&mut self, context: C) -> Option<Self::Item> {
(**self).walk_next(context)
}
}
impl<G> Walker<G> for Dfs<G::NodeId, G::Map>
where
G: IntoNeighbors + Visitable,
{
type Item = G::NodeId;
fn walk_next(&mut self, context: G) -> Option<Self::Item> {
self.next(context)
}
}
impl<G> Walker<G> for DfsPostOrder<G::NodeId, G::Map>
where
G: IntoNeighbors + Visitable,
{
type Item = G::NodeId;
fn walk_next(&mut self, context: G) -> Option<Self::Item> {
self.next(context)
}
}
impl<G> Walker<G> for Bfs<G::NodeId, G::Map>
where
G: IntoNeighbors + Visitable,
{
type Item = G::NodeId;
fn walk_next(&mut self, context: G) -> Option<Self::Item> {
self.next(context)
}
}
impl<G> Walker<G> for Topo<G::NodeId, G::Map>
where
G: IntoNeighborsDirected + Visitable,
{
type Item = G::NodeId;
fn walk_next(&mut self, context: G) -> Option<Self::Item> {
self.next(context)
}
}

View File

@@ -0,0 +1,111 @@
use crate::visit::{
Data, GraphBase, GraphProp, GraphRef, IntoEdgeReferences, IntoEdges, IntoEdgesDirected,
IntoNeighbors, IntoNeighborsDirected, IntoNodeIdentifiers, IntoNodeReferences,
NodeCompactIndexable, NodeCount, NodeIndexable, Visitable,
};
use crate::Direction;
/// An edge direction removing graph adaptor.
#[derive(Copy, Clone, Debug)]
pub struct UndirectedAdaptor<G>(pub G);
impl<G: GraphRef> GraphRef for UndirectedAdaptor<G> {}
impl<G> IntoNeighbors for UndirectedAdaptor<G>
where
G: IntoNeighborsDirected,
{
type Neighbors = std::iter::Chain<G::NeighborsDirected, G::NeighborsDirected>;
fn neighbors(self, n: G::NodeId) -> Self::Neighbors {
self.0
.neighbors_directed(n, Direction::Incoming)
.chain(self.0.neighbors_directed(n, Direction::Outgoing))
}
}
impl<G> IntoEdges for UndirectedAdaptor<G>
where
G: IntoEdgesDirected,
{
type Edges = std::iter::Chain<G::EdgesDirected, G::EdgesDirected>;
fn edges(self, a: Self::NodeId) -> Self::Edges {
self.0
.edges_directed(a, Direction::Incoming)
.chain(self.0.edges_directed(a, Direction::Outgoing))
}
}
impl<G> GraphProp for UndirectedAdaptor<G>
where
G: GraphBase,
{
type EdgeType = crate::Undirected;
fn is_directed(&self) -> bool {
false
}
}
macro_rules! access0 {
($e:expr) => {
$e.0
};
}
GraphBase! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
Data! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
IntoEdgeReferences! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
Visitable! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
NodeIndexable! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
NodeCompactIndexable! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
IntoNodeIdentifiers! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
IntoNodeReferences! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
NodeCount! {delegate_impl [[G], G, UndirectedAdaptor<G>, access0]}
#[cfg(test)]
mod tests {
use super::*;
use crate::graph::{DiGraph, Graph};
use crate::visit::Dfs;
static LINEAR_EDGES: [(u32, u32); 5] = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)];
#[test]
pub fn test_is_reachable() {
// create a linear digraph, choose a node in the centre and check all nodes are visited
// by a dfs
let graph = DiGraph::<(), ()>::from_edges(&LINEAR_EDGES);
let mut nodes = graph.node_identifiers().collect::<Vec<_>>();
nodes.sort();
let graph = UndirectedAdaptor(&graph);
use crate::visit::Walker;
let mut visited_nodes: Vec<_> = Dfs::new(&graph, nodes[2]).iter(&graph).collect();
visited_nodes.sort();
assert_eq!(visited_nodes, nodes);
}
#[test]
pub fn test_neighbors_count() {
{
let graph = Graph::<(), ()>::from_edges(&LINEAR_EDGES);
let graph = UndirectedAdaptor(&graph);
let mut nodes = graph.node_identifiers().collect::<Vec<_>>();
nodes.sort();
assert_eq!(graph.neighbors(nodes[1]).count(), 2);
}
{
let graph = Graph::<(), ()>::from_edges(&LINEAR_EDGES);
let graph = UndirectedAdaptor(&graph);
let mut nodes = graph.node_identifiers().collect::<Vec<_>>();
nodes.sort();
assert_eq!(graph.neighbors(nodes[1]).count(), 2);
}
}
}

View File

@@ -0,0 +1,202 @@
use petgraph::{
adj::List,
csr::Csr,
visit::{EdgeRef, GetAdjacencyMatrix, GraphProp, IntoEdgeReferences, IntoNodeIdentifiers},
Directed, EdgeType, Graph, Undirected,
};
#[cfg(feature = "graphmap")]
use petgraph::graphmap::GraphMap;
#[cfg(feature = "matrix_graph")]
use petgraph::matrix_graph::MatrixGraph;
#[cfg(feature = "stable_graph")]
use petgraph::stable_graph::StableGraph;
fn test_adjacency_matrix<G>(g: G)
where
G: GetAdjacencyMatrix + IntoNodeIdentifiers + IntoEdgeReferences + GraphProp,
{
let matrix = g.adjacency_matrix();
let node_ids: Vec<G::NodeId> = g.node_identifiers().collect();
let edges: Vec<(G::NodeId, G::NodeId)> = g
.edge_references()
.map(|edge| (edge.source(), edge.target()))
.collect();
for &a in &node_ids {
for &b in &node_ids {
if edges.contains(&(a, b)) || (!g.is_directed() && edges.contains(&(b, a))) {
assert!(g.is_adjacent(&matrix, a, b));
} else {
assert!(!g.is_adjacent(&matrix, a, b));
}
}
}
}
fn test_adjacency_matrix_for_graph<Ty: EdgeType>() {
for (order, edges) in TEST_CASES {
let mut g: Graph<(), (), Ty, u16> = Graph::with_capacity(order, edges.len());
for _ in 0..order {
g.add_node(());
}
g.extend_with_edges(edges);
test_adjacency_matrix(&g);
}
}
#[test]
fn test_adjacency_matrix_for_graph_directed() {
test_adjacency_matrix_for_graph::<Directed>();
}
#[test]
fn test_adjacency_matrix_for_graph_undirected() {
test_adjacency_matrix_for_graph::<Undirected>();
}
#[cfg(feature = "stable_graph")]
fn test_adjacency_matrix_for_stable_graph<Ty: EdgeType>() {
for (order, edges) in TEST_CASES {
let mut g: StableGraph<(), (), Ty, u16> = StableGraph::with_capacity(order, edges.len());
for _ in 0..order {
g.add_node(());
}
g.extend_with_edges(edges);
test_adjacency_matrix(&g);
}
}
#[cfg(feature = "stable_graph")]
#[test]
fn test_adjacency_matrix_for_stable_graph_directed() {
test_adjacency_matrix_for_stable_graph::<Directed>();
}
#[cfg(feature = "stable_graph")]
#[test]
fn test_adjacency_matrix_for_stable_graph_undirected() {
test_adjacency_matrix_for_stable_graph::<Undirected>();
}
#[cfg(feature = "graphmap")]
fn test_adjacency_matrix_for_graph_map<Ty: EdgeType>() {
for (order, edges) in TEST_CASES {
let mut g: GraphMap<u16, (), Ty> = GraphMap::with_capacity(order, edges.len());
for i in 0..order {
g.add_node(i as u16);
}
for &(a, b) in edges {
g.add_edge(a, b, ());
}
test_adjacency_matrix(&g);
}
}
#[cfg(feature = "graphmap")]
#[test]
fn test_adjacency_matrix_for_graph_map_directed() {
test_adjacency_matrix_for_graph_map::<Directed>();
}
#[cfg(feature = "graphmap")]
#[test]
fn test_adjacency_matrix_for_graph_map_undirected() {
test_adjacency_matrix_for_graph_map::<Undirected>();
}
#[cfg(feature = "matrix_graph")]
fn test_adjacency_matrix_for_matrix_graph<Ty: EdgeType>() {
for (order, edges) in TEST_CASES {
let mut g: MatrixGraph<(), (), Ty> = MatrixGraph::with_capacity(order);
for _ in 0..order {
g.add_node(());
}
g.extend_with_edges(edges);
test_adjacency_matrix(&g);
}
}
#[cfg(feature = "matrix_graph")]
#[test]
fn test_adjacency_matrix_for_matrix_graph_directed() {
test_adjacency_matrix_for_matrix_graph::<Directed>();
}
#[cfg(feature = "matrix_graph")]
#[test]
fn test_adjacency_matrix_for_matrix_graph_undirected() {
test_adjacency_matrix_for_matrix_graph::<Undirected>();
}
fn test_adjacency_matrix_for_csr<Ty: EdgeType>() {
for (order, edges) in TEST_CASES {
let mut g: Csr<(), (), Ty, u16> = Csr::new();
for _ in 0..order {
g.add_node(());
}
for &(a, b) in edges {
g.add_edge(a, b, ());
}
test_adjacency_matrix(&g);
}
}
#[test]
fn test_adjacency_matrix_for_csr_directed() {
test_adjacency_matrix_for_csr::<Directed>();
}
#[test]
fn test_adjacency_matrix_for_csr_undirected() {
test_adjacency_matrix_for_csr::<Undirected>();
}
#[test]
fn test_adjacency_matrix_for_adj_list() {
for (order, edges) in TEST_CASES {
let mut g: List<(), u16> = List::with_capacity(order);
for _ in 0..order {
g.add_node();
}
for &(a, b) in edges {
g.add_edge(a, b, ());
}
test_adjacency_matrix(&g);
}
}
// Test cases format: (graph order, graph edges)
#[rustfmt::skip]
const TEST_CASES: [(usize, &[(u16, u16)]); 10] = [
// Empty Graphs
(0, &[]),
(1, &[]),
(2, &[]),
// Graph with a loop
(2, &[(0, 0)]),
// Small Graphs
(5, &[(0, 2), (0, 4), (1, 3), (3, 4)]),
(6, &[(2, 3)]),
(9, &[(1, 4), (2, 8), (3, 7), (4, 8), (5, 8)]),
// Complete Graphs
(2, &[(0, 1)]),
(7, &[(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 3), (2, 4), (2, 5), (2, 6), (3, 4), (3, 5), (3, 6), (4, 5), (4, 6), (5, 6)]),
// Petersen
(10, &[(0, 1), (0, 4), (0, 5), (1, 2), (1, 6), (2, 3), (2, 7), (3, 4), (3, 8), (4, 9), (5, 7), (5, 8), (6, 8), (6, 9), (7, 9)]),
];

59
vendor/petgraph/tests/coloring.rs vendored Normal file
View File

@@ -0,0 +1,59 @@
use petgraph::algo::dsatur_coloring;
use petgraph::{Graph, Undirected};
#[test]
fn dsatur_coloring_cycle6() {
let mut graph: Graph<(), (), Undirected> = Graph::new_undirected();
let a = graph.add_node(());
let d = graph.add_node(());
let b = graph.add_node(());
let c = graph.add_node(());
let e = graph.add_node(());
let f = graph.add_node(());
graph.extend_with_edges(&[(a, b), (b, c), (c, d), (d, e), (e, f), (f, e)]);
let (coloring, nb_colors) = dsatur_coloring(&graph);
assert_eq!(nb_colors, 2);
assert_eq!(coloring.len(), 6);
}
#[test]
fn dsatur_coloring_bipartite() {
let mut graph: Graph<(), (), Undirected> = Graph::new_undirected();
let a = graph.add_node(());
let d = graph.add_node(());
let b = graph.add_node(());
let c = graph.add_node(());
let e = graph.add_node(());
let f = graph.add_node(());
let g = graph.add_node(());
let h = graph.add_node(());
let i = graph.add_node(());
let j = graph.add_node(());
let k = graph.add_node(());
let l = graph.add_node(());
graph.extend_with_edges(&[
(a, b),
(a, g),
(a, l),
(b, d),
(b, h),
(b, k),
(c, d),
(c, k),
(d, l),
(e, f),
(e, j),
(f, i),
(f, l),
(g, h),
(g, j),
(g, k),
(h, i),
(i, j),
(i, k),
]);
let (_, nb_colors) = dsatur_coloring(&graph);
assert_eq!(nb_colors, 2);
}

341
vendor/petgraph/tests/floyd_warshall.rs vendored Normal file
View File

@@ -0,0 +1,341 @@
use petgraph::algo::floyd_warshall;
use petgraph::{prelude::*, Directed, Graph, Undirected};
use std::collections::HashMap;
#[test]
fn floyd_warshall_uniform_weight() {
let mut graph: Graph<(), (), Directed> = Graph::new();
let a = graph.add_node(());
let b = graph.add_node(());
let c = graph.add_node(());
let d = graph.add_node(());
let e = graph.add_node(());
let f = graph.add_node(());
let g = graph.add_node(());
let h = graph.add_node(());
graph.extend_with_edges(&[
(a, b),
(b, c),
(c, d),
(d, a),
(e, f),
(b, e),
(f, g),
(g, h),
(h, e),
]);
// a ----> b ----> e ----> f
// ^ | ^ |
// | v | v
// d <---- c h <---- g
let inf = std::i32::MAX;
let expected_res: HashMap<(NodeIndex, NodeIndex), i32> = [
((a, a), 0),
((a, b), 1),
((a, c), 2),
((a, d), 3),
((a, e), 2),
((a, f), 3),
((a, g), 4),
((a, h), 5),
((b, a), 3),
((b, b), 0),
((b, c), 1),
((b, d), 2),
((b, e), 1),
((b, f), 2),
((b, g), 3),
((b, h), 4),
((c, a), 2),
((c, b), 3),
((c, c), 0),
((c, d), 1),
((c, e), 4),
((c, f), 5),
((c, g), 6),
((c, h), 7),
((d, a), 1),
((d, b), 2),
((d, c), 3),
((d, d), 0),
((d, e), 3),
((d, f), 4),
((d, g), 5),
((d, h), 6),
((e, a), inf),
((e, b), inf),
((e, c), inf),
((e, d), inf),
((e, e), 0),
((e, f), 1),
((e, g), 2),
((e, h), 3),
((f, a), inf),
((f, b), inf),
((f, c), inf),
((f, d), inf),
((f, e), 3),
((f, f), 0),
((f, g), 1),
((f, h), 2),
((g, a), inf),
((g, b), inf),
((g, c), inf),
((g, d), inf),
((g, e), 2),
((g, f), 3),
((g, g), 0),
((g, h), 1),
((h, a), inf),
((h, b), inf),
((h, c), inf),
((h, d), inf),
((h, e), 1),
((h, f), 2),
((h, g), 3),
((h, h), 0),
]
.iter()
.cloned()
.collect();
let res = floyd_warshall(&graph, |_| 1_i32).unwrap();
let nodes = [a, b, c, d, e, f, g, h];
for node1 in &nodes {
for node2 in &nodes {
assert_eq!(
res.get(&(*node1, *node2)).unwrap(),
expected_res.get(&(*node1, *node2)).unwrap()
);
}
}
}
#[test]
fn floyd_warshall_weighted() {
let mut graph: Graph<(), (), Directed> = Graph::new();
let a = graph.add_node(());
let b = graph.add_node(());
let c = graph.add_node(());
let d = graph.add_node(());
graph.extend_with_edges(&[(a, b), (a, c), (a, d), (b, c), (b, d), (c, d)]);
let inf = std::i32::MAX;
let expected_res: HashMap<(NodeIndex, NodeIndex), i32> = [
((a, a), 0),
((a, b), 1),
((a, c), 3),
((a, d), 3),
((b, a), inf),
((b, b), 0),
((b, c), 2),
((b, d), 2),
((c, a), inf),
((c, b), inf),
((c, c), 0),
((c, d), 2),
((d, a), inf),
((d, b), inf),
((d, c), inf),
((d, d), 0),
]
.iter()
.cloned()
.collect();
let weight_map: HashMap<(NodeIndex, NodeIndex), i32> = [
((a, a), 0),
((a, b), 1),
((a, c), 4),
((a, d), 10),
((b, b), 0),
((b, c), 2),
((b, d), 2),
((c, c), 0),
((c, d), 2),
]
.iter()
.cloned()
.collect();
let res = floyd_warshall(&graph, |edge| {
if let Some(weight) = weight_map.get(&(edge.source(), edge.target())) {
*weight
} else {
inf
}
})
.unwrap();
let nodes = [a, b, c, d];
for node1 in &nodes {
for node2 in &nodes {
assert_eq!(
res.get(&(*node1, *node2)).unwrap(),
expected_res.get(&(*node1, *node2)).unwrap()
);
}
}
}
#[test]
fn floyd_warshall_weighted_undirected() {
let mut graph: Graph<(), (), Undirected> = Graph::new_undirected();
let a = graph.add_node(());
let b = graph.add_node(());
let c = graph.add_node(());
let d = graph.add_node(());
graph.extend_with_edges(&[(a, b), (a, c), (a, d), (b, d), (c, b), (c, d)]);
let inf = std::i32::MAX;
let expected_res: HashMap<(NodeIndex, NodeIndex), i32> = [
((a, a), 0),
((a, b), 1),
((a, c), 3),
((a, d), 3),
((b, a), 1),
((b, b), 0),
((b, c), 2),
((b, d), 2),
((c, a), 3),
((c, b), 2),
((c, c), 0),
((c, d), 2),
((d, a), 3),
((d, b), 2),
((d, c), 2),
((d, d), 0),
]
.iter()
.cloned()
.collect();
let weight_map: HashMap<(NodeIndex, NodeIndex), i32> = [
((a, a), 0),
((a, b), 1),
((a, c), 4),
((a, d), 10),
((b, b), 0),
((b, d), 2),
((c, b), 2),
((c, c), 0),
((c, d), 2),
]
.iter()
.cloned()
.collect();
let res = floyd_warshall(&graph, |edge| {
if let Some(weight) = weight_map.get(&(edge.source(), edge.target())) {
*weight
} else {
inf
}
})
.unwrap();
let nodes = [a, b, c, d];
for node1 in &nodes {
for node2 in &nodes {
assert_eq!(
res.get(&(*node1, *node2)).unwrap(),
expected_res.get(&(*node1, *node2)).unwrap()
);
}
}
}
#[test]
fn floyd_warshall_negative_cycle() {
let mut graph: Graph<(), (), Directed> = Graph::new();
let a = graph.add_node(());
let b = graph.add_node(());
let c = graph.add_node(());
graph.extend_with_edges(&[(a, b), (b, c), (c, a)]);
let inf = std::i32::MAX;
let weight_map: HashMap<(NodeIndex, NodeIndex), i32> = [
((a, a), 0),
((a, b), 1),
((b, b), 0),
((b, c), -3),
((c, c), 0),
((c, a), 1),
]
.iter()
.cloned()
.collect();
let res = floyd_warshall(&graph, |edge| {
if let Some(weight) = weight_map.get(&(edge.source(), edge.target())) {
*weight
} else {
inf
}
});
assert!(res.is_err());
}
#[test]
fn floyd_warshall_multiple_edges() {
let mut graph: Graph<(), i32, Directed> = Graph::new();
let a = graph.add_node(());
let b = graph.add_node(());
let c = graph.add_node(());
let d = graph.add_node(());
graph.extend_with_edges(&[
(a, b, 10),
(a, b, 1),
(a, c, 4),
(a, d, 10),
(b, c, 2),
(b, d, 2),
(c, d, 2),
(a, d, 100),
(c, d, 20),
(a, a, 5),
]);
let inf = std::i32::MAX;
let expected_res: HashMap<(NodeIndex, NodeIndex), i32> = [
((a, a), 0),
((a, b), 1),
((a, c), 3),
((a, d), 3),
((b, a), inf),
((b, b), 0),
((b, c), 2),
((b, d), 2),
((c, a), inf),
((c, b), inf),
((c, c), 0),
((c, d), 2),
((d, a), inf),
((d, b), inf),
((d, c), inf),
((d, d), 0),
]
.iter()
.cloned()
.collect();
let res = floyd_warshall(&graph, |edge| *edge.weight()).unwrap();
let nodes = [a, b, c, d];
for node1 in &nodes {
for node2 in &nodes {
assert_eq!(
res.get(&(*node1, *node2)).unwrap(),
expected_res.get(&(*node1, *node2)).unwrap()
);
}
}
}

121
vendor/petgraph/tests/ford_fulkerson.rs vendored Normal file
View File

@@ -0,0 +1,121 @@
use petgraph::algo::ford_fulkerson;
use petgraph::prelude::Graph;
#[test]
fn test_ford_fulkerson() {
// Example from https://downey.io/blog/max-flow-ford-fulkerson-algorithm-explanation/
let mut graph = Graph::<usize, u16>::new();
let source = graph.add_node(0);
let _ = graph.add_node(1);
let _ = graph.add_node(2);
let destination = graph.add_node(3);
graph.extend_with_edges(&[(0, 1, 3), (0, 2, 2), (1, 2, 5), (1, 3, 2), (2, 3, 3)]);
let (max_flow, _) = ford_fulkerson(&graph, source, destination);
assert_eq!(5, max_flow);
// Example from https://brilliant.org/wiki/ford-fulkerson-algorithm/
let mut graph = Graph::<usize, f32>::new();
let source = graph.add_node(0);
let _ = graph.add_node(1);
let _ = graph.add_node(2);
let _ = graph.add_node(3);
let _ = graph.add_node(4);
let destination = graph.add_node(5);
graph.extend_with_edges(&[
(0, 1, 4.),
(0, 2, 3.),
(1, 3, 4.),
(2, 4, 6.),
(3, 2, 3.),
(3, 5, 2.),
(4, 5, 6.),
]);
let (max_flow, _) = ford_fulkerson(&graph, source, destination);
assert_eq!(7.0, max_flow);
// Example from https://cp-algorithms.com/graph/edmonds_karp.html
let mut graph = Graph::<usize, f32>::new();
let source = graph.add_node(0);
let _ = graph.add_node(1);
let _ = graph.add_node(2);
let _ = graph.add_node(3);
let _ = graph.add_node(4);
let destination = graph.add_node(5);
graph.extend_with_edges(&[
(0, 1, 7.),
(0, 2, 4.),
(1, 3, 5.),
(1, 4, 3.),
(2, 1, 3.),
(2, 4, 2.),
(3, 5, 8.),
(4, 3, 3.),
(4, 5, 5.),
]);
let (max_flow, _) = ford_fulkerson(&graph, source, destination);
assert_eq!(10.0, max_flow);
// Example from https://www.programiz.com/dsa/ford-fulkerson-algorithm (corrected: result not 6 but 5)
let mut graph = Graph::<u8, f32>::new();
let source = graph.add_node(0);
let _ = graph.add_node(1);
let _ = graph.add_node(2);
let _ = graph.add_node(3);
let _ = graph.add_node(4);
let destination = graph.add_node(5);
graph.extend_with_edges(&[
(0, 1, 8.),
(0, 2, 3.),
(1, 3, 9.),
(2, 3, 7.),
(2, 4, 4.),
(3, 5, 2.),
(4, 5, 5.),
]);
let (max_flow, _) = ford_fulkerson(&graph, source, destination);
assert_eq!(5.0, max_flow);
let mut graph = Graph::<u8, u8>::new();
let source = graph.add_node(0);
let _ = graph.add_node(1);
let _ = graph.add_node(2);
let _ = graph.add_node(3);
let _ = graph.add_node(4);
let destination = graph.add_node(5);
graph.extend_with_edges(&[
(0, 1, 16),
(0, 2, 13),
(1, 2, 10),
(1, 3, 12),
(2, 1, 4),
(2, 4, 14),
(3, 2, 9),
(3, 5, 20),
(4, 3, 7),
(4, 5, 4),
]);
let (max_flow, _) = ford_fulkerson(&graph, source, destination);
assert_eq!(23, max_flow);
// Example taken from https://medium.com/@jithmisha/solving-the-maximum-flow-problem-with-ford-fulkerson-method-3fccc2883dc7
let mut graph = Graph::<u8, u8>::new();
let source = graph.add_node(0);
let _ = graph.add_node(1);
let _ = graph.add_node(2);
let _ = graph.add_node(3);
let _ = graph.add_node(4);
let destination = graph.add_node(5);
graph.extend_with_edges(&[
(0, 1, 10),
(0, 2, 10),
(1, 2, 2),
(1, 3, 4),
(1, 4, 8),
(2, 4, 9),
(3, 5, 10),
(4, 3, 6),
(4, 5, 10),
]);
let (max_flow, _) = ford_fulkerson(&graph, source, destination);
assert_eq!(19, max_flow);
}

Some files were not shown because too many files have changed in this diff Show More