make matrix and vector abstract
This commit is contained in:
parent
f192f29a86
commit
a74dc6ef88
@ -1,5 +1,6 @@
|
|||||||
use crate::bkz::bkz_reduce;
|
use crate::bkz::bkz_reduce;
|
||||||
use crate::deep_lll::deep_lll;
|
use crate::deep_lll::deep_lll;
|
||||||
|
// use crate::lll::lattice_reduce;
|
||||||
use crate::matrix::Matrix;
|
use crate::matrix::Matrix;
|
||||||
use crate::utils::abs;
|
use crate::utils::abs;
|
||||||
use lll_rs::l2::bigl2;
|
use lll_rs::l2::bigl2;
|
||||||
@ -26,6 +27,10 @@ pub fn agcd(ciphertexts: Vec<Integer>, noise_bits: usize, algorithm: u8) -> Inte
|
|||||||
let reduced = deep_lll(basis_matrix.clone(), Rational::from((51, 100))).unwrap();
|
let reduced = deep_lll(basis_matrix.clone(), Rational::from((51, 100))).unwrap();
|
||||||
reduced.columns[0][0].clone()
|
reduced.columns[0][0].clone()
|
||||||
}
|
}
|
||||||
|
// 3u8 => {
|
||||||
|
// lattice_reduce(&mut basis_matrix, 0.51, 0.75);
|
||||||
|
// lll_matrix[0][0].clone()
|
||||||
|
// }
|
||||||
_ => panic!("Unknown algorithm value: {}", algorithm),
|
_ => panic!("Unknown algorithm value: {}", algorithm),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use crate::matrix::Matrix;
|
use crate::matrix::Matrix;
|
||||||
use rug::Rational;
|
use rug::{Rational, Integer};
|
||||||
|
|
||||||
/// Perform DeepLLL reduction on a given lattice basis represented by Matrix.
|
/// Perform DeepLLL reduction on a given lattice basis represented by Matrix.
|
||||||
/// 1/4 < delta < 1.
|
/// 1/4 < delta < 1.
|
||||||
pub fn deep_lll(mut mat: Matrix, delta: Rational) -> Option<Matrix> {
|
pub fn deep_lll(mut mat: Matrix<Integer>, delta: Rational) -> Option<Matrix<Integer>> {
|
||||||
let n = mat.n;
|
let n = mat.n;
|
||||||
let (mut mu, mut b_star_sq) = gramm_schmidt(&mat);
|
let (mut mu, mut b_star_sq) = gramm_schmidt(&mat);
|
||||||
let mut k = 2;
|
let mut k = 2;
|
||||||
@ -12,7 +12,10 @@ pub fn deep_lll(mut mat: Matrix, delta: Rational) -> Option<Matrix> {
|
|||||||
|
|
||||||
while k <= n {
|
while k <= n {
|
||||||
if iterations >= MAX_ITERATIONS {
|
if iterations >= MAX_ITERATIONS {
|
||||||
eprintln!("Warning: DeepLLL did not converge after {} iterations", MAX_ITERATIONS);
|
eprintln!(
|
||||||
|
"Warning: DeepLLL did not converge after {} iterations",
|
||||||
|
MAX_ITERATIONS
|
||||||
|
);
|
||||||
return Some(mat);
|
return Some(mat);
|
||||||
}
|
}
|
||||||
iterations += 1;
|
iterations += 1;
|
||||||
@ -40,7 +43,7 @@ pub fn deep_lll(mut mat: Matrix, delta: Rational) -> Option<Matrix> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Compute Gram–Schmidt coefficients and squared norms of orthogonal vectors b*_i as Rationals.
|
/// Compute Gram–Schmidt coefficients and squared norms of orthogonal vectors b*_i as Rationals.
|
||||||
fn gramm_schmidt(mat: &Matrix) -> (Vec<Vec<Rational>>, Vec<Rational>) {
|
fn gramm_schmidt(mat: &Matrix<Integer>) -> (Vec<Vec<Rational>>, Vec<Rational>) {
|
||||||
let n = mat.n;
|
let n = mat.n;
|
||||||
let m = mat.m;
|
let m = mat.m;
|
||||||
let mut mu = vec![vec![Rational::from((0, 1)); n]; n];
|
let mut mu = vec![vec![Rational::from((0, 1)); n]; n];
|
||||||
@ -75,7 +78,7 @@ fn gramm_schmidt(mat: &Matrix) -> (Vec<Vec<Rational>>, Vec<Rational>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Size-reduce column k in-place
|
/// Size-reduce column k in-place
|
||||||
fn size_reduce(mat: &mut Matrix, mu: &mut [Vec<Rational>], b_star_sq: &mut [Rational], k: usize) {
|
fn size_reduce(mat: &mut Matrix<Integer>, mu: &mut [Vec<Rational>], b_star_sq: &mut [Rational], k: usize) {
|
||||||
let mut updated = true;
|
let mut updated = true;
|
||||||
while updated {
|
while updated {
|
||||||
updated = false;
|
updated = false;
|
||||||
@ -100,13 +103,13 @@ fn size_reduce(mat: &mut Matrix, mu: &mut [Vec<Rational>], b_star_sq: &mut [Rati
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Deep insertion: move column k into position i (1-based), shifting intermediate columns right.
|
/// Deep insertion: move column k into position i (1-based), shifting intermediate columns right.
|
||||||
fn deep_insert(mat: &mut Matrix, i: usize, k: usize) {
|
fn deep_insert(mat: &mut Matrix<Integer>, i: usize, k: usize) {
|
||||||
let col = mat.columns.remove(k - 1);
|
let col = mat.columns.remove(k - 1);
|
||||||
mat.columns.insert(i - 1, col);
|
mat.columns.insert(i - 1, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute squared Euclidean norm of column k as a Rational.
|
/// Compute squared Euclidean norm of column k as a Rational.
|
||||||
fn norm_sq(mat: &Matrix, k: usize) -> Rational {
|
fn norm_sq(mat: &Matrix<Integer>, k: usize) -> Rational {
|
||||||
let mut sum = Rational::from((0, 1));
|
let mut sum = Rational::from((0, 1));
|
||||||
for row in 0..mat.n {
|
for row in 0..mat.n {
|
||||||
let v = mat[(k - 1, row)].clone();
|
let v = mat[(k - 1, row)].clone();
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
use lll_rs::{matrix::Matrix as LLLMatrix, vector::BigVector};
|
|
||||||
|
|
||||||
use crate::matrix::Matrix;
|
use crate::matrix::Matrix;
|
||||||
|
use lll_rs::{matrix::Matrix as LLLMatrix, vector::BigVector};
|
||||||
|
use rug::{Integer, Rational};
|
||||||
|
use std::cmp::max;
|
||||||
|
use std::ops::Sub;
|
||||||
|
|
||||||
impl Matrix {
|
impl Matrix<Integer> {
|
||||||
pub fn to_lll_matrix(&self) -> LLLMatrix<BigVector> {
|
pub fn to_lll_matrix(&self) -> LLLMatrix<BigVector> {
|
||||||
let n = self.n;
|
let n = self.n;
|
||||||
let mut lll_mat = LLLMatrix::init(n, n);
|
let mut lll_mat = LLLMatrix::init(n, n);
|
||||||
|
146
src/matrix.rs
146
src/matrix.rs
@ -1,27 +1,27 @@
|
|||||||
use crate::vector::IntVector;
|
use crate::vector::Vector;
|
||||||
use rug::ops::Pow;
|
use rug::{ops::Pow, Integer};
|
||||||
use rug::Integer;
|
use std::{
|
||||||
use std::ops::{Index, IndexMut};
|
fmt,
|
||||||
|
ops::{Index, IndexMut},
|
||||||
macro_rules! int {
|
};
|
||||||
($x:expr) => {
|
|
||||||
rug::Integer::from($x)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Matrix {
|
pub struct Matrix<T> {
|
||||||
pub n: usize, // number of columns
|
pub n: usize, // number of columns
|
||||||
pub m: usize, // number of rows
|
pub m: usize, // number of rows
|
||||||
pub columns: Vec<IntVector>,
|
pub columns: Vec<Vector<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Matrix {
|
impl<T> Matrix<T> {
|
||||||
pub fn new(n: usize, m: usize, values: Vec<Integer>) -> Option<Self> {
|
pub fn new(n: usize, m: usize, values: Vec<T>) -> Option<Self> {
|
||||||
if n * m != values.len() {
|
if n * m != values.len() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let mut columns = vec![Vec::with_capacity(m); n];
|
// avoid requiring Vec<T>: Clone by building manually
|
||||||
|
let mut columns = Vec::with_capacity(n);
|
||||||
|
for _ in 0..n {
|
||||||
|
columns.push(Vec::with_capacity(m));
|
||||||
|
}
|
||||||
for (i, value) in values.into_iter().enumerate() {
|
for (i, value) in values.into_iter().enumerate() {
|
||||||
let col = i % n;
|
let col = i % n;
|
||||||
columns[col].push(value);
|
columns[col].push(value);
|
||||||
@ -29,39 +29,47 @@ impl Matrix {
|
|||||||
Some(Matrix {
|
Some(Matrix {
|
||||||
n,
|
n,
|
||||||
m,
|
m,
|
||||||
columns: columns.into_iter().map(IntVector::from_vec).collect(),
|
columns: columns.into_iter().map(Vector::from_vec).collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_lattice(noise_bits: usize, ciphertexts: Vec<Integer>) -> Option<Self> {
|
impl<T> Matrix<T>
|
||||||
|
where
|
||||||
|
T: Clone + Default + From<Integer>,
|
||||||
|
{
|
||||||
|
pub fn new_lattice(noise_bits: usize, ciphertexts: Vec<T>) -> Option<Self> {
|
||||||
let n = ciphertexts.len();
|
let n = ciphertexts.len();
|
||||||
let mut columns = vec![Vec::with_capacity(n); n];
|
let mut columns = vec![Vec::with_capacity(n); n];
|
||||||
|
|
||||||
columns[0].push(int!(2u64).pow((noise_bits + 1) as u32));
|
// First row: [2^(noise+1), ciphertexts[1], ciphertexts[2], ...]
|
||||||
|
let two_pow = Integer::from(2u64).pow((noise_bits + 1) as u32);
|
||||||
|
columns[0].push(T::from(two_pow));
|
||||||
for i in 1..n {
|
for i in 1..n {
|
||||||
columns[i].push(ciphertexts[i].clone());
|
columns[i].push(ciphertexts[i].clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Subsequent rows form identity matrix with ciphertexts[0]
|
||||||
for i in 1..n {
|
for i in 1..n {
|
||||||
for (j, column) in columns.iter_mut().enumerate().take(n) {
|
for (j, column) in columns.iter_mut().enumerate().take(n) {
|
||||||
if i == j {
|
column.push(if i == j {
|
||||||
column.push(ciphertexts[0].clone());
|
ciphertexts[0].clone()
|
||||||
} else {
|
} else {
|
||||||
column.push(int!(0));
|
T::default()
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Matrix {
|
Some(Matrix {
|
||||||
n,
|
n,
|
||||||
m: n,
|
m: n,
|
||||||
columns: columns.into_iter().map(IntVector::from_vec).collect(),
|
columns: columns.into_iter().map(Vector::from_vec).collect(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<(usize, usize)> for Matrix {
|
impl<T> Index<(usize, usize)> for Matrix<T> {
|
||||||
type Output = Integer;
|
type Output = T;
|
||||||
fn index(&self, index: (usize, usize)) -> &Self::Output {
|
fn index(&self, index: (usize, usize)) -> &Self::Output {
|
||||||
let (col, row) = index;
|
let (col, row) = index;
|
||||||
if row >= self.n || col >= self.m {
|
if row >= self.n || col >= self.m {
|
||||||
@ -71,7 +79,7 @@ impl Index<(usize, usize)> for Matrix {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndexMut<(usize, usize)> for Matrix {
|
impl<T> IndexMut<(usize, usize)> for Matrix<T> {
|
||||||
fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
|
fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
|
||||||
let (col, row) = index;
|
let (col, row) = index;
|
||||||
if row >= self.n || col >= self.m {
|
if row >= self.n || col >= self.m {
|
||||||
@ -84,16 +92,23 @@ impl IndexMut<(usize, usize)> for Matrix {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::panic;
|
use rug::Rational;
|
||||||
|
|
||||||
|
macro_rules! int {
|
||||||
|
($x:expr) => {
|
||||||
|
Integer::from($x)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! rational {
|
||||||
|
($x:expr) => {
|
||||||
|
Rational::from(Integer::from($x))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple_dimensions_and_index() {
|
fn test_integer_matrix() {
|
||||||
let m = Matrix::new(2, 2, vec![int!(1), int!(2), int!(3), int!(4)]).unwrap();
|
let m = Matrix::new(2, 2, vec![int!(1), int!(2), int!(3), int!(4)]).unwrap();
|
||||||
assert_eq!(m.n, 2);
|
|
||||||
assert_eq!(m.m, 2);
|
|
||||||
|
|
||||||
// values: [1,2,3,4]
|
|
||||||
// columns: [[1,3], [2,4]]
|
|
||||||
assert_eq!(m[(0, 0)], int!(1));
|
assert_eq!(m[(0, 0)], int!(1));
|
||||||
assert_eq!(m[(0, 1)], int!(2));
|
assert_eq!(m[(0, 1)], int!(2));
|
||||||
assert_eq!(m[(1, 0)], int!(3));
|
assert_eq!(m[(1, 0)], int!(3));
|
||||||
@ -101,47 +116,26 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn indexes_and_mutation() {
|
fn test_rational_matrix() {
|
||||||
let mut m = Matrix::new(2, 2, vec![int!(1), int!(2), int!(3), int!(4)]).unwrap();
|
let m = Matrix::new(
|
||||||
assert_eq!(m[(1, 0)], int!(3));
|
|
||||||
|
|
||||||
m[(1, 0)] = int!(5);
|
|
||||||
assert_eq!(m[(1, 0)], int!(5));
|
|
||||||
|
|
||||||
let m2 = Matrix::new(
|
|
||||||
3,
|
|
||||||
2,
|
2,
|
||||||
vec![int!(1), int!(2), int!(3), int!(4), int!(5), int!(6)],
|
2,
|
||||||
|
vec![rational!(1), rational!(2), rational!(3), rational!(4)],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
assert_eq!(m[(0, 0)], rational!(1));
|
||||||
assert_eq!(m2[(0, 2)], int!(3));
|
assert_eq!(m[(0, 1)], rational!(2));
|
||||||
assert_eq!(m2[(1, 0)], int!(4));
|
assert_eq!(m[(1, 0)], rational!(3));
|
||||||
|
assert_eq!(m[(1, 1)], rational!(4));
|
||||||
let result = panic::catch_unwind(|| {
|
|
||||||
let _ = m2[(2, 0)];
|
|
||||||
});
|
|
||||||
assert!(result.is_err(), "Expected panic on m2[(2, 0)]");
|
|
||||||
|
|
||||||
let result2 = panic::catch_unwind(|| {
|
|
||||||
let _ = m2[(0, 3)];
|
|
||||||
});
|
|
||||||
assert!(result2.is_err(), "Expected panic on m2[(0, 3)]");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_new_lattice_layout() {
|
fn test_lattice_matrix() {
|
||||||
let ciphertexts = vec![int!(5), int!(8), int!(12)];
|
let ciphertexts = vec![int!(5), int!(8), int!(12)];
|
||||||
let noise_bits = 2;
|
let noise_bits = 2;
|
||||||
let lattice = Matrix::new_lattice(noise_bits, ciphertexts.clone()).unwrap();
|
let lattice = Matrix::new_lattice(noise_bits, ciphertexts).unwrap();
|
||||||
|
|
||||||
assert_eq!(lattice.n, 3);
|
let expected = vec![
|
||||||
assert_eq!(lattice.m, 3);
|
|
||||||
|
|
||||||
// 1st column = [2^(noise+1), 0, 0] = [8,0,0]
|
|
||||||
// 2nd column = [ciphertexts[1], ciphertexts[0], 0] = [8,5,0]
|
|
||||||
// 3rd column = [ciphertexts[2], 0, ciphertexts[0]] = [12,0,5]
|
|
||||||
let expected_flat = vec![
|
|
||||||
int!(8),
|
int!(8),
|
||||||
int!(8),
|
int!(8),
|
||||||
int!(12),
|
int!(12),
|
||||||
@ -152,14 +146,24 @@ mod tests {
|
|||||||
int!(0),
|
int!(0),
|
||||||
int!(5),
|
int!(5),
|
||||||
];
|
];
|
||||||
|
let mut actual = Vec::new();
|
||||||
let mut actual_flat = Vec::with_capacity(9);
|
for col in 0..3 {
|
||||||
for col in 0..lattice.m {
|
for row in 0..3 {
|
||||||
for row in 0..lattice.n {
|
actual.push(lattice[(col, row)].clone());
|
||||||
actual_flat.push(lattice[(col, row)].clone());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
assert_eq!(actual, expected);
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!(actual_flat, expected_flat);
|
#[test]
|
||||||
|
fn test_rational_lattice() {
|
||||||
|
let ciphertexts = vec![rational!(5), rational!(8), rational!(12)];
|
||||||
|
let noise_bits = 2;
|
||||||
|
let lattice = Matrix::new_lattice(noise_bits, ciphertexts).unwrap();
|
||||||
|
|
||||||
|
let two_pow = Rational::from(Integer::from(2u64).pow(3));
|
||||||
|
assert_eq!(lattice[(0, 0)], two_pow);
|
||||||
|
assert_eq!(lattice[(0, 1)], rational!(8));
|
||||||
|
assert_eq!(lattice[(0, 2)], rational!(12));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
158
src/vector.rs
158
src/vector.rs
@ -1,42 +1,53 @@
|
|||||||
use rug::Integer;
|
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
|
iter::Sum,
|
||||||
ops::{Add, Index, IndexMut, Mul, Sub},
|
ops::{Add, Index, IndexMut, Mul, Sub},
|
||||||
};
|
};
|
||||||
|
|
||||||
macro_rules! int {
|
|
||||||
($x:expr) => {
|
|
||||||
rug::Integer::from($x)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct IntVector {
|
pub struct Vector<T> {
|
||||||
elements: Vec<Integer>,
|
pub elements: Vec<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntVector {
|
impl<T: Default> Vector<T> {
|
||||||
pub fn init(size: usize) -> Self {
|
pub fn init(size: usize) -> Self {
|
||||||
Self {
|
let mut elements = Vec::with_capacity(size);
|
||||||
elements: vec![Default::default(); size],
|
for _ in 0..size {
|
||||||
|
elements.push(T::default());
|
||||||
}
|
}
|
||||||
|
Self { elements }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_vec(elements: Vec<Integer>) -> Self {
|
impl<T> Vector<T> {
|
||||||
|
pub fn from_vec(elements: Vec<T>) -> Self {
|
||||||
Self { elements }
|
Self { elements }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size(&self) -> usize {
|
pub fn size(&self) -> usize {
|
||||||
self.elements.len()
|
self.elements.len()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mul_scalar(&self, other: &Integer) -> Self {
|
impl<T> Vector<T>
|
||||||
let n = self.size();
|
where
|
||||||
Self::from_vec((0..n).map(|i| int!(&self.elements[i] * other)).collect())
|
T: Mul<Output = T> + Clone,
|
||||||
|
{
|
||||||
|
pub fn mul_scalar(&self, scalar: &T) -> Self {
|
||||||
|
let elements = self
|
||||||
|
.elements
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|e| e * scalar.clone())
|
||||||
|
.collect();
|
||||||
|
Self { elements }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add for IntVector {
|
impl<T> Add for Vector<T>
|
||||||
|
where
|
||||||
|
T: Add<Output = T>,
|
||||||
|
{
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
fn add(self, other: Self) -> Self::Output {
|
fn add(self, other: Self) -> Self::Output {
|
||||||
assert_eq!(self.size(), other.size());
|
assert_eq!(self.size(), other.size());
|
||||||
@ -46,11 +57,14 @@ impl Add for IntVector {
|
|||||||
.zip(other.elements)
|
.zip(other.elements)
|
||||||
.map(|(a, b)| a + b)
|
.map(|(a, b)| a + b)
|
||||||
.collect();
|
.collect();
|
||||||
IntVector::from_vec(elements)
|
Vector::from_vec(elements)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sub for IntVector {
|
impl<T> Sub for Vector<T>
|
||||||
|
where
|
||||||
|
T: Sub<Output = T>,
|
||||||
|
{
|
||||||
type Output = Self;
|
type Output = Self;
|
||||||
fn sub(self, other: Self) -> Self::Output {
|
fn sub(self, other: Self) -> Self::Output {
|
||||||
assert_eq!(self.size(), other.size());
|
assert_eq!(self.size(), other.size());
|
||||||
@ -60,36 +74,40 @@ impl Sub for IntVector {
|
|||||||
.zip(other.elements)
|
.zip(other.elements)
|
||||||
.map(|(a, b)| a - b)
|
.map(|(a, b)| a - b)
|
||||||
.collect();
|
.collect();
|
||||||
IntVector::from_vec(elements)
|
Vector::from_vec(elements)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mul for IntVector {
|
impl<T> Mul for Vector<T>
|
||||||
type Output = Integer;
|
where
|
||||||
fn mul(self, other: Self) -> Self::Output {
|
T: Mul<Output = T> + Sum,
|
||||||
let n = self.size();
|
{
|
||||||
assert_eq!(n, other.size());
|
type Output = T;
|
||||||
(0..n)
|
fn mul(self, other: Self) -> T {
|
||||||
.map(|i| Integer::from(&self.elements[i] * &other.elements[i]))
|
assert_eq!(self.size(), other.size());
|
||||||
|
self.elements
|
||||||
|
.into_iter()
|
||||||
|
.zip(other.elements)
|
||||||
|
.map(|(a, b)| a * b)
|
||||||
.sum()
|
.sum()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<usize> for IntVector {
|
impl<T> Index<usize> for Vector<T> {
|
||||||
type Output = Integer;
|
type Output = T;
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Integer {
|
fn index(&self, index: usize) -> &T {
|
||||||
&self.elements[index]
|
&self.elements[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndexMut<usize> for IntVector {
|
impl<T> IndexMut<usize> for Vector<T> {
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Integer {
|
fn index_mut(&mut self, index: usize) -> &mut T {
|
||||||
&mut self.elements[index]
|
&mut self.elements[index]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for IntVector {
|
impl<T: fmt::Debug> fmt::Debug for Vector<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{:?}", self.elements)
|
write!(f, "{:?}", self.elements)
|
||||||
}
|
}
|
||||||
@ -98,10 +116,23 @@ impl fmt::Debug for IntVector {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use rug::{Integer, Rational};
|
||||||
|
|
||||||
|
macro_rules! int {
|
||||||
|
($x:expr) => {
|
||||||
|
Integer::from($x)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! rational {
|
||||||
|
($x:expr) => {
|
||||||
|
Rational::from(Integer::from($x))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_vec() {
|
fn test_integer_vector_from_vec() {
|
||||||
let v = IntVector::from_vec(vec![int!(1), int!(2), int!(3)]);
|
let v = Vector::from_vec(vec![int!(1), int!(2), int!(3)]);
|
||||||
assert_eq!(v.size(), 3);
|
assert_eq!(v.size(), 3);
|
||||||
assert_eq!(v[0], int!(1));
|
assert_eq!(v[0], int!(1));
|
||||||
assert_eq!(v[1], int!(2));
|
assert_eq!(v[1], int!(2));
|
||||||
@ -109,9 +140,18 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_vectors() {
|
fn test_rational_vector_from_vec() {
|
||||||
let v1 = IntVector::from_vec(vec![int!(1), int!(2), int!(3)]);
|
let v = Vector::from_vec(vec![rational!(1), rational!(2), rational!(3)]);
|
||||||
let v2 = IntVector::from_vec(vec![int!(4), int!(5), int!(6)]);
|
assert_eq!(v.size(), 3);
|
||||||
|
assert_eq!(v[0], rational!(1));
|
||||||
|
assert_eq!(v[1], rational!(2));
|
||||||
|
assert_eq!(v[2], rational!(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_add_integer_vectors() {
|
||||||
|
let v1 = Vector::from_vec(vec![int!(1), int!(2), int!(3)]);
|
||||||
|
let v2 = Vector::from_vec(vec![int!(4), int!(5), int!(6)]);
|
||||||
let result = v1 + v2;
|
let result = v1 + v2;
|
||||||
assert_eq!(result[0], int!(5));
|
assert_eq!(result[0], int!(5));
|
||||||
assert_eq!(result[1], int!(7));
|
assert_eq!(result[1], int!(7));
|
||||||
@ -119,9 +159,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sub_vectors() {
|
fn test_sub_integer_vectors() {
|
||||||
let v1 = IntVector::from_vec(vec![int!(5), int!(7), int!(9)]);
|
let v1 = Vector::from_vec(vec![int!(5), int!(7), int!(9)]);
|
||||||
let v2 = IntVector::from_vec(vec![int!(4), int!(5), int!(6)]);
|
let v2 = Vector::from_vec(vec![int!(4), int!(5), int!(6)]);
|
||||||
let result = v1 - v2;
|
let result = v1 - v2;
|
||||||
assert_eq!(result[0], int!(1));
|
assert_eq!(result[0], int!(1));
|
||||||
assert_eq!(result[1], int!(2));
|
assert_eq!(result[1], int!(2));
|
||||||
@ -129,8 +169,8 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_scalar_multiplication() {
|
fn test_scalar_multiplication_integer() {
|
||||||
let v = IntVector::from_vec(vec![int!(2), int!(3), int!(4)]);
|
let v = Vector::from_vec(vec![int!(2), int!(3), int!(4)]);
|
||||||
let scalar = int!(5);
|
let scalar = int!(5);
|
||||||
let result = v.mul_scalar(&scalar);
|
let result = v.mul_scalar(&scalar);
|
||||||
assert_eq!(result[0], int!(10));
|
assert_eq!(result[0], int!(10));
|
||||||
@ -139,17 +179,37 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_dot_product() {
|
fn test_dot_product_integer() {
|
||||||
let v1 = IntVector::from_vec(vec![int!(1), int!(2), int!(3)]);
|
let v1 = Vector::from_vec(vec![int!(1), int!(2), int!(3)]);
|
||||||
let v2 = IntVector::from_vec(vec![int!(4), int!(5), int!(6)]);
|
let v2 = Vector::from_vec(vec![int!(4), int!(5), int!(6)]);
|
||||||
let dot = v1 * v2;
|
let dot = v1 * v2;
|
||||||
assert_eq!(dot, int!(32)); // 1*4 + 2*5 + 3*6 = 32
|
assert_eq!(dot, int!(32));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_indexing_mut() {
|
fn test_indexing_mut_integer() {
|
||||||
let mut v = IntVector::from_vec(vec![int!(1), int!(2), int!(3)]);
|
let mut v = Vector::from_vec(vec![int!(1), int!(2), int!(3)]);
|
||||||
v[1] += int!(10);
|
v[1] += int!(10);
|
||||||
assert_eq!(v[1], int!(12));
|
assert_eq!(v[1], int!(12));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_add_rational_vectors() {
|
||||||
|
let v1 = Vector::from_vec(vec![rational!(1), rational!(2), rational!(3)]);
|
||||||
|
let v2 = Vector::from_vec(vec![rational!(4), rational!(5), rational!(6)]);
|
||||||
|
let result = v1 + v2;
|
||||||
|
assert_eq!(result[0], rational!(5));
|
||||||
|
assert_eq!(result[1], rational!(7));
|
||||||
|
assert_eq!(result[2], rational!(9));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_scalar_multiplication_rational() {
|
||||||
|
let v = Vector::from_vec(vec![rational!(2), rational!(3), rational!(4)]);
|
||||||
|
let scalar = rational!(5);
|
||||||
|
let result = v.mul_scalar(&scalar);
|
||||||
|
assert_eq!(result[0], rational!(10));
|
||||||
|
assert_eq!(result[1], rational!(15));
|
||||||
|
assert_eq!(result[2], rational!(20));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user