faer 0.24.0

linear algebra library
Documentation
#![allow(non_snake_case, dead_code)]
use curl::easy::Easy;
use diol::prelude::*;
use faer::Side;
use faer::reborrow::*;
use faer::sparse::*;
use std::collections::HashMap;
use std::ffi::OsStr;
use std::sync::LazyLock;
#[cfg(suitesparse)]
use suitesparse_sys::*;
static MAP: LazyLock<HashMap<&'static str, &'static str>> = LazyLock::new(
	|| {
		HashMap::from([
		("nd24k", "http://sparse-files.engr.tamu.edu/MM/ND/nd24k.tar.gz"),
		("nd3k", "http://sparse-files.engr.tamu.edu/MM/ND/nd3k.tar.gz"),
		("af shell7", "http://sparse-files.engr.tamu.edu/MM/Schenk_AFE/af_shell7.tar.gz"),
		("G3 circuit", "http://sparse-files.engr.tamu.edu/MM/AMD/G3_circuit.tar.gz"),
	])
	},
);
fn download(name: &str, sym: bool) -> SparseColMat<usize, f64> {
	let url = MAP[name];
	let mut dst = Vec::new();
	{
		let mut easy = Easy::new();
		easy.url(url).unwrap();
		let mut transfer = easy.transfer();
		transfer
			.write_function(|data| {
				dst.extend_from_slice(data);
				Ok(data.len())
			})
			.unwrap();
		transfer.perform().unwrap();
	}
	let tmp = std::env::temp_dir().join("__tmp__.mtx");
	let tar = flate2::read::GzDecoder::new(&*dst);
	let mut mtx = tar::Archive::new(tar);
	let mut size = 0;
	for entry in mtx.entries().unwrap() {
		let mut entry = entry.unwrap();
		if entry.path().unwrap().extension() == Some(OsStr::new("mtx"))
			&& entry.size() > size
		{
			size = entry.size();
			entry.unpack(&tmp).unwrap();
		}
	}
	let matrix_market_rs::MtxData::Sparse([nrows, ncols], coord, val, _) =
		matrix_market_rs::MtxData::<f64, 2>::from_file(&tmp).unwrap()
	else {
		panic!();
	};
	SparseColMat::try_new_from_triplets(
		nrows,
		ncols,
		&if sym {
			coord
				.iter()
				.zip(&val)
				.flat_map(|(&[row, col], &val)| {
					let val = if row == col { val / 2.0 } else { val };
					[Triplet::new(row, col, val), Triplet::new(col, row, val)]
				})
				.collect::<Vec<_>>()
		} else {
			coord
				.iter()
				.zip(&val)
				.map(|(&[row, col], &val)| Triplet::new(row, col, val))
				.collect::<Vec<_>>()
		},
	)
	.unwrap()
}
#[cfg(suitesparse)]
fn suitesparse_llt(bencher: Bencher, name: String) {
	let A = download(&name, true);
	unsafe {
		let mut common = core::mem::zeroed::<cholmod_common>();
		let mut A = cholmod_sparse_struct {
			nrow: A.nrows(),
			ncol: A.ncols(),
			nzmax: A.compute_nnz(),
			p: A.col_ptr().as_ptr() as _,
			i: A.row_idx().as_ptr() as _,
			nz: A
				.col_nnz()
				.map(|x| x.as_ptr() as _)
				.unwrap_or(core::ptr::null_mut()),
			x: A.val().as_ptr() as _,
			z: core::ptr::null_mut(),
			stype: -1,
			itype: CHOLMOD_LONG as _,
			xtype: CHOLMOD_REAL as _,
			dtype: CHOLMOD_DOUBLE as _,
			sorted: 1,
			packed: A.col_nnz().is_none() as _,
		};
		cholmod_l_start(&mut common);
		cholmod_l_defaults(&mut common);
		common.nmethods = 1;
		common.method[0].ordering = CHOLMOD_AMD as _;
		let mut L = cholmod_l_analyze(&mut A, &mut common);
		bencher.bench(|| {
			cholmod_l_factorize(&mut A, L, &mut common);
		});
		cholmod_l_free_factor(&mut L, &mut common);
		cholmod_l_finish(&mut common);
	}
}
fn faer_llt(bencher: Bencher, name: String) {
	let A = download(&name, true);
	let symbolic =
		linalg::solvers::SymbolicLlt::try_new(A.symbolic(), Side::Lower)
			.unwrap();
	bencher.bench(|| {
		linalg::solvers::Llt::try_new_with_symbolic(
			symbolic.clone(),
			A.rb(),
			Side::Lower,
		)
	});
}
fn main() -> eyre::Result<()> {
	spindle::with_lock(rayon::current_num_threads(), || {
		let bench = Bench::from_args()?;
		bench.register_many(
			"llt",
			{
				let list = diol::variadics::Nil;
				#[cfg(suitesparse)]
				let list = diol::variadics::Cons {
					head: suitesparse_llt,
					tail: list,
				};
				#[cfg(faer)]
				let list = diol::variadics::Cons {
					head: faer_llt,
					tail: list,
				};
				list
			},
			["nd3k", "af shell7", "G3 circuit"].map(String::from),
		);
		bench.run()?;
		Ok(())
	})
}