Skip to main content

xz_knowledge_graph/types/
relation.rs

1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5use super::confidence::Confidence;
6use super::provenance::Provenance;
7
8#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
9pub enum WeightStrategy {
10    /// 1.0 - effective_weight (default, existing behavior)
11    InverseConfidence,
12    /// 1.0 / effective_weight (multiplicative)
13    InverseMultiplicative,
14    /// Fixed unit weight (unweighted)
15    Unweighted,
16    /// Custom multiplier on effective_weight
17    Custom(f32),
18}
19
20impl Default for WeightStrategy {
21    fn default() -> Self {
22        Self::InverseConfidence
23    }
24}
25
26/// Relation between two entities.
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct Relation {
29    pub id: String,
30    pub source_id: String,
31    pub target_id: String,
32    pub relation_type: String,
33    pub properties: HashMap<String, String>,
34    pub confidence: Confidence,
35    pub provenance: Option<Provenance>,
36    pub valid_from: Option<u64>,
37    pub valid_to: Option<u64>,
38    pub created_at: u64,
39    pub weight: Option<f32>,
40}
41
42impl Relation {
43    /// Default weight = confidence.as_f32()
44    pub fn effective_weight(&self) -> f32 {
45        self.weight.unwrap_or_else(|| self.confidence.as_f32())
46    }
47}
48
49impl WeightStrategy {
50    pub fn relation_cost(self, rel: &Relation) -> f32 {
51        match self {
52            Self::InverseConfidence => 1.0 - rel.effective_weight().max(0.01),
53            Self::InverseMultiplicative => {
54                let w = rel.effective_weight().max(0.01);
55                1.0 / w
56            }
57            Self::Unweighted => 1.0,
58            Self::Custom(m) => {
59                let w = rel.effective_weight() * m;
60                1.0 - w.max(0.0).min(0.99)
61            }
62        }
63    }
64}