Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

modify! — Mutation

modify! applies transactional changes to an existing graph — adding nodes, removing nodes, adding/removing edges, and swapping values — all atomically. It returns a Modification describing everything that changed.

DSL Primitives

SymbolMeaning
N(id)New node (local id for back-references within this modification)
N_()New node (auto-assigned local id)
n(id)Reference to new node defined earlier in same modify!
X(id)Existing graph node (by graph node id)
x(id)Reference to existing graph node (no value change)
!X(id)Remove existing node (and all its edges)
E()New edge constructor
e()Existing edge reference (for value swap)
!e()Remove existing edge
.val(v)Set value on node or edge
E().include(p)Add a part to a composite link, creating the link on a vacant pair
E().exclude::<T>()Drop a composite link’s T part
E().exclude_kind(k)Drop the part of a runtime kind

Adding Nodes and Edges

use grw::graph::{self, MGraph, edge};

let mut g: MGraph<(), edge::Undir<()>> = MGraph::default();

// add two connected nodes
modify!(g, [N(1) ^ N(2)]).unwrap();
assert_eq!(g.node_count(), 2);
assert_eq!(g.edge_count(), 1);

01

// connect new node to existing
modify!(g, [X(0) ^ N(3)]).unwrap();
assert_eq!(g.node_count(), 3);
assert_eq!(g.edge_count(), 2);

012

let mut g: MGraph<(), edge::Dir<()>> = MGraph::default();

// directed path
modify!(g, [N(1) >> (N(2) >> N(3))]).unwrap();
assert_eq!(g.node_count(), 3);
assert_eq!(g.edge_count(), 2);

012

let mut g: MGraph<(), edge::Undir<()>> = MGraph::default();

// triangle via back-reference
modify!(g, [N(1) ^ (N(2) ^ (N(3) ^ n(1)))]).unwrap();
assert_eq!(g.node_count(), 3);
assert_eq!(g.edge_count(), 3);

012

With Values

let mut g: MGraph<&str, edge::Undir<u32>> = MGraph::default();

// node and edge values
modify!(g, [
    N(1).val("a") & E().val(42u32) ^ N(2).val("b")
]).unwrap();
assert_eq!(g.node_count(), 2);
assert_eq!(g.edge_count(), 1);

0“a”1“b”42

// isolated node
modify!(g, [N(3).val("c")]).unwrap();
assert_eq!(g.node_count(), 3);

0“a”1“b”2“c”42

Removing Nodes and Edges

let mut g: MGraph<(), edge::Undir<()>> = MGraph::default();
modify!(g, [N(1) ^ N(2) ^ N(3)]).unwrap();

// remove node 1 (and its edges)
modify!(g, [!X(1)]).unwrap();
assert_eq!(g.node_count(), 2);

012

let mut g: MGraph<(), edge::Dir<()>> = MGraph::default();
modify!(g, [N(1) >> N(2)]).unwrap();

// remove edge, keep both nodes
modify!(g, [X(0) & !e() >> x(1)]).unwrap();
assert_eq!(g.node_count(), 2);
assert_eq!(g.edge_count(), 0);

01

Updating Values

A node value changes only through modify! — there is no get_mut for one — because the swap must release the value’s old index keys and claim its new ones, and adjust the degree tables, in the same transaction.

let mut g: MGraph<&str, edge::Undir<()>> = MGraph::default();
modify!(g, [N(1).val("old")]).unwrap();
assert_eq!(g.get(0), Some(&"old"));

// swap node value
modify!(g, [X(0).val("new")]).unwrap();
assert_eq!(g.get(0), Some(&"new"));

0“new”

let mut g: MGraph<(), edge::Undir<u32>> = MGraph::default();
modify!(g, [N(1) & E().val(100u32) ^ N(2)]).unwrap();

// swap edge value
modify!(g, [X(0) & e().val(200u32) ^ X(1)]).unwrap();

01200

On a graph whose edge value is a composite, a link changes part by part: E().include(p), E().exclude::<T>() and E().exclude_kind(k), while !e() still deletes the whole link. The combinator decides what a link with no parts left means — TypeSet removes it. Refusals are typed (PartRejected, PartNotHeld, PartConflict). See Composite Values.

Modification Result

The returned Modification struct contains:

  • new_node_ids — mapping from local ids to real graph ids
  • added_edges — edges that were created
  • removed_nodes / removed_edges — what was deleted
  • swapped_node_vals / swapped_edge_vals — old values that were replaced
let mut g: MGraph<(), edge::Undir<()>> = MGraph::default();
let result = modify!(g, [N(1) ^ N(2)]).unwrap();

// the local id 1 was assigned a real graph node id
let real_id = result.new_node_ids[&LocalId(1)];

Color Legend for Diagrams

Throughout this documentation:

  • Blue — added or changed elements
  • Red dashed — removed elements
  • Black — existing, unchanged elements