use std::os::raw::c_int;
#[allow(dead_code)]
unsafe extern "C" {
fn btf_order(
n: i32,
ap: *const i32,
ai: *const i32,
maxwork: f64,
work: *mut f64,
p: *mut i32,
q: *mut i32,
r: *mut i32,
nmatch: *mut i32,
work_arr: *mut i32,
) -> i32;
fn amd_order(
n: i32,
ap: *const i32,
ai: *const i32,
p: *mut i32,
control: *const f64,
info: *mut f64,
) -> c_int;
}
#[allow(dead_code)]
pub fn btf_order_oracle(n: usize, col_ptr: &[i32], row_idx: &[i32]) -> (Vec<i32>, Vec<i32>, Vec<i32>, i32) {
assert_eq!(col_ptr.len(), n + 1, "col_ptr must have n+1 entries");
let mut p = vec![0i32; n];
let mut q = vec![0i32; n];
let mut r = vec![0i32; n + 1];
let mut nmatch = 0i32;
let mut work = 0.0f64;
let mut work_arr = vec![0i32; 5 * n];
let nblocks = unsafe {
btf_order(
n as i32,
col_ptr.as_ptr(),
row_idx.as_ptr(),
0.0,
&mut work,
p.as_mut_ptr(),
q.as_mut_ptr(),
r.as_mut_ptr(),
&mut nmatch,
work_arr.as_mut_ptr(),
)
};
r.truncate(nblocks as usize + 1);
(p, q, r, nmatch)
}
#[allow(dead_code)]
pub fn amd_order_oracle(n: usize, col_ptr: &[i32], row_idx: &[i32]) -> Option<Vec<i32>> {
assert_eq!(col_ptr.len(), n + 1, "col_ptr must have n+1 entries");
let mut p = vec![0i32; n];
let status = unsafe {
amd_order(n as i32, col_ptr.as_ptr(), row_idx.as_ptr(), p.as_mut_ptr(), std::ptr::null(), std::ptr::null_mut())
};
(status >= 0).then_some(p)
}
#[allow(dead_code)]
pub fn klu_scale_oracle(scale: i32, n: usize, col_ptr: &[i32], row_idx: &[i32], values: &[f64]) -> Option<Vec<f64>> {
use crate::sparse_klu::{klu_common_for_oracle, klu_defaults_for_oracle, klu_scale_for_oracle};
assert_eq!(col_ptr.len(), n + 1, "col_ptr must have n+1 entries");
assert_eq!(row_idx.len(), values.len());
let mut common: klu_common_for_oracle = unsafe { std::mem::zeroed() };
unsafe { klu_defaults_for_oracle(&mut common) };
let mut rs = vec![0.0f64; n];
let mut w = vec![0i32; n];
let ok = unsafe {
klu_scale_for_oracle(
scale,
n as i32,
col_ptr.as_ptr() as *mut i32,
row_idx.as_ptr() as *mut i32,
values.as_ptr() as *mut f64,
rs.as_mut_ptr(),
w.as_mut_ptr(),
&mut common,
)
};
(ok != 0 && common.status == 0).then_some(rs)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn btf_order_oracle_on_identity_pattern() {
let col_ptr = [0, 1, 2, 3];
let row_idx = [0, 1, 2];
let (p, q, r, nmatch) = btf_order_oracle(3, &col_ptr, &row_idx);
assert_eq!(nmatch, 3, "diagonal matrix should have a full matching");
assert_eq!(r, vec![0, 1, 2, 3], "3 singleton blocks");
let mut sorted_p = p.clone();
sorted_p.sort_unstable();
assert_eq!(sorted_p, vec![0, 1, 2], "P must be a bijection");
let mut sorted_q: Vec<i32> = q.iter().map(|&x| super::super::types::unflip(x as i64) as i32).collect();
sorted_q.sort_unstable();
assert_eq!(sorted_q, vec![0, 1, 2], "Q (unflipped) must be a bijection");
}
#[test]
fn amd_order_oracle_on_identity_pattern() {
let col_ptr = [0, 1, 2, 3];
let row_idx = [0, 1, 2];
let p = amd_order_oracle(3, &col_ptr, &row_idx).expect("should succeed");
let mut sorted = p.clone();
sorted.sort_unstable();
assert_eq!(sorted, vec![0, 1, 2], "P must be a bijection");
}
}