Skip to content

Merge graphs package #100

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 90 commits into from
May 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
b83a4ca
Package description
natebosch Dec 4, 2017
4d9eaf0
Dart package boilerplate (#1)
natebosch Dec 4, 2017
d911c47
Implement stronglyConnectedComponents (#2)
natebosch Dec 4, 2017
b9dfcba
Add Travis config (#3)
natebosch Dec 4, 2017
d696165
Only test on master branch (#4)
natebosch Dec 4, 2017
f75feb6
Add test for self-cycles (#6)
natebosch Dec 4, 2017
edd9572
Expand README and add example (#5)
natebosch Dec 4, 2017
7ea7bc4
Allow `children` to return null (#8)
natebosch Dec 4, 2017
5f4c330
Use more precise language in docs for SCC (#9)
natebosch Dec 5, 2017
3ba4fcc
Implement crawlAsync (#10)
natebosch Dec 5, 2017
d3b1290
Add missing copyright notices, update changelog (#11)
natebosch Dec 5, 2017
5d98ea2
Add more lints (#12)
natebosch Dec 5, 2017
b16ce0c
Prepare to publish 0.1.0 (#13)
natebosch Dec 7, 2017
5876b0b
Add explicit type to for-in loop (#16)
natebosch Jan 17, 2018
7e5a23c
Ignore null nodes in `crawlAsync` (#17)
natebosch Apr 18, 2018
1f3e91b
Surface crawlAsync errors through the Stream (#18)
natebosch Apr 23, 2018
660aba1
Use new analyzer APIs.
scheglov May 25, 2018
6d3dac3
Fix naming nits.
scheglov May 26, 2018
f69e424
Try to require sdk >=2.0.0-dev.48.0 to see if this fixes Travis.
scheglov May 26, 2018
4132632
We cannot require sdk >=2.0.0-dev.48.0, because of stable SDK branch?
scheglov May 26, 2018
48c48cc
Stop testing on stable, and require sdk >=2.0.0-dev.48.0
scheglov May 26, 2018
c90b09f
Merge pull request #19 from scheglov/use-new-analyzer-api
scheglov May 26, 2018
00cf4b0
Allow the non-dev Dart 2 SDK (#21)
natebosch Jul 18, 2018
fc9f636
Update for Dart 2 (#22)
natebosch Aug 9, 2018
690e451
Add more lints used in package:pedantic (#24)
natebosch Sep 5, 2018
72974f2
Use HashMap/HashSet for stronglyConnectedComponents (#26)
kevmoo Nov 5, 2018
2498917
Add shortestPath(s) functions
kevmoo Nov 6, 2018
91e320b
update dev dependencies
kevmoo Nov 6, 2018
3eb499c
enable and fix a number of lints, use pedantic lints explicitly
kevmoo Nov 6, 2018
f2c6a24
prepare for release
kevmoo Nov 6, 2018
2a427b2
Remove accidental API in src/shortest_path
kevmoo Nov 8, 2018
9713e1d
Fix a bug with non-identity key in shortestPath functions
kevmoo Nov 8, 2018
0c928c0
shortestPath: calculate key(target) less
kevmoo Nov 8, 2018
93f8538
shortest path benchmark: keep running until terminated
kevmoo Nov 8, 2018
cce128f
Use HashSet in crawlAsync
kevmoo Nov 8, 2018
e062f90
prepare to release v0.1.3+1 (#31)
kevmoo Nov 8, 2018
a6327f9
Small tweaks to shortest path benchmark output
kevmoo Nov 8, 2018
2589919
Add connected component benchmark
kevmoo Nov 8, 2018
1aa0ad5
Breaking: change use optional equals/hashCode instead of keys
kevmoo Nov 8, 2018
10918ff
shortestPath: remove unused isValidKey param (#32)
kevmoo Nov 13, 2018
92d2a37
shortedPath(s): use fixed length List where possible
kevmoo Nov 13, 2018
239d259
Improve short-circuit logic
kevmoo Nov 13, 2018
b526732
Use setRange over setAll in fixed-length list (#34)
kevmoo Nov 13, 2018
5609bc5
shortestPath: add an integration test that validates invariants (#37)
kevmoo Dec 11, 2018
50455b3
shortestPath: update benchmark to report fastest iteration time (#36)
kevmoo Dec 11, 2018
ded0424
Update dev_dep to pkg:analyzer (#35)
kevmoo Dec 11, 2018
4979ead
Update description, prepare for 0.2.0 (#38)
kevmoo Dec 12, 2018
53f9d3b
Clarify that edges may have overlapping calls (#40)
natebosch Dec 28, 2018
99388aa
bump to latest analyzer (dev dep for examples), fixed duplicate lint …
kevmoo Feb 1, 2019
382698a
Allow latest pkg:analyzer in example, test on oldest supported SDK (#43)
kevmoo Apr 29, 2019
ccf20c9
update analyzer dep (#44)
kevmoo Jul 20, 2019
d13d065
Support latest pkg:analyzer (used in example) (#45)
kevmoo Oct 30, 2019
fac38fd
Fix strict-inference violations (#46)
natebosch Nov 6, 2019
3271470
Fix newly enforced package:pedantic lints (#48)
natebosch Dec 6, 2019
ece7727
Remove unused dart:async imports (#49)
MichaelRFairhurst Sep 22, 2020
81de4a8
bump pkg:analyzer dependency (#50)
kevmoo Sep 23, 2020
b6ef7d9
Remove unused dart:async imports. (#51)
srawlins Oct 28, 2020
1d23ba3
Migrate to GitHub Actions (#53)
kevmoo Jan 21, 2021
54e6458
Remove diagnostic upgrades to errors (#54)
natebosch Feb 19, 2021
1d3035d
Simplify shortestPath, and optimize it a bit (#56)
jakemac53 Feb 24, 2021
af25bfe
Migrate to null safety (#52)
hovadur Feb 25, 2021
93007c0
Prepare to publish (#57)
natebosch Feb 26, 2021
1809c29
Stop ignoring null nodes in crawlAsync (#59)
natebosch Mar 16, 2021
4550d2b
Prepare to publish version 2.0.0 (#60)
natebosch Mar 19, 2021
aec8919
Update LICENSE (#61)
franklinyow Apr 2, 2021
2cb2e76
Use latest setup action (#62)
kevmoo Apr 20, 2021
53054c7
update analyzer API access (#63)
pq Apr 26, 2021
c7c7b6c
Fix CI badge in readme (#64)
kevmoo Jul 16, 2021
dfbee79
Update CI (#65)
kevmoo Jul 16, 2021
e20cc60
Add a topologicalSort function (#66)
nex3 Sep 2, 2021
1437a7d
Bump analyzer dep, use pkg:lints, fix lints (#68)
kevmoo Oct 4, 2021
9fe5d2b
Support latest pkg:analyzer (#69)
kevmoo Jan 18, 2022
2f1fbdc
Remove leading underscore from local var (#72)
natebosch Feb 8, 2022
5985a88
Add a `secondarySort` parameter to `topologicalSort` (#70)
nex3 Feb 9, 2022
e22a6ac
update analyzer dependency (#73)
kevmoo Apr 20, 2022
c69ed05
Remove deprecated experimental invariant_booleans lint rule (#74)
srawlins Jul 25, 2022
ad6ec06
Update README.md (#67)
j-j-gajjar Oct 21, 2022
d7a5c41
update the CI configuration and add markdown badges (#75)
devoncarew Oct 21, 2022
241ac3f
Bump pkg:lints, bump mind Dart SDK and pkg:analyzer (#76)
kevmoo Nov 1, 2022
48e8274
Bump actions/checkout from 3.1.0 to 3.2.0 (#78)
dependabot[bot] Jan 3, 2023
ce61894
Bump dart-lang/setup-dart from 1.3 to 1.4 (#80)
dependabot[bot] Feb 1, 2023
daf03a8
Bump actions/checkout from 3.2.0 to 3.3.0 (#79)
dependabot[bot] Feb 1, 2023
b480ced
Bump actions/checkout from 3.3.0 to 3.5.0 (#82)
dependabot[bot] Apr 3, 2023
536f2ba
Bump dart-lang/setup-dart from 1.4.0 to 1.5.0 (#81)
dependabot[bot] Apr 3, 2023
d1641a4
Bump actions/checkout from 3.5.0 to 3.5.2 (#84)
dependabot[bot] May 1, 2023
cef9625
Add a transitiveClosure() function (#83)
nex3 May 9, 2023
d3bea48
Normalize changelog formatting (#85)
natebosch May 10, 2023
42218af
blast_repo fixes (#87)
devoncarew May 16, 2023
6b2f660
Prepare to merge into the tools repository
dcharkes May 23, 2023
4331e28
Merge package:graphs into shared tool repository
dcharkes May 23, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/workflows/graphs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: CI

on:
# Run on PRs and pushes to the default branch.
push:
branches: [ main ]
paths:
- '.github/workflows/graphs.yml'
- 'pkgs/graphs/**'
pull_request:
branches: [ main ]
paths:
- '.github/workflows/graphs.yml'
- 'pkgs/graphs/**'
schedule:
- cron: "0 0 * * 0"

env:
PUB_ENVIRONMENT: bot.github

jobs:
# Check code formatting and static analysis on a single OS (linux)
# against Dart beta.
analyze:
runs-on: ubuntu-latest
defaults:
run:
working-directory: pkgs/graphs/
strategy:
fail-fast: false
matrix:
sdk: [dev]
steps:
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
- uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
with:
sdk: ${{ matrix.sdk }}
- id: install
run: dart pub get
- run: dart format --output=none --set-exit-if-changed .
if: always() && steps.install.outcome == 'success'
- run: dart analyze --fatal-infos
if: always() && steps.install.outcome == 'success'

test:
needs: analyze
runs-on: ${{ matrix.os }}
defaults:
run:
working-directory: pkgs/graphs/
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
sdk: [2.18.0, dev]
steps:
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab
- uses: dart-lang/setup-dart@d6a63dab3335f427404425de0fbfed4686d93c4f
with:
sdk: ${{ matrix.sdk }}
- id: install
run: dart pub get
- run: dart test --platform vm
if: always() && steps.install.outcome == 'success'
- run: dart test --platform chrome
if: always() && steps.install.outcome == 'success'
5 changes: 5 additions & 0 deletions pkgs/graphs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.dart_tool/
.packages
.pub/
build/
pubspec.lock
64 changes: 64 additions & 0 deletions pkgs/graphs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
## 2.3.0

- Add a `transitiveClosure` function.
- Make `stronglyConnectedComponents` and `topologicalSort` iterative rather than
recursive to avoid stack overflows on very large graphs.
- Require Dart 2.18

## 2.2.0

- Add a `secondarySort` parameter to the `topologicalSort()` function which
applies an additional lexical sort where that doesn't break the topological
sort.

## 2.1.0

- Add a `topologicalSort()` function.

## 2.0.0

- **Breaking**: `crawlAsync` will no longer ignore a node from the graph if the
`readNode` callback returns null.

## 1.0.0

- Migrate to null safety.
- **Breaking**: Paths from `shortestPath[s]` are now returned as iterables to
reduce memory consumption of the algorithm to O(n).

## 0.2.0

- **BREAKING** `shortestPath`, `shortestPaths` and `stronglyConnectedComponents`
now have one generic parameter and have replaced the `key` parameter with
optional params: `{bool equals(T key1, T key2), int hashCode(T key)}`.
This follows the pattern used in `dart:collection` classes `HashMap` and
`LinkedHashMap`. It improves the usability and performance of the case where
the source values are directly usable in a hash data structure.

## 0.1.3+1

- Fixed a bug with non-identity `key` in `shortestPath` and `shortestPaths`.

## 0.1.3

- Added `shortestPath` and `shortestPaths` functions.
- Use `HashMap` and `HashSet` from `dart:collection` for
`stronglyConnectedComponents`. Improves runtime performance.

## 0.1.2+1

- Allow using non-dev Dart 2 SDK.

## 0.1.2

- `crawlAsync` surfaces exceptions while crawling through the result stream
rather than as uncaught asynchronous errors.

## 0.1.1

- `crawlAsync` will now ignore nodes that are resolved to `null`.

## 0.1.0

- Initial release with an implementation of `stronglyConnectedComponents` and
`crawlAsync`.
33 changes: 33 additions & 0 deletions pkgs/graphs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
Want to contribute? Great! First, read this page (including the small print at
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessary for this PR (can be done after its merged in), but we can delete this separate contributing file.

the end).

### Before you contribute
Before we can use your code, you must sign the
[Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual)
(CLA), which you can do online. The CLA is necessary mainly because you own the
copyright to your changes, even after your contribution becomes part of our
codebase, so we need your permission to use and distribute your code. We also
need to be sure of various other things—for instance that you'll tell us if you
know that your code infringes on other people's patents. You don't have to sign
the CLA until after you've submitted your code for review and a member has
approved it, but you must do it before we can put your code into our codebase.

Before you start working on a larger contribution, you should get in touch with
us first through the issue tracker with your idea so that we can help out and
possibly guide you. Coordinating up front makes it much easier to avoid
frustration later on.

### Code reviews
All submissions, including submissions by project members, require review.

### File headers
All files in the project must start with the following header.

// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

### The small print
Contributions made by corporations are covered by a different agreement than the
one above, the
[Software Grant and Corporate Contributor License Agreement](https://developers.google.com/open-source/cla/corporate).
27 changes: 27 additions & 0 deletions pkgs/graphs/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Copyright 2017, the Dart project authors.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 changes: 42 additions & 0 deletions pkgs/graphs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[![CI](https://github.com/dart-lang/tools/actions/workflows/graphs.yml/badge.svg)](https://github.com/dart-lang/tools/actions/workflows/graphs.yml)
[![pub package](https://img.shields.io/pub/v/graphs.svg)](https://pub.dev/packages/graphs)
[![package publisher](https://img.shields.io/pub/publisher/graphs.svg)](https://pub.dev/packages/graphs/publisher)

Graph algorithms that do not specify a particular approach for representing a
Graph.

Functions in this package will take arguments that provide the mechanism for
traversing the graph. For example two common approaches for representing a
graph:

```dart
class Graph {
Map<Node, List<Node>> nodes;
}
class Node {
// Interesting data
}
```

```dart
class Graph {
Node root;
}
class Node {
List<Node> edges;
// Interesting data
}
```

Any representation can be adapted to the needs of the algorithm:

- Some algorithms need to associate data with each node in the graph. If the
node type `T` does not correctly or efficiently implement `hashCode` or `==`,
you may provide optional `equals` and/or `hashCode` functions are parameters.
- Algorithms which need to traverse the graph take a `edges` function which provides the reachable nodes.
- `(node) => graph[node]`
- `(node) => node.edges`


Graphs that are resolved asynchronously will have similar functions which
return `FutureOr`.
56 changes: 56 additions & 0 deletions pkgs/graphs/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# https://dart.dev/guides/language/analysis-options
include: package:lints/recommended.yaml

analyzer:
language:
strict-casts: true
strict-inference: true
strict-raw-types: true

linter:
rules:
- always_declare_return_types
- avoid_bool_literals_in_conditional_expressions
- avoid_catching_errors
- avoid_classes_with_only_static_members
- avoid_dynamic_calls
- avoid_private_typedef_functions
- avoid_redundant_argument_values
- avoid_returning_null
- avoid_returning_null_for_future
- avoid_returning_this
- avoid_unused_constructor_parameters
- avoid_void_async
- cancel_subscriptions
- comment_references
- directives_ordering
- join_return_with_assignment
- lines_longer_than_80_chars
- literal_only_boolean_expressions
- missing_whitespace_between_adjacent_strings
- no_adjacent_strings_in_list
- no_runtimeType_toString
- omit_local_variable_types
- only_throw_errors
- package_api_docs
- prefer_asserts_in_initializer_lists
- prefer_const_constructors
- prefer_const_declarations
- prefer_expression_function_bodies
- prefer_final_locals
- prefer_relative_imports
- prefer_single_quotes
- require_trailing_commas
- test_types_in_equals
- throw_in_finally
- type_annotate_public_apis
- unawaited_futures
- unnecessary_await_in_return
- unnecessary_lambdas
- unnecessary_parenthesis
- unnecessary_raw_strings
- unnecessary_statements
- use_if_null_to_convert_nulls_to_bools
- use_raw_strings
- use_string_buffers
- use_super_parameters
50 changes: 50 additions & 0 deletions pkgs/graphs/benchmark/connected_components_benchmark.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:collection';
import 'dart:math' show Random;

import 'package:graphs/graphs.dart';

void main() {
final rnd = Random(0);
const size = 2000;
final graph = HashMap<int, List<int>>();

for (var i = 0; i < size * 3; i++) {
final toList = graph.putIfAbsent(rnd.nextInt(size), () => <int>[]);

final toValue = rnd.nextInt(size);
if (!toList.contains(toValue)) {
toList.add(toValue);
}
}

var maxCount = 0;
var maxIteration = 0;

const duration = Duration(milliseconds: 100);

for (var i = 1;; i++) {
var count = 0;
final watch = Stopwatch()..start();
while (watch.elapsed < duration) {
count++;
final length =
stronglyConnectedComponents(graph.keys, (e) => graph[e] ?? <Never>[])
.length;
assert(length == 244, '$length');
}

if (count > maxCount) {
maxCount = count;
maxIteration = i;
}

if (maxIteration == i || (i - maxIteration) % 20 == 0) {
print('max iterations in ${duration.inMilliseconds}ms: $maxCount\t'
'after $maxIteration of $i iterations');
}
}
}
Loading