Skip to main content

trit_core/
algebra.rs

1//! 三值代数的实现。
2//!
3//! 三种语义共用同一套记号(`¬ ∧ ∨ ⊕ ⊗ ⇒ ≡`),差别只在 `X` 的行为。
4//!
5//! | 语义 | `X` 的角色 | `X ∧ 0` | `X ∧ 1` | `X ∨ 0` | `X ∨ 1` | `X ⊕ X` | `X ⊗ X` | `X ⇒ X` | `0 ⇒ X` |
6//! |---|---|---|---|---|---|---|---|---|---|
7//! | Kleene (K3) | 中间元(“不知道”) | `0` | `X` | `X` | `1` | `X` | `X` | `X` | `1` |
8//! | Łukasiewicz (Ł3) | 0 与 1 之间的模糊值 | `0` | `X` | `X` | `1` | `1` | `0` | `1` | `1` |
9//! | Bochvar (B3) | 毒值(吸收元) | `X` | `X` | `X` | `X` | `X` | `X` | `X` | `X` |
10//!
11//! - `∧` / `∨` 在 K3 与 Ł3 下是格序的 min / max(`X` 是链的中点);
12//!   在 B3 下 `X` 吸收一切,沾上 `X` 即为 `X`。
13//! - `⊕` 是 Łukasiewicz **强加法** `min(1, a + b)`:Ł3 下 `X ⊕ X = 1`;
14//!   K3 与 B3 下 `X` 传播为 `X`。
15//! - `⊗` 是 Łukasiewicz **强合取** `max(0, a + b - 1)`:Ł3 下 `X ⊗ X = 0`;
16//!   K3 与 B3 下 `X` 传播为 `X`。
17//! - `⇒` 在 K3 下是材料蕴含 `¬a ∨ b`;在 Ł3 下是 MV 蕴含
18//!   `min(1, 1 - a + b)`,故 `X ⇒ X = 1`;在 B3 下 `X` 仍是毒值。
19
20use crate::value::Ternary;
21
22/// 三值逻辑的语义体系。
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
24pub enum Algebra {
25    /// Kleene 强三值逻辑:`X` 表示“不知道”,运算在不确定时产出 `X`。
26    Kleene,
27    /// Łukasiewicz 三值模糊逻辑:`X` 是 0 与 1 之间的不确定值。
28    Lukasiewicz,
29    /// Bochvar 弱三值逻辑:`X` 是“毒值”,沾上 `X` 即为 `X`。
30    Bochvar,
31}
32
33impl Algebra {
34    /// 全部语义体系。
35    pub const ALL: [Self; 3] = [Self::Kleene, Self::Lukasiewicz, Self::Bochvar];
36
37    /// 语义体系的稳定短名,用于 CLI 与序列化。
38    pub const fn as_str(self) -> &'static str {
39        match self {
40            Self::Kleene => "kleene",
41            Self::Lukasiewicz => "lukasiewicz",
42            Self::Bochvar => "bochvar",
43        }
44    }
45
46    /// 解析语义名称,接受 `kleene` / `k3`、`lukasiewicz` / `l3` / `luk` / `bochvar` / `b3`。
47    pub fn parse(s: &str) -> Option<Self> {
48        match s.trim().to_ascii_lowercase().as_str() {
49            "kleene" | "k3" => Some(Self::Kleene),
50            "lukasiewicz" | "luk" | "l3" => Some(Self::Lukasiewicz),
51            "bochvar" | "b3" => Some(Self::Bochvar),
52            _ => None,
53        }
54    }
55
56    /// 该语义下 `X` 是否是吸收元(Bochvar 毒值语义)。
57    pub const fn is_poisonous(self) -> bool {
58        matches!(self, Self::Bochvar)
59    }
60
61    /// 逻辑否定 `¬`。三种语义一致:`¬X = X`。
62    pub const fn not(self, a: Ternary) -> Ternary {
63        match a {
64            Ternary::False => Ternary::True,
65            Ternary::Unknown => Ternary::Unknown,
66            Ternary::True => Ternary::False,
67        }
68    }
69
70    /// 逻辑与 `∧`。
71    ///
72    /// K3 / Ł3:格序 min(`X` 是中间元)。B3:`X` 吸收。
73    pub const fn and(self, a: Ternary, b: Ternary) -> Ternary {
74        match self {
75            Self::Bochvar => {
76                if a.is_unknown() || b.is_unknown() {
77                    Ternary::Unknown
78                } else if a.is_true() && b.is_true() {
79                    Ternary::True
80                } else {
81                    Ternary::False
82                }
83            }
84            Self::Kleene | Self::Lukasiewicz => match (a, b) {
85                (Ternary::False, _) | (_, Ternary::False) => Ternary::False,
86                (Ternary::True, Ternary::True) => Ternary::True,
87                _ => Ternary::Unknown,
88            },
89        }
90    }
91
92    /// 逻辑或 `∨`。
93    ///
94    /// K3 / Ł3:格序 max(`X` 是中间元)。B3:`X` 吸收。
95    pub const fn or(self, a: Ternary, b: Ternary) -> Ternary {
96        match self {
97            Self::Bochvar => {
98                if a.is_unknown() || b.is_unknown() {
99                    Ternary::Unknown
100                } else if a.is_true() || b.is_true() {
101                    Ternary::True
102                } else {
103                    Ternary::False
104                }
105            }
106            Self::Kleene | Self::Lukasiewicz => match (a, b) {
107                (Ternary::True, _) | (_, Ternary::True) => Ternary::True,
108                (Ternary::False, Ternary::False) => Ternary::False,
109                _ => Ternary::Unknown,
110            },
111        }
112    }
113
114    /// 强加法 `⊕`。
115    ///
116    /// - Łukasiewicz:`min(1, a + b)`,`X ⊕ X = 1`。
117    /// - Kleene:`0/1` 上为 `max(0, a + b - 1)`,`X` 传播为 `X`。
118    /// - Bochvar:`X` 是毒值,沾上即 `X`。
119    pub const fn strong_add(self, a: Ternary, b: Ternary) -> Ternary {
120        match self {
121            Self::Lukasiewicz => {
122                // min(1, a + b),a,b ∈ {0, 0.5, 1}
123                let s = a.as_f64() + b.as_f64();
124                if s >= 1.0 {
125                    Ternary::True
126                } else if s <= 0.0 {
127                    Ternary::False
128                } else {
129                    Ternary::Unknown
130                }
131            }
132            Self::Kleene | Self::Bochvar => {
133                if a.is_unknown() || b.is_unknown() {
134                    Ternary::Unknown
135                } else if a.is_true() && b.is_true() {
136                    Ternary::True
137                } else {
138                    Ternary::False
139                }
140            }
141        }
142    }
143
144    /// 强合取 `⊗`。
145    ///
146    /// - Łukasiewicz:`max(0, a + b - 1)`,`X ⊗ X = 0`。
147    /// - Kleene / Bochvar:`X` 传播为 `X`。
148    pub const fn strong_and(self, a: Ternary, b: Ternary) -> Ternary {
149        match self {
150            Self::Lukasiewicz => {
151                let s = a.as_f64() + b.as_f64() - 1.0;
152                if s <= 0.0 {
153                    Ternary::False
154                } else if s >= 1.0 {
155                    Ternary::True
156                } else {
157                    Ternary::Unknown
158                }
159            }
160            Self::Kleene | Self::Bochvar => {
161                if a.is_unknown() || b.is_unknown() {
162                    Ternary::Unknown
163                } else if a.is_true() && b.is_true() {
164                    Ternary::True
165                } else {
166                    Ternary::False
167                }
168            }
169        }
170    }
171
172    /// 蕴含 `⇒`。
173    ///
174    /// - Kleene:材料蕴含 `¬a ∨ b`。
175    /// - Łukasiewicz:MV 蕴含 `min(1, 1 - a + b)`,故 `X ⇒ X = 1`。
176    /// - Bochvar:`X` 是毒值,沾上即 `X`。
177    pub const fn implies(self, a: Ternary, b: Ternary) -> Ternary {
178        match self {
179            Self::Kleene => self.or(self.not(a), b),
180            Self::Bochvar => {
181                if a.is_unknown() || b.is_unknown() {
182                    Ternary::Unknown
183                } else if a.is_true() {
184                    b
185                } else {
186                    Ternary::True
187                }
188            }
189            Self::Lukasiewicz => {
190                // min(1, 1 - a + b)
191                let s = 1.0 - a.as_f64() + b.as_f64();
192                if s >= 1.0 {
193                    Ternary::True
194                } else if s <= 0.0 {
195                    Ternary::False
196                } else {
197                    Ternary::Unknown
198                }
199            }
200        }
201    }
202
203    /// 等价 `≡`:`(a ⇒ b) ∧ (b ⇒ a)`。
204    pub const fn equiv(self, a: Ternary, b: Ternary) -> Ternary {
205        self.and(self.implies(a, b), self.implies(b, a))
206    }
207}
208
209impl std::fmt::Display for Algebra {
210    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
211        f.write_str(self.as_str())
212    }
213}
214
215#[cfg(test)]
216mod tests {
217    use super::*;
218
219    #[test]
220    fn kleene_and_truth_table() {
221        use Ternary::*;
222        assert_eq!(Algebra::Kleene.and(False, Unknown), False);
223        assert_eq!(Algebra::Kleene.and(Unknown, Unknown), Unknown);
224        assert_eq!(Algebra::Kleene.and(Unknown, True), Unknown);
225        assert_eq!(Algebra::Kleene.and(True, True), True);
226    }
227
228    #[test]
229    fn bochvar_and_is_poisonous() {
230        use Ternary::*;
231        assert_eq!(Algebra::Bochvar.and(False, Unknown), Unknown);
232        assert_eq!(Algebra::Bochvar.and(True, Unknown), Unknown);
233        assert_eq!(Algebra::Bochvar.and(True, True), True);
234        assert_eq!(Algebra::Bochvar.and(False, False), False);
235    }
236
237    #[test]
238    fn bochvar_or_is_poisonous() {
239        use Ternary::*;
240        assert_eq!(Algebra::Bochvar.or(True, Unknown), Unknown);
241        assert_eq!(Algebra::Bochvar.or(False, Unknown), Unknown);
242        assert_eq!(Algebra::Bochvar.or(True, True), True);
243    }
244
245    #[test]
246    fn kleene_and_or_are_lattice_ops() {
247        for a in Ternary::ALL {
248            for b in Ternary::ALL {
249                assert_eq!(Algebra::Kleene.and(a, b), Algebra::Lukasiewicz.and(a, b));
250                assert_eq!(Algebra::Kleene.or(a, b), Algebra::Lukasiewicz.or(a, b));
251            }
252        }
253    }
254
255    #[test]
256    fn strong_add_differs_between_semantics() {
257        use Ternary::*;
258        assert_eq!(Algebra::Kleene.strong_add(Unknown, Unknown), Unknown);
259        assert_eq!(Algebra::Lukasiewicz.strong_add(Unknown, Unknown), True);
260        assert_eq!(Algebra::Bochvar.strong_add(Unknown, Unknown), Unknown);
261        assert_eq!(Algebra::Kleene.strong_add(True, False), False);
262        assert_eq!(Algebra::Kleene.strong_add(False, True), False);
263        assert_eq!(Algebra::Bochvar.strong_add(True, False), False);
264        assert_eq!(Algebra::Lukasiewicz.strong_add(False, True), True);
265        assert_eq!(Algebra::Lukasiewicz.strong_add(False, False), False);
266        assert_eq!(Algebra::Kleene.strong_add(True, True), True);
267    }
268
269    #[test]
270    fn strong_and_lukasiewicz_matches_formula() {
271        use Ternary::*;
272        // max(0, a + b - 1)
273        assert_eq!(Algebra::Lukasiewicz.strong_and(Unknown, Unknown), False);
274        assert_eq!(Algebra::Lukasiewicz.strong_and(Unknown, True), Unknown);
275        assert_eq!(Algebra::Lukasiewicz.strong_and(True, True), True);
276        assert_eq!(Algebra::Lukasiewicz.strong_and(False, True), False);
277        assert_eq!(Algebra::Kleene.strong_and(Unknown, True), Unknown);
278        assert_eq!(Algebra::Kleene.strong_and(True, False), False);
279        assert_eq!(Algebra::Bochvar.strong_and(True, False), False);
280        assert_eq!(Algebra::Bochvar.strong_and(Unknown, True), Unknown);
281    }
282
283    #[test]
284    fn implication_differs_between_semantics() {
285        use Ternary::*;
286        // K3: X ⇒ X = X;Ł3: X ⇒ X = 1;B3: X ⇒ X = X
287        assert_eq!(Algebra::Kleene.implies(Unknown, Unknown), Unknown);
288        assert_eq!(Algebra::Lukasiewicz.implies(Unknown, Unknown), True);
289        assert_eq!(Algebra::Bochvar.implies(Unknown, Unknown), Unknown);
290        assert_eq!(Algebra::Kleene.implies(True, False), False);
291        assert_eq!(Algebra::Kleene.implies(False, True), True);
292        assert_eq!(Algebra::Kleene.implies(False, Unknown), True);
293        assert_eq!(Algebra::Bochvar.implies(False, Unknown), Unknown);
294        assert_eq!(Algebra::Lukasiewicz.implies(False, Unknown), True);
295    }
296
297    #[test]
298    fn algebra_parsing() {
299        assert_eq!(Algebra::parse("K3"), Some(Algebra::Kleene));
300        assert_eq!(Algebra::parse("luk"), Some(Algebra::Lukasiewicz));
301        assert_eq!(Algebra::parse("b3"), Some(Algebra::Bochvar));
302        assert_eq!(Algebra::parse("nope"), None);
303    }
304}