fn volume(&self) -> Option<f64> {
        let rank = self.rank();

        // We leave the nullitope's volume undefined.
        if rank == 0 {
            return None;
        }

        // The flattened vertices (may possibly be the original vertices).
        let subspace = Subspace::from_points(self.vertices().iter());
        let flat_vertices = subspace.flatten_vec(self.vertices());

        match flat_vertices.get(0)?.len().cmp(&(rank - 1)) {
            // Degenerate polytopes have volume 0.
            std::cmp::Ordering::Less => {
                return Some(0.0);
            }
            // Skew polytopes don't have a defined volume.
            std::cmp::Ordering::Greater => {
                return None;
            }
            _ => {}
        }

        // Maps every element of the polytope to one of its vertices.
        let vertex_map = self.vertex_map();
        let mut volume = 0.0;

        // All of the flags we've found so far.
        let mut all_flags = HashSet::new();

        // We iterate over all flags in the polytope.
        for flag in self.flags() {
            // If this flag forms a new component of the polytope, we iterate
            // over the oriented flags in this component.
            if !all_flags.contains(&flag) {
                let mut component_volume = 0.0;

                for flag_event in
                    OrientedFlagIter::with_flags(self.abs(), FlagChanges::all(rank), flag.into())
                {
                    if let FlagEvent::Flag(oriented_flag) = flag_event {
                        let new = all_flags.insert(oriented_flag.flag.clone());
                        debug_assert!(new, "A flag is in two different components.");

                        // For each flag, there's a simplex defined by any vertices in its
                        // elements and the origin. We add up the volumes of all of these
                        // simplices times the sign of the flag that generated them.
                        component_volume += oriented_flag.orientation.sign()
                            * Matrix::from_iterator(
                                rank - 1,
                                rank - 1,
                                oriented_flag
                                    .into_iter()
                                    .enumerate()
                                    .skip(1)
                                    .take(rank - 1)
                                    .map(|(rank, idx)| &flat_vertices[vertex_map[(rank, idx)]])
                                    .flatten()
                                    .copied(),
                            )
                            .determinant();
                    }
                    // A non-orientable polytope doesn't have a volume.
                    else {
                        return None;
                    }
                }

                // We add up the volumes of all components.
                volume += component_volume.fabs();
            }
        }

        Some(volume / f64::u32(crate::factorial(rank - 1)))
    }
/// Computes the volume of a polytope by adding up the contributions of all
/// flags. Returns `None` if the volume is undefined.
///
/// # Panics
/// You must call [`Polytope::element_sort`] before calling this method.
Computes the volume of a polytope by adding up the contributions of all
flags. Returns `None` if the volume is undefined.
Computes the volume of a polytope by adding up the contributions of all flags . Returns ` None ` if the volume is undefined .
fn volume(&self) -> Option<f64> {
        let rank = self.rank();
        // We leave the nullitope's volume undefined.
        if rank == 0 {
            return None;
        }
        // The flattened vertices (may possibly be the original vertices).
        let subspace = Subspace::from_points(self.vertices().iter());
        let flat_vertices = subspace.flatten_vec(self.vertices());
        match flat_vertices.get(0)?.len().cmp(&(rank - 1)) {
            // Degenerate polytopes have volume 0.
            std::cmp::Ordering::Less => {
                return Some(0.0);
            }
            // Skew polytopes don't have a defined volume.
            std::cmp::Ordering::Greater => {
                return None;
            }
            _ => {}
        }
        // Maps every element of the polytope to one of its vertices.
        let vertex_map = self.vertex_map();
        let mut volume = 0.0;
        // All of the flags we've found so far.
        let mut all_flags = HashSet::new();
        // We iterate over all flags in the polytope.
        for flag in self.flags() {
            // If this flag forms a new component of the polytope, we iterate
            // over the oriented flags in this component.
            if !all_flags.contains(&flag) {
                let mut component_volume = 0.0;
                for flag_event in
                    OrientedFlagIter::with_flags(self.abs(), FlagChanges::all(rank), flag.into())
                {
                    if let FlagEvent::Flag(oriented_flag) = flag_event {
                        let new = all_flags.insert(oriented_flag.flag.clone());
                        debug_assert!(new, "A flag is in two different components.");
                        // For each flag, there's a simplex defined by any vertices in its
                        // elements and the origin. We add up the volumes of all of these
                        // simplices times the sign of the flag that generated them.
                        component_volume += oriented_flag.orientation.sign()
                            * Matrix::from_iterator(
                                rank - 1,
                                rank - 1,
                                oriented_flag
                                    .into_iter()
                                    .enumerate()
                                    .skip(1)
                                    .take(rank - 1)
                                    .map(|(rank, idx)| &flat_vertices[vertex_map[(rank, idx)]])
                                    .flatten()
                                    .copied(),
                            )
                            .determinant();
                    }
                    // A non-orientable polytope doesn't have a volume.
                    else {
                        return None;
                    }
                }
                // We add up the volumes of all components.
                volume += component_volume.fabs();
            }
        }
        Some(volume / f64::u32(crate::factorial(rank - 1)))
    }
fn volume ( & self ) -> Option < f64 > { let rank = self . rank ( ) ; // We leave the nullitope's volume undefined. if rank == 0 { return None ; } // The flattened vertices (may possibly be the original vertices). let subspace = Subspace :: from_points ( self . vertices ( ) . iter ( ) ) ; let flat_vertices = subspace . flatten_vec ( self . vertices ( ) ) ; match flat_vertices . get ( 0 ) ? . len ( ) . cmp ( & ( rank - 1 ) ) { // Degenerate polytopes have volume 0. std :: cmp :: Ordering :: Less => { return Some ( 0.0 ) ; } // Skew polytopes don't have a defined volume. std :: cmp :: Ordering :: Greater => { return None ; } _ => { } } // Maps every element of the polytope to one of its vertices. let vertex_map = self . vertex_map ( ) ; let mut volume = 0.0 ; // All of the flags we've found so far. let mut all_flags = HashSet :: new ( ) ; // We iterate over all flags in the polytope. for flag in self . flags ( ) { // If this flag forms a new component of the polytope, we iterate // over the oriented flags in this component. if ! all_flags . contains ( & flag ) { let mut component_volume = 0.0 ; for flag_event in OrientedFlagIter :: with_flags ( self . abs ( ) , FlagChanges :: all ( rank ) , flag . into ( ) ) { if let FlagEvent :: Flag ( oriented_flag ) = flag_event { let new = all_flags . insert ( oriented_flag . flag . clone ( ) ) ; debug_assert ! ( new " " ) ; // For each flag, there's a simplex defined by any vertices in its // elements and the origin. We add up the volumes of all of these // simplices times the sign of the flag that generated them. component_volume += oriented_flag . orientation . sign ( ) * Matrix :: from_iterator ( rank - 1 , rank - 1 , oriented_flag . into_iter ( ) . enumerate ( ) . skip ( 1 ) . take ( rank - 1 ) . map ( | ( rank , idx ) | & flat_vertices [ vertex_map [ ( rank , idx ) ] ] ) . flatten ( ) . copied ( ) , ) . determinant ( ) ; } // A non-orientable polytope doesn't have a volume. else { return None ; } } // We add up the volumes of all components. volume += component_volume . fabs ( ) ; } } Some ( volume / f64 :: u32 ( crate :: factorial ( rank - 1 ) ) ) }
Computes the volume of a polytope by adding up the contributions of all
flags.
Computes the volume of a polytope by adding up the contributions of all flags .
&self
panics
You must call [`Polytope::element_sort`] before calling this method.
You must call [ ` Polytope :: element_sort ` ] before calling this method .