Merge SparseVec into SparseOctetVec

This commit is contained in:
Christopher Berner 2020-01-04 12:26:58 -08:00
parent 8f8637be8a
commit f0f0f98247
2 changed files with 66 additions and 75 deletions

@ -1,7 +1,7 @@
use crate::octet::Octet;
use crate::octets::fused_addassign_mul_scalar;
use crate::octets::{add_assign, count_ones_and_nonzeros, mulassign_scalar};
use crate::sparse_vec::{SparseOctetVec, SparseVec};
use crate::sparse_vec::{SparseOctetVec, SparseValuelessVec};
use crate::util::get_both_indices;
use std::cmp::min;
@ -32,7 +32,7 @@ pub struct BorrowedKeyIter<'a> {
sparse: bool,
dense_index: usize,
dense_end: usize,
sparse_rows: Option<&'a Vec<(usize, ())>>,
sparse_rows: Option<&'a Vec<(usize, Octet)>>,
sparse_start_row: usize,
sparse_end_row: usize,
sparse_index: usize,
@ -397,7 +397,7 @@ pub struct SparseOctetMatrix {
dense_elements: Vec<Vec<u8>>,
// Sparse vector indicating which rows may have a non-zero value in the given column
// Does not guarantee that the row has a non-zero value, since FMA may have added to zero
sparse_column_index: Vec<SparseVec<()>>,
sparse_column_index: Vec<SparseValuelessVec>,
// Mapping of logical row numbers to index in sparse_elements, dense_elements, and sparse_column_index
logical_row_to_physical: Vec<usize>,
physical_row_to_logical: Vec<usize>,
@ -440,7 +440,7 @@ impl OctetMatrix for SparseOctetMatrix {
let mut column_index = Vec::with_capacity(width);
#[allow(clippy::needless_range_loop)]
for i in 0..width {
column_index.push(SparseVec::with_capacity(10));
column_index.push(SparseValuelessVec::with_capacity(10));
col_mapping[i] = i;
}
SparseOctetMatrix {
@ -467,7 +467,7 @@ impl OctetMatrix for SparseOctetMatrix {
self.sparse_elements[physical_i].insert(physical_j, value);
}
if !self.column_index_disabled {
self.sparse_column_index[physical_j].insert(physical_i, ());
self.sparse_column_index[physical_j].insert(physical_i);
}
}
@ -532,7 +532,7 @@ impl OctetMatrix for SparseOctetMatrix {
unimplemented!("It was assumed that this wouldn't be needed, because the method would only be called on the V section of matrix A");
}
let physical_row = self.logical_row_to_physical[row];
let sparse_elements = &self.sparse_elements[physical_row].elements.elements;
let sparse_elements = &self.sparse_elements[physical_row].elements;
OctetIter {
sparse: true,
start_col,
@ -551,7 +551,7 @@ impl OctetMatrix for SparseOctetMatrix {
sparse: true,
dense_index: 0,
dense_end: 0,
sparse_rows: Some(&self.sparse_column_index[physical_col].elements),
sparse_rows: Some(&self.sparse_column_index[physical_col].elements.elements),
sparse_start_row: start_row,
sparse_end_row: end_row,
sparse_index: 0,
@ -598,7 +598,7 @@ impl OctetMatrix for SparseOctetMatrix {
}
let mut physical_row = 0;
let physical_i = self.logical_col_to_physical[i];
for (maybe_present_in_row, _) in self.sparse_column_index[physical_i].keys_values() {
for maybe_present_in_row in self.sparse_column_index[physical_i].keys() {
while physical_row < *maybe_present_in_row {
physical_row += 1;
}
@ -647,7 +647,7 @@ impl OctetMatrix for SparseOctetMatrix {
self.dense_elements[physical_row] = temp_dense.pop().unwrap();
if !self.column_index_disabled {
for (col, _) in self.sparse_elements[physical_row].keys_values() {
self.sparse_column_index[*col].insert(physical_row, ())
self.sparse_column_index[*col].insert(physical_row)
}
}
}
@ -690,7 +690,7 @@ impl OctetMatrix for SparseOctetMatrix {
let new_columns = dest_row.fma(temp_row, scalar);
if !self.column_index_disabled {
for new_col in new_columns {
self.sparse_column_index[new_col].insert(physical_dest, ());
self.sparse_column_index[new_col].insert(physical_dest);
}
}

@ -2,99 +2,55 @@ use crate::octet::Octet;
use std::cmp::Ordering;
#[derive(Clone, Debug, PartialEq)]
pub struct SparseVec<T: Clone> {
pub struct SparseOctetVec {
// Kept sorted by the usize (key)
pub elements: Vec<(usize, T)>,
pub elements: Vec<(usize, Octet)>,
}
impl<T: Clone> SparseVec<T> {
pub fn with_capacity(capacity: usize) -> SparseVec<T> {
SparseVec {
impl SparseOctetVec {
pub fn with_capacity(capacity: usize) -> SparseOctetVec {
SparseOctetVec {
elements: Vec::with_capacity(capacity),
}
}
pub fn retain<P: Fn(&(usize, T)) -> bool>(&mut self, predicate: P) {
self.elements.retain(predicate);
}
// Returns the internal index into self.elements matching key i, or the index
// at which it can be inserted (maintaining sorted order)
fn key_to_internal_index(&self, i: usize) -> Result<usize, usize> {
self.elements.binary_search_by_key(&i, |(index, _)| *index)
}
pub fn remove(&mut self, i: usize) -> Option<T> {
match self.key_to_internal_index(i) {
Ok(index) => Some(self.elements.remove(index).1),
Err(_) => None,
}
}
pub fn get(&self, i: usize) -> Option<&T> {
match self.key_to_internal_index(i) {
Ok(index) => Some(&self.elements[index].1),
Err(_) => None,
}
}
pub fn keys_values(&self) -> impl Iterator<Item = &(usize, T)> {
self.elements.iter()
}
pub fn insert(&mut self, i: usize, value: T) {
match self.key_to_internal_index(i) {
Ok(index) => self.elements[index] = (i, value),
Err(index) => self.elements.insert(index, (i, value)),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct SparseOctetVec {
// Kept sorted by the usize (key)
pub elements: SparseVec<Octet>,
}
impl SparseOctetVec {
pub fn with_capacity(capacity: usize) -> SparseOctetVec {
SparseOctetVec {
elements: SparseVec::with_capacity(capacity),
}
}
// Returns a vector of new column indices that this row contains
pub fn fma(&mut self, other: &SparseOctetVec, scalar: &Octet) -> Vec<usize> {
// Fast path for a single value that's being eliminated
// TODO: Probably wouldn't need this if we implemented "Furthermore, the row operations
// required for the HDPC rows may be performed for all such rows in one
// process, by using the algorithm described in Section 5.3.3.3."
if other.elements.elements.len() == 1 {
let (other_col, other_value) = &other.elements.elements[0];
match self.elements.key_to_internal_index(*other_col) {
if other.elements.len() == 1 {
let (other_col, other_value) = &other.elements[0];
match self.key_to_internal_index(*other_col) {
Ok(index) => {
let elements_len = self.elements.elements.len();
let self_value = &mut self.elements.elements[index].1;
let elements_len = self.elements.len();
let self_value = &mut self.elements[index].1;
self_value.fma(other_value, scalar);
// XXX: heuristic for handling large rows, since these are somewhat common (HDPC rows)
// It would be very expensive to always remove from those rows
if elements_len < 1000 && *self_value == Octet::zero() {
self.elements.elements.remove(index);
self.elements.remove(index);
}
}
Err(index) => {
let value = other_value * scalar;
self.elements.elements.insert(index, (*other_col, value));
self.elements.insert(index, (*other_col, value));
return vec![*other_col];
}
};
return vec![];
}
let mut result =
Vec::with_capacity(self.elements.elements.len() + other.elements.elements.len());
let mut self_iter = self.elements.elements.iter();
let mut other_iter = other.elements.elements.iter();
let mut result = Vec::with_capacity(self.elements.len() + other.elements.len());
let mut self_iter = self.elements.iter();
let mut other_iter = other.elements.iter();
let mut self_entry = self_iter.next();
let mut other_entry = other_iter.next();
@ -141,13 +97,16 @@ impl SparseOctetVec {
break;
}
}
self.elements.elements = result;
self.elements = result;
return new_columns;
}
pub fn remove(&mut self, i: usize) -> Option<Octet> {
self.elements.remove(i)
match self.key_to_internal_index(i) {
Ok(index) => Some(self.elements.remove(index).1),
Err(_) => None,
}
}
pub fn retain<P: Fn(&(usize, Octet)) -> bool>(&mut self, predicate: P) {
@ -155,21 +114,53 @@ impl SparseOctetVec {
}
pub fn get(&self, i: usize) -> Option<&Octet> {
self.elements.get(i)
match self.key_to_internal_index(i) {
Ok(index) => Some(&self.elements[index].1),
Err(_) => None,
}
}
pub fn mul_assign(&mut self, scalar: &Octet) {
for (_, value) in self.elements.elements.iter_mut() {
for (_, value) in self.elements.iter_mut() {
*value = value as &Octet * scalar;
}
}
pub fn keys_values(&self) -> impl Iterator<Item = &(usize, Octet)> {
self.elements.keys_values()
self.elements.iter()
}
pub fn insert(&mut self, i: usize, value: Octet) {
self.elements.insert(i, value);
match self.key_to_internal_index(i) {
Ok(index) => self.elements[index] = (i, value),
Err(index) => self.elements.insert(index, (i, value)),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct SparseValuelessVec {
pub elements: SparseOctetVec,
}
impl SparseValuelessVec {
pub fn with_capacity(capacity: usize) -> SparseValuelessVec {
SparseValuelessVec {
elements: SparseOctetVec::with_capacity(capacity),
}
}
#[cfg(debug_assertions)]
pub fn get(&self, i: usize) -> Option<()> {
self.elements.get(i).map(|_| ())
}
pub fn keys(&self) -> impl Iterator<Item = &usize> {
self.elements.keys_values().map(|(key, _)| key)
}
pub fn insert(&mut self, i: usize) {
self.elements.insert(i, Octet::zero())
}
}