narust_158/inference/functions/
utility_functions.rs

1//! 🎯复刻OpenNARS `nars.inference.UtilityFunctions`
2//! * 🚩一些【与原OpenNARS不太相关,但的确通用】的函数,也放在这里
3//!   * 📄如[`UtilityFunctions::max_from`]对[`super::BudgetFunctions::merge`]的抽象
4//! * ✅【2024-05-02 21:17:31】基本实现所有OpenNARS原有功能
5//!   * `and`
6//!   * `or`
7//!   * `aveAri`
8//!   * `aveGeo`
9//!   * `w2c`
10//!   * `c2w`
11//! * ✅【2024-05-03 19:28:13】基本完成所有单元测试
12
13use crate::{entity::ShortFloat, global::Float, parameters::DEFAULT_PARAMETERS};
14use nar_dev_utils::pipe;
15use std::ops::Not;
16
17/// 【派生】用于「短浮点」的实用方法
18/// * 🚩【2024-06-20 22:21:57】现在直接对「短浮点」实现功能,不再搞特征那一套
19///   * 💭实际上也可以重启「短浮点特征」,但此方面Rust比Java方便,故无需徒增复杂性
20///
21/// # 📄OpenNARS
22///
23/// Common functions on real numbers, mostly in [0,1].
24impl ShortFloat {
25    // * 🚩现在直接使用[`ShortFloat`]基于的[`std::ops::Not`]特征
26    // /// 🆕扩展逻辑「非」
27    // /// * 📄这个在OpenNARS中直接用`1 - v`表示了,但此处仍然做出抽象
28    // /// * 📝在使用了`Copy`并且是「按值传参」的情况下,才可省略[`clone`](Clone::clone)
29    // ///   * ⚠️要分清是在「拷贝值」还是在「拷贝引用」
30    // #[inline(always)]
31    // pub fn not(self) -> Self {
32    //     // Self::one() - self
33    //     !self
34    // }
35
36    /// 模拟`UtilityFunctions.and`
37    /// * 🚩扩展逻辑「与」
38    /// * 🚩现在直接使用[`ShortFloat`]基于的[`std::ops::BitAnd`]特征
39    ///
40    /// # 📄OpenNARS
41    ///
42    /// A function where the output is conjunctively determined by the inputs
43    ///
44    ///  @param arr The inputs, each in [0, 1]
45    ///  @return The output that is no larger than each input
46    #[inline(always)]
47    pub fn and(self, value: Self) -> Self {
48        self & value
49    }
50
51    /// 🆕多个值相与
52    /// * 🚩直接派生自「两个值相与」
53    ///   * 📝「扩展逻辑与」遵循交换律和结合律
54    pub fn and_multi(values: impl IntoIterator<Item = Self>) -> Self {
55        values
56            // 逐个迭代值的迭代器
57            .into_iter()
58            // 从「1」开始不断取「与」
59            .fold(Self::ONE, Self::and)
60    }
61
62    /// 模拟`UtilityFunctions.or`
63    /// * 🚩扩展逻辑「或」
64    /// * 🚩【2024-05-02 17:53:22】利用德摩根律行事
65    ///   * 💭可能会有性能损失
66    /// * 🚩现在直接使用[`ShortFloat`]基于的[`std::ops::BitOr`]特征
67    ///
68    /// # 📄OpenNARS
69    ///
70    /// A function where the output is disjunctively determined by the inputs
71    ///
72    /// @param arr The inputs, each in [0, 1]
73    /// @return The output that is no smaller than each input
74    pub fn or(self, value: Self) -> Self {
75        self | value
76    }
77
78    /// 🆕多个值相或
79    /// * 🚩直接派生自「多个值相与」
80    ///   * 📝「扩展逻辑或」遵循交换律和结合律
81    ///   * ⚡优化:无需重复进行逻辑非
82    pub fn or_multi(values: impl IntoIterator<Item = Self>) -> Self {
83        pipe! {
84            // 逐个迭代值的迭代器
85            values.into_iter()
86            // 逐个取逻辑非
87            => .map(Self::not)
88            // 所有值取逻辑与
89            => Self::and_multi
90            // 最后再取逻辑非
91            => .not()
92        }
93    }
94
95    /// 复刻OpenNARS `nars.inference.UtilityFunctions.aveAri`
96    /// * 🚩求代数平均值
97    /// * ❌不能用`impl IntoIterator<Item = Self>`:要计算长度
98    /// * ⚠️迭代器不能为空
99    ///
100    /// # 📄OpenNARS
101    ///
102    /// A function where the output is the arithmetic average the inputs
103    ///
104    /// @param arr The inputs, each in [0, 1]
105    /// @return The arithmetic average the inputs
106    #[doc(alias = "ave_ari")]
107    pub fn arithmetical_average(values: impl IntoIterator<Item = Self>) -> Self {
108        // * 💭【2024-05-02 00:44:41】大概会长期存留,因为与「真值函数」无关而无需迁移
109        /* 📄OpenNARS源码:
110        float product = 1;
111        for (float f : arr) {
112            product *= f;
113        }
114        return (float) Math.pow(product, 1.00 / arr.length); */
115        let mut sum: Float = 0.0;
116        let mut len: usize = 0;
117        for v in values.into_iter() {
118            sum += v.to_float(); // 转换为浮点并追加 | 因此不担心溢出
119            len += 1; // 与此同时,计数
120        }
121        Self::from_float(sum / len as Float)
122        // * 🚩【2024-05-03 12:50:23】边遍历边计数,就能解决问题
123        // pipe! {
124        //     values
125        //     // 逐个迭代值的迭代器
126        //     => .iter()
127        //     // ! 必须先转换为浮点数:连续加和会越界
128        //     => .map(Self::to_float)
129        //     // 所有值的和(从`1`开始)
130        //     => {.sum::<Float>()}#
131        //     // 除以值的个数
132        //     => .div(values.len() as Float)
133        //     // 转换回「短浮点」(保证不越界)
134        //     => Self::from_float
135        // }
136    }
137
138    /// 复刻OpenNARS `nars.inference.UtilityFunctions.aveGeo`
139    /// * 🚩求几何平均值
140    /// * ❌不能用`impl IntoIterator<Item = Self>`:要计算长度
141    ///
142    /// # 📄OpenNARS
143    ///
144    /// A function where the output is the geometric average the inputs
145    ///
146    /// @param arr The inputs, each in [0, 1]
147    /// @return The geometric average the inputs
148    #[doc(alias = "ave_geo")]
149    pub fn geometrical_average(values: impl IntoIterator<Item = Self>) -> Self {
150        // * 💭【2024-05-02 00:44:41】大概会长期存留,因为与「真值函数」无关而无需迁移
151        /* 📄OpenNARS源码:
152        float product = 1;
153        for (float f : arr) {
154            product *= f;
155        }
156        return (float) Math.pow(product, 1.00 / arr.length); */
157        let mut product: Float = 1.0;
158        let mut len: usize = 0;
159        for v in values.into_iter() {
160            product *= v.to_float(); // 转换为浮点并追加
161            len += 1; // 与此同时,计数
162        }
163        // 因为乘法在0~1封闭,故无需顾忌panic
164        Self::from_float(product.powf(1.0 / len as Float))
165        // * ❌【2024-05-03 12:51:44】弃用下述代码:在数值过小时会引发精度丢失
166        /* [src\inference\utility_functions.rs:446:52] [sf1, sf2] = [
167            ShortFloat {
168                value: 3,
169            },
170            ShortFloat {
171                value: 3,
172            },
173        ]
174        thread 'inference::utility_functions::tests::geometrical_average' panicked at src\inference\utility_functions.rs:448:13:
175        assertion `left == right` failed
176          left: ShortFloat { value: 0 }
177         right: ShortFloat { value: 3 } */
178        // values
179        //     // 逐个迭代值的迭代器
180        //     .iter()
181        //     .cloned()
182        //     // 所有值的乘积(从`1`开始)
183        //     .fold(Self::one(), Self::mul)
184        //     // 值个数次开根
185        //     .root(values.len())
186    }
187
188    /// 从真值的「w值」到「c值」
189    /// * 📄超参数`Parameters.HORIZON`参见[`crate::control::Parameters`]
190    ///
191    /// # 📄OpenNARS
192    ///
193    /// A function to convert weight to confidence
194    ///
195    /// @param w Weight of evidence, a non-negative real number
196    /// @return The corresponding confidence, in [0, 1)
197    pub fn w2c(w: Float) -> Self {
198        Self::from_float(Self::w2c_float(w))
199    }
200
201    /// 🎯能利用尽量直接用,避免重复转换
202    pub fn w2c_float(w: Float) -> Float {
203        /* 📄OpenNARS源码:
204        return w / (w + Parameters.HORIZON); */
205        w / (w + DEFAULT_PARAMETERS.horizon)
206    }
207
208    /// 在改版OpenNARS中是常量,在此处因为「常量函数难以构建」改为变量
209    #[allow(non_snake_case)]
210    pub fn W2C1() -> ShortFloat {
211        Self::w2c(1.0)
212    }
213
214    /// 在改版OpenNARS中是常量,在此处因为「常量函数难以构建」改为变量
215    #[allow(non_snake_case)]
216    pub fn W2C1_float() -> Float {
217        Self::w2c_float(1.0)
218    }
219
220    /// 从真值的「c值」到「w值」
221    /// * 📌此处的`c`就是`self`
222    ///
223    /// # 📄OpenNARS
224    ///
225    /// A function to convert confidence to weight
226    ///
227    /// @param c confidence, in [0, 1)
228    /// @return The corresponding weight of evidence, a non-negative real number
229    pub fn c2w(&self) -> Float {
230        /* 📄OpenNARS源码:
231        return Parameters.HORIZON * c / (1 - c); */
232        let c = self.to_float();
233        DEFAULT_PARAMETERS.horizon * c / (1.0 - c)
234    }
235
236    // // 其它用途 //
237    // // ! 🆕这些都不是原OpenNARS「实用函数」中的,而是为了代码统一加上的
238    // * 🚩【2024-06-20 22:23:36】此处随着对「预算值 inc/dec 方法」的抛弃,不再使用
239    // //   * 📄如:`merge`是为了在「预算函数」中减少重复而统一设计的
240
241    // /// 🆕「增长」值
242    // /// * 🎯用于(统一)OpenNARS`incPriority`系列方法
243    // /// * 📝核心逻辑:自己的值和对面取「或」,越取越多
244    // /// * ❓【2024-05-02 00:31:19】是否真的要放到这儿来,在「数据结构定义」中引入「真值函数」的概念
245    // pub fn inc(&mut self, value: Self) {
246    //     // self.set(UtilityFunctions.or(priority.getValue(), v));
247    //     self.set(*self | value)
248    // }
249
250    // /// 🆕「减少」值
251    // /// * 🎯用于(统一)OpenNARS`incPriority`系列方法
252    // /// * 📝核心逻辑:自己的值和对面取「与」,越取越少
253    // /// * ❓【2024-05-02 00:31:19】是否真的要放到这儿来,在「数据结构定义」中引入「真值函数」的概念
254    // pub fn dec(&mut self, value: Self) {
255    //     // self.set(UtilityFunctions.and(priority.getValue(), v));
256    //     self.set(*self & value)
257    // }
258
259    /// 🆕「最大值合并」
260    /// * 🎯用于(统一)OpenNARS`merge`的重复调用
261    /// * 🚩现在已经在[「短浮点」](EvidenceReal)中要求了[`Ord`]
262    /// * 📝【2024-05-03 14:55:29】虽然现在「预算函数」以「直接创建新值」为主范式,
263    ///   * 但在用到该函数的`merge`方法上,仍然是「修改」语义——需要可变引用
264    pub fn max_from(&mut self, other: Self) {
265        let max = (*self).max(other);
266        self.set(max);
267    }
268}
269
270#[cfg(test)]
271mod tests {
272    use super::*;
273    use crate::entity::ShortFloat;
274    use crate::{ok, util::AResult};
275    use nar_dev_utils::{asserts, for_in_ifs, macro_once};
276
277    /// 定义要测试的「短浮点」类型
278    type SF = ShortFloat;
279
280    /// 健壮性测试所用到的「测试精度」
281    /// * 🎯尽可能多地遍历「短浮点」的所有可能情形
282    /// * 🚩测试的案例量
283    /// * 🕒2000不到0.5s,5000大约1s,10000要大约7s
284    const N: usize = 4000;
285    const N_FLOAT: Float = N as Float;
286
287    /// 快捷构造宏
288    macro_rules! sf {
289        // 0、1、0.5 特殊映射
290        (0) => {
291            SF::ZERO
292        };
293        (1) => {
294            SF::ONE
295        };
296        (HALF) => {
297            SF::HALF
298        };
299        (1/2) => {
300            SF::HALF
301        };
302        // 值映射
303        ($float:expr) => {
304            SF::from_float($float)
305        };
306    }
307
308    /// 以一定数目遍历从0到1的所有「短浮点」
309    /// * 🚩用到常量[`N`]与[`N_FLOAT`]
310    fn all_sf() -> impl Iterator<Item = SF> {
311        (0..=N).map(|v| sf!(v as Float / N_FLOAT))
312    }
313
314    /// 海测/快捷遍历所有「短浮点」(所有组合)
315    macro_rules! for_all_sf {
316        ( ( $($var:pat $(if $cond:expr)?),* $(,)? ) => $($code:tt)* ) => {
317            for_in_ifs! {
318                // 遍历时要执行的代码
319                { $($code)* }
320                // 遍历范围
321                $( for $var in (all_sf()) $(if ($cond))? )*
322            }
323        };
324    }
325
326    /// 测试/and
327    #[test]
328    fn and() -> AResult {
329        // 海测(健壮性测试) | 🎯确保正常值不会panic
330        for_all_sf! {
331            (sf1, sf2) =>
332            // 直接计算
333            let _ = sf1 & sf2;
334        }
335        // 例侧(案例测试)
336        macro_once! {
337            /// * 🚩模式:值1 & 值2 ⇒ 预期
338            macro test($($f1:tt & $f2:tt => $expected:tt)*) {
339                asserts! {
340                    $(
341                        sf!($f1) & sf!($f2) => sf!($expected)
342                    )*
343                }
344            }
345            // 0、1
346            0 & 0 => 0
347            0 & 1 => 0
348            1 & 0 => 0
349            1 & 1 => 1
350            // 1:幺元
351            1 & 0.1 => 0.1
352            1 & 0.2 => 0.2
353            1 & 0.3 => 0.3
354            1 & 0.4 => 0.4
355            1 & 0.5 => 0.5
356            1 & 0.6 => 0.6
357            1 & 0.7 => 0.7
358            1 & 0.8 => 0.8
359            1 & 0.9 => 0.9
360            // 0:零元
361            0 & 0.1 => 0
362            0 & 0.2 => 0
363            0 & 0.3 => 0
364            0 & 0.4 => 0
365            0 & 0.5 => 0
366            0 & 0.6 => 0
367            0 & 0.7 => 0
368            0 & 0.8 => 0
369            0 & 0.9 => 0
370            // 乘法语义
371            0.5 & 0.5 => 0.25
372        }
373        ok!()
374    }
375
376    /// 测试/and_multi
377    #[test]
378    fn and_multi() -> AResult {
379        // 海测(健壮性测试) // * 🚩验证与二元运算的逻辑一致
380        for_all_sf! {
381            (sf1, sf2) =>
382            // 直接计算
383            assert_eq!(sf1 & sf2, SF::and_multi([sf1, sf2]));
384        }
385        // * 🚩验证多元运算的正常结果(乘方)
386        let mut sfs = Vec::new();
387        let v = 0.9;
388        for n in 1..=4 {
389            // ! ❌【2024-05-03 12:42:37】对零次幂处理不善:1.0🆚0.9,但OpenNARS中不会用到
390            // ! ⚠️【2024-05-03 12:39:56】目前对五次及以上会有微弱不一致:5904🆚5905
391            sfs.push(sf!(v));
392            let multi = SF::and_multi(sfs.iter().cloned());
393            let pow = sf!(v.powi(n));
394            assert_eq!(multi, pow);
395        }
396        // 例侧(案例测试)
397        macro_once! {
398            /// * 🚩模式:值1 & 值2 & 值3 & ...;
399            macro test($( $($f:tt)&* ;)*) {
400                asserts! {
401                    $(
402                        $(sf!($f))&* => SF::and_multi([$(sf!($f)),*])
403                    )*
404                }
405            }
406            // 0、1 & 二元、三元(最常见即如此)
407            0 & 0;
408            0 & 1;
409            1 & 0;
410            1 & 1;
411            0 & 0 & 0;
412            0 & 0 & 1;
413            0 & 1 & 0;
414            0 & 1 & 1;
415            1 & 0 & 0;
416            1 & 0 & 1;
417            1 & 1 & 0;
418            1 & 1 & 1;
419            // 0.5的幂次
420            0.5;
421            0.5 & 0.5;
422            0.5 & 0.5 & 0.5;
423            0.5 & 0.5 & 0.5 & 0.5;
424            0.5 & 0.5 & 0.5 & 0.5 & 0.5;
425            0.5 & 0.5 & 0.5 & 0.5 & 0.5 & 0.5;
426        }
427        ok!()
428    }
429
430    /// 测试/or
431    #[test]
432    fn or() -> AResult {
433        // 海测(健壮性测试) | 🎯确保正常值不会panic
434        for_all_sf! {
435            (sf1, sf2) =>
436            // 直接计算
437            let _ = sf1 | sf2;
438        }
439        // 例侧(案例测试)
440        macro_once! {
441            /// * 🚩模式:值1 | 值2 ⇒ 预期
442            macro test($($f1:tt | $f2:tt => $expected:tt)*) {
443                asserts! {
444                    $(
445                        sf!($f1) | sf!($f2) => sf!($expected)
446                    )*
447                }
448            }
449            // 0、1
450            0 | 0 => 0
451            0 | 1 => 1
452            1 | 0 => 1
453            1 | 1 => 1
454            // 1:零元
455            1 | 0.1 => 1
456            1 | 0.2 => 1
457            1 | 0.3 => 1
458            1 | 0.4 => 1
459            1 | 0.5 => 1
460            1 | 0.6 => 1
461            1 | 0.7 => 1
462            1 | 0.8 => 1
463            1 | 0.9 => 1
464            // 0:幺元
465            0 | 0.1 => 0.1
466            0 | 0.2 => 0.2
467            0 | 0.3 => 0.3
468            0 | 0.4 => 0.4
469            0 | 0.5 => 0.5
470            0 | 0.6 => 0.6
471            0 | 0.7 => 0.7
472            0 | 0.8 => 0.8
473            0 | 0.9 => 0.9
474            // 德摩根 乘法语义
475            0.5 | 0.5 => 0.75
476        }
477        ok!()
478    }
479
480    /// 测试/or_multi
481    #[test]
482    fn or_multi() -> AResult {
483        // 海测(健壮性测试) // * 🚩验证与二元运算的逻辑一致
484        for_all_sf! {
485            (sf1, sf2) =>
486            // 直接计算
487            assert_eq!(sf1 | sf2, SF::or_multi([sf1, sf2]));
488        }
489        // 例侧(案例测试)
490        macro_once! {
491            /// * 🚩模式:值1 | 值2 | 值3 | ...;
492            macro test($( $($f:tt)|* ;)*) {
493                asserts! {
494                    $(
495                        $(sf!($f))|* => SF::or_multi([$(sf!($f)),*])
496                    )*
497                }
498            }
499            // 0、1 | 二元、三元(最常见即如此)
500            0 | 0;
501            0 | 1;
502            1 | 0;
503            1 | 1;
504            0 | 0 | 0;
505            0 | 0 | 1;
506            0 | 1 | 0;
507            0 | 1 | 1;
508            1 | 0 | 0;
509            1 | 0 | 1;
510            1 | 1 | 0;
511            1 | 1 | 1;
512            // 0.5的幂次
513            0.5;
514            0.5 | 0.5;
515            0.5 | 0.5 | 0.5;
516            0.5 | 0.5 | 0.5 | 0.5;
517            0.5 | 0.5 | 0.5 | 0.5 | 0.5;
518            0.5 | 0.5 | 0.5 | 0.5 | 0.5 | 0.5;
519        }
520        ok!()
521    }
522
523    /// 测试/arithmetical_average
524    #[test]
525    fn arithmetical_average() -> AResult {
526        // * 🚩验证与浮点运算的逻辑一致
527        for_all_sf! {
528            (sf1, sf2) =>
529            // 直接计算
530            let ave_ari = SF::arithmetical_average([sf1 ,sf2]);
531            let float_ari = sf!((sf1.to_float() + sf2.to_float()) / 2.0);
532            assert_eq!(ave_ari, float_ari);
533        }
534        ok!()
535    }
536
537    /// 测试/geometrical_average
538    #[test]
539    fn geometrical_average() -> AResult {
540        // * 🚩验证与浮点运算的逻辑一致
541        for_all_sf! {
542            (sf1, sf2) =>
543            // 直接计算
544            let ave_geo = SF::geometrical_average([sf1 ,sf2]);
545            let float_geo = sf!((sf1.to_float() * sf2.to_float()).sqrt());
546            assert_eq!(ave_geo, float_geo);
547        }
548        ok!()
549    }
550
551    /// 测试/w2c
552    #[test]
553    fn w2c() -> AResult {
554        // * 🚩验证与浮点运算的逻辑一致
555        const N: usize = 1000;
556        for w in 0..=N {
557            let w = w as Float;
558            let k = DEFAULT_PARAMETERS.horizon;
559            let c = SF::w2c(w);
560            // ! ⚠️【2024-05-03 19:18:14】与`1 - k / (w + k)`有微小不一致:0.0063🆚0.0062
561            assert_eq!(c, sf!(w / (w + k)))
562        }
563        ok!()
564    }
565
566    /// 测试/c2w
567    #[test]
568    fn c2w() -> AResult {
569        // * 🚩验证与浮点运算的逻辑一致
570        for_all_sf! {
571            // * 📌「1」会导致「除以零」溢出
572            (c if !c.is_one()) =>
573                let k = DEFAULT_PARAMETERS.horizon;
574                let w = c.c2w();
575                let c = c.to_float();
576                // ! ⚠️【2024-05-03 19:18:14】与`1 - k / (w + k)`有微小不一致:0.0063🆚0.0062
577                assert_eq!(w, c * k / (1.0 - c))
578        }
579        ok!()
580    }
581
582    // /// 测试/inc
583    // #[test]
584    // fn inc() -> AResult {
585    //     // * 🚩验证与逻辑运算的结果一致
586    //     for_all_sf! {
587    //         (mut sf1, sf2) =>
588    //         let expected = sf1 | sf2;
589    //         sf1.inc(sf2);
590    //         assert_eq!(sf1, expected);
591    //     }
592    //     ok!()
593    // }
594
595    // /// 测试/dec
596    // #[test]
597    // fn dec() -> AResult {
598    //     // * 🚩验证与逻辑运算的结果一致
599    //     for_all_sf! {
600    //         (mut sf1, sf2) =>
601    //         let expected = sf1 & sf2;
602    //         sf1.dec(sf2);
603    //         assert_eq!(sf1, expected);
604    //     }
605    //     ok!()
606    // }
607
608    /// 测试/max_from
609    #[test]
610    fn max_from() -> AResult {
611        // * 🚩验证与最大值运算的结果一致
612        for_all_sf! {
613            (mut sf1, sf2) =>
614            let expected = sf1.max(sf2);
615            sf1.max_from(sf2);
616            assert_eq!(sf1, expected);
617        }
618        ok!()
619    }
620}