Skip to content
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

Override default implementations by more efficient ones where it makes sense #6

Open
3 tasks
pnevyk opened this issue Feb 6, 2022 · 1 comment
Open
3 tasks
Labels
good first issue Good for newcomers

Comments

@pnevyk
Copy link
Owner

pnevyk commented Feb 6, 2022

The core traits Vertices{Base,Mut,}, Edges{Base,Mut,} and Neighbors contain default implementations for some methods that can be expressed in the means of others. These implementations are often inefficient, however, and should be overridden by reasonable implementations in each graph storage.

This applies both to graph storages (AdjList, AdjMatrix, EdgeList) and their adapters (Stable, Frozen, operators, ...). The latter should always explicitly delegate the behavior to the underlying graph (i.e., implementing fn <function>(...) { self.graph.<function>(...) } or equivalent), but this is often guaranteed because of using derive macros.

A few known examples:

  • VerticesBase::contains_vertex -- after 4229680 the default implementation changed to going through all vertex indices and checking if there is the vertex of interest. This definitely should be overridden in all graph storages to self.vertex(index).is_some()
  • Neighbors::degree{,_directed} in AdjList -- the degree can be computed in constant time by getting the number of outgoing and/or incoming edges which is stored in the vertices.
  • Neighbors::degree{,_directed} in Complement -- the degree can be computed by subtracting the real degree from the maximum possible degree of a vertex
@pnevyk pnevyk added the good first issue Good for newcomers label Feb 6, 2022
@pnevyk
Copy link
Owner Author

pnevyk commented Aug 6, 2024

Recommended approach to find the optimization opportunities:

  1. Find an impl Trait for Storage item, where Trait is any graph-related trait and Storage is AdjList, AdjMatrix, etc.
  2. Use your Rust Analyzer (or a different tool with equivalent functionality) to "implement default members", which inlines the default implementations to the concrete impl Trait for Storage.
  3. Knowing the internal representation of the storage at hand, determine whether the default implementation can be improved. If so, improve it. If not, delete it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

1 participant