Skip to main content

trit_core/
value.rs

1//! 三值逻辑的核心值类型。
2//!
3//! 三值逻辑(ternary logic)中的每个值属于 `{0, 1, X}`,其中 `X` 表示
4//! “未知 / 无关 / 不确定”。不同的三值代数对 `X` 的解释不同:
5//!
6//! - **Kleene 强三值逻辑**(K3):`X` 是“不知道”,是格序的中点。
7//! - **Łukasiewicz 三值模糊逻辑**(Ł3):`X` 是“介于 0 与 1 之间的不确定值”。
8//! - **Bochvar 弱三值逻辑**(B3):`X` 是“毒值”,吸收一切运算。
9
10use serde::{Deserialize, Serialize};
11use std::fmt;
12
13/// 三值逻辑中的单个取值。
14///
15/// 顺序即枚举顺序,`Ord` 的派生保证 `False < Unknown < True`,
16/// 方便用 `min` / `max` 表达格序的 `AND` / `OR`。
17#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
18pub enum Ternary {
19    /// 假(0)。
20    False,
21    /// 未知(X)。
22    Unknown,
23    /// 真(1)。
24    True,
25}
26
27impl Ternary {
28    /// 逻辑常量假。
29    pub const FALSE: Self = Self::False;
30    /// 逻辑常量未知。
31    pub const UNKNOWN: Self = Self::Unknown;
32    /// 逻辑常量真。
33    pub const TRUE: Self = Self::True;
34
35    /// 三值的所有取值,按 `False < Unknown < True` 顺序。
36    pub const ALL: [Self; 3] = [Self::False, Self::Unknown, Self::True];
37
38    /// `bool -> Ternary`:`true -> True`,`false -> False`(无分支 Select)。
39    pub const fn from_bool(value: bool) -> Self {
40        if value { Self::True } else { Self::False }
41    }
42
43    /// `Ternary -> Option<bool>`:`Unknown` 返回 `None`。
44    pub const fn to_bool(self) -> Option<bool> {
45        match self {
46            Self::True => Some(true),
47            Self::False => Some(false),
48            Self::Unknown => None,
49        }
50    }
51
52    /// 是否为二值(非 `Unknown`)。
53    pub const fn is_binary(self) -> bool {
54        !matches!(self, Self::Unknown)
55    }
56
57    /// 数值形式:`False -> 0`,`Unknown -> 0.5`,`True -> 1`。
58    ///
59    /// 这是把 `X` 视为“0 与 1 之间的不确定值”时的自然映射,
60    /// 也是 Łukasiewicz 强加法 / 强合取的定义基础。
61    pub const fn as_f64(self) -> f64 {
62        match self {
63            Self::False => 0.0,
64            Self::Unknown => 0.5,
65            Self::True => 1.0,
66        }
67    }
68
69    /// 是否**精确等于**假;`X` 返回 `false`。
70    ///
71    /// 这里不做任何折叠。若要把 `X` 当假/当真的二值化,请用
72    /// [`to_bool_strict`](Self::to_bool_strict) / [`to_bool_loose`](Self::to_bool_loose)。
73    pub const fn is_false(self) -> bool {
74        matches!(self, Self::False)
75    }
76
77    /// 是否**精确等于**真;`X` 返回 `false`。
78    ///
79    /// 若要把 `X` 当真的二值化,请用 [`to_bool_loose`](Self::to_bool_loose)。
80    pub const fn is_true(self) -> bool {
81        matches!(self, Self::True)
82    }
83
84    /// 是否为未知值。
85    pub const fn is_unknown(self) -> bool {
86        matches!(self, Self::Unknown)
87    }
88
89    /// 是否为确定值(`0` 或 `1`)。
90    pub const fn is_known(self) -> bool {
91        !matches!(self, Self::Unknown)
92    }
93
94    /// 经典二值化:把 `X` 折成假。
95    pub const fn to_bool_strict(self) -> bool {
96        matches!(self, Self::True)
97    }
98
99    /// 经典二值化:把 `X` 折成真。
100    pub const fn to_bool_loose(self) -> bool {
101        !matches!(self, Self::False)
102    }
103
104    /// 解析单个字符:`0`/`f`/`F` → 假,`1`/`t`/`T` → 真,`x`/`X`/`?` → 未知。
105    pub fn parse_char(c: char) -> Option<Self> {
106        match c {
107            '0' | 'f' | 'F' => Some(Self::False),
108            '1' | 't' | 'T' => Some(Self::True),
109            'x' | 'X' | '?' => Some(Self::Unknown),
110            _ => None,
111        }
112    }
113
114    /// 单字符表示:假为 `0`,未知为 `X`,真为 `1`。
115    pub const fn as_char(self) -> char {
116        match self {
117            Self::False => '0',
118            Self::Unknown => 'X',
119            Self::True => '1',
120        }
121    }
122
123    /// 单字符紧凑表示(用于真值表列头,未知记作小写 `x`)。
124    pub const fn as_compact_char(self) -> char {
125        match self {
126            Self::False => '0',
127            Self::Unknown => 'x',
128            Self::True => '1',
129        }
130    }
131}
132
133impl fmt::Display for Ternary {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        f.write_str(match self {
136            Self::False => "0",
137            Self::Unknown => "X",
138            Self::True => "1",
139        })
140    }
141}
142
143#[cfg(test)]
144mod tests {
145    use super::*;
146
147    #[test]
148    fn ordering_is_false_unknown_true() {
149        assert!(Ternary::False < Ternary::Unknown);
150        assert!(Ternary::Unknown < Ternary::True);
151    }
152
153    #[test]
154    fn parse_char_round_trips() {
155        for v in Ternary::ALL {
156            assert_eq!(Ternary::parse_char(v.as_char()), Some(v));
157        }
158        assert_eq!(Ternary::parse_char('?'), Some(Ternary::Unknown));
159        assert_eq!(Ternary::parse_char('z'), None);
160    }
161
162    #[test]
163    fn numeric_mapping() {
164        assert!((Ternary::False.as_f64() - 0.0).abs() < f64::EPSILON);
165        assert!((Ternary::Unknown.as_f64() - 0.5).abs() < f64::EPSILON);
166        assert!((Ternary::True.as_f64() - 1.0).abs() < f64::EPSILON);
167    }
168
169    #[test]
170    fn binarization() {
171        assert!(!Ternary::Unknown.to_bool_strict());
172        assert!(Ternary::Unknown.to_bool_loose());
173        assert!(Ternary::True.to_bool_strict());
174        assert!(Ternary::False.is_known());
175        assert!(!Ternary::Unknown.is_known());
176    }
177}