#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SignedEdge {
pub src: usize,
pub dst: usize,
pub sign: i8,
}
impl SignedEdge {
pub fn new(src: usize, dst: usize, sign: i8) -> Self {
Self { src, dst, sign }
}
pub fn is_positive(&self) -> bool {
self.sign > 0
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct DirectedEdge {
pub src: usize,
pub dst: usize,
pub weight: f64,
}
impl DirectedEdge {
pub fn new(src: usize, dst: usize, weight: f64) -> Self {
Self { src, dst, weight }
}
}
#[derive(Debug, Clone)]
pub struct SignedGraph {
pub n_nodes: usize,
pub edges: Vec<SignedEdge>,
pub pos_adj: Vec<Vec<usize>>,
pub neg_adj: Vec<Vec<usize>>,
}
impl SignedGraph {
pub fn new(n_nodes: usize) -> Self {
Self {
n_nodes,
edges: Vec::new(),
pos_adj: vec![Vec::new(); n_nodes],
neg_adj: vec![Vec::new(); n_nodes],
}
}
pub fn add_edge(&mut self, src: usize, dst: usize, sign: i8) {
assert!(
src < self.n_nodes && dst < self.n_nodes,
"node index out of range"
);
self.edges.push(SignedEdge { src, dst, sign });
if sign > 0 {
self.pos_adj[src].push(dst);
self.pos_adj[dst].push(src);
} else {
self.neg_adj[src].push(dst);
self.neg_adj[dst].push(src);
}
}
pub fn positive_edge_count(&self) -> usize {
self.edges.iter().filter(|e| e.sign > 0).count()
}
pub fn negative_edge_count(&self) -> usize {
self.edges.iter().filter(|e| e.sign < 0).count()
}
pub fn abs_degree(&self, v: usize) -> usize {
self.pos_adj[v].len() + self.neg_adj[v].len()
}
}
#[derive(Debug, Clone)]
pub struct DirectedGraph {
pub n_nodes: usize,
pub edges: Vec<DirectedEdge>,
pub out_adj: Vec<Vec<(usize, f64)>>,
pub in_adj: Vec<Vec<(usize, f64)>>,
}
impl DirectedGraph {
pub fn new(n_nodes: usize) -> Self {
Self {
n_nodes,
edges: Vec::new(),
out_adj: vec![Vec::new(); n_nodes],
in_adj: vec![Vec::new(); n_nodes],
}
}
pub fn add_edge(&mut self, src: usize, dst: usize, weight: f64) {
assert!(
src < self.n_nodes && dst < self.n_nodes,
"node index out of range"
);
self.edges.push(DirectedEdge { src, dst, weight });
self.out_adj[src].push((dst, weight));
self.in_adj[dst].push((src, weight));
}
pub fn out_degree(&self, v: usize) -> usize {
self.out_adj[v].len()
}
pub fn in_degree(&self, v: usize) -> usize {
self.in_adj[v].len()
}
}
#[derive(Debug, Clone)]
pub struct SignedEmbedConfig {
pub dim: usize,
pub n_iter: usize,
pub lr: f64,
pub neg_sample: usize,
}
impl Default for SignedEmbedConfig {
fn default() -> Self {
Self {
dim: 16,
n_iter: 100,
lr: 0.01,
neg_sample: 5,
}
}
}
#[derive(Debug, Clone)]
pub struct DirectedEmbedConfig {
pub dim: usize,
pub n_iter: usize,
}
impl Default for DirectedEmbedConfig {
fn default() -> Self {
Self {
dim: 16,
n_iter: 10,
}
}
}
#[derive(Debug, Clone)]
pub struct EmbeddingResult {
pub embeddings: Vec<Vec<f64>>,
pub dim: usize,
pub n_nodes: usize,
}
impl EmbeddingResult {
pub fn zeros(n_nodes: usize, dim: usize) -> Self {
Self {
embeddings: vec![vec![0.0_f64; dim]; n_nodes],
dim,
n_nodes,
}
}
pub fn get(&self, v: usize) -> &[f64] {
&self.embeddings[v]
}
}