1use std::{fmt::Debug, iter::Sum, mem};
2
3use approx::UlpsEq;
4use num_traits::{Float, FromPrimitive, NumAssign, ToPrimitive};
5use rand_distr::{uniform::SampleUniform, Distribution, Exp1, Open01, Standard, StandardNormal};
6use subjective_logic::{
7 domain::{Domain, DomainConv, Keys},
8 iter::FromFn,
9 mul::{
10 labeled::{OpinionD1, OpinionD2, OpinionD3, OpinionRefD1, SimplexD1},
11 InverseCondition, MergeJointConditions2,
12 },
13 multi_array::labeled::{MArrD1, MArrD2, MArrD3},
14 new_type_domain,
15 ops::{Deduction, Discount, Fuse, FuseAssign, FuseOp, Product2, Product3, Projection},
16};
17use tracing::debug;
18
19use crate::info::InfoContent;
20
21pub trait MyFloat
22where
23 Self: Float
24 + NumAssign
25 + UlpsEq
26 + Sum
27 + FromPrimitive
28 + ToPrimitive
29 + SampleUniform
30 + Default
31 + Send
32 + Sync
33 + Debug,
34{
35}
36
37impl MyFloat for f32 {}
38impl MyFloat for f64 {}
39
40new_type_domain!(pub Psi = 2);
41new_type_domain!(pub FPsi from Psi);
42new_type_domain!(pub KPsi from Psi);
43new_type_domain!(pub Phi = 2);
44new_type_domain!(pub FPhi from Phi);
45new_type_domain!(pub KPhi from Phi);
46new_type_domain!(pub O = 2);
47new_type_domain!(pub FO from O);
48new_type_domain!(pub KO from O);
49new_type_domain!(pub A = 2);
50new_type_domain!(pub B = 2);
51new_type_domain!(pub H = 2);
52new_type_domain!(pub FH from H);
53new_type_domain!(pub KH from H);
54new_type_domain!(pub Theta from H);
55new_type_domain!(pub Thetad from H);
56
57#[derive(Default, Debug)]
58pub struct StateOpinions<V> {
59 pub psi: OpinionD1<Psi, V>,
60 pub phi: OpinionD1<Phi, V>,
61 pub o: OpinionD1<O, V>,
62 pub fo: OpinionD1<FO, V>,
63 pub ko: OpinionD1<KO, V>,
64 pub h_psi_if_phi1: MArrD1<Psi, SimplexD1<H, V>>,
65 pub h_b_if_phi1: MArrD1<B, SimplexD1<H, V>>,
66 pub fpsi: OpinionD1<FPsi, V>,
67 pub fphi: OpinionD1<FPhi, V>,
68 pub fh_fpsi_if_fphi1: MArrD1<FPsi, SimplexD1<FH, V>>,
69 pub kpsi: OpinionD1<KPsi, V>,
70 pub kphi: OpinionD1<KPhi, V>,
71 pub kh_kpsi_if_kphi1: MArrD1<KPsi, SimplexD1<KH, V>>,
72}
73
74#[derive(Default, Debug)]
75pub struct FixedOpinions<V> {
76 pub o_b: MArrD1<B, SimplexD1<O, V>>,
77 pub b_kh: MArrD1<KH, SimplexD1<B, V>>,
78 pub a_fh: MArrD1<FH, SimplexD1<A, V>>,
79 pub theta_h: MArrD1<H, SimplexD1<Theta, V>>,
80 pub thetad_h: MArrD1<H, SimplexD1<Thetad, V>>,
81 pub h_psi_if_phi0: MArrD1<Psi, SimplexD1<H, V>>,
82 pub h_b_if_phi0: MArrD1<B, SimplexD1<H, V>>,
83 pub uncertainty_fh_fpsi_if_fphi0: MArrD1<FPsi, V>,
84 pub uncertainty_kh_kpsi_if_kphi0: MArrD1<KPsi, V>,
85 pub uncertainty_fh_fphi_fo: MArrD2<FPhi, FO, V>,
86 pub uncertainty_kh_kphi_ko: MArrD2<KPhi, KO, V>,
87}
88
89#[derive(Debug)]
90enum DiffOpinions<V: MyFloat> {
91 Causal {
92 psi: OpinionD1<Psi, V>,
93 fpsi: OpinionD1<FPsi, V>,
94 kpsi: OpinionD1<KPsi, V>,
95 },
96 Observed {
97 o: OpinionD1<O, V>,
98 fo: OpinionD1<FO, V>,
99 ko: OpinionD1<KO, V>,
100 },
101 Inhibition {
102 phi: OpinionD1<Phi, V>,
103 fphi: OpinionD1<FPhi, V>,
104 kphi: OpinionD1<KPhi, V>,
105 h_psi_if_phi1: MArrD1<Psi, SimplexD1<H, V>>,
106 h_b_if_phi1: MArrD1<B, SimplexD1<H, V>>,
107 fh_fpsi_if_fphi1: MArrD1<FPsi, SimplexD1<FH, V>>,
108 kh_kpsi_if_kphi1: MArrD1<KPsi, SimplexD1<KH, V>>,
109 },
110}
111
112#[derive(Debug)]
113enum PredDiffOpinions<V: MyFloat> {
114 Causal {
115 fpsi: OpinionD1<FPsi, V>,
116 },
117 Observed {
118 fo: OpinionD1<FO, V>,
119 },
120 Inhibition {
121 fphi: OpinionD1<FPhi, V>,
122 fh_fpsi_if_fphi1: MArrD1<FPsi, SimplexD1<FH, V>>,
123 },
124}
125
126#[derive(Debug, Default)]
127pub struct DeducedOpinions<V> {
128 pub h: OpinionD1<H, V>,
129 pub fh: OpinionD1<FH, V>,
130 pub kh: OpinionD1<KH, V>,
131 pub a: OpinionD1<A, V>,
132 pub b: OpinionD1<B, V>,
133 pub theta: OpinionD1<Theta, V>,
134 pub thetad: OpinionD1<Thetad, V>,
135}
136
137#[derive(Debug)]
138pub struct Trusts<V> {
139 pub my_trust: V,
141 pub friend_trusts: OtherTrusts<V>,
142 pub social_trusts: OtherTrusts<V>,
143 pub friend_misinfo_trusts: OtherTrusts<V>,
144 pub social_misinfo_trusts: OtherTrusts<V>,
145 pub pred_friend_trusts: OtherTrusts<V>,
146}
147
148fn transform<
149 D1: Domain<Idx: Copy> + Keys<D1::Idx>,
150 D2: Domain<Idx: Debug> + From<D1> + Keys<D2::Idx>,
151 V: MyFloat,
152>(
153 w: OpinionRefD1<D1, V>,
154 certainty: V,
155) -> OpinionD1<D2, V> {
156 let p: MArrD1<D2, _> = w.projection().conv();
157 OpinionD1::new(
158 MArrD1::from_fn(|i| p[i] * certainty),
159 V::one() - certainty,
160 w.base_rate.clone().conv(),
161 )
162}
163
164fn transform_simplex<
165 D1: Domain<Idx: Copy> + Keys<D1::Idx>,
166 D2: Domain<Idx: Debug> + From<D1> + Keys<D2::Idx>,
167 V: MyFloat,
168>(
169 p: MArrD1<D1, V>,
170 c: V,
171) -> SimplexD1<D2, V> {
172 let q: MArrD1<D2, _> = p.conv();
173 SimplexD1::new_unchecked(MArrD1::from_fn(|i| q[i] * c), V::one() - c)
174}
175
176#[derive(Debug)]
177pub struct OtherTrusts<V> {
178 pub trust: V,
179 pub certainty: V,
180}
181
182impl<V> OtherTrusts<V> {
183 fn approximate<D1, D2, O>(&self, w: O) -> OpinionD1<D2, V>
184 where
185 V: MyFloat,
186 D1: Domain<Idx: Copy> + Keys<D1::Idx>,
187 O: AsRef<OpinionD1<D1, V>>,
188 D2: Domain<Idx: Debug> + From<D1> + Keys<D2::Idx>,
189 {
190 transform(w.as_ref().discount(self.trust).as_ref(), self.certainty)
191 }
192 fn approximate_simplex<D1, D2>(
193 &self,
194 s: &SimplexD1<D1, V>,
195 base_rate: &MArrD1<D1, V>,
196 ) -> SimplexD1<D2, V>
197 where
198 V: MyFloat,
199 D1: Domain<Idx: Copy> + Keys<D1::Idx>,
200 D2: Domain<Idx: Debug> + From<D1> + Keys<D2::Idx>,
201 {
202 transform_simplex(s.discount(self.trust).projection(base_rate), self.certainty)
203 }
204}
205
206impl<V: MyFloat> StateOpinions<V> {
207 pub fn reset(
208 &mut self,
209 psi: OpinionD1<Psi, V>,
210 phi: OpinionD1<Phi, V>,
211 o: OpinionD1<O, V>,
212 fo: OpinionD1<FO, V>,
213 ko: OpinionD1<KO, V>,
214 h_psi_if_phi1: MArrD1<Psi, SimplexD1<H, V>>,
215 h_b_if_phi1: MArrD1<B, SimplexD1<H, V>>,
216 fpsi: OpinionD1<FPsi, V>,
217 fphi: OpinionD1<FPhi, V>,
218 fh_fpsi_if_fphi1: MArrD1<FPsi, SimplexD1<FH, V>>,
219 kpsi: OpinionD1<KPsi, V>,
220 kphi: OpinionD1<KPhi, V>,
221 kh_kpsi_if_kphi1: MArrD1<KPsi, SimplexD1<KH, V>>,
222 ) where
223 Standard: Distribution<V>,
224 StandardNormal: Distribution<V>,
225 Exp1: Distribution<V>,
226 Open01: Distribution<V>,
227 {
228 *self = Self {
229 psi,
230 phi,
231 o,
232 fo,
233 ko,
234 h_psi_if_phi1,
235 h_b_if_phi1,
236 fpsi,
237 fphi,
238 fh_fpsi_if_fphi1,
239 kpsi,
240 kphi,
241 kh_kpsi_if_kphi1,
242 };
243 }
244
245 fn receive(
246 &self,
247 p: &InfoContent<V>,
248 trusts: &Trusts<V>,
249 ded: &DeducedOpinions<V>,
251 ) -> DiffOpinions<V> {
252 match p {
253 InfoContent::Misinfo { op } => {
254 let psi = FuseOp::Wgh.fuse(&self.psi, &op.discount(trusts.my_trust));
255 let fpsi = FuseOp::Wgh.fuse(&self.fpsi, &trusts.friend_trusts.approximate(op));
256 let kpsi = FuseOp::Wgh.fuse(&self.kpsi, &trusts.social_trusts.approximate(op));
257 DiffOpinions::Causal { psi, fpsi, kpsi }
258 }
259 InfoContent::Correction { op, misinfo } => {
260 let psi = FuseOp::Wgh.fuse(&self.psi, &op.discount(trusts.my_trust));
261 let mut fpsi = FuseOp::Wgh.fuse(&self.fpsi, &trusts.friend_trusts.approximate(op));
262 FuseOp::Wgh.fuse_assign(
263 &mut fpsi,
264 &trusts.friend_misinfo_trusts.approximate(misinfo),
265 );
266 let mut kpsi = FuseOp::Wgh.fuse(&self.kpsi, &trusts.social_trusts.approximate(op));
267 FuseOp::Wgh.fuse_assign(
268 &mut kpsi,
269 &trusts.social_misinfo_trusts.approximate(misinfo),
270 );
271 DiffOpinions::Causal { psi, fpsi, kpsi }
272 }
273 InfoContent::Observation { op } => {
274 let o = FuseOp::ACm.fuse(&self.o, &op.discount(trusts.my_trust));
275 let fo = FuseOp::Wgh.fuse(&self.fo, &trusts.friend_trusts.approximate(op));
276 let ko = FuseOp::Wgh.fuse(&self.ko, &trusts.social_trusts.approximate(op));
277 DiffOpinions::Observed { o, fo, ko }
278 }
279 InfoContent::Inhibition { op1, op2, op3 } => {
280 let phi = FuseOp::Wgh.fuse(&self.phi, &op1.discount(trusts.my_trust));
281 let fphi = FuseOp::Wgh.fuse(&self.fphi, &trusts.friend_trusts.approximate(op1));
282 let kphi = FuseOp::Wgh.fuse(&self.kphi, &trusts.social_trusts.approximate(op1));
283
284 let h_psi_if_phi1 = MArrD1::from_iter(
285 self.h_psi_if_phi1
286 .iter()
287 .zip(op2.iter().map(|o| o.discount(trusts.my_trust)))
288 .map(|(c, o)| FuseOp::Wgh.fuse(c, &o)),
289 );
290 let h_b_if_phi1 = MArrD1::from_iter(
291 self.h_b_if_phi1
292 .iter()
293 .zip(op3.iter().map(|o| o.discount(trusts.my_trust)))
294 .map(|(c, o)| FuseOp::Wgh.fuse(c, &o)),
295 );
296 let ah = &ded.h.base_rate;
297 let fh_fpsi_if_fphi1 = MArrD1::from_iter(
298 self.fh_fpsi_if_fphi1
299 .iter()
300 .zip(op2.iter())
301 .map(|(c, s)| {
303 FuseOp::Wgh.fuse(c, &trusts.friend_trusts.approximate_simplex(s, ah))
304 }),
305 );
306 let kh_kpsi_if_kphi1 = MArrD1::from_iter(
307 self.kh_kpsi_if_kphi1.iter().zip(op2.iter()).map(|(c, s)| {
308 FuseOp::Wgh.fuse(c, &trusts.social_trusts.approximate_simplex(s, ah))
309 }),
310 );
311 DiffOpinions::Inhibition {
312 phi,
313 fphi,
314 kphi,
315 h_psi_if_phi1,
316 h_b_if_phi1,
317 fh_fpsi_if_fphi1,
318 kh_kpsi_if_kphi1,
319 }
320 }
321 }
322 }
323
324 fn predict(
325 &self,
326 p: &InfoContent<V>,
327 trusts: &Trusts<V>,
328 ded: &DeducedOpinions<V>,
329 ) -> PredDiffOpinions<V> {
330 match p {
331 InfoContent::Misinfo { op } => {
332 let fpsi = FuseOp::Wgh.fuse(&self.fpsi, &trusts.pred_friend_trusts.approximate(op));
333 PredDiffOpinions::Causal { fpsi }
334 }
335 InfoContent::Observation { op } => {
336 let fo = FuseOp::Wgh.fuse(&self.fo, &trusts.pred_friend_trusts.approximate(op));
337 PredDiffOpinions::Observed { fo }
338 }
339 InfoContent::Correction { op, .. } => {
340 let fpsi = FuseOp::Wgh.fuse(&self.fpsi, &trusts.pred_friend_trusts.approximate(op));
341 PredDiffOpinions::Causal { fpsi }
342 }
343 InfoContent::Inhibition { op1, op2, .. } => {
344 let fphi =
345 FuseOp::Wgh.fuse(&self.fphi, &trusts.pred_friend_trusts.approximate(op1));
346 let ah = &ded.h.base_rate;
347 let fh_fpsi_if_fphi1 = MArrD1::from_iter(
348 self.fh_fpsi_if_fphi1.iter().zip(op2.iter()).map(|(c, s)| {
349 FuseOp::Wgh.fuse(c, &trusts.pred_friend_trusts.approximate_simplex(s, ah))
350 }),
351 );
352 PredDiffOpinions::Inhibition {
353 fphi,
354 fh_fpsi_if_fphi1,
355 }
356 }
357 }
358 }
359
360 fn h_psi_b_if_phi1(
361 &self,
362 b: &MArrD1<B, V>,
363 h: &MArrD1<H, V>,
364 ) -> MArrD2<Psi, B, SimplexD1<H, V>> {
365 let h_psi_b_if_phi1 = MArrD1::<H, _>::merge_cond2(
366 &self.h_psi_if_phi1,
367 &self.h_b_if_phi1,
368 &self.psi.base_rate,
369 b,
370 h,
371 );
372 h_psi_b_if_phi1
373 }
374
375 fn deduce_fh(
376 &self,
377 fh_fphi_fpsi_fo: &MArrD3<FPhi, FPsi, FO, SimplexD1<FH, V>>,
378 base_rate_fh: &MArrD1<FH, V>,
379 ) -> OpinionD1<FH, V> {
380 OpinionD3::product3(&self.fphi, &self.fpsi, &self.fo)
381 .deduce_with(fh_fphi_fpsi_fo, || base_rate_fh.clone())
382 }
383
384 fn deduce_kh(
385 &self,
386 kh_kphi_kpsi_ko: &MArrD3<KPhi, KPsi, KO, SimplexD1<KH, V>>,
387 base_rate_kh: &MArrD1<KH, V>,
388 ) -> OpinionD1<KH, V> {
389 OpinionD3::product3(&self.kphi, &self.kpsi, &self.ko)
390 .deduce_with(kh_kphi_kpsi_ko, || base_rate_kh.clone())
391 }
392
393 fn deduce_b(
394 &self,
395 kh: &OpinionD1<KH, V>,
396 b_kh_o: &MArrD2<KH, O, SimplexD1<B, V>>,
397 base_rate_b: &MArrD1<B, V>,
398 ) -> OpinionD1<B, V> {
399 debug!(target: "B|KH,O", cond=?b_kh_o);
400 OpinionD2::product2(kh, &self.o).deduce_with(b_kh_o, || base_rate_b.clone())
401 }
402
403 fn deduce_h(
404 &self,
405 b: &OpinionD1<B, V>,
406 h_phi_psi_b: &MArrD3<Phi, Psi, B, SimplexD1<H, V>>,
407 base_rate_h: &MArrD1<H, V>,
408 ) -> OpinionD1<H, V> {
409 debug!(target: "H|Phi,Psi,B", Cond=?h_phi_psi_b);
410 OpinionD3::product3(&self.phi, &self.psi, b)
411 .deduce_with(h_phi_psi_b, || base_rate_h.clone())
412 }
413}
414
415impl<V: MyFloat> FixedOpinions<V> {
416 fn h_psi_b_if_phi0(
417 &self,
418 psi: &MArrD1<Psi, V>,
419 b: &MArrD1<B, V>,
420 h: &MArrD1<H, V>,
421 ) -> MArrD2<Psi, B, SimplexD1<H, V>> {
422 let h_psi_b_if_phi0 =
423 MArrD1::<H, _>::merge_cond2(&self.h_psi_if_phi0, &self.h_b_if_phi0, psi, b, h);
424 h_psi_b_if_phi0
425 }
426
427 pub fn reset(
428 &mut self,
429 o_b: MArrD1<B, SimplexD1<O, V>>,
430 b_kh: MArrD1<KH, SimplexD1<B, V>>,
431 a_fh: MArrD1<FH, SimplexD1<A, V>>,
432 theta_h: MArrD1<H, SimplexD1<Theta, V>>,
433 thetad_h: MArrD1<H, SimplexD1<Thetad, V>>,
434 h_psi_if_phi0: MArrD1<Psi, SimplexD1<H, V>>,
435 h_b_if_phi0: MArrD1<B, SimplexD1<H, V>>,
436 uncertainty_fh_fpsi_if_fphi0: MArrD1<FPsi, V>,
437 uncertainty_kh_kpsi_if_kphi0: MArrD1<KPsi, V>,
438 uncertainty_fh_fphi_fo: MArrD2<FPhi, FO, V>,
439 uncertainty_kh_kphi_ko: MArrD2<KPhi, KO, V>,
440 ) {
441 *self = Self {
442 o_b,
443 b_kh,
444 a_fh,
445 theta_h,
446 thetad_h,
447 h_psi_if_phi0,
448 h_b_if_phi0,
449 uncertainty_fh_fpsi_if_fphi0,
450 uncertainty_kh_kpsi_if_kphi0,
451 uncertainty_fh_fphi_fo,
452 uncertainty_kh_kphi_ko,
453 }
454 }
455}
456
457fn compute_fh_fphi_fpsi_fo<V: MyFloat>(
458 state: &StateOpinions<V>,
459 fixed: &FixedOpinions<V>,
460 b_o: &MArrD1<O, SimplexD1<B, V>>,
461 base_rate_b: &MArrD1<B, V>,
462 base_rate_h: &MArrD1<H, V>,
463 base_rate_fh: &MArrD1<FH, V>,
464) -> MArrD3<FPhi, FPsi, FO, SimplexD1<FH, V>> {
465 let fh_fpsi_if_fphi0 = MArrD1::<FPsi, _>::from_fn(|fpsi| {
466 transform_simplex::<_, FH, _>(
467 fixed.h_psi_if_phi0[fpsi.into()].projection(base_rate_h),
468 V::one() - fixed.uncertainty_fh_fpsi_if_fphi0[fpsi.into()],
469 )
470 });
471 let h_o_if_phi0 = MArrD1::<O, _>::from_fn(|o| {
472 OpinionRefD1::<_, V>::from((&b_o[o], base_rate_b))
473 .deduce_with(&fixed.h_b_if_phi0, || base_rate_h.clone())
474 });
475
476 let fh_fo_if_fphi0 = MArrD1::<FO, _>::from_fn(|fo| {
477 transform_simplex::<_, FH, _>(
478 h_o_if_phi0[fo.into()].projection(),
479 V::one() - fixed.uncertainty_fh_fphi_fo[(FPhi(0), fo)],
480 )
481 });
482
483 let fh_fo_if_fphi1 = MArrD1::<FO, _>::from_fn(|fo| {
484 transform_simplex::<_, FH, _>(
485 OpinionRefD1::from((&b_o[fo.into()], base_rate_b))
486 .deduce_with(&state.h_b_if_phi1, || base_rate_h.clone())
487 .projection(),
488 V::one() - fixed.uncertainty_fh_fphi_fo[(FPhi(1), fo)],
489 )
490 });
491 let fh_fpsi_fo_if_fphi0 = MArrD1::<FH, _>::merge_cond2(
492 &fh_fpsi_if_fphi0,
493 &fh_fo_if_fphi0,
494 &state.fpsi.base_rate,
495 &state.fo.base_rate,
496 base_rate_fh,
497 );
498 let fh_fpsi_fo_if_fphi1 = MArrD1::<FH, _>::merge_cond2(
499 &state.fh_fpsi_if_fphi1,
500 &fh_fo_if_fphi1,
501 &state.fpsi.base_rate,
502 &state.fo.base_rate,
503 base_rate_fh,
504 );
505
506 debug!(target: " H|O,phi0", Cond=?h_o_if_phi0);
507 debug!(target: "FH|Fphi0,FPsi", Cond=?fh_fpsi_if_fphi0);
508 debug!(target: "FH|Fphi0, FO", Cond=?fh_fo_if_fphi0);
509 debug!(target: "FH|Fphi0,FPsi,FO", Cond=?fh_fpsi_fo_if_fphi0);
510 debug!(target: "FH|Fphi1,FPsi", Cond=?state.fh_fpsi_if_fphi1);
511 debug!(target: "FH|Fphi1, FO", Cond=?fh_fo_if_fphi1);
512 debug!(target: "FH|Fphi1,FPsi,FO", Cond=?fh_fpsi_fo_if_fphi1);
513
514 MArrD3::new(vec![fh_fpsi_fo_if_fphi0, fh_fpsi_fo_if_fphi1])
515}
516
517fn compute_kh_kphi_kpsi_ko<V: MyFloat>(
518 state: &StateOpinions<V>,
519 fixed: &FixedOpinions<V>,
520 b_o: &MArrD1<O, SimplexD1<B, V>>,
521 base_rate_b: &MArrD1<B, V>,
522 base_rate_h: &MArrD1<H, V>,
523 base_rate_kh: &MArrD1<KH, V>,
524) -> MArrD3<KPhi, KPsi, KO, SimplexD1<KH, V>> {
525 let kh_kpsi_if_kphi0 = MArrD1::<KPsi, _>::from_fn(|kpsi| {
526 transform_simplex::<_, KH, _>(
527 fixed.h_psi_if_phi0[kpsi.into()].projection(base_rate_h),
528 V::one() - fixed.uncertainty_kh_kpsi_if_kphi0[kpsi],
529 )
530 });
531 let kh_ko_if_kphi0 = MArrD1::<KO, _>::from_fn(|ko| {
532 transform_simplex::<_, KH, _>(
533 OpinionRefD1::from((&b_o[ko.into()], base_rate_b))
534 .deduce_with(&fixed.h_b_if_phi0, || base_rate_h.clone())
535 .projection(),
536 V::one() - fixed.uncertainty_kh_kphi_ko[(KPhi(0), ko)],
537 )
538 });
539 let kh_ko_if_kphi1 = MArrD1::<KO, _>::from_fn(|ko| {
540 transform_simplex::<_, KH, _>(
541 OpinionRefD1::from((&b_o[ko.into()], base_rate_b))
542 .deduce_with(&state.h_b_if_phi1, || base_rate_h.clone())
543 .projection(),
544 V::one() - fixed.uncertainty_kh_kphi_ko[(KPhi(1), ko)],
545 )
546 });
547
548 let kh_kpsi_ko_if_kphi0 = MArrD1::<KH, _>::merge_cond2(
549 &kh_kpsi_if_kphi0,
550 &kh_ko_if_kphi0,
551 &state.kpsi.base_rate,
552 &state.ko.base_rate,
553 base_rate_kh,
554 );
555 let kh_kpsi_ko_if_kphi1 = MArrD1::<KH, _>::merge_cond2(
556 &state.kh_kpsi_if_kphi1,
557 &kh_ko_if_kphi1,
558 &state.kpsi.base_rate,
559 &state.ko.base_rate,
560 base_rate_kh,
561 );
562
563 debug!(target: "KH|Kphi0,KPsi", Cond=?kh_kpsi_if_kphi0);
564 debug!(target: "KH|Kphi0, KO", Cond=?kh_ko_if_kphi0);
565 debug!(target: "KH|Kphi1,KPsi", Cond=?state.kh_kpsi_if_kphi1);
566 debug!(target: "KH|Kphi1, KO", Cond=?kh_ko_if_kphi1);
567 debug!(target: "KH|Kphi0,KPsi,KO", Cond=?kh_kpsi_ko_if_kphi0);
568
569 MArrD3::new(vec![kh_kpsi_ko_if_kphi0, kh_kpsi_ko_if_kphi1])
570}
571
572fn compute_b_kh_o<V: MyFloat>(
573 state: &StateOpinions<V>,
574 fixed: &FixedOpinions<V>,
575 b_o: &MArrD1<O, SimplexD1<B, V>>,
576 base_rate_kh: &MArrD1<KH, V>,
577 base_rate_b: &MArrD1<B, V>,
578) -> MArrD2<KH, O, SimplexD1<B, V>> {
579 MArrD1::<B, _>::merge_cond2(
580 &fixed.b_kh,
581 b_o,
582 base_rate_kh,
583 &state.o.base_rate,
584 base_rate_b,
585 )
586}
587
588fn compute_h_phi_psi_b<V: MyFloat>(
589 state: &StateOpinions<V>,
590 fixed: &FixedOpinions<V>,
591 base_rate_b: &MArrD1<B, V>,
592 base_rate_h: &MArrD1<H, V>,
593) -> MArrD3<Phi, Psi, B, SimplexD1<H, V>> {
594 let h_psi_b_if_phi0 = fixed.h_psi_b_if_phi0(&state.psi.base_rate, base_rate_b, base_rate_h);
595 let h_psi_b_if_phi1 = state.h_psi_b_if_phi1(base_rate_b, base_rate_h);
596 MArrD3::new(vec![h_psi_b_if_phi0, h_psi_b_if_phi1])
597}
598
599impl<V: MyFloat> DeducedOpinions<V> {
600 pub fn reset(
601 &mut self,
602 h: OpinionD1<H, V>,
603 fh: OpinionD1<FH, V>,
604 kh: OpinionD1<KH, V>,
605 a: OpinionD1<A, V>,
606 b: OpinionD1<B, V>,
607 theta: OpinionD1<Theta, V>,
608 thetad: OpinionD1<Thetad, V>,
609 ) {
610 *self = Self {
611 a,
612 b,
613 fh,
614 h,
615 kh,
616 theta,
617 thetad,
618 }
619 }
620
621 fn deduce(&self, state: &StateOpinions<V>, fixed: &FixedOpinions<V>) -> Self {
622 let b_o = fixed.o_b.inverse(&self.b.base_rate, &state.o.base_rate);
623 let fh_fphi_fpsi_fo = compute_fh_fphi_fpsi_fo(
624 state,
625 fixed,
626 &b_o,
627 &self.b.base_rate,
628 &self.h.base_rate,
629 &self.fh.base_rate,
630 );
631 let fh = state.deduce_fh(&fh_fphi_fpsi_fo, &self.fh.base_rate);
632 let kh_kphi_kpsi_ko = compute_kh_kphi_kpsi_ko(
633 state,
634 fixed,
635 &b_o,
636 &self.b.base_rate,
637 &self.h.base_rate,
638 &self.kh.base_rate,
639 );
640 let kh = state.deduce_kh(&kh_kphi_kpsi_ko, &self.kh.base_rate);
641 let b_kh_o = compute_b_kh_o(state, fixed, &b_o, &kh.base_rate, &self.b.base_rate);
642 let b = state.deduce_b(&kh, &b_kh_o, &self.b.base_rate);
643 let h_phi_psi_b = compute_h_phi_psi_b(state, fixed, &b.base_rate, &self.h.base_rate);
644 let h = state.deduce_h(&b, &h_phi_psi_b, &self.h.base_rate);
645 let a = fh.deduce_with(&fixed.a_fh, || self.a.base_rate.clone());
646 let theta = h.deduce_with(&fixed.theta_h, || self.theta.base_rate.clone());
647 let thetad = h.deduce_with(&fixed.thetad_h, || self.thetad.base_rate.clone());
648
649 Self {
650 h,
651 fh,
652 kh,
653 a,
654 b,
655 theta,
656 thetad,
657 }
658 }
659
660 pub fn p_theta(&self) -> MArrD1<Theta, V> {
661 self.theta.projection()
662 }
663}
664
665fn projection_a_thetad<V: MyFloat>(
666 a: &OpinionD1<A, V>,
667 thetad: &OpinionD1<Thetad, V>,
668) -> MArrD2<A, Thetad, V> {
669 OpinionD2::product2(a, thetad).projection()
670}
671
672impl<V: MyFloat> DiffOpinions<V> {
673 fn swap(&mut self, state: &mut StateOpinions<V>) {
674 match self {
675 DiffOpinions::Causal { psi, fpsi, kpsi } => {
676 mem::swap(&mut state.psi, psi);
677 mem::swap(&mut state.fpsi, fpsi);
678 mem::swap(&mut state.kpsi, kpsi);
679 }
680 DiffOpinions::Observed { o, fo, ko } => {
681 mem::swap(&mut state.o, o);
682 mem::swap(&mut state.fo, fo);
683 mem::swap(&mut state.ko, ko);
684 }
685 DiffOpinions::Inhibition {
686 phi,
687 fphi,
688 kphi,
689 h_psi_if_phi1,
690 h_b_if_phi1,
691 fh_fpsi_if_fphi1,
692 kh_kpsi_if_kphi1,
693 } => {
694 mem::swap(&mut state.phi, phi);
695 mem::swap(&mut state.fphi, fphi);
696 mem::swap(&mut state.kphi, kphi);
697 mem::swap(&mut state.h_psi_if_phi1, h_psi_if_phi1);
698 mem::swap(&mut state.h_b_if_phi1, h_b_if_phi1);
699 mem::swap(&mut state.fh_fpsi_if_fphi1, fh_fpsi_if_fphi1);
700 mem::swap(&mut state.kh_kpsi_if_kphi1, kh_kpsi_if_kphi1);
701 }
702 }
703 }
704}
705
706impl<V: MyFloat> PredDiffOpinions<V> {
707 fn swap(&mut self, state: &mut StateOpinions<V>) {
708 match self {
709 PredDiffOpinions::Causal { fpsi } => {
710 mem::swap(fpsi, &mut state.fpsi);
711 }
712 PredDiffOpinions::Observed { fo } => {
713 mem::swap(fo, &mut state.fo);
714 }
715 PredDiffOpinions::Inhibition {
716 fphi,
717 fh_fpsi_if_fphi1,
718 } => {
719 mem::swap(fphi, &mut state.fphi);
720 mem::swap(fh_fpsi_if_fphi1, &mut state.fh_fpsi_if_fphi1);
721 }
722 }
723 }
724}
725
726#[derive(Debug)]
727struct PredDeducedOpinions<V> {
728 pub fh: OpinionD1<FH, V>,
729 pub a: OpinionD1<A, V>,
730}
731
732impl<V: MyFloat> PredDeducedOpinions<V> {
733 fn deduce(
734 ded: &DeducedOpinions<V>,
735 state: &StateOpinions<V>,
736 fixed: &FixedOpinions<V>,
737 ) -> Self {
738 let b_o = fixed.o_b.inverse(&ded.b.base_rate, &state.o.base_rate);
739 let fh_fphi_fpsi_fo = compute_fh_fphi_fpsi_fo(
740 state,
741 fixed,
742 &b_o,
743 &ded.b.base_rate,
744 &ded.h.base_rate,
745 &ded.fh.base_rate,
746 );
747 let fh = state.deduce_fh(&fh_fphi_fpsi_fo, &ded.fh.base_rate);
748 let a = fh.deduce_with(&fixed.a_fh, || ded.a.base_rate.clone());
749 Self { fh, a }
750 }
751
752 fn set(self, ded: &mut DeducedOpinions<V>) {
753 ded.fh = self.fh;
754 ded.a = self.a;
755 }
756}
757
758#[derive(Default, Debug)]
759pub struct MyOpinions<V> {
760 pub state: StateOpinions<V>,
761 pub ded: DeducedOpinions<V>,
762 pub fixed: FixedOpinions<V>,
763}
764
765impl<V> MyOpinions<V>
766where
767 V: MyFloat,
768{
769 pub fn receive<'a>(
770 &'a mut self,
771 p: &'a InfoContent<V>,
772 trusts: Trusts<V>,
773 ) -> MyOpinionsUpd<'a, V> {
774 debug!("{:?}", &trusts);
775 debug!("before: {:?}", &self.state);
776
777 let mut diff = self.state.receive(p, &trusts, &self.ded);
778 debug!(diff=?diff);
779
780 diff.swap(&mut self.state);
781 debug!(target:"after", state=?self.state);
782
783 self.ded = self.ded.deduce(&self.state, &self.fixed);
784 debug!(target:"after", ded=?self.ded);
785
786 MyOpinionsUpd {
787 inner: self,
788 p,
789 trusts,
790 }
791 }
792
793 fn predict(
794 &mut self,
795 p: &InfoContent<V>,
796 trusts: &Trusts<V>,
797 ) -> (PredDiffOpinions<V>, PredDeducedOpinions<V>) {
798 let mut pred_diff = self.state.predict(p, trusts, &self.ded);
799 pred_diff.swap(&mut self.state);
800 let pred_ded = PredDeducedOpinions::deduce(&self.ded, &self.state, &self.fixed);
801 debug!(target:"pred", ded=?pred_ded);
802
803 (pred_diff, pred_ded)
804 }
805}
806
807pub struct MyOpinionsUpd<'a, V: MyFloat> {
808 inner: &'a mut MyOpinions<V>,
809 p: &'a InfoContent<'a, V>,
810 trusts: Trusts<V>,
811}
812
813impl<'a, V: MyFloat> MyOpinionsUpd<'a, V> {
814 pub fn decide1<F>(&self, mut f: F)
815 where
816 F: FnMut(&DeducedOpinions<V>),
817 {
818 f(&self.inner.ded);
819 }
820
821 pub fn decide2<F>(&mut self, mut f: F) -> bool
822 where
823 F: FnMut(&MArrD2<A, Thetad, V>, &MArrD2<A, Thetad, V>) -> bool,
824 {
825 let (mut pred_diff, pred_ded) = self.inner.predict(self.p, &self.trusts);
826 let p_a_thetad = projection_a_thetad(&self.inner.ded.a, &self.inner.ded.thetad);
827 let pred_p_a_thetad = projection_a_thetad(&pred_ded.a, &self.inner.ded.thetad);
828 if f(&p_a_thetad, &pred_p_a_thetad) {
829 pred_ded.set(&mut self.inner.ded);
830 true
831 } else {
832 pred_diff.swap(&mut self.inner.state);
833 false
834 }
835 }
836}
837
838#[cfg(test)]
839mod tests {
840 use approx::UlpsEq;
841 use num_traits::{Float, NumAssign};
842 use std::fmt::Debug;
843 use std::iter::Sum;
844 use subjective_logic::domain::DomainConv;
845 use subjective_logic::iter::FromFn;
846 use subjective_logic::mul::labeled::OpinionD1;
847 use subjective_logic::mul::{mbr, MergeJointConditions2};
848 use subjective_logic::multi_array::labeled::MArrD1;
849 use subjective_logic::ops::{Deduction, Discount, FuseAssign, FuseOp, Projection};
850 use subjective_logic::{marr_d1, mul::labeled::SimplexD1};
851
852 use super::{transform, FPsi, MyFloat, Psi, B, FH, H};
853
854 #[allow(dead_code)]
855 fn deduce<V: Float + Sum + NumAssign + UlpsEq + Debug>(
856 psi: &OpinionD1<Psi, V>,
857 fpsi: &OpinionD1<FPsi, V>,
858 c: &MArrD1<Psi, SimplexD1<H, V>>,
859 cf: &MArrD1<FPsi, SimplexD1<FH, V>>,
860 ah: &MArrD1<H, V>,
861 ) {
862 let h = psi.deduce_with(c, || ah.clone());
863 let fh = fpsi.deduce(cf);
864 println!("h {:?}", h);
865 println!("Ph {:?}", h.projection());
866 println!("fh {:?}", fh);
867 println!("Pfh {:?}", fh.unwrap().projection());
868 }
869
870 enum Info<V> {
871 Mis(OpinionD1<Psi, V>),
872 Cor(OpinionD1<Psi, V>, OpinionD1<Psi, V>),
873 }
874
875 struct Trust<V> {
876 mis: V,
877 cor: V,
878 }
879
880 impl<V> Trust<V> {
881 fn new(mis: V, cor: V) -> Self {
882 Self { mis, cor }
883 }
884 }
885
886 #[derive(Default)]
887 struct Body<V> {
888 e: V,
889 psi: OpinionD1<Psi, V>,
890 fpsi: OpinionD1<FPsi, V>,
891 c: MArrD1<Psi, SimplexD1<H, V>>,
892 cf: MArrD1<FPsi, SimplexD1<FH, V>>,
893 ah: MArrD1<H, V>,
894 pi: V,
895 }
896
897 impl Body<f32> {
898 fn reset(&mut self, pi: f32) {
899 *self = Body {
900 e: 0.2,
901 psi: OpinionD1::vacuous_with(marr_d1![0.99, 0.01]),
902 fpsi: OpinionD1::vacuous_with(marr_d1![0.99, 0.01]),
903 c: marr_d1![
904 SimplexD1::new(marr_d1![0.9, 0.0], 0.1),
905 SimplexD1::new(marr_d1![0.0, 0.8], 0.2),
906 ],
907 cf: marr_d1![
908 SimplexD1::new(marr_d1![0.7, 0.1], 0.2),
909 SimplexD1::new(marr_d1![0.1, 0.7], 0.2),
910 ],
911 ah: marr_d1![0.99, 0.01],
912 pi,
913 };
914 }
915 }
916
917 #[allow(dead_code)]
918 impl<V: MyFloat> Body<V> {
919 fn update(&mut self, p: &Info<V>, t: &Trust<V>) {
920 println!("[update]");
921 match p {
922 Info::Mis(op) => {
923 let rcv = op.discount(t.mis);
924 let est = transform(rcv.as_ref(), self.e);
925 println!("-");
926 println!("rcv {:?}", rcv);
927 println!("est {:?}", est);
928 FuseOp::Wgh.fuse_assign(&mut self.psi, &rcv);
929 FuseOp::Wgh.fuse_assign(&mut self.fpsi, &est);
930 }
931 Info::Cor(op, m) => {
932 let rcv = op.discount(t.cor);
933 let est_op = transform(rcv.as_ref(), self.e);
934 let est_m = transform(m.discount(t.mis).as_ref(), self.pi);
935 println!("-");
936 println!("rcv {:?}", rcv);
937 println!("est {:?}", est_op);
938 println!("estm {:?}", est_m);
939 FuseOp::Wgh.fuse_assign(&mut self.psi, &rcv);
940 FuseOp::Wgh.fuse_assign(&mut self.fpsi, &est_op);
941 FuseOp::Wgh.fuse_assign(&mut self.fpsi, &est_m);
942 }
943 }
944 let h = self.psi.deduce_with(&self.c, || self.ah.clone());
945 let fh = self.fpsi.deduce(&self.cf).unwrap();
946 println!("-");
947 println!("psi {:?}", self.psi);
948 println!("h {:?}", h);
949 println!("Ph {:?}", h.projection());
950 println!("-");
951 println!("fpsi {:?}", self.fpsi);
952 println!("fh {:?}", fh);
953 println!("Pfh {:?}", fh.projection());
954 }
955
956 fn gen_cf(
957 apsi: &MArrD1<Psi, V>,
958 c: &MArrD1<Psi, SimplexD1<H, V>>,
959 ah: &MArrD1<H, V>,
960 ) -> MArrD1<FPsi, SimplexD1<FH, V>> {
961 let mah = mbr(apsi, c).unwrap_or_else(|| ah.clone());
962 let cf = MArrD1::<FPsi, _>::from_fn(|fpsi| {
963 let psi = fpsi.into();
964 SimplexD1::<FH, _>::new(
965 MArrD1::from_iter(
966 c[psi]
967 .projection(&mah)
968 .iter()
969 .map(|p| *p * (V::one() - *c[psi].u())),
970 ),
971 *c[psi].u(),
972 )
973 });
974 cf
975 }
976
977 fn gen_cf2(
978 apsi: &MArrD1<Psi, V>,
979 c: &MArrD1<Psi, SimplexD1<H, V>>,
980 ah: &MArrD1<H, V>,
981 ) -> MArrD1<FPsi, SimplexD1<FH, V>>
982 where
983 V: Float + Debug + Sum + UlpsEq + NumAssign,
984 {
985 let cf0 = OpinionD1::new(marr_d1![V::one(), V::zero()], V::zero(), apsi.clone())
986 .deduce_with(c, || ah.clone());
987 let cf1 = OpinionD1::new(marr_d1![V::zero(), V::one()], V::zero(), apsi.clone())
988 .deduce_with(c, || ah.clone());
989 let cf = MArrD1::new(vec![cf0.simplex.conv(), cf1.simplex.conv()]);
990 cf
991 }
992 }
993
994 #[test]
995 fn test_misinfo() {
996 let mis = [
997 Info::Mis(OpinionD1::new(
998 marr_d1![0.05, 0.9],
999 0.05,
1000 marr_d1![0.99, 0.01],
1001 )),
1002 Info::Mis(OpinionD1::new(
1003 marr_d1![0.05, 0.9],
1004 0.05,
1005 marr_d1![0.80, 0.20],
1006 )),
1007 ];
1008 let cis = [
1009 Info::Cor(
1010 OpinionD1::new(marr_d1![0.9, 0.05], 0.05, marr_d1![0.99, 0.01]),
1011 OpinionD1::new(marr_d1![0.05, 0.9], 0.05, marr_d1![0.50, 0.50]),
1012 ),
1013 Info::Cor(
1014 OpinionD1::new(marr_d1![0.9, 0.05], 0.05, marr_d1![0.90, 0.10]),
1015 OpinionD1::new(marr_d1![0.05, 0.9], 0.05, marr_d1![0.80, 0.20]),
1016 ),
1017 ];
1018
1019 let mut body = Body::default();
1020 let ts = [Trust::new(0.5, 0.9), Trust::new(0.5, 0.5)];
1021 let pis = [0.0, 0.25, 0.5];
1022
1023 for (h, t) in ts.iter().enumerate() {
1024 for (i, ci) in cis.iter().enumerate() {
1025 for (k, pi) in pis.iter().enumerate() {
1026 println!("\n-- case x.{h}.{i}.{k} --");
1027 body.reset(*pi);
1028 body.update(ci, &t);
1029 }
1030 }
1031 }
1032
1033 for (h, t) in ts.iter().enumerate() {
1034 for (i, mi) in mis.iter().enumerate() {
1035 for (j, ci) in cis.iter().enumerate() {
1036 for (k, pi) in pis.iter().enumerate() {
1037 println!("\n-- Case {h}.{i}.{j}.{k} --");
1038 body.reset(*pi);
1039 body.update(mi, t);
1040 body.update(ci, t);
1041 }
1042 }
1043 }
1044 }
1045 }
1046
1047 #[test]
1048 fn merge() {
1049 let h_psi_if_phi0 = marr_d1!(Psi; [
1050 SimplexD1::new(marr_d1!(H; [0.95f32, 0.01]), 0.04),
1051 SimplexD1::new(marr_d1!(H; [0.01, 0.95]), 0.04),
1052 ]);
1053
1054 let h_b_if_phi0 = marr_d1!(B; [
1055 SimplexD1::new(marr_d1!(H; [0.95, 0.01]), 0.04),
1056 SimplexD1::new(marr_d1!(H; [1.8101491e-5, 0.9998891]),9.2769165e-5),
1057 ]);
1058 let psi = marr_d1!(Psi; [0.1, 0.9]);
1062 let b = marr_d1!(B; [0.5, 0.5]);
1063 let h = marr_d1!(H; [0.99, 0.01]);
1064 let c = MArrD1::<H, _>::merge_cond2(&h_psi_if_phi0, &h_b_if_phi0, &psi, &b, &h);
1065
1066 println!("{:?}", c);
1067 }
1068}