use libc;
use std::mem::size_of;
use crate::misc::m4ri_one;
use crate::misc::m4ri_radix;
use crate::misc::Rci;
use crate::misc::Wi;
use crate::misc::Word;
use crate::misc::BIT;
#[repr(C)]
struct MzdBlock {
size: libc::size_t,
begin: *mut Word,
end: *mut Word,
}
#[repr(C)]
pub struct Mzd {
pub nrows: Rci,
pub ncols: Rci,
pub width: Wi,
rowstride: Wi,
offset_vector: Wi,
row_offset: Wi,
flags: u8,
blockrows_log: u8,
padding: [u8; 62
- 2 * size_of::<Rci>()
- 4 * size_of::<Wi>()
- size_of::<Word>()
- 2 * size_of::<*const libc::c_void>()],
high_bitmask: Word,
blocks: *const MzdBlock,
pub rows: *const *mut Word,
}
pub static MZD_FLAG_NONZERO_EXCESS: u8 = 0x2;
pub static MZD_FLAG_WINDOWED_ZEROOFFSET: u8 = 0x4;
pub static MZD_FLAG_WINDOWED_ZEROEXCESS: u8 = 0x8;
pub static MZD_FLAG_WINDOWED_OWNSBLOCKS: u8 = 0x10;
pub static MZD_FLAG_MULTIPLE_BLOCKS: u8 = 0x20;
extern "C" {
pub fn mzd_init(rows: Rci, columns: Rci) -> *mut Mzd;
pub fn mzd_free(matrix: *mut Mzd);
pub fn mzd_init_window(
matrix: *mut Mzd,
lowr: Rci,
lowc: Rci,
highr: Rci,
highc: Rci,
) -> *mut Mzd;
pub fn mzd_row_swap(matrix: *mut Mzd, rowa: Rci, rowb: Rci);
pub fn mzd_copy_row(b: *mut Mzd, i: Rci, a: *const Mzd, j: Rci);
pub fn mzd_col_swap(matrix: *mut Mzd, cola: Rci, colb: Rci);
pub fn mzd_transpose(dest: *mut Mzd, source: *const Mzd) -> *mut Mzd;
pub fn mzd_mul_naive(dest: *mut Mzd, a: *const Mzd, b: *const Mzd) -> *mut Mzd;
pub fn _mzd_mul_naive(
dest: *mut Mzd,
a: *const Mzd,
b: *const Mzd,
clear: libc::c_int,
) -> *mut Mzd;
pub fn mzd_addmul_naive(c: *mut Mzd, a: *const Mzd, b: *const Mzd) -> *mut Mzd;
pub fn _mzd_mul_va(c: *mut Mzd, v: *const Mzd, a: *const Mzd, clear: libc::c_int) -> *mut Mzd;
pub fn mzd_randomize(m: *mut Mzd);
pub fn mzd_equal(a: *const Mzd, b: *const Mzd) -> libc::c_int;
pub fn mzd_copy(dest: *mut Mzd, src: *const Mzd) -> *mut Mzd;
pub fn mzd_concat(c: *mut Mzd, a: *const Mzd, b: *const Mzd) -> *mut Mzd;
pub fn mzd_set_ui(a: *mut Mzd, n: libc::c_uint);
pub fn mzd_stack(c: *mut Mzd, a: *mut Mzd, b: *const Mzd) -> *mut Mzd;
pub fn mzd_submatrix(
s: *mut Mzd,
m: *const Mzd,
lowr: Rci,
lowc: Rci,
highr: Rci,
highc: Rci,
) -> *mut Mzd;
pub fn mzd_invert_naive(inv: *mut Mzd, a: *const Mzd, identity: *const Mzd) -> *mut Mzd;
pub fn mzd_add(c: *mut Mzd, a: *const Mzd, b: *const Mzd) -> *mut Mzd;
pub fn mzd_sub(c: *mut Mzd, a: *const Mzd, b: *const Mzd) -> *mut Mzd;
pub fn mzd_is_zero(a: *const Mzd);
pub fn mzd_row_clear_offset(m: *mut Mzd, row: Rci, coloffset: Rci);
}
#[inline]
pub unsafe fn mzd_write_bit(matrix: *mut Mzd, row: Rci, col: Rci, value: BIT) {
let therow: *const *mut Word = (*matrix).rows.offset(row as isize);
let column: *mut Word = (*therow).offset((col / m4ri_radix) as isize);
let pos = col % m4ri_radix;
let column_bitmasked: Word = *column & !(m4ri_one << pos);
let column_newbit: Word = (value as Word & m4ri_one) << pos;
debug_assert_eq!(column_newbit.count_ones(), value as u32);
*column = column_bitmasked | column_newbit;
}
#[inline]
pub unsafe fn mzd_read_bit(matrix: *const Mzd, row: Rci, col: Rci) -> BIT {
let therow: *const *mut Word = (*matrix).rows.offset(row as isize);
let column: Word = *(*therow).offset((col / m4ri_radix) as isize);
let thebit = (column >> (col % m4ri_radix)) & m4ri_one;
thebit as BIT
}
#[inline]
pub unsafe fn mzd_first_row(matrix: *const Mzd) -> *mut Word {
let result: *mut Word = (*(*matrix).blocks)
.begin
.offset((*matrix).offset_vector as isize);
debug_assert!(
(*matrix).nrows == 0 || result == *(*matrix).rows,
"Result is not the expected ptr"
);
result
}
#[inline]
pub unsafe fn mzd_row(matrix: *const Mzd, row: Rci) -> *mut Word {
debug_assert!(row >= 0);
let big_vector: Wi = (*matrix).offset_vector + row * (*matrix).rowstride;
let result: *mut Word = if (*matrix).flags & MZD_FLAG_MULTIPLE_BLOCKS != 0 {
let n = ((*matrix).row_offset + row) >> (*matrix).blockrows_log;
(*(*matrix).blocks.add(n as usize)).begin.offset(
(big_vector - n * ((*(*matrix).blocks).size / ::std::mem::size_of::<Word>()) as i32)
as isize,
)
} else {
(*(*matrix).blocks).begin.add(big_vector as usize)
};
debug_assert_eq!(
result,
*(*matrix).rows.add(row as usize),
"Result is not the expected ptr"
);
result
}
pub unsafe fn mzd_init_window_const(
matrix: *const Mzd,
lowr: Rci,
lowc: Rci,
highr: Rci,
highc: Rci,
) -> *const Mzd {
mzd_init_window(std::mem::transmute(matrix), lowr, lowc, highr, highc)
}
#[inline]
pub unsafe fn mzd_is_windowed(m: *const Mzd) -> u8 {
(*m).flags & MZD_FLAG_WINDOWED_ZEROOFFSET
}
#[inline]
pub unsafe fn mzd_owns_blocks(m: *const Mzd) -> bool {
!(*m).blocks.is_null()
&& (mzd_is_windowed(m) == 0 || ((*m).flags & MZD_FLAG_WINDOWED_OWNSBLOCKS != 0))
}
impl Drop for Mzd {
#[inline]
fn drop(&mut self) {
unsafe {
mzd_free(self);
}
}
}
#[inline]
pub unsafe fn mzd_free_window(matrix: *mut Mzd) {
std::ptr::drop_in_place(matrix)
}
#[inline]
pub unsafe fn mzd_free_window_const(matrix: *const Mzd) {
let matrix: *mut Mzd = std::mem::transmute(matrix);
std::ptr::drop_in_place(matrix)
}
#[cfg(test)]
mod test {
use super::*;
use std::mem;
use std::ptr;
#[test]
fn init() {
for _ in 0..100 {
let result: libc::c_int;
unsafe {
assert_eq!(mem::size_of::<Mzd>(), 64);
let matrix = mzd_init(10, 10);
assert!(!(*matrix).blocks.is_null());
assert!(!(*matrix).rows.is_null());
mzd_randomize(matrix);
result = mzd_equal(matrix, matrix);
assert_eq!(result, 1);
let m2 = mzd_copy(ptr::null_mut(), matrix);
mzd_randomize(m2);
assert_eq!(mzd_equal(m2, matrix), 0);
ptr::drop_in_place(matrix);
ptr::drop_in_place(m2);
}
}
}
#[test]
fn test_mzd_first_row() {
for _ in 0..100 {
unsafe {
let matrix = mzd_init(10, 10);
mzd_set_ui(matrix, 0);
mzd_first_row(matrix);
ptr::drop_in_place(matrix);
}
}
}
#[test]
fn test_mzd_row() {
for _ in 0..100 {
unsafe {
let matrix = mzd_init(10, 10);
mzd_set_ui(matrix, 0);
mzd_row(matrix, 5);
ptr::drop_in_place(matrix);
}
}
}
#[test]
fn test_mzd_read_bit() {
for _ in 0..10 {
unsafe {
let matrix = mzd_init(1000, 1000);
mzd_set_ui(matrix, 1);
for i in 0..1000 {
for j in 0..1000 {
let bit = mzd_read_bit(matrix, i as Rci, j as Rci);
assert_eq!(bit == 1, i == j, "Should be unit matrix");
}
}
ptr::drop_in_place(matrix);
}
}
}
#[test]
fn test_mzd_write_bit() {
for _ in 0..10 {
unsafe {
let matrix = mzd_init(1000, 1000);
for i in 0..1000 {
for j in 0..1000 {
mzd_write_bit(matrix, i as Rci, j as Rci, if i == j { 1 } else { 0 });
}
}
for i in 0..1000 {
for j in 0..1000 {
let bit = mzd_read_bit(matrix, i as Rci, j as Rci);
assert_eq!(bit == 1, i == j, "Should be unit matrix");
}
}
ptr::drop_in_place(matrix);
}
}
}
}