use ark_ff::PrimeField; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, fields::nonnative::NonNativeFieldVar, }; use ark_relations::r1cs::{Matrix as R1CSMatrix, Namespace, SynthesisError}; use core::{borrow::Borrow, marker::PhantomData}; pub struct SparseMatrix { pub n_rows: usize, pub n_cols: usize, /// coeffs = R1CSMatrix = Vec>, which contains each row and the F is the value /// of the coefficient and the usize indicates the column position pub coeffs: R1CSMatrix, } #[derive(Debug, Clone)] pub struct SparseMatrixVar { _f: PhantomData, _cf: PhantomData, pub n_rows: usize, pub n_cols: usize, // same format as the native SparseMatrix (which follows ark_relations::r1cs::Matrix format pub coeffs: Vec, usize)>>, } impl AllocVar, CF> for SparseMatrixVar where F: PrimeField, CF: PrimeField, { fn new_variable>>( cs: impl Into>, f: impl FnOnce() -> Result, mode: AllocationMode, ) -> Result { f().and_then(|val| { let cs = cs.into(); let mut coeffs: Vec, usize)>> = Vec::new(); for row in val.borrow().coeffs.iter() { let mut rowVar: Vec<(NonNativeFieldVar, usize)> = Vec::new(); for &(value, col_i) in row.iter() { let coeffVar = NonNativeFieldVar::::new_variable(cs.clone(), || Ok(value), mode)?; rowVar.push((coeffVar, col_i)); } coeffs.push(rowVar); } Ok(Self { _f: PhantomData, _cf: PhantomData, n_rows: val.borrow().n_rows, n_cols: val.borrow().n_cols, coeffs, }) }) } } pub fn mat_vec_mul_sparse(M: &SparseMatrix, z: &[F]) -> Vec { assert_eq!(M.n_cols, z.len()); let mut res = vec![F::zero(); M.n_rows]; for (row_i, row) in M.coeffs.iter().enumerate() { for &(value, col_i) in row.iter() { res[row_i] += value * z[col_i]; } } res } pub fn dense_matrix_to_sparse(m: Vec>) -> SparseMatrix { let mut r = SparseMatrix:: { n_rows: m.len(), n_cols: m[0].len(), coeffs: Vec::new(), }; for m_row in m.iter() { let mut row: Vec<(F, usize)> = Vec::new(); for (col_i, value) in m_row.iter().enumerate() { if !value.is_zero() { row.push((*value, col_i)); } } r.coeffs.push(row); } r } // just some helpers to define matrices and vectors by hand pub fn to_F_matrix(M: Vec>) -> SparseMatrix { dense_matrix_to_sparse(to_F_dense_matrix(M)) } pub fn to_F_dense_matrix(M: Vec>) -> Vec> { M.iter() .map(|m| m.iter().map(|r| F::from(*r as u64)).collect()) .collect() } pub fn to_F_vec(z: Vec) -> Vec { z.iter().map(|c| F::from(*c as u64)).collect() }