pub struct MultiGraph { /* private fields */ }Implementations§
Source§impl MultiGraph
impl MultiGraph
Sourcepub fn clone_with_fresh_policy(&self) -> Self
pub fn clone_with_fresh_policy(&self) -> Self
br-r37-c1-7dpyg: structural clone with a FRESH RuntimePolicy — see Graph::clone_with_fresh_policy.
Sourcepub fn reorder_rows_for_nx_copy_walk(&mut self)
pub fn reorder_rows_for_nx_copy_walk(&mut self)
br-r37-c1-s0d4x: reorder every adjacency row into NetworkX’s
MultiGraph.copy() walk order — the multigraph counterpart of
Graph::reorder_rows_for_nx_copy_walk (cells move wholesale). A
pair’s cells enter both rows at the first u-major touch: row u =
earlier-position neighbors sorted by (pos(v), index of u within
row v), then the rest (self-loops included) in original order.
Sourcepub fn apply_row_orders(&mut self, orders: &[(String, Vec<String>)])
pub fn apply_row_orders(&mut self, orders: &[(String, Vec<String>)])
br-r37-c1-u3qyn: restore explicit adjacency row orders (pickle round-trip) — see Graph::apply_row_orders. Multigraph rows are keyed cells (neighbor -> key set); the cells move wholesale.
Sourcepub fn reorder_rows_like(&mut self, source: &Self)
pub fn reorder_rows_like(&mut self, source: &Self)
br-r37-c1-36v6r: order each row as source’s row for the node of the
same name - a graph built from a filtered view of source by a
copy-shaped walk, whose rows the view shows as source’s rows
filtered (see Graph::reorder_rows_like). Cells move wholesale; like
apply_row_orders, drops the int-adjacency memo rather than moving
revision.
pub fn new(mode: CompatibilityMode) -> Self
pub fn with_runtime_policy(runtime_policy: RuntimePolicy) -> Self
pub fn strict() -> Self
pub fn hardened() -> Self
pub fn mode(&self) -> CompatibilityMode
pub fn node_count(&self) -> usize
pub fn edge_count(&self) -> usize
pub fn number_of_selfloops(&self) -> usize
Sourcepub fn edge_keys(&self, left: &str, right: &str) -> Option<Vec<usize>>
pub fn edge_keys(&self, left: &str, right: &str) -> Option<Vec<usize>>
Return edge keys as Vec (needed by Python bindings).
Sourcepub fn edge_keys_iter(&self, left: &str, right: &str) -> Option<MgEdgeKeys<'_>>
pub fn edge_keys_iter(&self, left: &str, right: &str) -> Option<MgEdgeKeys<'_>>
Return an iterator over keys for edges between left and right.
pub fn revision(&self) -> u64
pub fn has_node(&self, node: &str) -> bool
pub fn has_edge(&self, left: &str, right: &str) -> bool
Sourcepub fn has_edge_by_indices(&self, li: usize, ri: usize) -> bool
pub fn has_edge_by_indices(&self, li: usize, ri: usize) -> bool
br-r37-c1-04z53 (cc): resolve has_edge straight from insertion-order
indices, skipping the i.to_string() heap alloc the Python binding pays
for int nodes. The names come from the node table by index (borrowed, no
alloc); the caller (PyMultiGraph::has_edge) guards each index with
node_index_matches_int so the identity index == int-value holds
(any removal / remap that broke it fails the guard and falls through to
the String path). Mirror of Graph::has_edge_by_indices.
br-r37-c1-2ndmw: THIS TAKES A POSITION AND THE EDGE MAP IS KEYED BY SLOT,
which is the whole subtlety. It used to bridge the two spaces by
resolving both positions back to NAMES and calling the string
has_edge, which re-hashes both node keys – so this was O(node key
length) while Graph::has_edge_by_indices was a genuine O(1)
contains_key, and every caller taking the “index fast path”
(PyMultiGraph::has_edge, the edge-view probe, the algorithms bulk
paths) still paid for the key length it was trying to avoid.
slot_at_position bridges the same gap in O(1) with no hashing, and
substitutes an EQUAL value rather than changing behaviour:
MgSlabStorage::has_edge(l, r) is itself defined as node_order.get(l)
and node_order.get(r) followed by has_edge_by_pair, and the slot
get(name) returns for an entry is the slot get_index(position)
returns for that same entry.
What must NEVER happen is passing the position straight to
has_edge_by_pair: the spaces coincide only until a node is removed,
after which that reports a real edge as absent. Pinned by
multigraph_node_slot_and_position_are_distinct_index_spaces, and the
equivalence pinned by
multigraph_has_edge_by_indices_matches_the_string_path_across_removals.
Sourcepub fn edge_attrs_by_indices(
&self,
li: usize,
ri: usize,
key: usize,
) -> Option<&AttrMap>
pub fn edge_attrs_by_indices( &self, li: usize, ri: usize, key: usize, ) -> Option<&AttrMap>
br-r37-c1-s8dj1: attributes of a KEYED edge, addressed by node POSITION.
The keyed sibling of Self::has_edge_by_indices, and it exists for the
same reason: PyMultiGraph::has_edge had an O(1) path only while key
was None, so (u, v) in G.edges – which passes key 0 – paid two
canonicalisations and several node-key hashes and grew 3.6x from 2- to
2000-character keys while the keyless form stayed flat.
Takes POSITIONS and converts them to SLOTS, exactly as the keyless
sibling does. Passing a position straight to the slot-keyed store
reports a real edge as absent after any node removal – see
multigraph_node_slot_and_position_are_distinct_index_spaces.
pub fn nodes_ordered(&self) -> Vec<&str>
Sourcepub fn get_node_index(&self, node: &str) -> Option<usize>
pub fn get_node_index(&self, node: &str) -> Option<usize>
Resolve a node through the insertion-ordered node table without rebuilding a query-local name-to-index map.
Sourcepub fn get_node_name(&self, index: usize) -> Option<&str>
pub fn get_node_name(&self, index: usize) -> Option<&str>
Resolve the current node name for an insertion-order index.
Sourcepub fn node_index_matches_int(&self, idx: usize) -> bool
pub fn node_index_matches_int(&self, idx: usize) -> bool
br-cc-nbunchbulk: int membership fast path for _nbunch_present — see the
simple-Graph accessor.
Sourcepub fn node_names_are_positions(&self) -> bool
pub fn node_names_are_positions(&self) -> bool
br-r37-c1-qaqog: every node’s name is the decimal of its position, so
an int key k IS the node at position k when k < node_count() and
is absent otherwise - Graph::node_names_are_positions. O(V) on first
use, kept current in O(1) after.
pub fn neighbors(&self, node: &str) -> Option<Vec<&str>>
pub fn neighbors_iter(&self, node: &str) -> Option<MgNeighborNames<'_>>
Sourcepub fn with_int_adjacency<R>(&self, f: impl FnOnce(&[Vec<usize>]) -> R) -> R
pub fn with_int_adjacency<R>(&self, f: impl FnOnce(&[Vec<usize>]) -> R) -> R
br-r37-c1-thp6w slice 1: run f with the integer adjacency (hash-free neighbor rows),
built lazily from the stable-slot rows and memoized until the next mutation. The
memo is keyed on revision (bumped by every content mutation) and cleared by
apply_row_orders (the one order-only mutator), so the rows always match the current
storage byte-for-byte. The closure form lets a whole traversal borrow the rows
under one read lock without a per-node allocation. Foundation for the epoch’s
neighbors_indices traversal; no caller yet (infrastructure).
pub fn edge_keys_vec(&self, left: &str, right: &str) -> Vec<usize>
pub fn node_attrs(&self, node: &str) -> Option<&AttrMap>
pub fn edge_attrs( &self, left: &str, right: &str, key: usize, ) -> Option<&AttrMap>
Sourcepub fn edge_attr_values(
&self,
left: &str,
right: &str,
) -> Option<impl Iterator<Item = &AttrMap> + '_>
pub fn edge_attr_values( &self, left: &str, right: &str, ) -> Option<impl Iterator<Item = &AttrMap> + '_>
Iterator over the AttrMaps of every parallel edge between left and
right (undirected: the single canonical bucket), yielded in the SAME
order as edge_keys / edge_keys_iter. The adjacency IndexSet<usize>
and this edges IndexMap<usize, AttrMap> are appended together on add
and both shift_removed on per-key remove (whole bucket dropped on
node/endpoint removal), so their key order stays identical — callers that
need adjacency-order iteration (e.g. the order-sensitive Neumaier weighted
degree) may consume this directly instead of re-looking-up each key.
Undirected sibling of MultiDiGraph::edge_attr_values.
pub fn evidence_ledger(&self) -> &EvidenceLedger
pub fn drain_decision_records(&mut self) -> Vec<DecisionRecord>
Sourcepub fn record_external_recovery(
&mut self,
operation: impl Into<Cow<'static, str>>,
rationale: impl Into<Cow<'static, str>>,
)
pub fn record_external_recovery( &mut self, operation: impl Into<Cow<'static, str>>, rationale: impl Into<Cow<'static, str>>, )
Record a bounded recovery performed OUTSIDE the graph (e.g. a reader
that skipped a malformed input line in hardened mode) in this graph’s
evidence ledger, so decision_records() reports it like a native one.
pub fn runtime_policy(&self) -> &RuntimePolicy
pub fn set_runtime_policy(&mut self, runtime_policy: RuntimePolicy)
pub fn is_directed(&self) -> bool
pub fn is_multigraph(&self) -> bool
Sourcepub fn degree(&self, node: &str) -> usize
pub fn degree(&self, node: &str) -> usize
Return the degree of a node (total number of parallel edges incident). Self-loops contribute 2 to the degree each (NetworkX convention).
Sourcepub fn isolates(&self) -> Vec<String>
pub fn isolates(&self) -> Vec<String>
br-r37-c1-mgisol (cc): native isolate detection for MultiGraph. A node
is isolated iff it has no incident edges (empty/absent adjacency row);
a self-loop keeps a node non-isolated (the loop records the node in its
own row, matching nx’s degree-2 self-loop convention). Yields nodes in
insertion order — identical to the G.degree()-driven nx generator and
to the old multigraph_to_simple_graph projection path, but WITHOUT the
per-call O(V+E) simple-graph rebuild that dominated the binding.
Sourcepub fn number_of_isolates(&self) -> usize
pub fn number_of_isolates(&self) -> usize
br-r37-c1-mgisol (cc): isolate count without the simple-graph projection.
Sourcepub fn is_isolate(&self, node: &str) -> bool
pub fn is_isolate(&self, node: &str) -> bool
br-r37-c1-mgisol (cc): O(1) isolate predicate. Absent node -> false
(mirrors is_isolate(&Graph)); the binding validates presence first.
pub fn add_node(&mut self, node: impl AsRef<str>) -> bool
pub fn add_node_with_attrs( &mut self, node: impl AsRef<str>, attrs: AttrMap, ) -> bool
pub fn add_edge( &mut self, left: impl Into<String>, right: impl Into<String>, ) -> Result<usize, GraphError>
pub fn add_edge_with_attrs( &mut self, left: impl Into<String>, right: impl Into<String>, attrs: AttrMap, ) -> Result<usize, GraphError>
pub fn add_edge_with_key_and_attrs( &mut self, left: impl Into<String>, right: impl Into<String>, key: usize, attrs: AttrMap, ) -> Result<usize, GraphError>
Sourcepub fn add_fresh_edge_unrecorded(
&mut self,
left: impl Into<String>,
right: impl Into<String>,
) -> Option<usize>
pub fn add_fresh_edge_unrecorded( &mut self, left: impl Into<String>, right: impl Into<String>, ) -> Option<usize>
Insert one attribute-free edge for a pair known to have no existing
parallel edge bucket. Returns None if the pair already exists.
Sourcepub fn add_fresh_edge_with_key_unrecorded(
&mut self,
left: impl Into<String>,
right: impl Into<String>,
key: usize,
) -> Option<usize>
pub fn add_fresh_edge_with_key_unrecorded( &mut self, left: impl Into<String>, right: impl Into<String>, key: usize, ) -> Option<usize>
Insert one attribute-free edge with an explicit key for a pair known to
have no existing parallel edge bucket. Returns None if the pair
already exists.
Sourcepub fn extend_nodes_with_attrs_unrecorded<I>(&mut self, nodes: I) -> usize
pub fn extend_nodes_with_attrs_unrecorded<I>(&mut self, nodes: I) -> usize
br-r37-c1-l5ve7: bulk node insert WITH attrs, one ledger record — MultiGraph mirror of MultiDiGraph::extend_nodes_with_attrs_unrecorded. Existing nodes merge attrs (extend).
Sourcepub fn extend_nodes_unrecorded<I, N>(&mut self, nodes: I) -> usize
pub fn extend_nodes_unrecorded<I, N>(&mut self, nodes: I) -> usize
Bulk node insert without attrs, one summary ledger record.
Sourcepub fn extend_keyed_edges_with_attrs_unrecorded<I>(&mut self, edges: I) -> usize
pub fn extend_keyed_edges_with_attrs_unrecorded<I>(&mut self, edges: I) -> usize
br-r37-c1-l5ve7: bulk KEYED edge insert WITH attrs, one ledger record — MultiGraph mirror of MultiDiGraph::extend_keyed_edges_with_attrs_unrecorded (add_edge_impl pays TWO record_decision calls per edge). Endpoint nodes are created on demand; an existing (u, v, key) cell merges attrs (extend), matching add_edge_with_key_and_attrs.
Sourcepub fn extend_fresh_int_prefix_keyed_edges_unrecorded<I>(
&mut self,
node_count: usize,
edges: I,
) -> usize
pub fn extend_fresh_int_prefix_keyed_edges_unrecorded<I>( &mut self, node_count: usize, edges: I, ) -> usize
Bulk-load attribute-free keyed edges for a freshly-created integer
prefix graph. The caller has already validated that node first-seen
order is exactly 0..node_count and that internal keys are sequential
per undirected pair, so this builds the string-keyed MultiGraph state
directly from indices instead of canonicalizing both endpoints for every
edge in the Python boundary layer.
Sourcepub fn extend_fresh_index_keyed_edges_with_attrs_unrecorded<I, N>(
&mut self,
nodes: N,
edges: I,
) -> usize
pub fn extend_fresh_index_keyed_edges_with_attrs_unrecorded<I, N>( &mut self, nodes: N, edges: I, ) -> usize
Bulk-load attributed keyed edges for a freshly-created integer-indexed graph. The caller has already assigned NetworkX-compatible node labels and per-undirected-pair keys, so this avoids endpoint string hashing in the Python boundary layer while preserving the normal MultiGraph storage layout.
Sourcepub fn replace_edge_attrs(
&mut self,
left: &str,
right: &str,
key: usize,
attrs: AttrMap,
) -> bool
pub fn replace_edge_attrs( &mut self, left: &str, right: &str, key: usize, attrs: AttrMap, ) -> bool
br-r37-c1-sjf4t: overwrite the attribute map for an existing (u, v, key) edge. Returns whether the edge existed.
Sourcepub fn replace_node_attrs(&mut self, node: &str, attrs: AttrMap) -> bool
pub fn replace_node_attrs(&mut self, node: &str, attrs: AttrMap) -> bool
br-r37-c1-sjf4t: overwrite the attribute map for an existing node.
pub fn remove_edge( &mut self, left: &str, right: &str, key: Option<usize>, ) -> bool
pub fn clear_edges(&mut self)
pub fn remove_node(&mut self, node: &str) -> bool
Sourcepub fn remove_nodes_from<'a, I>(&mut self, nodes: I) -> (usize, usize)where
I: IntoIterator<Item = &'a str>,
pub fn remove_nodes_from<'a, I>(&mut self, nodes: I) -> (usize, usize)where
I: IntoIterator<Item = &'a str>,
br-r37-c1-mgrnf: batch node removal — one O(|V|+|E|) retain pass,
matching the simple-Graph batch (Graph::remove_nodes_from) that the
directed types already carry. (remove_node itself is O(degree) since
yr2oc.1, so this pays off only for a large share of the graph.)
Returns (removed_node_count, removed_edge_instance_count).
pub fn edges_ordered(&self) -> Vec<MultiEdgeSnapshot>
pub fn edges_ordered_borrowed(&self) -> Vec<(&str, &str, usize, &AttrMap)>
Sourcepub fn weighted_size_int(&self, weight: &str) -> Option<i128>
pub fn weighted_size_int(&self, weight: &str) -> Option<i128>
br-r37-c1-wsize (cc): integer size(weight) from the store — the
multigraph twin of Graph::weighted_size_int. Each parallel edge is one
bucket entry in self.edges and contributes its weight once (size halves
degree’s double count); a self-loop key is one stored edge counted once.
Returns None on any non-integer weight (caller uses the exact
float/PyObject degree path); missing weight defaults to nx’s int 1.