/// See `unfold_one` in the python code for documentation of the arguments.
See `unfold_one` in the python code for documentation of the arguments.
See ` unfold_one ` in the python code for documentation of the arguments .
fn unfold_one(
    site_phases: &[Complex64],
    translation_sfracs: &[V3],
    translation_deperms: &[Perm],
    translation_phases: &[&[Complex64]],
    gpoint_sfracs: &[V3],
    qpoint_sfrac: &V3,
    eigenvector: &[V3<Complex64>],
    gamma_only: bool,
) -> Vec<f64> {
    let num_quotient = translation_sfracs.len();
    // our "Frankenstein bloch function" with the magnitudes of the eigenvector and
    // the phases of the displacement vector.
    let ref bloch_function: Vec<_> = {
        zip_eq!(eigenvector, site_phases)
            .map(|(&v3, phase)| v3.map(|x| x * phase))
            .collect()
    };
    // Expectation value of each translation operator.
    let inner_prods: Vec<_> = {
        translation_deperms.par_iter().zip_eq(translation_phases).map(|(perm, &image_phases)| {
            let permuted = bloch_function.to_vec().permuted_by(perm);
            zip_eq!(bloch_function, image_phases, permuted)
                .map(|(orig_v3, &image_phase, perm_v3)| {
                    let true_translated_v3 = perm_v3.map(|x| x * image_phase);
                    inner_prod_v3(orig_v3, &true_translated_v3)
                })
                .sum::<Complex64>()
        }).collect()
    };
    // Expectation value of each P(Q -> Q + G) projection operator.
    let compute_at_g = |g: &V3| {
        let phases: Vec<_> = {
            translation_sfracs.iter()
                // Phases from Allen Eq 3.  Due to our differing phase conventions,
                // we have exp(+i...) rather than exp(-i...).
                .map(|t| exp_i2pi(V3::dot(&(qpoint_sfrac + g), t)))
                .collect()
        };
        let prob = zip_eq!(&inner_prods, phases).map(|(a, b)| a * b).sum::<Complex64>() / num_quotient as f64;
        // analytically, these are all real, positive numbers
        //
        // numerically, however, cancellation may cause issues
        assert!(f64::abs(prob.im) < 1e-7);
        assert!(-1e-7 < prob.re);
        f64::max(prob.re, 0.0)
    };
    let gpoint_probs: Vec<_> = if gamma_only {
        assert_eq!(gpoint_sfracs[0], V3::zero());
        let mut gpoint_probs = vec![0.0; gpoint_sfracs.len()];
        gpoint_probs[0] = compute_at_g(&gpoint_sfracs[0]);
        gpoint_probs
    } else {
        gpoint_sfracs.par_iter().map(compute_at_g).collect()
    };
    if !gamma_only {
        assert_close!(
            abs=1e-7,
            gpoint_probs.iter().sum::<f64>(),
            inner_prod_ev(eigenvector, eigenvector).norm(),
        );
    }
    gpoint_probs
}
fn unfold_one ( site_phases : & [ Complex64 ] , translation_sfracs : & [ V3 ] , translation_deperms : & [ Perm ] , translation_phases : & [ & [ Complex64 ] ] , gpoint_sfracs : & [ V3 ] , qpoint_sfrac : & V3 , eigenvector : & [ V3 < Complex64 > ] , gamma_only : bool , ) -> Vec < f64 > { let num_quotient = translation_sfracs . len ( ) ; // our "Frankenstein bloch function" with the magnitudes of the eigenvector and // the phases of the displacement vector. let ref bloch_function : Vec < _ > = { zip_eq ! ( eigenvector site_phases ) . map ( | ( & v3 , phase ) | v3 . map ( | x | x * phase ) ) . collect ( ) } ; // Expectation value of each translation operator. let inner_prods : Vec < _ > = { translation_deperms . par_iter ( ) . zip_eq ( translation_phases ) . map ( | ( perm , & image_phases ) | { let permuted = bloch_function . to_vec ( ) . permuted_by ( perm ) ; zip_eq ! ( bloch_function image_phases permuted ) . map ( | ( orig_v3 , & image_phase , perm_v3 ) | { let true_translated_v3 = perm_v3 . map ( | x | x * image_phase ) ; inner_prod_v3 ( orig_v3 , & true_translated_v3 ) } ) . sum :: < Complex64 > ( ) } ) . collect ( ) } ; // Expectation value of each P(Q -> Q + G) projection operator. let compute_at_g = | g : & V3 | { let phases : Vec < _ > = { translation_sfracs . iter ( ) // Phases from Allen Eq 3.  Due to our differing phase conventions, // we have exp(+i...) rather than exp(-i...). . map ( | t | exp_i2pi ( V3 :: dot ( & ( qpoint_sfrac + g ) , t ) ) ) . collect ( ) } ; let prob = zip_eq ! ( inner_prods phases ) . map ( | ( a , b ) | a * b ) . sum :: < Complex64 > ( ) / num_quotient as f64 ; // analytically, these are all real, positive numbers // // numerically, however, cancellation may cause issues assert ! ( f64 abs ( prob im ) 1e-7 ) ; assert ! ( 1e-7 prob re ) ; f64 :: max ( prob . re , 0.0 ) } ; let gpoint_probs : Vec < _ > = if gamma_only { assert_eq ! ( gpoint_sfracs [ 0 ] V3 zero ( ) ) ; let mut gpoint_probs = vec ! [ 0.0 gpoint_sfracs len ( ) ] ; gpoint_probs [ 0 ] = compute_at_g ( & gpoint_sfracs [ 0 ] ) ; gpoint_probs } else { gpoint_sfracs . par_iter ( ) . map ( compute_at_g ) . collect ( ) } ; if ! gamma_only { assert_close ! ( abs 1e-7 gpoint_probs iter ( ) sum f64 ( ) inner_prod_ev ( eigenvector eigenvector ) norm ( ) ) ; } gpoint_probs }
See `unfold_one` in the python code for documentation of the arguments.
See ` unfold_one ` in the python code for documentation of the arguments .
site_phases
&[Complex64]
translation_sfracs
&[V3]
translation_deperms
&[Perm]
translation_phases
&[&[Complex64]]
gpoint_sfracs
&[V3]
qpoint_sfrac
&V3
eigenvector
&[V3<Complex64>]
gamma_only
bool