You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: cholesky.rs
    path of file: ./repos/faer-rs/src/sparse/linalg
    
    the code of the file until where you have to start completion: //! Computes the Cholesky decomposition (either LLT, LDLT, or Bunch-Kaufman) of a given sparse
//! matrix. See [`crate::linalg::cholesky`] for more info.
//!
//! The entry point in this module is [`SymbolicCholesky`] and [`factorize_symbolic_cholesky`].
//!
//! # Note
//! The functions in this module accept unsorted input, producing a sorted decomposition factor
//! (simplicial).
//!
//! # Example (low level API)
//! Simplicial:
//! ```
//! fn simplicial_cholesky() -> Result<(), faer::sparse::FaerError> {
//!     use faer::{
//!         assert_matrix_eq,
//!         dyn_stack::{GlobalPodBuffer, PodStack, StackReq},
//!         reborrow::*,
//!         sparse::{
//!             linalg::{
//!                 amd,
//!                 cholesky::{simplicial, LdltRegularization, LltRegularization},
//!             },
//!             CreationError, SparseColMat, SymbolicSparseColMat,
//!         },
//!     };
//!     use rand::prelude::*;
//!
//!     // The simplicial Cholesky api takes an upper triangular matrix as input, to be
//!     // interpreted as self-adjoint.
//!     let dim = 4;
//!     let A_upper = match SparseColMat::<usize, f64>::try_new_from_triplets(
//!         dim,
//!         dim,
//!         &[
//!             // diagonal entries
//!             (0, 0, 10.0),
//!             (1, 1, 11.0),
//!             (2, 2, 12.0),
//!             (3, 3, 13.0),
//!             // non diagonal entries
//!             (0, 1, 1.0),
//!             (0, 3, 1.5),
//!             (1, 3, -3.2),
//!         ],
//!     ) {
//!         Ok(A) => Ok(A),
//!         Err(CreationError::Generic(err)) => Err(err),
//!         Err(CreationError::OutOfBounds { .. }) => panic!(),
//!     }?;
//!
//!     let mut A = faer::sparse::ops::add(
//!         A_upper.as_ref(),
//!         A_upper.to_row_major()?.as_ref().transpose(),
//!     )?;
//!     for i in 0..dim {
//!         A[(i, i)] /= 2.0;
//!     }
//!
//!     let A_nnz = A_upper.compute_nnz();
//!     let mut rhs = Vec::new();
//!     let mut rng = StdRng::seed_from_u64(0);
//!     rhs.try_reserve_exact(dim)?;
//!     rhs.resize_with(dim, || rng.gen::<f64>());
//!
//!     let mut sol = Vec::new();
//!     sol.try_reserve_exact(dim)?;
//!     sol.resize(dim, 0.0f64);
//!
//!     let rhs = faer::mat::from_column_major_slice::<f64>(&rhs, dim, 1);
//!     let mut sol = faer::mat::from_column_major_slice_mut::<f64>(&mut sol, dim, 1);
//!
//!     // Optional: fill reducing permutation
//!     let (perm, perm_inv) = {
//!         let mut perm = Vec::new();
//!         let mut perm_inv = Vec::new();
//!         perm.try_reserve_exact(dim)?;
//!         perm_inv.try_reserve_exact(dim)?;
//!         perm.resize(dim, 0usize);
//!         perm_inv.resize(dim, 0usize);
//!
//!         let mut mem = GlobalPodBuffer::try_new(amd::order_req::<usize>(dim, A_nnz)?)?;
//!         amd::order(
//!             &mut perm,
//!             &mut perm_inv,
//!             A_upper.symbolic(),
//!             amd::Control::default(),
//!             PodStack::new(&mut mem),
//!         )?;
//!
//!         (perm, perm_inv)
//!     };
//!
//!     let perm = unsafe { faer::perm::PermRef::new_unchecked(&perm, &perm_inv) };
//!
//!     let A_perm_upper = {
//!         let mut A_perm_col_ptrs = Vec::new();
//!         let mut A_perm_row_indices = Vec::new();
//!         let mut A_perm_values = Vec::new();
//!
//!         A_perm_col_ptrs.try_reserve_exact(dim + 1)?;
//!         A_perm_col_ptrs.resize(dim + 1, 0usize);
//!         A_perm_row_indices.try_reserve_exact(A_nnz)?;
//!         A_perm_row_indices.resize(A_nnz, 0usize
    
    fn test_solver_llt<I: Index>() {
        type E = Complex<Double<f64>>;
        let truncate = I::truncate;

        for (_, col_ptr, row_ind, values) in [SMALL, MEDIUM] {
            let mut gen = rand::rngs::StdRng::seed_from_u64(0);
            let i = E::faer_one().faer_neg().faer_sqrt();
            let mut complexify = |e: E| {
                if e == E::faer_from_f64(1.0) {
                    e.faer_add(i.faer_mul(E::faer_from_f64(gen.gen())))
                } else {
                    e
                }
            };

            let n = col_ptr.len() - 1;
            let nnz = values.len();
            let col_ptr = &*col_ptr.iter().copied().map(truncate).collect::<Vec<_>>();
            let row_ind = &*row_ind.iter().copied().map(truncate).collect::<Vec<_>>();
            let values_mat =
                crate::Mat::<E>::from_fn(nnz, 1, |i, _| complexify(E::faer_from_f64(values[i])));
            let values = values_mat.col_as_slice(0);

            let A_upper = SparseColMatRef::<'_, I, E>::new(
                SymbolicSparseColMatRef::new_unsorted_checked(n, n, col_ptr, None, row_ind),
                values,
            );

            let mut A_lower_col_ptr = col_ptr.to_vec();
            let mut A_lower_values = values_mat.clone();
            let mut A_lower_row_ind = row_ind.to_vec();
            let A_lower = crate::sparse::utils::adjoint(
                &mut A_lower_col_ptr,
                &mut A_lower_row_ind,
                A_lower_values.col_as_slice_mut(0),
                A_upper,
                PodStack::new(&mut GlobalPodBuffer::new(StackReq::new::<I>(20 * n))),
            )
            .into_const();

            let mut A_dense = sparse_to_dense(A_upper);
            for j in 0..n {
                for i in j + 1..n {
                    A_dense.write(i, j, A_dense.read(j, i).faer_conj());
                }
            }

            for (A, side, supernodal_flop_ratio_threshold, parallelism) in [
                (
                    A_upper,
                    Side::Upper,
                    SupernodalThreshold::FORCE_SIMPLICIAL,
                    Parallelism::None,
                ),
                (
                    A_upper,
                    Side::Upper,
                    SupernodalThreshold::FORCE_SUPERNODAL,
                    Parallelism::None,
                ),
                (
                    A_lower,
                    Side::Lower,
                    SupernodalThreshold::FORCE_SIMPLICIAL,
                    Parallelism::None,
                ),
                (
                    A_lower,
                    Side::Lower,
                    SupernodalThreshold::FORCE_SUPERNODAL,
                    Parallelism::None,
                ),
            ] {
                let symbolic = factorize_symbolic_cholesky(
                    A.symbolic(),
                    side,
                    CholeskySymbolicParams {
                        supernodal_flop_ratio_threshold,
                        ..Default::default()
                    },
                )
                .unwrap();
                let mut mem = GlobalPodBuffer::new(
                    symbolic
                        .factorize_numeric_ldlt_req::<E>(false, parallelism)
                        .unwrap(),
                );
                let mut L_values = Mat::<E>::zeros(symbolic.len_values(), 1);

                symbolic
                    .factorize_numeric_llt::<E>(
                        L_values.col_as_slice_mut(0),
                        A,
                        side,
                        Default::default(),
                        parallelism,
                        PodStack::new(&mut mem),
                    )
                    .unwrap();
                let L_values = L_values.col_as_slice(0);

                let A_reconstructed = match symbolic.raw() {
                    SymbolicCholeskyRaw::Simplicial(symbolic) => {
                        reconstruct_from_simplicial_llt::<I, E>(symbolic, L_values)
                    }
                    SymbolicCholeskyRaw::Supernodal(symbolic) => {
                        reconstruct_from_supernodal_llt::<I, E>(symbolic, L_values)
                    }
                };

                let (perm_fwd, _) = symbolic.perm().arrays();

                let mut max = <E as ComplexField>::Real::faer_zero();
                for j in 0..n {
                    for i in 0..n {
                        let x = (A_reconstructed
                            .read(i, j)
                            .faer_sub(A_dense.read(perm_fwd[i].zx(), perm_fwd[j].zx())))
                        .faer_abs();
                        max = if max > x { max } else { x }
                    }
                }
                assert!(max < <E as ComplexField>::Real::faer_from_f64(1e-25));

                for k in (1..16).chain(128..132) {
                    let rhs = Mat::<E>::from_fn(n, k, |_, _| {
                        E::faer_from_f64(gen.gen())
                            .faer_add(i.faer_mul(E::faer_from_f64(gen.gen())))
                    });
                    for conj in [Conj::Yes, Conj::No] {
                        let mut x = rhs.clone();
                        let llt = LltRef::new(&symbolic, L_values);
                        llt.solve_in_place_with_conj(
                            conj,
                            x.as_mut(),
                            parallelism,
                            PodStack::new(&mut GlobalPodBuffer::new(
                                symbolic.solve_in_place_req::<E>(k).unwrap(),
                            )),
                        );

                        let rhs_reconstructed = if conj == Conj::No {
                            &A_dense * &x
                        } else {
                            A_dense.conjugate() * &x
                        };
                        let mut max = <E as ComplexField>::Real::faer_zero();
                        for j in 0..k {
                            for i in 0..n {
                                let x = rhs_reconstructed
                                    .read(i, j)
                                    .faer_sub(rhs.read(i, j))
                                    .faer_abs();
                                max = if max > x { max } else { x }
                            }
                        }
                        assert!(max < <E as ComplexField>::Real::faer_from_f64(1e-25));
                    }
                }
            }
        }
    }