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}