petgraph-0.6.4/.cargo_vcs_info.json 0000644 00000000136 00000000001 0012655 0 ustar {
"git": {
"sha1": "47302280867627dc58b4dec628c85fe64d656186"
},
"path_in_vcs": ""
} petgraph-0.6.4/.github/ISSUE_TEMPLATE.md 0000644 0000000 0000000 00000002754 10461020230 0015522 0 ustar 0000000 0000000
### Test Case
Insert your test case here, ideally in the form of Rust code that creates a
graph.
### Steps To Reproduce
Insert instructions for reproducing the bug with the above test case:
* First, ...
* Then, ...
* ...
Bonus points if these STR are in the form of a `#[test]` that demonstrates the
bug, and can be used as a regression test once the bug is fixed
### Actual Results
Insert a panic backtrace here, or wrong answer, or whatever.
### Expected Results
The correct result / behavior that you expect when following the STR with the
test case. Maybe a `None` returned instead of a panic, or some node A instead of
the node B that was returned.
### Summary
A couple sentence summary of the requested feature.
### Motivation
What does adding this feature enable that isn't possible without it? Does it
improve performance? Turn dynamic checks into statically enforced properties?
Explain why this feature should be implemented.
### Details
* What code needs to change? New traits? Which modules?
* Is this a new graph algorithm? Include links to papers, Wikipedia, or other
implementations of this algorithm that exist.
* Are you willing to implement this yourself? Mentor someone else and help them
implement it?
petgraph-0.6.4/.github/workflows/ci.yml 0000644 0000000 0000000 00000003612 10461020230 0016162 0 ustar 0000000 0000000 on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
name: Continuous integration
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- rust: 1.64.0 # MSRV
- rust: stable
features: unstable quickcheck
test_all: --all
- rust: beta
test_all: --all
- rust: nightly
features: unstable quickcheck
test_all: --all
bench: true
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
- name: Build
run: |
cargo build --verbose --no-default-features
cargo build --verbose --features "${{ matrix.features }}"
- name: Tests
run: |
cargo test --verbose --no-default-features
cargo test ${{ matrix.test_all }} --verbose --features "${{ matrix.features }}"
- name: Build benchmarks
if: ${{ matrix.bench }}
run: |
cargo bench --verbose --no-run
cargo bench --verbose --no-run --all-features
rustfmt:
runs-on: ubuntu-latest
continue-on-error: true
strategy:
matrix:
include:
- rust: stable
rustfmt: rustfmt
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
components: ${{ matrix.rustfmt }}
override: true
- name: Rustfmt
if: matrix.rustfmt
run: cargo fmt -- --check
miri:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@nightly
with:
components: miri
- run: cargo miri test
petgraph-0.6.4/.gitignore 0000644 0000000 0000000 00000000051 10461020230 0013431 0 ustar 0000000 0000000 # Generated by Cargo
/target/
Cargo.lock
petgraph-0.6.4/CONTRIBUTING.rst 0000644 0000000 0000000 00000006562 10461020230 0014117 0 ustar 0000000 0000000 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
petgraph-0.6.4/Cargo.toml 0000644 00000004002 00000000001 0010647 0 ustar # 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.6.4"
authors = [
"bluss",
"mitchmindtree",
]
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 = [
"serde-1",
"quickcheck",
]
[package.metadata.release]
no-dev-version = true
[profile.bench]
debug = 2
[profile.release]
[lib]
name = "petgraph"
bench = false
[dependencies.fixedbitset]
version = "0.4.0"
default-features = false
[dependencies.indexmap]
version = "2.0"
[dependencies.quickcheck]
version = "0.8"
optional = true
default-features = false
[dependencies.serde]
version = "1.0"
optional = true
[dependencies.serde_derive]
version = "1.0"
optional = true
[dev-dependencies.bincode]
version = "1.3.3"
[dev-dependencies.defmac]
version = "0.2.1"
[dev-dependencies.itertools]
version = "0.11.0"
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",
]
default = [
"graphmap",
"stable_graph",
"matrix_graph",
]
generate = []
graphmap = []
matrix_graph = []
serde-1 = [
"serde",
"serde_derive",
]
stable_graph = []
unstable = ["generate"]
petgraph-0.6.4/Cargo.toml.orig 0000644 0000000 0000000 00000002712 10461020230 0014336 0 ustar 0000000 0000000 [package]
name = "petgraph"
version = "0.6.4"
readme = "README.md"
license = "MIT OR Apache-2.0"
authors = [
"bluss",
"mitchmindtree",
]
description = "Graph data structure library. Provides graph types and graph algorithms."
documentation = "https://docs.rs/petgraph/"
repository = "https://github.com/petgraph/petgraph"
keywords = ["data-structure", "graph", "unionfind", "graph-algorithms"]
categories = ["data-structures"]
rust-version = "1.64"
edition = "2018"
[package.metadata.docs.rs]
features = ["serde-1", "quickcheck"]
[package.metadata.release]
no-dev-version = true
[lib]
bench = false
name = "petgraph"
[profile.release]
[profile.bench]
debug = true
[dependencies]
fixedbitset = { version = "0.4.0", default-features = false }
indexmap = "2.0"
quickcheck = { optional = true, version = "0.8", default-features = false }
serde = { version = "1.0", optional = true }
serde_derive = { version = "1.0", optional = true }
[dev-dependencies]
bincode = "1.3.3"
defmac = "0.2.1"
itertools = { version = "0.11.0", default-features = false }
odds = { version = "0.4.0" }
rand = "0.5.5"
[features]
# feature flags for testing use only
all = ["unstable", "quickcheck", "matrix_graph", "stable_graph", "graphmap"]
default = ["graphmap", "stable_graph", "matrix_graph"]
generate = [] # For unstable features
graphmap = []
matrix_graph = []
serde-1 = ["serde", "serde_derive"]
stable_graph = []
unstable = ["generate"]
[workspace]
members = ["serialization-tests"]
petgraph-0.6.4/LICENSE-APACHE 0000644 0000000 0000000 00000025137 10461020230 0013401 0 ustar 0000000 0000000 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.
petgraph-0.6.4/LICENSE-MIT 0000644 0000000 0000000 00000002023 10461020230 0013076 0 ustar 0000000 0000000 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.
petgraph-0.6.4/Makefile 0000644 0000000 0000000 00000001726 10461020230 0013113 0 ustar 0000000 0000000 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/
\(.*\) - Rust/$@ $(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)
petgraph-0.6.4/README.md 0000644 0000000 0000000 00000002616 10461020230 0012731 0 ustar 0000000 0000000 # petgraph
Graph data structure library. Please read the [API documentation here][].
Supports Rust 1.64 and later.
[![build_status][]](https://github.com/petgraph/petgraph/actions) [![crates][]](https://crates.io/crates/petgraph) [![gitter][]](https://gitter.im/petgraph-rs/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
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.
## Recent Changes
See [RELEASES][] for a list of changes. The minimum supported rust
version will only change on major releases.
## License
Dual-licensed to be compatible with the Rust project.
Licensed under the Apache License, Version 2.0
or the MIT license
, 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
[crates]: https://img.shields.io/crates/v/petgraph
[gitter]: https://badges.gitter.im/petgraph-rs/community.svg
[RELEASES]: RELEASES.rst
petgraph-0.6.4/RELEASES.rst 0000644 0000000 0000000 00000047650 10461020230 0013416 0 ustar 0000000 0000000 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` 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`` 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`` 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 module’s 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 graph’s 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``
- Element type of ``GraphMap::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
petgraph-0.6.4/benches/bellman_ford.rs 0000644 0000000 0000000 00000003372 10461020230 0016053 0 ustar 0000000 0000000 #![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]
fn bellman_ford_bench(bench: &mut Bencher) {
static NODE_COUNT: usize = 100;
let mut g = Graph::new();
let nodes: Vec> = (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];
let mut distance: f64 = ((i + 3) % 10) as f64;
if n1 != n2 {
distance -= 1.0
}
g.add_edge(n1, n2, distance as f64);
}
}
bench.iter(|| {
let _scores = bellman_ford(&g, nodes[0]);
});
}
#[bench]
fn find_negative_cycle_bench(bench: &mut Bencher) {
static NODE_COUNT: usize = 100;
let mut g = Graph::new();
let nodes: Vec> = (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];
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]);
});
}
petgraph-0.6.4/benches/common/factories.rs 0000644 0000000 0000000 00000025245 10461020230 0016701 0 ustar 0000000 0000000 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(s: &str) -> G
where
Ty: EdgeType,
G: Default + Build + 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::().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: PhantomData,
g: PhantomData,
}
impl GraphFactory
where
Ty: EdgeType,
G: Default + Build + NodeIndexable,
{
fn new() -> Self {
GraphFactory {
ty: PhantomData,
g: PhantomData,
}
}
pub fn petersen_a(self) -> G {
parse_graph::(PETERSEN_A)
}
pub fn petersen_b(self) -> G {
parse_graph::(PETERSEN_B)
}
pub fn full_a(self) -> G {
parse_graph::(FULL_A)
}
pub fn full_b(self) -> G {
parse_graph::(FULL_B)
}
pub fn praust_a(self) -> G {
parse_graph::(PRAUST_A)
}
pub fn praust_b(self) -> G {
parse_graph::(PRAUST_B)
}
pub fn bigger(self) -> G {
parse_graph::(BIGGER)
}
pub fn bipartite(self) -> G {
parse_graph::(BIPARTITE)
}
}
pub fn graph() -> GraphFactory> {
GraphFactory::new()
}
pub fn ungraph() -> GraphFactory> {
graph()
}
pub fn digraph() -> GraphFactory> {
graph()
}
pub fn stable_graph() -> GraphFactory> {
GraphFactory::new()
}
pub fn stable_ungraph() -> GraphFactory> {
stable_graph()
}
pub fn stable_digraph() -> GraphFactory> {
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
}
petgraph-0.6.4/benches/common/mod.rs 0000644 0000000 0000000 00000000045 10461020230 0015470 0 ustar 0000000 0000000 mod factories;
pub use factories::*;
petgraph-0.6.4/benches/dijkstra.rs 0000644 0000000 0000000 00000001572 10461020230 0015242 0 ustar 0000000 0000000 #![feature(test)]
extern crate petgraph;
extern crate test;
use petgraph::prelude::*;
use std::cmp::{max, min};
use test::Bencher;
use petgraph::algo::dijkstra;
#[bench]
fn dijkstra_bench(bench: &mut Bencher) {
static NODE_COUNT: usize = 10_000;
let mut g = Graph::new_undirected();
let nodes: Vec> = (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];
let distance = (i + 3) % 10;
g.add_edge(n1, n2, distance);
}
}
bench.iter(|| {
let _scores = dijkstra(&g, nodes[0], None, |e| *e.weight());
});
}
petgraph-0.6.4/benches/feedback_arc_set.rs 0000644 0000000 0000000 00000002216 10461020230 0016647 0 ustar 0000000 0000000 #![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(|_| ()))
}
petgraph-0.6.4/benches/floyd_warshall.rs 0000644 0000000 0000000 00000001571 10461020230 0016440 0 ustar 0000000 0000000 #![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]
fn floyd_warshall_bench(bench: &mut Bencher) {
static NODE_COUNT: usize = 100;
let mut g = Graph::new_undirected();
let nodes: Vec> = (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];
let distance = (i + 3) % 10;
g.add_edge(n1, n2, distance);
}
}
bench.iter(|| {
let _scores = floyd_warshall(&g, |e| *e.weight());
});
}
petgraph-0.6.4/benches/iso.rs 0000644 0000000 0000000 00000002265 10461020230 0014221 0 ustar 0000000 0000000 #![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));
}
petgraph-0.6.4/benches/k_shortest_path.rs 0000644 0000000 0000000 00000001563 10461020230 0016630 0 ustar 0000000 0000000 #![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]
fn k_shortest_path_bench(bench: &mut Bencher) {
static NODE_COUNT: usize = 10_000;
let mut g = Graph::new_undirected();
let nodes: Vec> = (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];
let distance = (i + 3) % 10;
g.add_edge(n1, n2, distance);
}
}
bench.iter(|| k_shortest_path(&g, nodes[0], None, 2, |e| *e.weight()));
}
petgraph-0.6.4/benches/matching.rs 0000644 0000000 0000000 00000003106 10461020230 0015214 0 ustar 0000000 0000000 #![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));
}
petgraph-0.6.4/benches/matrix_graph.rs 0000644 0000000 0000000 00000020240 10461020230 0016105 0 ustar 0000000 0000000 #![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()
.map(|(i, &node)| {
let edges: Vec<_> = (0..5)
.map(|j| (i + j + 1) % nodes.len())
.map(|j| (node, nodes[j]))
.collect();
edges
})
.flatten()
.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(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::().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::(FULL);
bench.iter(|| a.edges_directed(node_index(1), Outgoing).count())
}
#[bench]
fn full_edges_in(bench: &mut Bencher) {
let a = parse_matrix::(FULL);
bench.iter(|| a.edges_directed(node_index(1), Incoming).count())
}
#[bench]
fn full_neighbors_out(bench: &mut Bencher) {
let a = parse_matrix::(FULL);
bench.iter(|| a.neighbors_directed(node_index(1), Outgoing).count())
}
#[bench]
fn full_neighbors_in(bench: &mut Bencher) {
let a = parse_matrix::(FULL);
bench.iter(|| a.neighbors_directed(node_index(1), Incoming).count())
}
#[bench]
fn full_kosaraju_sccs(bench: &mut Bencher) {
let a = parse_matrix::(FULL);
bench.iter(|| algo::kosaraju_scc(&a));
}
#[bench]
fn full_tarjan_sccs(bench: &mut Bencher) {
let a = parse_matrix::(FULL);
bench.iter(|| algo::tarjan_scc(&a));
}
#[bench]
fn bigger_edges_out(bench: &mut Bencher) {
let a = parse_matrix::(BIGGER);
bench.iter(|| a.edges_directed(node_index(1), Outgoing).count())
}
#[bench]
fn bigger_edges_in(bench: &mut Bencher) {
let a = parse_matrix::(BIGGER);
bench.iter(|| a.edges_directed(node_index(1), Incoming).count())
}
#[bench]
fn bigger_neighbors_out(bench: &mut Bencher) {
let a = parse_matrix::(BIGGER);
bench.iter(|| a.neighbors_directed(node_index(1), Outgoing).count())
}
#[bench]
fn bigger_neighbors_in(bench: &mut Bencher) {
let a = parse_matrix::(BIGGER);
bench.iter(|| a.neighbors_directed(node_index(1), Incoming).count())
}
#[bench]
fn bigger_kosaraju_sccs(bench: &mut Bencher) {
let a = parse_matrix::(BIGGER);
bench.iter(|| algo::kosaraju_scc(&a));
}
#[bench]
fn bigger_tarjan_sccs(bench: &mut Bencher) {
let a = parse_matrix::(BIGGER);
bench.iter(|| algo::tarjan_scc(&a));
}
petgraph-0.6.4/benches/ograph.rs 0000644 0000000 0000000 00000002116 10461020230 0014702 0 ustar 0000000 0000000 #![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);
}
})
}
petgraph-0.6.4/benches/serialize.rs 0000644 0000000 0000000 00000003234 10461020230 0015413 0 ustar 0000000 0000000 #![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 {
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 = bincode::deserialize(&data).unwrap();
graph2
});
}
}
petgraph-0.6.4/benches/stable_graph.rs 0000644 0000000 0000000 00000004465 10461020230 0016066 0 ustar 0000000 0000000 #![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));
}
petgraph-0.6.4/benches/unionfind.rs 0000644 0000000 0000000 00000010007 10461020230 0015411 0 ustar 0000000 0000000 #![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, min_spanning_tree};
#[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)));
}
#[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)));
}
petgraph-0.6.4/clippy.toml 0000644 0000000 0000000 00000000017 10461020230 0013640 0 ustar 0000000 0000000 msrv = "1.41.0" petgraph-0.6.4/custom.css 0000644 0000000 0000000 00000001025 10461020230 0013467 0 ustar 0000000 0000000
.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;
}
petgraph-0.6.4/graph-example.dot 0000644 0000000 0000000 00000000336 10461020230 0014711 0 ustar 0000000 0000000 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
}
petgraph-0.6.4/src/adj.rs 0000644 0000000 0000000 00000046460 10461020230 0013352 0 ustar 0000000 0000000 //! 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;
/// Adjacency list edge index type, a pair of integers.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct EdgeIndex
where
Ix: IndexType,
{
/// Source of the edge.
from: NodeIndex,
/// 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 where { Ix: IndexType }
item: EdgeIndex,
iter: std::iter::Map, std::iter::Repeat>>, fn((usize, NodeIndex)) -> EdgeIndex>,
}
/// Weighted sucessor
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct WSuc {
/// Index of the sucessor.
suc: Ix,
/// Weight of the edge to `suc`.
weight: E,
}
/// One row of the adjacency list.
type Row = Vec>;
type RowIter<'a, E, Ix> = std::slice::Iter<'a, WSuc>;
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,
iter: std::iter::Map, fn(&WSuc) -> NodeIndex>,
}
/// 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,
/// a reference to the corresponding item in the adjacency list
edge: &'a WSuc,
}
impl<'a, E, Ix: IndexType> Copy for EdgeReference<'a, E, Ix> {}
impl<'a, E, Ix: IndexType> Clone for EdgeReference<'a, E, Ix> {
fn clone(&self) -> Self {
EdgeReference {
id: self.id,
edge: self.edge,
}
}
}
impl<'a, E, Ix: IndexType> visit::EdgeRef for EdgeReference<'a, E, Ix> {
type NodeId = NodeIndex;
type EdgeId = EdgeIndex;
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>>,
row_index: usize,
row_len: usize,
cur: usize,
}
impl<'a, E, Ix: IndexType> Iterator for EdgeIndices<'a, E, Ix> {
type Item = EdgeIndex;
fn next(&mut self) -> Option> {
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 where {}
item: Ix,
iter: std::iter::Map, 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
where
Ix: IndexType,
{
suc: Vec>,
}
impl List {
/// Creates a new, empty adjacency list.
pub fn new() -> List {
List { suc: Vec::new() }
}
/// Creates a new, empty adjacency list tailored for `nodes` nodes.
pub fn with_capacity(nodes: usize) -> List {
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 {
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 {
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, E)>>(
&mut self,
edges: I,
) -> NodeIndex {
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.
///
/// **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, b: NodeIndex, weight: E) -> EdgeIndex {
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) -> Option<&WSuc> {
self.suc
.get(e.from.index())
.and_then(|row| row.get(e.successor_index))
}
fn get_edge_mut(&mut self, e: EdgeIndex) -> Option<&mut WSuc> {
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) -> Option<(NodeIndex, NodeIndex)> {
self.get_edge(e).map(|x| (e.from, x.suc))
}
pub fn edge_indices_from(&self, a: NodeIndex) -> OutgoingEdgeIndices {
let proj: fn((usize, NodeIndex)) -> EdgeIndex =
|(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, b: NodeIndex) -> 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, b: NodeIndex) -> Option> {
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 {
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 {
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 = List<(), Ix>;
impl Build for List {
/// 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 {
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.
///
/// **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, b: NodeIndex, weight: E) -> Option> {
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.
fn update_edge(&mut self, a: NodeIndex, b: NodeIndex, weight: E) -> EdgeIndex {
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<'a, E, Ix> fmt::Debug for EdgeReferences<'a, 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::() != 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 fmt::Debug for List
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 visit::GraphBase for List
where
Ix: IndexType,
{
type NodeId = NodeIndex;
type EdgeId = EdgeIndex;
}
impl visit::Visitable for List
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<'a, E, Ix: IndexType> visit::IntoNodeIdentifiers for &'a List {
type NodeIdentifiers = NodeIndices;
fn node_identifiers(self) -> NodeIndices {
self.node_indices()
}
}
impl visit::NodeRef for NodeIndex {
type NodeId = NodeIndex;
type Weight = ();
fn id(&self) -> Self::NodeId {
*self
}
fn weight(&self) -> &Self::Weight {
&()
}
}
impl<'a, Ix: IndexType, E> visit::IntoNodeReferences for &'a List {
type NodeRef = NodeIndex;
type NodeReferences = NodeIndices;
fn node_references(self) -> Self::NodeReferences {
self.node_indices()
}
}
impl visit::Data for List {
type NodeWeight = ();
type EdgeWeight = E;
}
impl<'a, E, Ix: IndexType> IntoNeighbors for &'a List {
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) -> Self::Neighbors {
let proj: fn(&WSuc) -> NodeIndex = |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::Repeat>,
fn(((usize, &'a WSuc), 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>
>,
SomeIter<'a, E, Ix>,
fn(
(usize, &'a Vec>)
) -> SomeIter<'a, E, Ix>,
>,
}
impl<'a, E, Ix: IndexType> Clone for EdgeReferences<'a, E, Ix> {
fn clone(&self) -> Self {
EdgeReferences {
iter: self.iter.clone(),
}
}
}
fn proj1(
((successor_index, edge), from): ((usize, &WSuc), Ix),
) -> EdgeReference {
let id = EdgeIndex {
from,
successor_index,
};
EdgeReference { id, edge }
}
fn proj2((row_index, row): (usize, &Vec>)) -> SomeIter {
row.iter()
.enumerate()
.zip(std::iter::repeat(Ix::new(row_index)))
.map(proj1 as _)
}
impl<'a, Ix: IndexType, E> visit::IntoEdgeReferences for &'a List {
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 {
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 visit::GraphProp for List {
type EdgeType = crate::Directed;
fn is_directed(&self) -> bool {
true
}
}
impl NodeCount for List {
/// Returns the number of nodes in the list
///
/// Computes in **O(1)** time.
fn node_count(&self) -> usize {
self.suc.len()
}
}
impl EdgeCount for List {
/// Returns the number of edges in the list
///
/// Computes in **O(|V|)** time.
fn edge_count(&self) -> usize {
List::edge_count(self)
}
}
impl visit::NodeIndexable for List {
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 visit::NodeCompactIndexable for List {}
impl DataMap for List {
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) -> Option<&E> {
self.get_edge(e).map(|x| &x.weight)
}
}
impl DataMapMut for List {
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) -> 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 GetAdjacencyMatrix for List
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);
let j = edge.source().index() + n * edge.target().index();
matrix.put(j);
}
matrix
}
fn is_adjacent(&self, matrix: &FixedBitSet, a: NodeIndex, b: NodeIndex) -> bool {
let n = self.edge_count();
let index = n * a.index() + b.index();
matrix.contains(index)
}
}
petgraph-0.6.4/src/algo/astar.rs 0000644 0000000 0000000 00000012343 10461020230 0014641 0 ustar 0000000 0000000 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(
graph: G,
start: G::NodeId,
mut is_goal: IsGoal,
mut edge_cost: F,
mut estimate_cost: H,
) -> Option<(K, Vec)>
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::::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
where
G: GraphBase,
G::NodeId: Eq + Hash,
{
came_from: HashMap,
}
impl PathTracker
where
G: GraphBase,
G::NodeId: Eq + Hash,
{
fn new() -> PathTracker {
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 {
let mut path = vec![last];
let mut current = last;
while let Some(&previous) = self.came_from.get(¤t) {
path.push(previous);
current = previous;
}
path.reverse();
path
}
}
petgraph-0.6.4/src/algo/bellman_ford.rs 0000644 0000000 0000000 00000017604 10461020230 0016160 0 ustar 0000000 0000000 //! 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 {
pub distances: Vec,
pub predecessors: Vec