Skip to main content

gammalooprs/numerator/
ufo.rs

1use crate::utils::{GS, W_};
2use idenso::color::CS;
3use idenso::dirac::AGS;
4use idenso::representations::{
5    Bispinor, ColorAdjoint, ColorAntiFundamental, ColorAntiSextet, ColorFundamental, ColorSextet,
6};
7use linnet::half_edge::involution::{EdgeIndex, Flow};
8use spenso::network::library::symbolic::ETS;
9use spenso::structure::representation::{LibraryRep, Minkowski, RepName};
10use spenso::structure::slot::{IsAbstractSlot, Slot};
11use spenso::structure::{OrderedStructure, TensorStructure};
12use symbolica::atom::FunctionBuilder;
13use symbolica::atom::{AtomCore, AtomView};
14use symbolica::domains::rational::Rational;
15use symbolica::symbol;
16use symbolica::{
17    atom::{Atom, Symbol},
18    function,
19    id::Replacement,
20};
21
22use color_eyre::Result;
23
24use super::aind::Aind;
25
26#[allow(dead_code)]
27pub struct UFOSymbols {
28    pub identity: Symbol,
29    pub identityl: Symbol,
30    pub gamma: Symbol,
31    pub gamma5: Symbol,
32    pub projm: Symbol,
33    pub projp: Symbol,
34    pub sigma: Symbol,
35    pub charge_conj: Symbol,
36    pub metric: Symbol,
37    pub momentum: Symbol,
38    pub levicivita: Symbol,
39    pub t: Symbol,
40    pub f: Symbol,
41    pub d: Symbol,
42    pub antilevicivita: Symbol,
43    pub t6: Symbol,
44    pub k6: Symbol,
45    pub idx: Symbol,
46    pub dummy: Symbol,
47    pub k6bar: Symbol,
48    pub complexconjugate: Symbol,
49    pub pslash: Symbol,
50    pub complex: Symbol,
51}
52
53spenso::symbolica_init_lazy_static! {
54pub static UFO, UFO_INNER: UFOSymbols = || UFOSymbols {
55    identity: symbol!("UFO::Identity"),
56    identityl: symbol!("UFO::IdentityL"),
57    gamma: symbol!("UFO::Gamma"),
58    complexconjugate: symbol!(
59        "UFO::complexconjugate",
60        norm = |f, out| {
61            if let AtomView::Fun(ff) = f
62                && ff.get_nargs() == 1
63            {
64                **out = ff.iter().next().unwrap().conj();
65            }
66        }
67    ),
68    idx: symbol!("UFO::idx"),
69    dummy: symbol!("UFO::dummy"),
70    gamma5: symbol!("UFO::Gamma5"),
71    projm: symbol!("UFO::ProjM"),
72    projp: symbol!("UFO::ProjP"),
73    sigma: symbol!("UFO::Sigma"),
74    charge_conj: symbol!("UFO::C"),
75    metric: symbol!("UFO::Metric"),
76    momentum: symbol!("UFO::P"),
77    levicivita: symbol!("UFO::Epsilon"),
78    t: symbol!("UFO::T"),
79    f: symbol!("UFO::f"),
80    d: symbol!("UFO::d"),
81    antilevicivita: symbol!("UFO::EpsilonBar"),
82    t6: symbol!("UFO::T6"),
83    k6: symbol!("UFO::K6"),
84    k6bar: symbol!("UFO::K6Bar"),
85    pslash: symbol!("UFO::PSlash"),
86    complex: symbol!(
87        "UFO::complex",
88        norm = |f, out| {
89            if let AtomView::Fun(ff) = f {
90                let mut re = Rational::zero();
91                let mut im = Rational::zero();
92                let mut count = 0;
93                for i in ff.iter() {
94                    if let Ok(i) = Rational::try_from(i) {
95                        if count == 0 {
96                            re = i;
97                        } else {
98                            im = i;
99                        }
100                        count += 1;
101                    } else if let Ok(i) = i64::try_from(i) {
102                        if count == 0 {
103                            re = i.into();
104                        } else {
105                            im = i.into();
106                        }
107                        count += 1;
108                    }
109
110                    if count > 1 {
111                        break;
112                    }
113                }
114
115                if count == 2 {
116                    **out = Atom::num(symbolica::domains::float::Complex { re, im });
117                }
118            }
119        }
120    ),
121};
122}
123
124impl UFOSymbols {
125    pub fn idx(&self, id: usize, shift: usize) -> Atom {
126        function!(self.idx, shift, id)
127    }
128    pub(crate) fn reindex_spin(
129        &self,
130        slots: &[&OrderedStructure<LibraryRep, Aind>],
131        momenta: &[(Flow, EdgeIndex)],
132        mut atom: Atom,
133        dummy: impl Fn(usize) -> Aind,
134    ) -> Result<Atom> {
135        let mink: LibraryRep = Minkowski {}.into();
136        let bis: LibraryRep = Bispinor {}.into();
137
138        // for s in slots {
139        //     println!("{}", s);
140        // }
141        // println!("In{}", atom.to_ordered_simple());
142
143        //`P(i,j)` = $$p_j^{\mu_i}$$
144        // and P(i)= $$p^{\mu_i}$$
145        atom = atom
146            .replace(self.momentum.call_args([W_.a_, W_.b___]))
147            .with(self.momentum.call((W_.b___, mink.to_symbolic([W_.a_]))))
148            .replace(self.momentum.call((self.idx.call((1, W_.a_)), W_.b_)))
149            .with(self.momentum.call_args([W_.a_, W_.b_]));
150
151        // Fill in representations
152        let reps: Vec<_> = [
153            (
154                self.gamma.call_args([W_.a_, W_.i_, W_.j_]),
155                self.gamma.call_args([
156                    mink.to_symbolic([W_.a_]),
157                    bis.to_symbolic([W_.i_]),
158                    bis.to_symbolic([W_.j_]),
159                ]),
160            ),
161            (
162                self.identityl.call_args([W_.a_, W_.b_]),
163                self.identityl
164                    .call_args([mink.to_symbolic([W_.a_]), mink.to_symbolic([W_.b_])]),
165            ),
166            (
167                self.metric.call_args([W_.a_, W_.b_]),
168                self.metric
169                    .call_args([mink.to_symbolic([W_.a_]), mink.to_symbolic([W_.b_])]),
170            ),
171            (
172                self.sigma.call_args([W_.a_, W_.b_, W_.i_, W_.j_]),
173                self.sigma.call_args([
174                    mink.to_symbolic([W_.a_]),
175                    mink.to_symbolic([W_.b_]),
176                    bis.to_symbolic([W_.i_]),
177                    bis.to_symbolic([W_.j_]),
178                ]),
179            ),
180            (
181                self.pslash.call_args([W_.i_, W_.j_, W_.a___]),
182                self.pslash
183                    .call((bis.to_symbolic([W_.i_]), bis.to_symbolic([W_.j_]), W_.a___)),
184            ),
185            (
186                self.identity.call_args([W_.i_, W_.j_]),
187                self.identity
188                    .call_args([bis.to_symbolic([W_.i_]), bis.to_symbolic([W_.j_])]),
189            ),
190            (
191                self.gamma5.call_args([W_.i_, W_.j_]),
192                self.gamma5
193                    .call_args([bis.to_symbolic([W_.i_]), bis.to_symbolic([W_.j_])]),
194            ),
195            (
196                self.projm.call_args([W_.i_, W_.j_]),
197                self.projm
198                    .call_args([bis.to_symbolic([W_.i_]), bis.to_symbolic([W_.j_])]),
199            ),
200            (
201                self.projp.call_args([W_.i_, W_.j_]),
202                self.projp
203                    .call_args([bis.to_symbolic([W_.i_]), bis.to_symbolic([W_.j_])]),
204            ),
205            (
206                self.charge_conj.call_args([W_.i_, W_.j_]),
207                self.charge_conj
208                    .call_args([bis.to_symbolic([W_.i_]), bis.to_symbolic([W_.j_])]),
209            ),
210        ]
211        .into_iter()
212        .map(|(pat, rep)| Replacement::new(pat.to_pattern(), rep))
213        .collect();
214
215        atom = atom
216            .replace_multiple(&reps)
217            .replace(self.levicivita.call((W_.a___, W_.i_, W_.b___)))
218            .repeat()
219            .with(
220                self.levicivita
221                    .call((W_.a___, mink.to_symbolic([W_.i_]), W_.b___)),
222            );
223
224        for (i, s) in slots.iter().enumerate() {
225            let i = i + 1;
226            for (shift, r) in s.external_structure_iter().enumerate() {
227                let rep = r.rep_name();
228                let wrappedi = self.idx(i, shift + 1);
229                let wrappedi = wrappedi.as_view();
230
231                // println!("{}", rep.to_symbolic([i]));
232                atom = atom
233                    .replace(rep.to_symbolic([wrappedi]))
234                    .level_range((1, Some(1)))
235                    .with(r.to_atom())
236                    .replace(rep.to_symbolic([i]))
237                    .level_range((1, Some(1)))
238                    .with(r.to_atom())
239            }
240        }
241        // debug!(in = atom.printer(LOGPRINTOPTS).to_string());
242
243        // Handle dummies:
244
245        let mut max_dummy = 0;
246
247        // debug!("Before dummies : {}", atom.to_ordered_simple());
248
249        for rep in [mink, bis] {
250            let mut max_dummy = 0;
251
252            atom = atom.replace_map(|term, _, out| {
253                let AtomView::Fun(f) = term else {
254                    return;
255                };
256
257                let name = f.get_symbol();
258                if name != rep.symbol() {
259                    return;
260                }
261
262                let mut fbuilder = FunctionBuilder::new(name);
263
264                if f.get_nargs() == 1 {
265                    fbuilder = fbuilder.add_arg(4);
266                    let arg = f.iter().next().unwrap();
267                    let a = if let Ok(a) = i64::try_from(arg) {
268                        if a < 0 {
269                            (-a) as usize
270                        } else {
271                            return;
272                        }
273                    } else if let AtomView::Fun(f) = arg
274                        && f.get_symbol() == self.dummy
275                        && f.get_nargs() == 1
276                        && let Ok(a) = usize::try_from(f.iter().next().unwrap())
277                    {
278                        a
279                    } else {
280                        return;
281                    };
282                    if a > max_dummy {
283                        max_dummy = a;
284                    }
285                    fbuilder = fbuilder.add_arg(Atom::from(dummy(a)));
286                    **out = fbuilder.finish();
287                }
288            });
289        }
290
291        let mink = Minkowski {}.new_rep(4);
292        let bis = Bispinor {}.new_rep(4);
293        // debug!(after_dummies = atom.printer(LOGPRINTOPTS).to_string());
294        // debug!("After dummies{}", atom);
295
296        let reps: Vec<_> = [
297            (
298                self.identity
299                    .call_args([bis.pattern(W_.a_), bis.pattern(W_.b_)]),
300                bis.g(W_.a_, W_.b_),
301            ),
302            (
303                self.identityl
304                    .call_args([mink.pattern(W_.a_), mink.pattern(W_.b_)]),
305                mink.g(W_.a_, W_.b_),
306            ),
307            (
308                self.metric
309                    .call_args([mink.pattern(W_.a_), mink.pattern(W_.b_)]),
310                mink.g(W_.a_, W_.b_),
311            ),
312            (
313                self.gamma
314                    .call_args([mink.pattern(W_.i_), bis.pattern(W_.a_), bis.pattern(W_.b_)]),
315                AGS.gamma
316                    .call_args([bis.pattern(W_.a_), bis.pattern(W_.b_), mink.pattern(W_.i_)]),
317            ),
318            (
319                self.gamma5
320                    .call_args([bis.pattern(W_.a_), bis.pattern(W_.b_)]),
321                AGS.gamma5
322                    .call_args([bis.pattern(W_.a_), bis.pattern(W_.b_)]),
323            ),
324            (
325                self.projm
326                    .call_args([bis.pattern(W_.a_), bis.pattern(W_.b_)]),
327                AGS.projm
328                    .call_args([bis.pattern(W_.a_), bis.pattern(W_.b_)]),
329            ),
330            (
331                self.projp
332                    .call_args([bis.pattern(W_.a_), bis.pattern(W_.b_)]),
333                AGS.projp
334                    .call_args([bis.pattern(W_.a_), bis.pattern(W_.b_)]),
335            ),
336            (
337                self.sigma.call_args([
338                    bis.pattern(W_.a_),
339                    bis.pattern(W_.b_),
340                    mink.pattern(W_.i_),
341                    mink.pattern(W_.j_),
342                ]),
343                AGS.sigma.call_args([
344                    bis.pattern(W_.a_),
345                    bis.pattern(W_.b_),
346                    mink.pattern(W_.i_),
347                    mink.pattern(W_.j_),
348                ]),
349            ),
350        ]
351        .into_iter()
352        .map(|(pat, rep)| Replacement::new(pat.to_pattern(), rep))
353        .collect();
354
355        // println!("out:{atom}");
356        atom = atom.replace_multiple(&reps);
357
358        atom = atom.replace_map(|term, _, out| {
359            if let AtomView::Fun(f) = term
360                && f.get_symbol() == self.pslash
361            {
362                let mut gamma = FunctionBuilder::new(AGS.gamma);
363
364                let mut count = 0;
365
366                for a in f.iter() {
367                    count += 1;
368                    if count <= 2 {
369                        gamma = gamma.add_arg(a);
370                    } else if let Ok(i) = i64::try_from(a) {
371                        max_dummy += 1;
372
373                        let minki: Slot<Minkowski, Aind> = mink.slot(dummy(max_dummy));
374
375                        gamma = gamma.add_arg(minki.to_atom());
376
377                        **out = gamma.finish() * GS.emr_mom(momenta[i as usize].1, minki.to_atom());
378                        return;
379                    }
380                }
381
382                if count == 2 {
383                    max_dummy += 1;
384
385                    let minki: Slot<Minkowski, Aind> = mink.slot(dummy(max_dummy));
386
387                    gamma = gamma.add_arg(minki.to_atom());
388
389                    **out = gamma.finish() * GS.emr_mom(momenta[0].1, minki.to_atom());
390                }
391            }
392        });
393
394        for (i, (f, e)) in momenta.iter().enumerate() {
395            atom = atom
396                .replace(function!(UFO.momentum, (i + 1) as i64, W_.a_))
397                .with(match f {
398                    Flow::Sink => GS.emr_mom(*e, W_.a_),
399                    Flow::Source => -GS.emr_mom(*e, W_.a_),
400                })
401        }
402
403        atom = atom
404            .replace(function!(UFO.momentum, W_.a_))
405            .with(GS.emr_mom(momenta[0].1, W_.a_));
406
407        // debug!(out = atom.printer(LOGPRINTOPTS).to_string());
408        // println!("out:{atom:#}");
409
410        if atom
411            .replace(self.gamma.call_args([W_.a__]))
412            .match_iter()
413            .next()
414            .is_some()
415            || atom
416                .replace(self.sigma.call_args([W_.a___]))
417                .match_iter()
418                .next()
419                .is_some()
420            || atom
421                .replace(self.pslash.call_args([W_.a___]))
422                .match_iter()
423                .next()
424                .is_some()
425            || atom
426                .replace(self.gamma5.call_args([W_.a__]))
427                .match_iter()
428                .next()
429                .is_some()
430            || atom
431                .replace(self.projm.call_args([W_.a__]))
432                .match_iter()
433                .next()
434                .is_some()
435            || atom
436                .replace(self.projp.call_args([W_.a__]))
437                .match_iter()
438                .next()
439                .is_some()
440            || atom
441                .replace(self.charge_conj.call_args([W_.a__]))
442                .match_iter()
443                .next()
444                .is_some()
445        {
446            return Err(color_eyre::eyre::eyre!(
447                "Some spinor structures were not fully re-indexed: {}",
448                atom
449            ));
450        }
451
452        Ok(atom)
453    }
454
455    pub(crate) fn reindex_color(
456        &self,
457        slots: &[&OrderedStructure<LibraryRep, Aind>],
458        mut atom: Atom,
459        dummy: impl Fn(usize) -> Aind,
460    ) -> Result<Atom> {
461        let adj = ColorAdjoint {};
462        let fund = ColorFundamental {};
463        let antifund = ColorAntiFundamental {};
464        let sext = ColorSextet {};
465        let antisext = ColorAntiSextet {};
466        // for s in slots {
467        //     debug!("{}", s);
468        // }
469
470        // debug!("In:{}", atom);
471        // Fill in representations
472        let reps: Vec<_> = [
473            (
474                self.t.call_args([W_.a_, W_.i_, W_.j_]),
475                self.t.call_args([
476                    adj.to_symbolic([W_.a_]),
477                    fund.to_symbolic([W_.i_]),
478                    antifund.to_symbolic([W_.j_]),
479                ]),
480            ),
481            (
482                self.f.call_args([W_.a_, W_.b_, W_.c_]),
483                self.f.call_args([
484                    adj.to_symbolic([W_.a_]),
485                    adj.to_symbolic([W_.b_]),
486                    adj.to_symbolic([W_.c_]),
487                ]),
488            ),
489            (
490                self.d.call_args([W_.a_, W_.b_, W_.c_]),
491                self.d.call_args([
492                    adj.to_symbolic([W_.a_]),
493                    adj.to_symbolic([W_.b_]),
494                    adj.to_symbolic([W_.c_]),
495                ]),
496            ),
497            (
498                self.levicivita.call_args([W_.i_, W_.j_, W_.k_]),
499                self.levicivita.call_args([
500                    fund.to_symbolic([W_.i_]),
501                    fund.to_symbolic([W_.j_]),
502                    fund.to_symbolic([W_.k_]),
503                ]),
504            ),
505            (
506                self.antilevicivita.call_args([W_.i_, W_.j_, W_.k_]),
507                self.levicivita.call_args([
508                    antifund.to_symbolic([W_.i_]),
509                    antifund.to_symbolic([W_.j_]),
510                    antifund.to_symbolic([W_.k_]),
511                ]),
512            ),
513            (
514                self.t6.call_args([W_.a_, W_.i_, W_.j_]),
515                self.t6.call_args([
516                    adj.to_symbolic([W_.a_]),
517                    sext.to_symbolic([W_.i_]),
518                    antisext.to_symbolic([W_.j_]),
519                ]),
520            ),
521            (
522                self.k6.call_args([W_.a_, W_.i_, W_.j_]),
523                self.k6.call_args([
524                    sext.to_symbolic([W_.a_]),
525                    antifund.to_symbolic([W_.i_]),
526                    antifund.to_symbolic([W_.j_]),
527                ]),
528            ),
529            (
530                self.k6bar.call_args([W_.a_, W_.i_, W_.j_]),
531                self.k6bar.call_args([
532                    antisext.to_symbolic([W_.a_]),
533                    fund.to_symbolic([W_.i_]),
534                    fund.to_symbolic([W_.j_]),
535                ]),
536            ),
537        ]
538        .into_iter()
539        .map(|(pat, rep)| Replacement::new(pat.to_pattern(), rep))
540        .collect();
541
542        // println!("preid:{atom}");
543        atom = atom.replace_multiple(&reps);
544
545        // Now identify the kroneker reps:
546
547        atom = atom
548            .replace(
549                function!(self.identity, W_.a_, W_.b_)
550                    * function!(W_.f_, W_.a___, function!(W_.g_, W_.a_), W_.b___),
551            )
552            .repeat()
553            .with(
554                self.identity.call((W_.g_.call_args([W_.a_]), W_.b_))
555                    * W_.f_.call((W_.a___, W_.g_.call_args([W_.a_]), W_.b___)),
556            );
557
558        // debug!("Postid:{}", atom);
559
560        // println!("postid:{atom}");
561
562        for (i, s) in slots.iter().enumerate() {
563            let i = i + 1;
564            for (shift, r) in s.external_structure_iter().enumerate() {
565                let rep = r.rep_name();
566                let wrappedi = self.idx(i, shift + 1);
567                let wrappedi = wrappedi.as_view();
568
569                // println!("{}", rep.to_symbolic([i]));
570                atom = atom
571                    .replace(rep.to_symbolic([wrappedi]))
572                    .level_range((1, Some(1)))
573                    .with(r.to_atom())
574                    .replace(self.identity.call((wrappedi, W_.i_)))
575                    .with(self.identity.call((r.to_atom(), W_.i_)))
576                    .replace(self.identity.call((W_.i_, wrappedi)))
577                    .with(self.identity.call((W_.i_, r.to_atom())))
578                    .replace(rep.to_symbolic([i]))
579                    .level_range((1, Some(1)))
580                    .with(r.to_atom())
581                    .replace(self.identity.call((i, W_.i_)))
582                    .with(self.identity.call((r.to_atom(), W_.i_)))
583                    .replace(self.identity.call((W_.i_, i)))
584                    .with(self.identity.call((W_.i_, r.to_atom())));
585            }
586        }
587
588        // println!("slot:{atom}");
589        // Handle dummies:
590        //
591        for rep in [
592            LibraryRep::from(adj).new_rep(8),
593            fund.new_rep(3).to_lib(),
594            antifund.new_rep(3).to_lib(),
595            sext.new_rep(6).to_lib(),
596            antisext.new_rep(6).to_lib(),
597        ] {
598            let mut max_dummy = 0;
599
600            atom = atom.replace_map(|term, _, out| {
601                let AtomView::Fun(f) = term else {
602                    return;
603                };
604
605                let name = f.get_symbol();
606                if name != rep.rep.symbol() {
607                    return;
608                }
609
610                let mut fbuilder = FunctionBuilder::new(name);
611
612                if f.get_nargs() == 1 {
613                    fbuilder = fbuilder.add_arg(rep.dim.to_symbolic());
614                    let arg = f.iter().next().unwrap();
615                    let a = if let Ok(a) = i64::try_from(arg) {
616                        if a < 0 {
617                            (-a) as usize
618                        } else {
619                            return;
620                        }
621                    } else if let AtomView::Fun(f) = arg
622                        && f.get_symbol() == self.dummy
623                        && f.get_nargs() == 1
624                        && let Ok(a) = usize::try_from(f.iter().next().unwrap())
625                    {
626                        a
627                    } else {
628                        return;
629                    };
630                    if a > max_dummy {
631                        max_dummy = a;
632                    }
633                    fbuilder = fbuilder.add_arg(Atom::from(dummy(a)));
634                    **out = fbuilder.finish();
635                }
636            });
637        }
638
639        let reps: Vec<_> = [
640            (
641                self.identity.call_args([W_.a_, W_.b_]),
642                ETS.metric.call_args([W_.a_, W_.b_]),
643            ),
644            (
645                self.t.call_args([
646                    adj.to_symbolic([W_.a__]),
647                    fund.to_symbolic([W_.i__]),
648                    antifund.to_symbolic([W_.j__]),
649                ]),
650                CS.t.call_args([
651                    adj.to_symbolic([W_.a__]),
652                    fund.to_symbolic([W_.i__]),
653                    antifund.to_symbolic([W_.j__]),
654                ]),
655            ),
656            (
657                self.f.call_args([
658                    adj.to_symbolic([W_.a__]),
659                    adj.to_symbolic([W_.b__]),
660                    adj.to_symbolic([W_.c__]),
661                ]),
662                CS.f.call_args([
663                    adj.to_symbolic([W_.a__]),
664                    adj.to_symbolic([W_.b__]),
665                    adj.to_symbolic([W_.c__]),
666                ]),
667            ),
668        ]
669        .into_iter()
670        .map(|(pat, rep)| Replacement::new(pat.to_pattern(), rep))
671        .collect();
672
673        atom = atom.replace_multiple(&reps);
674
675        if atom
676            .replace(self.t.call_args([W_.a___]))
677            .match_iter()
678            .next()
679            .is_some()
680            || atom
681                .replace(self.f.call_args([W_.a___]))
682                .match_iter()
683                .next()
684                .is_some()
685            || atom
686                .replace(self.d.call_args([W_.a___]))
687                .match_iter()
688                .next()
689                .is_some()
690            || atom
691                .replace(self.levicivita.call_args([W_.a___]))
692                .match_iter()
693                .next()
694                .is_some()
695            || atom
696                .replace(self.antilevicivita.call_args([W_.a___]))
697                .match_iter()
698                .next()
699                .is_some()
700            || atom
701                .replace(self.t6.call_args([W_.a___]))
702                .match_iter()
703                .next()
704                .is_some()
705            || atom
706                .replace(self.k6.call_args([W_.a___]))
707                .match_iter()
708                .next()
709                .is_some()
710            || atom
711                .replace(self.k6bar.call_args([W_.a___]))
712                .match_iter()
713                .next()
714                .is_some()
715        {
716            return Err(color_eyre::eyre::eyre!(
717                "Some color structures were not fully re-indexed: {}",
718                atom
719            ));
720        }
721
722        // println!("Out:{:#}", atom);
723        Ok(atom)
724    }
725}
726
727#[cfg(test)]
728pub mod test {
729
730    #[test]
731    fn ufo_spin_processing() {}
732}