// First-claim value propagation (PropagateBFS): a depth-bounded BFS from// seeded nodes where the first relationship, in BFS order, to reach a node// claims it and sets the value the node carries onward. The claim order --// FIFO over discovery, with each expansion's eligible rels ordered by a rel// property and optionally truncated -- is part of the semantics, not a perf// detail: which rels survive truncation decides which rel claims which// neighbor. Each seed runs an independent traversal (its own visited set);// across seeds a node accumulates the sum of its per-seed claimed values// and its minimum depth. This is the stateful money-flow/taint-trace shape// (e.g. LDBC FinBench's truncated fund tracing) that path enumeration plus// aggregation cannot reproduce and that explodes on hubs if attempted.package chickpeasimport// PropagateSeed is one traversal start: the node enters at depth 1 carrying// Value. The same node may be seeded more than once (one run each).typePropagateSeedstruct { Node NodeID Value float64}// PropagateResult is one reached node with its accumulated value and// minimum depth (seeds are depth 1).typePropagateResultstruct { Node NodeID Value float64 Depth uint32}// PropagateOpts parameterizes PropagateBFS. The zero value is not useful:// set RelTypes (empty matches no rels), Direction, MaxDepth, and ValueProp.typePropagateOptsstruct {// RelTypes is the fan-out union of relationship types. RelTypes []string// Direction of expansion from each claimed node. Direction Direction// MaxDepth bounds the traversal: seeds sit at depth 1 and nodes expand // while their depth is below MaxDepth (values below 1 mean seeds only). MaxDepth uint32// ValueProp is the float rel property a claiming rel carries to the // node it claims (absent values read as 0). ValueProp string// Desc orders each expansion's eligible rels by ValueProp descending // instead of ascending. Ties keep adjacency order (stable). Desc bool// TruncLimit caps each expansion's ordered rels (0 = no cap). TruncLimit int// MinValue is an exclusive lower bound on a claiming rel's carried // value; the default 0 propagates only positive values. Pass -Inf to // disable. MinValue float64// FilterProp, when non-empty, names an integer rel property that must // be present and within [FilterMin, FilterMax] for a rel to be // eligible at all. FilterProp string FilterMin, FilterMax int64}// propEntry is one node's accumulation across per-seed runs.type propEntry struct { value float64 depth uint32}// propHop is a queued claim: node claimed at depth carrying value.type propHop struct { node NodeID depth uint32 value float64}// propRel is one eligible fan-out rel during an expansion.type propRel struct { value float64 nbr NodeID}// PropagateBFS runs first-claim value propagation from seeds under opts.// Results are sorted by node id ascending; a seed node itself is a result// (depth 1, its seed value) even when it expands nowhere.func ( *Snapshot) ( []PropagateSeed, PropagateOpts) []PropagateResult {varF64Col := falseif .ValueProp != "" {if , := .RelCol(.ValueProp); && .Dtype() == DtypeF64 { = .F64() = true } }varI64Col := falseif .FilterProp != "" {if , := .RelCol(.FilterProp); && .Dtype() == DtypeI64 { = .I64() = true } } := .FilterProp != "" := map[NodeID]*propEntry{}var []propHopvar []propRelfor , := range { := map[NodeID]bool{.Node: true} = append([:0], propHop{.Node, 1, .Value})for := 0; < len(); ++ { := []if := [.node]; != nil { .value += .valueif .depth < .depth { .depth = .depth } } else { [.node] = &propEntry{.value, .depth} }if .depth >= .MaxDepth {continue } = [:0]for := range .Rels(.node, .Direction, .RelTypes...) {if {if ! {continue } , := .Get(.Pos)if ! || < .FilterMin || > .FilterMax {continue } } := 0.0if { , _ = .Get(.Pos) } = append(, propRel{, .Neighbor}) }if .Desc {sort.SliceStable(, func(, int) bool { return [].value > [].value }) } else {sort.SliceStable(, func(, int) bool { return [].value < [].value }) }if .TruncLimit > 0 && len() > .TruncLimit { = [:.TruncLimit] }for , := range {if .value > .MinValue && ![.nbr] { [.nbr] = true = append(, propHop{.nbr, .depth + 1, .value}) } } } } := make([]PropagateResult, 0, len())for , := range { = append(, PropagateResult{, .value, .depth}) }sort.Slice(, func(, int) bool { return [].Node < [].Node })return}
The pages are generated with Goldsv0.8.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.