1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
//! 复刻抽象的「证据基」特征
//! * 🎯以「时间戳」为基本结构,使「语句」「任务」直接支持其中的功能
use crate::{global::ClockTime, symbols::*, util::ToDisplayAndBrief};
use nar_dev_utils::{join, JoinTo};
use narsese::lexical::Stamp as LexicalStamp;
/// [`Vec`]集合判等
fn set_vec_eq<T: Clone + Ord>(v1: &[T], v2: &[T]) -> bool {
v1.len() == v2.len() && v1.iter().all(|i| v2.contains(i))
// let mut v1 = v1.to_owned();
// let mut v2 = v2.to_owned();
// v1.sort();
// v2.sort();
// v1 == v2
}
/// 🆕证据(基)
/// * 🎯抽象描述「时间戳」的特征
/// * 📝核心:记载一系列「证据时间」,提供「证据是否重复」方法,以避免「重复推理」
pub trait Evidential: ToDisplayAndBrief {
/// 模拟`Stamp.evidentialBase`、`Stamp.getBase`
/// * 📝译名为「证据基」
/// * 🚩【2024-05-05 14:09:16】目前仅使用数组切片,所有权应该在`self`内部存储
///
/// # 📄OpenNARS
///
/// serial numbers
fn evidential_base(&self) -> &[ClockTime];
/// 模拟`Stamp.baseLength`、`Stamp.length`
/// * 🚩🆕【2024-05-05 14:11:23】不直接模拟`Stamp.baseLength`:实际上就是[`Stamp::__evidential_base`]的长度
/// * 📝OpenNARS中在所有「构造方法之外的方法」中均只读
///
/// # 📄OpenNARS
///
/// evidentialBase baseLength
#[doc(alias = "base_length")]
#[inline(always)]
fn evidence_length(&self) -> usize {
self.evidential_base().len()
}
/// 模拟`Stamp.creationTime`、`Stamp.getCreationTime`
/// * 📝这个「创建时间」是一个特殊的元素
/// * ⚠️不一定在[`Stamp::__evidential_base`]中
///
/// # 📄OpenNARS
///
/// creation time of the stamp
fn creation_time(&self) -> ClockTime;
/// 模拟`Stamp.get`
///
/// # 📄OpenNARS
///
/// Get a number from the evidentialBase by index, called in this class only
///
/// @param i The index
/// @return The number at the index
fn get(&self, i: usize) -> ClockTime {
self.evidential_base()[i]
}
/// 模拟`new Stamp(Stamp first, Stamp second, long time)`
/// * 🚩【2024-05-05 14:30:28】根据OpenNARS,`current_serial`参数就与[「创建时间」](Stamp::creation_time)对应
/// * 因此直接将「创建时间」传入
///
/// # 📄OpenNARS
///
/// Generate a new stamp for derived sentence by merging the two from parents
/// the first one is no shorter than the second
///
/// @param first The first Stamp
/// @param second The second Stamp
fn merged_evidential_base(
first: &[ClockTime],
second: &[ClockTime],
max_evidence_base_length: usize,
) -> Vec<ClockTime> {
/* 📄OpenNARS
// * 🚩计算新证据基长度:默认长度相加,一定长度后截断
final int baseLength = Math.min( // * 📝一定程度上允许重复推理:在证据复杂时遗漏一定数据
base1.length + base2.length,
maxEvidenceBaseLength);
// * 🚩计算长短证据基
final long[] longer, shorter;
if (base1.length > base2.length) {
longer = base1;
shorter = base2;
} else {
longer = base2;
shorter = base1;
}
// * 🚩开始构造并填充数据:拉链式填充,1-2-1-2……
int i1, i2, j;
i1 = i2 = j = 0;
final long[] evidentialBase = new long[baseLength];
while (i2 < shorter.length && j < baseLength) {
evidentialBase[j] = longer[i1];
i1++;
j++;
evidentialBase[j] = shorter[i2];
i2++;
j++;
}
// * 🚩2的长度比1小,所以此后随1填充
while (i1 < longer.length && j < baseLength) {
evidentialBase[j] = longer[i1];
i1++;
j++;
}
// * 🚩返回构造好的新证据基
return evidentialBase; */
// * 🚩计算新证据基长度:默认长度相加,一定长度后截断
let base_length = ClockTime::min(first.len() + second.len(), max_evidence_base_length);
// * 🚩计算长短证据基
let [longer, shorter] = match first.len() > second.len() {
true => [first, second],
false => [second, first],
};
// * 🚩构造返回值
let mut j = 0;
let mut evidential_base = vec![0; base_length];
let mut put_in_base = |evidence| {
// * 🚩【2024-06-27 00:45:30】使用一个闭包来简化「放置前判断」
if j < base_length {
evidential_base[j] = evidence;
j += 1;
}
};
// * 🚩填充数据:拉链式填充,1-2-1-2……
for (&evidence_l, &evidence_s) in longer.iter().zip(shorter.iter()) {
put_in_base(evidence_l);
put_in_base(evidence_s);
}
// * 🚩2的长度比1小,所以此后随1填充
for &evidence_l_residual in longer.iter().skip(shorter.len()) {
put_in_base(evidence_l_residual);
}
// 返回
evidential_base
}
/// 🆕判断两个「时间戳」是否含有相同证据
/// * 🎯用于「概念处理」中的「获取信念」,并反映到后续「推理上下文」的分派中
/// * 🎯深层目的:防止重复推理
/// * 🚩包含相同证据基⇒返回空值
/// * 🚩【2024-06-20 23:47:41】现在按照OpenNARS改版的来:名之曰「证据上重合」
fn evidential_overlap(&self, second: &impl Evidential) -> bool {
self.evidential_base()
.iter()
.any(|i| second.evidential_base().contains(i))
}
/// 判断是否【在证据上】相等
fn evidential_eq(&self, other: &impl Evidential) -> bool {
set_vec_eq(self.evidential_base(), other.evidential_base())
}
/// 🆕与OpenNARS改版不同:将其中的「证据基」成分转换为「词法时间戳」
fn stamp_to_lexical(&self) -> LexicalStamp;
/// 模拟`toString`
/// * 🚩【2024-05-08 22:12:42】现在鉴于实际情况,仍然实现`toString`、`toStringBrief`方法
/// * 🚩具体方案:实现一个统一的、内部的、默认的`__to_display(_brief)`,再通过「手动嫁接」完成最小成本实现
/// * ⚠️🆕具体格式化结果相比OpenNARS**没有头尾空白**
///
/// # 📄OpenNARS
///
/// Get a String form of the Stamp for display
/// Format: {creationTime [: eventTime] : evidentialBase}
///
/// @return The Stamp as a String
fn stamp_to_display(&self) -> String {
/* 📄OpenNARS源码:
StringBuilder buffer = new StringBuilder(" " + Symbols.STAMP_OPENER + creationTime);
buffer.append(" ").append(Symbols.STAMP_STARTER).append(" ");
for (int i = 0; i < baseLength; i++) {
buffer.append(Long.toString(evidentialBase[i]));
if (i < (baseLength - 1)) {
buffer.append(Symbols.STAMP_SEPARATOR);
} else {
buffer.append(Symbols.STAMP_CLOSER).append(" ");
}
}
return buffer.toString(); */
join!(
// 生成头部:`{0:`
=> STAMP_OPENER.to_string()
=> {# self.creation_time()}
=> ' '
=> STAMP_STARTER
=> ' '
// 循环迭代加入中部:`0;1;2`
=> self.evidential_base()
.iter().map(ToString::to_string) // 迭代器转换为字符串
.join_to_new(STAMP_SEPARATOR) // 加入到新字串中
// 最终加入尾部:`}`
=> STAMP_CLOSER
)
}
}
#[cfg(test)]
mod tests {
use nar_dev_utils::macro_once;
/// 测试/set_vec_eq
/// * 🎯数组集合判等
#[test]
fn set_vec_eq() {
macro_once! {
/// * 🚩正例 模式:原数组⇒预期相等
macro test($($value:expr => $($equivalent:expr $(,)? )* ; )*) {
$(
$(
assert!(super::set_vec_eq::<usize>(&$value, &$equivalent));
)*
)*
}
[] => [];
[1] => [1];
[1, 2] => [2, 1];
[1, 2, 3] => [2, 3, 1], [3, 2, 1], [1, 3, 2], [3, 1, 2], [2, 1, 3];
}
macro_once! {
/// * 🚩反例 模式:原数组⇒预期相等
macro test($($value:tt != $($equivalent:expr $(,)? )* ; )*) {
$(
$(
assert!(!super::set_vec_eq::<usize>(&$value, &$equivalent));
)*
)*
}
[1] != [];
[1] != [0];
[1, 2] != [1, 1];
[1, 2] != [1];
[1, 2, 3] != [2, 0, 1], [0, 2, 1], [1, 0, 2], [0, 1, 2], [2, 1, 0];
}
}
}