dart-archive / graphs Goto Github PK
View Code? Open in Web Editor NEWGraph algorithms
Home Page: https://pub.dev/packages/graphs
License: BSD 3-Clause "New" or "Revised" License
Graph algorithms
Home Page: https://pub.dev/packages/graphs
License: BSD 3-Clause "New" or "Revised" License
Missing:
"avoid_relative_lib_imports",
"avoid_types_as_parameter_names",
"prefer_contains",
"prefer_equal_for_default_values",
"use_rethrow_when_possible"
Filing for discussion. @jakemac53 - any thoughts?
Initial implementation uses positional arguments for everything. For the algorithms we know we want to add the arguments which are Function
s have relatively clear argument and return types, but when looking at the code without getting hints about analyzer errors they aren't super clear. Should we add some named arguments and use @required
to give analyzer hints that they all need to be included?
before:
var components = stronglyConnectedComponents<Node, Node>(
graph.nodes.keys, (node) => node, (node) => graph.nodes[node] ?? []);
after:
var components = stronglyConnectedComponents<Node, Node>(
searchFrom: graph.nodes.keys,
key: (node) => node,
children: (node) => graph.nodes[node] ?? []);
Do a +1 release with <3.0.0
Here's a tested implementation.
The only downside: I use PriorityQueue
from pkg:collection
. You could nix that and loose a bit of perf – whatever... CC @natebosch
import 'dart:collection';
import 'package:collection/collection.dart' show PriorityQueue;
/// If [sourceNode] equals [targetNode], `true` is always returned.
///
/// Assumes that [T] implements correct and efficient `==` and `hashCode`.
List<T> shortestPath<T>(
T sourceNode, T targetNode, Iterable<T> Function(T) edgeWeight) =>
shortestWeightedPath(sourceNode, targetNode,
(T node) => edgeWeight(node).map((n) => MapEntry(n, 1)))?.value;
/// The value returned from [edgeWeight] must be greater than zero. This
/// requirement is verified in an assert. If violated When running without
/// asserts, the behavior is undefined.
///
/// If [sourceNode] equals [targetNode], `true` is always returned.
///
/// Assumes that [T] implements correct and efficient `==` and `hashCode`.
MapEntry<num, List<T>> shortestWeightedPath<T>(T sourceNode, T targetNode,
Iterable<MapEntry<T, num>> Function(T) edgeWeight) {
if (sourceNode == targetNode) {
return MapEntry<num, List<T>>(0, []);
}
final distances = HashMap<T, MapEntry<num, List<T>>>();
distances[sourceNode] = MapEntry<num, List<T>>(0, []);
int compareDistance(T a, T b) {
final distanceA = distances[a]?.key ?? double.infinity;
final distanceB = distances[b]?.key ?? double.infinity;
return distanceA.compareTo(distanceB);
}
final toVisit = PriorityQueue<T>(compareDistance)..add(sourceNode);
MapEntry<num, List<T>> bestOption;
while (toVisit.isNotEmpty) {
final current = toVisit.removeFirst();
final distanceToCurrent = distances[current];
if (bestOption != null && distanceToCurrent.key >= bestOption.key) {
// Skip any existing `toVisit` items that have no change of being
// better than bestOption (if it exists)
continue;
}
for (var edge in edgeWeight(current)) {
assert(edge.value > 0, 'Edge weight must be greater than zero.');
final existingDistance = distances[edge.key];
final newOptionDistance = distanceToCurrent.key + edge.value;
if (existingDistance == null ||
existingDistance.key > newOptionDistance) {
final newOption = MapEntry<num, List<T>>(newOptionDistance,
distanceToCurrent.value.followedBy(<T>[edge.key]).toList());
if (edge.key == targetNode) {
assert(bestOption == null || bestOption.key > newOptionDistance);
bestOption = newOption;
}
distances[edge.key] = newOption;
if (bestOption == null || bestOption.key > newOption.key) {
// Only add a node to visit if it might be a better path to the
// target node
toVisit.add(edge.key);
}
}
}
}
assert(bestOption == distances[targetNode]);
return bestOption;
}
In 6adde6d, the return type of readNode
in crawlAsync
was changed to a potentially non-nullable FutureOr<V>
. Quoting the documentation of crawlAsync
:
/// If [readNode] returns null for any key it will be ignored from the rest of
/// the graph.
Should we make this a FutureOr<V?> Function(K)
then? Or are users supposed to provide a nullable V
and then filter out nulls in the end? If that's the intention, maybe the documentation needs some tweaking. Note that a nullable V
wouldn't really work, since null
values are still not added to the result.
cc @natebosch
I dunno if this is your issue, but...
Your library is in dependencies in build_runner
and after last updating 2.2.0 --> 2.3.0 an issue was happened.
When there are both annotations in class, like that,
part 'user.freezed.dart';
part 'user.g.dart';
/// Класс пользователя для авторизации
@freezed
class AuthUser with _$AuthUser {
/// Базовый класс typeId: 0, adapterName: 'AuthUserAdapter'
@HiveType(typeId: 0)
const factory AuthUser({
@HiveField(0) required String id,
}) = _AuthUser;
/// AuthUser.fromJson
factory AuthUser.fromJson(Map<String, dynamic> json) =>
_$AuthUserFromJson(json);
json_annotation
which is indirectly called from freezed
had been adding its annotations in ".g.dart" alongside with hive
part of 'user.dart';
// **************************************************************************
// TypeAdapterGenerator
// **************************************************************************
class AuthUserAdapter extends TypeAdapter<_$_AuthUser> {
@override
final int typeId = 0;
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$_AuthUser _$$_AuthUserFromJson(Map<String, dynamic> json) => $checkedCreate(
r'_$_AuthUser',
json,
($checkedConvert) {
final val = _$_AuthUser(
As a result of last night updating of graphs
json generator overrides file .g.dart
and previous info disappears.
I added this issue to build_runner repository too.
If you don't care about insertion ordering, you'll get better perf and mem usage if you use the Hash* flavor
graphs/example/crawl_async_example.dart
Line 20 in 20ecb4b
Does this library supports directed graphs ?
Noticed in an example that this crashes when used with HTTP if the number of edges returned is more HTTP requests to be created than the VM can handle.
crawlAsync
should either implement its own throttling/pooling or at least should document that the number of pending async operations may grow unbounded and that users should implement their own throttling/pooling
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.