ax_rd
4 hours ago 60eb89c12ee0661785395bff90940204b16dcb3a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package graph
 
// AdjEdge 带权邻接边(导出:index 包 LoadRWRGraph 需引用该类型)
type AdjEdge struct {
    To     int64
    Weight float64
}
 
// RWR Random-Walk-with-Restart(个性化 PageRank):
// 从种子集合出发在无向带权图上做 power iteration,restart 概率 alpha 回到种子。
// 返回归一化到 [0,1] 的游走质量。确定性算法,无随机数。
func RWR(seedIDs []int64, adj map[int64][]AdjEdge, alpha float64) map[int64]float64 {
    if len(seedIDs) == 0 {
        return map[int64]float64{}
    }
    // 收集参与节点:种子 + 邻接可达
    nodes := make(map[int64]bool)
    for _, s := range seedIDs {
        nodes[s] = true
    }
    for from := range adj {
        nodes[from] = true
        for _, e := range adj[from] {
            nodes[e.To] = true
        }
    }
    n := len(nodes)
    if n == 0 {
        return map[int64]float64{}
    }
    idx := make(map[int64]int, n)
    ids := make([]int64, 0, n)
    for id := range nodes {
        idx[id] = len(ids)
        ids = append(ids, id)
    }
 
    // 重启向量:种子均匀
    r := make([]float64, n)
    for _, s := range seedIDs {
        if i, ok := idx[s]; ok {
            r[i] = 1.0 / float64(len(seedIDs))
        }
    }
 
    const maxIter = 50
    const eps = 1e-6
    newR := make([]float64, n)
    for iter := 0; iter < maxIter; iter++ {
        for i := range newR {
            newR[i] = 0
        }
        // 游走传播:out[i] = sum(w_ij)
        for i, id := range ids {
            var total float64
            for _, e := range adj[id] {
                total += e.Weight
            }
            if total == 0 {
                continue
            }
            for _, e := range adj[id] {
                j, ok := idx[e.To]
                if !ok {
                    continue
                }
                newR[j] += (1 - alpha) * r[i] * e.Weight / total
            }
        }
        // restart
        for i := range newR {
            newR[i] += alpha * r[i]
        }
        // 收敛判断
        diff := 0.0
        for i := range newR {
            d := newR[i] - r[i]
            if d < 0 {
                d = -d
            }
            diff += d
        }
        r, newR = newR, r
        if diff < eps {
            break
        }
    }
    // 归一化 [0,1]
    maxV := 0.0
    for _, v := range r {
        if v > maxV {
            maxV = v
        }
    }
    out := make(map[int64]float64, n)
    if maxV == 0 {
        for _, id := range ids {
            out[id] = 0
        }
        return out
    }
    for i, id := range ids {
        out[id] = r[i] / maxV
    }
    return out
}