pub fn spacegroup_coperms_with_meta<M: Ord>(
    // Arbitrary superstructure (the thing we want to permute)
    coords: &Coords,
    // Metadata, which is assumed to obey the symmetry of the spacegroup.
    // (i.e. sites in a symmetry star should have the same metadata)
    //
    // (FIXME: This is not checked)
    metadata: &[M],

    // Spacegroup operators.
    cart_ops: &[CartOp],

    tol: f64,
) -> Result<Vec<Perm>, Error>
{Ok({
    let lattice = coords.lattice();
    let from_fracs = coords.to_fracs();

    // Integer-based spacegroup operators, because we need a form of
    // the operators that is hashable for the GroupTree composition trick.
    let int_ops: Vec<_> = {
        cart_ops.iter()
            .map(|c| c.int_rot(lattice))
            .collect::<Result<_, _>>()?
    };

    // Find relations between the group operators and
    // identify a small number of base cases ("generators").
    let tree = GroupTree::from_all_members(
        int_ops,
        |a, b| a.then(b),
    );

    // `transform_ops` must convert to cartesian and back, so it may introduce
    // errors on the order of a few ULP into the fracs.  Add a bit more fuzz to
    // the tolerance to account for this, scaling it with the lattice since the
    // tolerance is applied in cartesian space.
    //
    // This ensures that the identity transformation can be found for tol = 0.
    //
    // 1e-12 was found to be large enough for matrices of sufficiently small skew,
    // as verified by the unit tests.
    let adjusted_tol = tol + 1e-12 * f64::cbrt(lattice.volume());

    tree.try_compute_homomorphism(
        // Generators: Do a (very expensive!) brute force search.
        |op_ind, _int_op| {
            let to_fracs = cart_ops[op_ind].transform_fracs(lattice, &from_fracs);
            brute_force_with_sort_trick(
                lattice,
                metadata, CoordsKind::Fracs(&from_fracs),
                metadata, CoordsKind::Fracs(&to_fracs[..]),
                adjusted_tol,
            )
        },
        // Other operators: Quickly compose the results from other operators.
        |a, b| Ok({
            // Flip the order, because the permutations we seek
            //  actually come from the opposite group.
            //
            // i.e.  given P_a X = X R_a
            //         and P_b X = X R_b,
            //  one can easily show that  X R_a R_b = P_a P_b X
            b.clone().permuted_by(a)
        }),
    )?
})}
// NOTE: This version uses the metadata to group the atoms and potentially
//       elide even more comparisons. Is it effective? No idea! But it comes at
//       zero extra cost for `M = ()` and hasn't been hurting anyone, so I
//       figured I'll leave it in.
This version uses the metadata to group the atoms and potentially
elide even more comparisons. Is it effective. No idea. But it comes at
zero extra cost for `M = ()` and hasn't been hurting anyone, so I
figured I'll leave it in.
This version uses the metadata to group the atoms and potentially elide even more comparisons . Is it effective . No idea . But it comes at zero extra cost for ` M = () ` and hasn ' t been hurting anyone so I figured I ' ll leave it in .
pub fn spacegroup_coperms_with_meta<M: Ord>(
    // Arbitrary superstructure (the thing we want to permute)
    coords: &Coords,
    // Metadata, which is assumed to obey the symmetry of the spacegroup.
    // (i.e. sites in a symmetry star should have the same metadata)
    //
    // (FIXME: This is not checked)
    metadata: &[M],
    // Spacegroup operators.
    cart_ops: &[CartOp],
    tol: f64,
) -> Result<Vec<Perm>, Error>
{Ok({
    let lattice = coords.lattice();
    let from_fracs = coords.to_fracs();
    // Integer-based spacegroup operators, because we need a form of
    // the operators that is hashable for the GroupTree composition trick.
    let int_ops: Vec<_> = {
        cart_ops.iter()
            .map(|c| c.int_rot(lattice))
            .collect::<Result<_, _>>()?
    };
    // Find relations between the group operators and
    // identify a small number of base cases ("generators").
    let tree = GroupTree::from_all_members(
        int_ops,
        |a, b| a.then(b),
    );
    // `transform_ops` must convert to cartesian and back, so it may introduce
    // errors on the order of a few ULP into the fracs.  Add a bit more fuzz to
    // the tolerance to account for this, scaling it with the lattice since the
    // tolerance is applied in cartesian space.
    //
    // This ensures that the identity transformation can be found for tol = 0.
    //
    // 1e-12 was found to be large enough for matrices of sufficiently small skew,
    // as verified by the unit tests.
    let adjusted_tol = tol + 1e-12 * f64::cbrt(lattice.volume());
    tree.try_compute_homomorphism(
        // Generators: Do a (very expensive!) brute force search.
        |op_ind, _int_op| {
            let to_fracs = cart_ops[op_ind].transform_fracs(lattice, &from_fracs);
            brute_force_with_sort_trick(
                lattice,
                metadata, CoordsKind::Fracs(&from_fracs),
                metadata, CoordsKind::Fracs(&to_fracs[..]),
                adjusted_tol,
            )
        },
        // Other operators: Quickly compose the results from other operators.
        |a, b| Ok({
            // Flip the order, because the permutations we seek
            //  actually come from the opposite group.
            //
            // i.e.  given P_a X = X R_a
            //         and P_b X = X R_b,
            //  one can easily show that  X R_a R_b = P_a P_b X
            b.clone().permuted_by(a)
        }),
    )?
})}
pub fn spacegroup_coperms_with_meta < M : Ord > ( // Arbitrary superstructure (the thing we want to permute) coords : & Coords , // Metadata, which is assumed to obey the symmetry of the spacegroup. // (i.e. sites in a symmetry star should have the same metadata) // // (FIXME: This is not checked) metadata : & [ M ] , // Spacegroup operators. cart_ops : & [ CartOp ] , tol : f64 , ) -> Result < Vec < Perm > , Error > { Ok ( { let lattice = coords . lattice ( ) ; let from_fracs = coords . to_fracs ( ) ; // Integer-based spacegroup operators, because we need a form of // the operators that is hashable for the GroupTree composition trick. let int_ops : Vec < _ > = { cart_ops . iter ( ) . map ( | c | c . int_rot ( lattice ) ) . collect :: < Result < _ , _ > > ( ) ? } ; // Find relations between the group operators and // identify a small number of base cases ("generators"). let tree = GroupTree :: from_all_members ( int_ops , | a , b | a . then ( b ) , ) ; // `transform_ops` must convert to cartesian and back, so it may introduce // errors on the order of a few ULP into the fracs.  Add a bit more fuzz to // the tolerance to account for this, scaling it with the lattice since the // tolerance is applied in cartesian space. // // This ensures that the identity transformation can be found for tol = 0. // // 1e-12 was found to be large enough for matrices of sufficiently small skew, // as verified by the unit tests. let adjusted_tol = tol + 1e-12 * f64 :: cbrt ( lattice . volume ( ) ) ; tree . try_compute_homomorphism ( // Generators: Do a (very expensive!) brute force search. | op_ind , _int_op | { let to_fracs = cart_ops [ op_ind ] . transform_fracs ( lattice , & from_fracs ) ; brute_force_with_sort_trick ( lattice , metadata , CoordsKind :: Fracs ( & from_fracs ) , metadata , CoordsKind :: Fracs ( & to_fracs [ .. ] ) , adjusted_tol , ) } , // Other operators: Quickly compose the results from other operators. | a , b | Ok ( { // Flip the order, because the permutations we seek //  actually come from the opposite group. // // i.e.  given P_a X = X R_a //         and P_b X = X R_b, //  one can easily show that  X R_a R_b = P_a P_b X b . clone ( ) . permuted_by ( a ) } ) , ) ? } ) }
NOTE: This version uses the metadata to group the atoms and potentially
elide even more comparisons.
NOTE : This version uses the metadata to group the atoms and potentially elide even more comparisons .
coords
&Coords
metadata
&[M]
cart_ops
&[CartOp]
tol
f64
coords
&Coords
metadata
&[M]
cart_ops
&[CartOp]
tol
f64