use std::{
collections::HashMap,
fmt,
ops::{Deref, DerefMut},
};
#[derive(Clone, Debug)]
pub struct EntryBasePtr<T: Clone + Default> {
ptr: *mut EntryBase<T>,
}
unsafe impl<T: Clone + Default> Send for EntryBasePtr<T> {}
impl<T: Clone + Default> Deref for EntryBasePtr<T> {
type Target = EntryBase<T>;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr }
}
}
impl<T: Clone + Default> DerefMut for EntryBasePtr<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.ptr }
}
}
impl<T: Clone + Default> Copy for EntryBasePtr<T> {}
unsafe impl<T: Clone + Default + Send> Send for EntryBase<T> {}
impl<T: Clone + Default> EntryBasePtr<T> {
pub fn null_mut() -> Self {
EntryBasePtr {
ptr: std::ptr::null_mut(),
}
}
pub fn from_raw(ptr: *mut EntryBase<T>) -> Self {
EntryBasePtr { ptr }
}
pub fn as_ref(&self) -> Option<&EntryBase<T>> {
if self.ptr.is_null() {
None
} else {
Some(unsafe { &*self.ptr })
}
}
pub fn as_mut(&mut self) -> Option<&mut EntryBase<T>> {
if self.ptr.is_null() {
None
} else {
Some(unsafe { &mut *self.ptr })
}
}
}
impl<T: Clone + Default> Default for EntryBasePtr<T> {
fn default() -> Self {
EntryBasePtr::null_mut()
}
}
pub struct EntryBase<T: Clone + Default> {
pub row_index: isize,
pub col_index: isize,
pub left: *mut EntryBase<T>,
pub right: *mut EntryBase<T>,
pub up: *mut EntryBase<T>,
pub down: *mut EntryBase<T>,
pub inner: T,
}
impl<T: Clone + Default> Default for EntryBase<T> {
fn default() -> Self {
EntryBase::new()
}
}
impl<T: Clone + Default> std::clone::Clone for EntryBase<T> {
fn clone(&self) -> Self {
EntryBase {
row_index: self.row_index,
col_index: self.col_index,
left: self.left,
right: self.right,
up: self.up,
down: self.down,
inner: self.inner.clone(),
}
}
}
impl<T: Clone + Default> EntryBase<T> {
pub fn new() -> Self {
let mut entry = EntryBase {
row_index: -100,
col_index: -100,
left: std::ptr::null_mut(),
right: std::ptr::null_mut(),
up: std::ptr::null_mut(),
down: std::ptr::null_mut(),
inner: T::default(),
};
let entry_ptr: *mut EntryBase<T> = &mut entry;
entry.left = entry_ptr;
entry.right = entry_ptr;
entry.up = entry_ptr;
entry.down = entry_ptr;
entry
}
pub fn reset(&mut self) {
self.row_index = -100;
self.col_index = -100;
let self_ptr: *mut EntryBase<T> = self;
self.left = self_ptr;
self.right = self_ptr;
self.up = self_ptr;
self.down = self_ptr;
}
pub fn at_end(&self) -> bool {
self.row_index == -100
}
pub fn str(&self) -> &str {
"1"
}
}
impl<T: Clone + Default> fmt::Debug for EntryBase<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "EntryBase(row_index: {}, col_index: {})", self.row_index, self.col_index)
}
}
pub struct CsrMatrix {
pub m: usize,
pub n: usize,
pub entry_count: usize,
pub row_adjacency_list: Vec<Vec<usize>>,
}
#[derive(Default, Debug)]
pub struct SparseMatrixBase<T: Clone + Default, E = EntryBase<T>, P = EntryBasePtr<T>> {
pub m: usize, pub n: usize, pub node_count: usize,
pub entry_block_size: usize,
pub allocated_entry_count: usize,
pub released_entry_count: usize,
pub block_position: usize,
pub block_idx: isize,
pub entries: Vec<Vec<E>>,
pub removed_entries: Vec<P>,
pub row_heads: Vec<P>,
pub column_heads: Vec<P>,
pub memory_allocated: bool,
pub _marker: std::marker::PhantomData<T>,
}
impl<T: Clone + Default> Clone for SparseMatrixBase<T> {
fn clone(&self) -> Self {
let mut new_matrix = SparseMatrixBase::new();
new_matrix.m = self.m;
new_matrix.n = self.n;
new_matrix.node_count = self.node_count;
new_matrix.entry_block_size = self.entry_block_size;
new_matrix.allocated_entry_count = self.allocated_entry_count;
new_matrix.released_entry_count = self.released_entry_count;
new_matrix.block_position = self.block_position;
new_matrix.block_idx = self.block_idx;
new_matrix.memory_allocated = self.memory_allocated;
new_matrix._marker = std::marker::PhantomData;
let mut entry_map = HashMap::new();
for block in &self.entries {
let mut new_block = Vec::with_capacity(block.capacity());
for entry in block {
new_block.push(entry.clone());
}
new_matrix.entries.push(new_block);
}
for (old_block, new_block) in self.entries.iter().zip(new_matrix.entries.iter_mut()) {
for (old_entry, new_entry) in old_block.iter().zip(new_block.iter_mut()) {
let old_ptr = old_entry as *const EntryBase<T> as *mut EntryBase<T>;
let new_ptr = new_entry as *mut EntryBase<T>;
entry_map.insert(old_ptr, new_ptr);
}
}
for block in new_matrix.entries.iter_mut() {
for entry in block.iter_mut() {
if entry.row_index == -100 && entry.col_index == -100 {
entry.left = entry as *mut EntryBase<T>;
entry.right = entry as *mut EntryBase<T>;
entry.up = entry as *mut EntryBase<T>;
entry.down = entry as *mut EntryBase<T>;
} else {
entry.left = *entry_map
.get(&entry.left)
.expect(format!("left: {:p}, entry: {:?}", entry.left, unsafe { &*(entry.left) }).as_str());
entry.right = *entry_map.get(&entry.right).unwrap();
entry.up = *entry_map.get(&entry.up).unwrap();
entry.down = *entry_map.get(&entry.down).unwrap();
}
}
}
new_matrix.row_heads = Vec::with_capacity(self.row_heads.capacity());
for old_head in self.row_heads.iter() {
let old_head_ptr = old_head.ptr;
let new_head = EntryBasePtr {
ptr: *entry_map.get(&old_head_ptr).unwrap(),
};
new_matrix.row_heads.push(new_head);
}
new_matrix.column_heads = Vec::with_capacity(self.column_heads.capacity());
for old_head in self.column_heads.iter() {
let old_head_ptr = old_head.ptr;
let new_head = EntryBasePtr {
ptr: *entry_map.get(&old_head_ptr).unwrap(),
};
new_matrix.column_heads.push(new_head);
}
new_matrix.removed_entries = Vec::with_capacity(self.removed_entries.capacity());
for old_removed_ptr in self.removed_entries.iter() {
let old_ptr = old_removed_ptr.ptr;
let new_ptr = if old_ptr.is_null() {
std::ptr::null_mut()
} else {
*entry_map.get(&old_ptr).unwrap()
};
new_matrix.removed_entries.push(EntryBasePtr { ptr: new_ptr });
}
new_matrix
}
}
impl<T: Clone + Default> SparseMatrixBase<T> {
pub fn new() -> Self {
SparseMatrixBase {
m: 0,
n: 0,
node_count: 0,
entry_block_size: 0,
allocated_entry_count: 0,
released_entry_count: 0,
block_position: 0,
block_idx: 0,
entries: Vec::new(),
removed_entries: Vec::new(),
row_heads: Vec::new(),
column_heads: Vec::new(),
memory_allocated: false,
_marker: std::marker::PhantomData,
}
}
pub fn initialise_sparse_matrix(&mut self, check_count: usize, bit_count: usize, entry_count: usize) {
self.reset_matrix();
self.m = check_count;
self.n = bit_count;
self.block_idx = -1;
self.released_entry_count = 0;
self.allocated_entry_count = 0;
self.entry_block_size = self.m + self.n + entry_count;
self.allocate_memory();
self.entry_block_size = self.m + self.n;
}
pub fn reset_matrix(&mut self) {
if self.memory_allocated {
self.column_heads.clear();
self.row_heads.clear();
self.removed_entries.clear();
for entry_block in &mut self.entries {
entry_block.clear();
}
self.entries.clear();
}
self.m = 0;
self.n = 0;
self.block_idx = -1;
self.released_entry_count = 0;
self.allocated_entry_count = 0;
self.entry_block_size = 0;
self.memory_allocated = false;
}
pub fn allocate_memory(&mut self) {
self.memory_allocated = true;
self.row_heads.resize(self.m, EntryBasePtr::null_mut());
self.column_heads.resize(self.n, EntryBasePtr::null_mut());
for i in 0..self.m {
let row_entry_ptr = self.allocate_new_entry();
unsafe {
(*row_entry_ptr).row_index = -100;
(*row_entry_ptr).col_index = -100;
(*row_entry_ptr).up = row_entry_ptr;
(*row_entry_ptr).down = row_entry_ptr;
(*row_entry_ptr).left = row_entry_ptr;
(*row_entry_ptr).right = row_entry_ptr;
}
self.row_heads[i] = EntryBasePtr::from_raw(row_entry_ptr);
}
for i in 0..self.n {
let col_entry_ptr = self.allocate_new_entry();
unsafe {
(*col_entry_ptr).row_index = -100;
(*col_entry_ptr).col_index = -100;
(*col_entry_ptr).up = col_entry_ptr;
(*col_entry_ptr).down = col_entry_ptr;
(*col_entry_ptr).left = col_entry_ptr;
(*col_entry_ptr).right = col_entry_ptr;
}
self.column_heads[i] = EntryBasePtr::from_raw(col_entry_ptr);
}
}
pub fn allocate_new_entry(&mut self) -> *mut EntryBase<T> {
if !self.removed_entries.is_empty() {
return self.removed_entries.pop().unwrap().ptr;
}
if self.released_entry_count == self.allocated_entry_count {
let new_entry = EntryBase::<T>::new();
self.entries.push(vec![new_entry; self.entry_block_size]);
self.allocated_entry_count += self.entry_block_size;
self.block_idx += 1;
self.block_position = 0;
}
let e_ptr = &mut self.entries[self.block_idx as usize][self.block_position] as *mut EntryBase<T>;
self.block_position += 1;
self.released_entry_count += 1;
e_ptr
}
pub fn entry_count(&self) -> usize {
self.released_entry_count - self.n - self.m - self.removed_entries.len()
}
pub fn sparsity(&self) -> f64 {
self.entry_count() as f64 / (self.m * self.n) as f64
}
pub fn swap_rows(&mut self, i: usize, j: usize) {
self.row_heads.swap(i, j);
for e in self.iterate_row_mut(i) {
unsafe {
(*e).row_index = i as isize;
}
}
for e in self.iterate_row_mut(j) {
unsafe {
(*e).row_index = j as isize;
}
}
}
pub fn reorder_rows(&mut self, rows: &Vec<usize>) {
let temp_row_heads = self.row_heads.clone();
for i in 0..self.m {
self.row_heads[i] = temp_row_heads[rows[i]];
for e in self.iterate_row_mut(i) {
unsafe {
(*e).row_index = i as isize;
}
}
}
}
pub fn swap_columns(&mut self, i: usize, j: usize) {
self.column_heads.swap(i, j);
for e in self.iterate_column_mut(i) {
unsafe {
(*e).col_index = i as isize;
}
}
for e in self.iterate_column_mut(j) {
unsafe {
(*e).col_index = j as isize;
}
}
}
pub fn get_row_degree(&self, row: usize) -> isize {
self.row_heads[row].as_ref().unwrap().col_index.abs() - 100
}
pub fn get_col_degree(&self, col: usize) -> isize {
self.column_heads[col].as_ref().unwrap().col_index.abs() - 100
}
pub fn remove_entry(&mut self, i: usize, j: usize) {
let e = self.get_entry_mut(i, j);
unsafe { self.remove(e) };
}
pub unsafe fn remove(&mut self, e_ptr: *mut EntryBase<T>) {
unsafe {
if !(*e_ptr).at_end() {
let e_left_ptr = (*e_ptr).left;
let e_right_ptr = (*e_ptr).right;
let e_up_ptr = (*e_ptr).up;
let e_down_ptr = (*e_ptr).down;
(*e_left_ptr).right = e_right_ptr;
(*e_right_ptr).left = e_left_ptr;
(*e_up_ptr).down = e_down_ptr;
(*e_down_ptr).up = e_up_ptr;
self.row_heads[(*e_ptr).row_index as usize].as_mut().unwrap().col_index += 1;
self.column_heads[(*e_ptr).col_index as usize].as_mut().unwrap().col_index += 1;
(*e_ptr).reset();
}
self.removed_entries.push(EntryBasePtr::from_raw(e_ptr));
}
}
pub fn insert_entry(&mut self, j: usize, i: usize) -> *mut EntryBase<T> {
if j >= self.m || i >= self.n {
panic!("Index i or j is out of bounds");
}
let mut left_entry_ptr = self.row_heads[j];
let mut right_entry_ptr = self.row_heads[j];
for e in self.reverse_iterate_row_mut(j) {
let index = unsafe { (*e).col_index as usize };
if index == i {
return e;
}
if index > i {
right_entry_ptr = EntryBasePtr::from_raw(e);
}
if index < i {
left_entry_ptr = EntryBasePtr::from_raw(e);
break;
}
}
let mut up_entry_ptr = self.column_heads[i];
let mut down_entry_ptr = self.column_heads[i];
for e in self.reverse_iterate_column_mut(i) {
let row_index = unsafe { (*e).row_index as usize };
if row_index > j {
down_entry_ptr = EntryBasePtr::from_raw(e);
}
if row_index < j {
up_entry_ptr = EntryBasePtr::from_raw(e);
break;
}
}
let e_ptr = self.allocate_new_entry();
self.node_count += 1;
unsafe {
(*e_ptr).row_index = j as isize;
(*e_ptr).col_index = i as isize;
(*e_ptr).right = right_entry_ptr.ptr;
(*e_ptr).left = left_entry_ptr.ptr;
(*e_ptr).up = up_entry_ptr.ptr;
(*e_ptr).down = down_entry_ptr.ptr;
(*left_entry_ptr).right = e_ptr;
(*right_entry_ptr).left = e_ptr;
(*up_entry_ptr).down = e_ptr;
(*down_entry_ptr).up = e_ptr;
(*self.row_heads[(*e_ptr).row_index as usize]).col_index -= 1;
(*self.column_heads[(*e_ptr).col_index as usize]).col_index -= 1;
}
e_ptr
}
pub fn get_entry_mut(&mut self, j: usize, i: usize) -> *mut EntryBase<T> {
if j >= self.m || i >= self.n {
panic!("Index i or j is out of bounds");
}
for e in self.reverse_iterate_column(i) {
unsafe {
if (*e).row_index as usize == j {
return e;
}
}
}
self.column_heads[i].ptr
}
pub fn get_entry(&self, j: usize, i: usize) -> *const EntryBase<T> {
if j >= self.m || i >= self.n {
panic!("Index i or j is out of bounds");
}
for e in self.reverse_iterate_column(i) {
unsafe {
if (*e).row_index as usize == j {
return e;
}
}
}
self.column_heads[i].ptr
}
pub fn insert_row(&mut self, row_index: usize, col_indices: &Vec<usize>) -> *mut EntryBase<T> {
for &j in col_indices {
self.insert_entry(row_index, j);
}
self.row_heads[row_index].ptr
}
pub fn nonzero_coordinates(&mut self) -> Vec<(usize, usize)> {
let mut nonzero = Vec::new();
let mut node_count = 0;
for i in 0..self.m {
for e in self.iterate_row_mut(i) {
node_count += 1;
nonzero.push(unsafe { ((*e).row_index as usize, (*e).col_index as usize) });
}
}
self.node_count = node_count;
nonzero
}
pub fn row_adjacency_list(&mut self) -> Vec<Vec<usize>> {
let mut adj_list = Vec::new();
for i in 0..self.m {
let mut row = Vec::new();
for e in self.iterate_row_mut(i) {
unsafe {
row.push((*e).col_index as usize);
}
}
adj_list.push(row);
}
adj_list
}
pub fn col_adjacency_list(&mut self) -> Vec<Vec<usize>> {
let mut adj_list = Vec::new();
for i in 0..self.n {
let mut col = Vec::new();
for e in self.iterate_column_mut(i) {
unsafe {
col.push((*e).row_index as usize);
}
}
adj_list.push(col);
}
adj_list
}
pub fn get_column_csc(&mut self, col_index: usize) -> Vec<usize> {
let mut col = Vec::new();
for e in self.iterate_column_mut(col_index) {
unsafe {
col.push((*e).row_index as usize);
}
}
col
}
pub fn to_csr_matrix(&mut self) -> CsrMatrix {
CsrMatrix {
m: self.m,
n: self.n,
entry_count: self.entry_count(),
row_adjacency_list: self.row_adjacency_list(),
}
}
pub fn nonzero_rows(&mut self) -> Vec<Vec<usize>> {
let mut nonzero = Vec::new();
let mut node_count = 0;
for i in 0..self.m {
let mut row = Vec::new();
for e in self.iterate_row_mut(i) {
node_count += 1;
row.push(unsafe { (*e).col_index as usize });
}
nonzero.push(row);
}
self.node_count = node_count;
nonzero
}
pub fn iterate_row_mut(&mut self, i: usize) -> RowIterator<T> {
if i >= self.m {
panic!("Iterator index out of bounds");
}
RowIterator::new(self, i)
}
pub fn iterate_row(&self, i: usize) -> RowIterator<T> {
if i >= self.m {
panic!("Iterator index out of bounds");
}
RowIterator::new(self, i)
}
pub fn reverse_iterate_row_mut(&mut self, i: usize) -> ReverseRowIterator<T> {
if i >= self.m {
panic!("Iterator index out of bounds");
}
ReverseRowIterator::new(self, i)
}
pub fn reverse_iterate_row(&self, i: usize) -> ReverseRowIterator<T> {
if i >= self.m {
panic!("Iterator index out of bounds");
}
ReverseRowIterator::new(self, i)
}
pub fn iterate_column_mut(&mut self, i: usize) -> ColumnIterator<T> {
if i >= self.n {
panic!("Iterator index out of bounds");
}
ColumnIterator::new(self, i)
}
pub fn iterate_column(&self, i: usize) -> ColumnIterator<T> {
if i >= self.n {
panic!("Iterator index out of bounds");
}
ColumnIterator::new(self, i)
}
pub fn reverse_iterate_column_mut(&mut self, i: usize) -> ReverseColumnIterator<T> {
if i >= self.n {
panic!("Iterator index out of bounds");
}
ReverseColumnIterator::new(self, i)
}
pub fn reverse_iterate_column(&self, i: usize) -> ReverseColumnIterator<T> {
if i >= self.n {
panic!("Iterator index out of bounds");
}
ReverseColumnIterator::new(self, i)
}
}
pub struct RowIterator<'a, T: Clone + Default> {
_matrix: &'a SparseMatrixBase<T>,
it_count: isize,
entry_count: isize,
e: *mut EntryBase<T>,
}
impl<'a, T: Clone + Default> RowIterator<'a, T> {
fn new(matrix: &'a SparseMatrixBase<T>, i: usize) -> Self {
RowIterator {
_matrix: matrix,
it_count: 0,
entry_count: matrix.get_row_degree(i),
e: matrix.row_heads[i].ptr,
}
}
}
impl<'a, T: Clone + Default> Iterator for RowIterator<'a, T> {
type Item = *mut EntryBase<T>;
fn next(&mut self) -> Option<Self::Item> {
if self.it_count >= self.entry_count {
return None;
}
unsafe {
self.e = (*self.e).right;
}
self.it_count += 1;
Some(self.e)
}
}
pub struct ReverseRowIterator<'a, T: Clone + Default> {
_matrix: &'a SparseMatrixBase<T>,
it_count: isize,
entry_count: isize,
e: *mut EntryBase<T>,
}
impl<'a, T: Clone + Default> ReverseRowIterator<'a, T> {
fn new(matrix: &'a SparseMatrixBase<T>, i: usize) -> Self {
ReverseRowIterator {
_matrix: matrix,
it_count: 0,
entry_count: matrix.get_row_degree(i),
e: matrix.row_heads[i].ptr,
}
}
}
impl<'a, T: Clone + Default> Iterator for ReverseRowIterator<'a, T> {
type Item = *mut EntryBase<T>;
fn next(&mut self) -> Option<Self::Item> {
if self.it_count >= self.entry_count {
return None;
}
unsafe {
self.e = (*self.e).left;
}
self.it_count += 1;
Some(self.e)
}
}
pub struct ColumnIterator<'a, T: Clone + Default> {
_matrix: &'a SparseMatrixBase<T>,
it_count: isize,
entry_count: isize,
e: *mut EntryBase<T>,
}
impl<'a, T: Clone + Default> ColumnIterator<'a, T> {
fn new(matrix: &'a SparseMatrixBase<T>, i: usize) -> Self {
ColumnIterator {
_matrix: matrix,
it_count: 0,
entry_count: matrix.get_col_degree(i),
e: matrix.column_heads[i].ptr,
}
}
}
impl<'a, T: Clone + Default> Iterator for ColumnIterator<'a, T> {
type Item = *mut EntryBase<T>;
fn next(&mut self) -> Option<Self::Item> {
if self.it_count >= self.entry_count {
return None;
}
unsafe {
self.e = (*self.e).down;
}
self.it_count += 1;
Some(self.e)
}
}
pub struct ReverseColumnIterator<'a, T: Clone + Default> {
_matrix: &'a SparseMatrixBase<T>,
it_count: isize,
entry_count: isize,
e: *mut EntryBase<T>,
}
impl<'a, T: Clone + Default> ReverseColumnIterator<'a, T> {
fn new(matrix: &'a SparseMatrixBase<T>, i: usize) -> Self {
ReverseColumnIterator {
_matrix: matrix,
it_count: 0,
entry_count: matrix.get_col_degree(i),
e: matrix.column_heads[i].ptr,
}
}
}
impl<'a, T: Clone + Default> Iterator for ReverseColumnIterator<'a, T> {
type Item = *mut EntryBase<T>;
fn next(&mut self) -> Option<Self::Item> {
if self.it_count >= self.entry_count {
return None;
}
unsafe {
self.e = (*self.e).up;
}
self.it_count += 1;
Some(self.e)
}
}