scirs2_graph/signed_directed/
types.rs1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct SignedEdge {
9 pub src: usize,
11 pub dst: usize,
13 pub sign: i8,
15}
16
17impl SignedEdge {
18 pub fn new(src: usize, dst: usize, sign: i8) -> Self {
20 Self { src, dst, sign }
21 }
22
23 pub fn is_positive(&self) -> bool {
25 self.sign > 0
26 }
27}
28
29#[derive(Debug, Clone, Copy, PartialEq)]
31pub struct DirectedEdge {
32 pub src: usize,
34 pub dst: usize,
36 pub weight: f64,
38}
39
40impl DirectedEdge {
41 pub fn new(src: usize, dst: usize, weight: f64) -> Self {
43 Self { src, dst, weight }
44 }
45}
46
47#[derive(Debug, Clone)]
49pub struct SignedGraph {
50 pub n_nodes: usize,
52 pub edges: Vec<SignedEdge>,
54 pub pos_adj: Vec<Vec<usize>>,
56 pub neg_adj: Vec<Vec<usize>>,
58}
59
60impl SignedGraph {
61 pub fn new(n_nodes: usize) -> Self {
63 Self {
64 n_nodes,
65 edges: Vec::new(),
66 pos_adj: vec![Vec::new(); n_nodes],
67 neg_adj: vec![Vec::new(); n_nodes],
68 }
69 }
70
71 pub fn add_edge(&mut self, src: usize, dst: usize, sign: i8) {
73 assert!(
74 src < self.n_nodes && dst < self.n_nodes,
75 "node index out of range"
76 );
77 self.edges.push(SignedEdge { src, dst, sign });
78 if sign > 0 {
79 self.pos_adj[src].push(dst);
80 self.pos_adj[dst].push(src);
81 } else {
82 self.neg_adj[src].push(dst);
83 self.neg_adj[dst].push(src);
84 }
85 }
86
87 pub fn positive_edge_count(&self) -> usize {
89 self.edges.iter().filter(|e| e.sign > 0).count()
90 }
91
92 pub fn negative_edge_count(&self) -> usize {
94 self.edges.iter().filter(|e| e.sign < 0).count()
95 }
96
97 pub fn abs_degree(&self, v: usize) -> usize {
99 self.pos_adj[v].len() + self.neg_adj[v].len()
100 }
101}
102
103#[derive(Debug, Clone)]
105pub struct DirectedGraph {
106 pub n_nodes: usize,
108 pub edges: Vec<DirectedEdge>,
110 pub out_adj: Vec<Vec<(usize, f64)>>,
112 pub in_adj: Vec<Vec<(usize, f64)>>,
114}
115
116impl DirectedGraph {
117 pub fn new(n_nodes: usize) -> Self {
119 Self {
120 n_nodes,
121 edges: Vec::new(),
122 out_adj: vec![Vec::new(); n_nodes],
123 in_adj: vec![Vec::new(); n_nodes],
124 }
125 }
126
127 pub fn add_edge(&mut self, src: usize, dst: usize, weight: f64) {
129 assert!(
130 src < self.n_nodes && dst < self.n_nodes,
131 "node index out of range"
132 );
133 self.edges.push(DirectedEdge { src, dst, weight });
134 self.out_adj[src].push((dst, weight));
135 self.in_adj[dst].push((src, weight));
136 }
137
138 pub fn out_degree(&self, v: usize) -> usize {
140 self.out_adj[v].len()
141 }
142
143 pub fn in_degree(&self, v: usize) -> usize {
145 self.in_adj[v].len()
146 }
147}
148
149#[derive(Debug, Clone)]
151pub struct SignedEmbedConfig {
152 pub dim: usize,
154 pub n_iter: usize,
156 pub lr: f64,
158 pub neg_sample: usize,
160}
161
162impl Default for SignedEmbedConfig {
163 fn default() -> Self {
164 Self {
165 dim: 16,
166 n_iter: 100,
167 lr: 0.01,
168 neg_sample: 5,
169 }
170 }
171}
172
173#[derive(Debug, Clone)]
175pub struct DirectedEmbedConfig {
176 pub dim: usize,
178 pub n_iter: usize,
180}
181
182impl Default for DirectedEmbedConfig {
183 fn default() -> Self {
184 Self {
185 dim: 16,
186 n_iter: 10,
187 }
188 }
189}
190
191#[derive(Debug, Clone)]
193pub struct EmbeddingResult {
194 pub embeddings: Vec<Vec<f64>>,
196 pub dim: usize,
198 pub n_nodes: usize,
200}
201
202impl EmbeddingResult {
203 pub fn zeros(n_nodes: usize, dim: usize) -> Self {
205 Self {
206 embeddings: vec![vec![0.0_f64; dim]; n_nodes],
207 dim,
208 n_nodes,
209 }
210 }
211
212 pub fn get(&self, v: usize) -> &[f64] {
214 &self.embeddings[v]
215 }
216}