use crate::binary_dense_vector::{BinaryDenseVector, BITS};
use std::fmt::Write;
use std::{fmt, ops};
pub trait BinaryMatrix {
fn nrows(&self) -> usize;
fn ncols(&self) -> usize;
fn expand(&mut self, new_rows: usize, new_cols: usize);
fn transpose(&self) -> Box<dyn BinaryMatrix>;
fn get(&self, r: usize, c: usize) -> u8;
fn set(&mut self, r: usize, c: usize, val: u8);
fn copy(&self) -> Box<dyn BinaryMatrix> {
self.transpose().transpose()
}
fn left_kernel(&self) -> Option<Vec<BinaryDenseVector>> {
self.transpose().kernel()
}
fn kernel(&self) -> Option<Vec<BinaryDenseVector>> {
let mut extend = self.copy();
let maxr = extend.nrows();
let maxc = extend.ncols();
extend.expand(maxc, 0);
for c in 0..maxc {
extend.set(maxr + c, c, 1);
}
let mut nextc = 0;
for r in 0..maxr {
let mut pivot = -1i32;
for c in nextc..maxc {
if extend.get(r, c) != 0 {
pivot = c as i32;
break;
}
}
if pivot == -1 {
continue;
}
extend.swap_columns(nextc, pivot as usize);
for c in (nextc as usize + 1)..maxc {
if extend.get(r, c) == 1 {
extend.xor_col(c, nextc);
}
}
nextc += 1;
}
let mut kernel = vec![];
for c in 0..maxc {
if extend.column_part_all_zero(c, maxr) {
let v = extend.extract_column_part(c, maxr, extend.nrows() - maxr);
kernel.push(v);
}
}
Some(kernel)
}
fn left_mul(&self, result_vector: &BinaryDenseVector) -> BinaryDenseVector {
assert_eq!(result_vector.size, self.nrows());
let mut result = Vec::with_capacity(self.ncols());
for c in 0..self.ncols() {
let mut bit = 0;
for r in 0..self.nrows() {
bit ^= self.get(r, c) * result_vector[r];
}
result.push(bit);
}
BinaryDenseVector::from_bits(&*result)
}
fn col(&self, c: usize) -> BinaryDenseVector {
assert!(c < self.ncols());
let mut v = BinaryDenseVector::zero(self.nrows());
for i in 0..self.nrows() {
v.set(i, self.get(i, c));
}
v
}
fn swap_columns(&mut self, c1: usize, c2: usize);
fn xor_col(&mut self, c1: usize, c2: usize);
fn add_col(&mut self, c1: usize, c2: usize) {
self.xor_col(c1, c2);
}
fn column_part_all_zero(&self, c: usize, maxr: usize) -> bool {
for x in 0..maxr {
if self.get(x, c) == 1 {
return false;
}
}
return true;
}
fn extract_column_part(&self, c: usize, maxr: usize, size: usize) -> BinaryDenseVector {
let mut bits: Vec<u8> = Vec::with_capacity(size);
for r in maxr..maxr + size {
bits.push(self.get(r, c));
}
BinaryDenseVector::from_bits(&*bits)
}
}
impl ops::Index<(usize, usize)> for dyn BinaryMatrix {
type Output = u8;
fn index(&self, index: (usize, usize)) -> &Self::Output {
&BITS[self.get(index.0, index.1) as usize]
}
}
impl ops::Index<(usize, usize)> for &dyn BinaryMatrix {
type Output = u8;
fn index(&self, index: (usize, usize)) -> &Self::Output {
&BITS[self.get(index.0, index.1) as usize]
}
}
impl ops::Mul<&dyn BinaryMatrix> for &BinaryDenseVector {
type Output = BinaryDenseVector;
fn mul(self, rhs: &dyn BinaryMatrix) -> Self::Output {
assert_eq!(self.size, rhs.nrows());
if self.size == 0 {
return BinaryDenseVector::new();
}
let mut acc = BinaryDenseVector::zero(self.size);
for i in 0..self.size {
acc.set(i, self * &rhs.col(i));
}
acc
}
}
impl ops::Mul<Box<dyn BinaryMatrix>> for &BinaryDenseVector {
type Output = BinaryDenseVector;
fn mul(self, rhs: Box<dyn BinaryMatrix>) -> Self::Output {
self * rhs.as_ref()
}
}
impl fmt::Debug for dyn BinaryMatrix {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_char('[')?;
for r in 0..self.nrows() {
if r != 0 {
f.write_str(", ")?;
}
f.write_char('[')?;
for c in 0..self.ncols() {
if c != 0 {
f.write_str(", ")?;
}
f.write_char(char::from(48 + self.get(r, c)))?;
}
f.write_char(']')?;
}
f.write_char(']')
}
}