base/
opinion.rs

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 m: V,
140    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        // ap: &AccessProb<V>,
250        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                        // .zip(op2.iter().map(|o| o.discount(trusts.fp)))
302                        .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 h_psi_if_phi1 = marr_d1!(Psi; [SimplexD1::vacuous(), SimplexD1::vacuous()]);
1059        // let h_b_if_phi1 = marr_d1!(Psi; [SimplexD1::vacuous(), SimplexD1::vacuous()]);
1060
1061        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}