Skip to content

Commit df602cd

Browse files
Merge pull request #501 from qfall/rework_base_error_handling
Rework base error handling
2 parents c851211 + 393fbb6 commit df602cd

File tree

34 files changed

+611
-158
lines changed

34 files changed

+611
-158
lines changed

src/integer/mat_poly_over_z/cmp.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//! This uses the traits from [`std::cmp`].
1111
1212
use super::MatPolyOverZ;
13+
use crate::traits::CompareBase;
1314
use flint_sys::fmpz_poly_mat::fmpz_poly_mat_equal;
1415

1516
impl PartialEq for MatPolyOverZ {
@@ -48,6 +49,8 @@ impl PartialEq for MatPolyOverZ {
4849
// This is not guaranteed by the [`PartialEq`] trait.
4950
impl Eq for MatPolyOverZ {}
5051

52+
impl CompareBase for MatPolyOverZ {}
53+
5154
/// Test that the [`PartialEq`] trait is correctly implemented.
5255
#[cfg(test)]
5356
mod test_partial_eq {
@@ -218,3 +221,20 @@ mod test_partial_eq {
218221
assert!(small_positive != min);
219222
}
220223
}
224+
225+
/// Test that the [`CompareBase`] trait uses the default implementation.
226+
#[cfg(test)]
227+
mod test_compare_base {
228+
use crate::{integer::MatPolyOverZ, traits::CompareBase};
229+
use std::str::FromStr;
230+
231+
/// Ensures that the [`CompareBase`] trait uses the default implementation.
232+
#[test]
233+
fn uses_default_implementation() {
234+
let one_1 = MatPolyOverZ::from_str("[[2 24 47],[2 24 42]]").unwrap();
235+
let one_2 = MatPolyOverZ::from_str("[[2 24 42]]").unwrap();
236+
237+
assert!(one_1.compare_base(&one_2));
238+
assert!(one_1.call_compare_base_error(&one_2).is_none());
239+
}
240+
}

src/integer/mat_z/cmp.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
//! This module contains implementations for comparison of [`MatZ`].
1010
1111
use super::MatZ;
12+
use crate::traits::CompareBase;
1213
use flint_sys::fmpz_mat::fmpz_mat_equal;
1314

1415
impl PartialEq for MatZ {
@@ -42,6 +43,8 @@ impl PartialEq for MatZ {
4243
}
4344
}
4445

46+
impl CompareBase for MatZ {}
47+
4548
// With the [`Eq`] trait, `a == a` is always true.
4649
// This is not guaranteed by the [`PartialEq`] trait.
4750
impl Eq for MatZ {}
@@ -104,3 +107,20 @@ mod test_partial_eq {
104107
assert_ne!(&d, &e);
105108
}
106109
}
110+
111+
/// Test that the [`CompareBase`] trait uses the default implementation.
112+
#[cfg(test)]
113+
mod test_compare_base {
114+
use crate::{integer::MatZ, traits::CompareBase};
115+
use std::str::FromStr;
116+
117+
/// Ensures that the [`CompareBase`] trait uses the default implementation.
118+
#[test]
119+
fn different_base() {
120+
let one_1 = MatZ::from_str("[[2, 24, 47],[2, 24, 42]]").unwrap();
121+
let one_2 = MatZ::from_str("[[2, 4, 42]]").unwrap();
122+
123+
assert!(one_1.compare_base(&one_2));
124+
assert!(one_1.call_compare_base_error(&one_2).is_none());
125+
}
126+
}

src/integer_mod_q/mat_polynomial_ring_zq.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use derive_more::Display;
1515
use serde::{Deserialize, Serialize};
1616

1717
mod arithmetic;
18+
mod cmp;
1819
mod coefficient_embedding;
1920
mod concat;
2021
mod default;

src/integer_mod_q/mat_polynomial_ring_zq/arithmetic/add.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use crate::{
1515
arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
1616
arithmetic_trait_mixed_borrowed_owned,
1717
},
18+
traits::CompareBase,
1819
};
1920
use std::ops::{Add, AddAssign};
2021

@@ -132,11 +133,8 @@ impl MatPolynomialRingZq {
132133
/// - Returns a [`MathError`] of type [`MathError::MismatchingMatrixDimension`]
133134
/// if the dimensions of both [`MatPolynomialRingZq`] mismatch.
134135
pub fn add_safe(&self, other: &Self) -> Result<MatPolynomialRingZq, MathError> {
135-
if self.modulus != other.modulus {
136-
return Err(MathError::MismatchingModulus(format!(
137-
"Tried to add polynomial with modulus '{}' and polynomial with modulus '{}'.",
138-
self.modulus, other.modulus
139-
)));
136+
if !self.compare_base(other) {
137+
return Err(self.call_compare_base_error(other).unwrap());
140138
}
141139
let matrix = self.matrix.add_safe(&other.matrix)?;
142140

src/integer_mod_q/mat_polynomial_ring_zq/arithmetic/mul.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::error::MathError;
1313
use crate::macros::arithmetics::{
1414
arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned,
1515
};
16+
use crate::traits::CompareBase;
1617
use std::ops::Mul;
1718

1819
impl Mul for &MatPolynomialRingZq {
@@ -101,12 +102,8 @@ impl MatPolynomialRingZq {
101102
/// - Returns a [`MathError`] of type
102103
/// [`MathError::MismatchingModulus`] if the moduli mismatch.
103104
pub fn mul_safe(&self, other: &Self) -> Result<Self, MathError> {
104-
if self.modulus != other.modulus {
105-
return Err(MathError::MismatchingModulus(format!(
106-
"Tried to multiply matrices with moduli '{}' and '{}'.",
107-
self.get_mod(),
108-
other.get_mod()
109-
)));
105+
if !self.compare_base(other) {
106+
return Err(self.call_compare_base_error(other).unwrap());
110107
}
111108

112109
let mut new =

src/integer_mod_q/mat_polynomial_ring_zq/arithmetic/sub.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::integer_mod_q::MatPolynomialRingZq;
1313
use crate::macros::arithmetics::{
1414
arithmetic_trait_borrowed_to_owned, arithmetic_trait_mixed_borrowed_owned,
1515
};
16+
use crate::traits::CompareBase;
1617
use std::ops::Sub;
1718

1819
impl Sub for &MatPolynomialRingZq {
@@ -84,11 +85,8 @@ impl MatPolynomialRingZq {
8485
/// - Returns a [`MathError`] of type [`MathError::MismatchingMatrixDimension`]
8586
/// if the dimensions of both [`MatPolynomialRingZq`] mismatch.
8687
pub fn sub_safe(&self, other: &Self) -> Result<MatPolynomialRingZq, MathError> {
87-
if self.modulus != other.modulus {
88-
return Err(MathError::MismatchingModulus(format!(
89-
"Tried to subtract polynomial with modulus '{}' and polynomial with modulus '{}'.",
90-
self.modulus, other.modulus
91-
)));
88+
if !self.compare_base(other) {
89+
return Err(self.call_compare_base_error(other).unwrap());
9290
}
9391
let matrix = self.matrix.sub_safe(&other.matrix)?;
9492

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright © 2025 Marvin Beckmann
2+
//
3+
// This file is part of qFALL-math.
4+
//
5+
// qFALL-math is free software: you can redistribute it and/or modify it under
6+
// the terms of the Mozilla Public License Version 2.0 as published by the
7+
// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8+
9+
//! This module contains implementations for comparison of [`MatPolynomialRingZq`].
10+
11+
use super::MatPolynomialRingZq;
12+
use crate::{error::MathError, traits::CompareBase};
13+
14+
impl CompareBase for MatPolynomialRingZq {
15+
/// Compares the moduli of the two elements.
16+
///
17+
/// Parameters:
18+
/// - `other`: The other object whose base is compared to `self`
19+
///
20+
/// Returns true if the moduli match and false otherwise.
21+
///
22+
/// # Example
23+
/// ```
24+
/// use qfall_math::{
25+
/// integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq},
26+
/// traits::CompareBase,
27+
/// };
28+
/// use std::str::FromStr;
29+
///
30+
/// let modulus = ModulusPolynomialRingZq::from_str("3 1 0 1 mod 17").unwrap();
31+
/// let one_1 = MatPolynomialRingZq::identity(10, 7, &modulus);
32+
/// let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 23").unwrap();
33+
/// let one_2 = MatPolynomialRingZq::identity(10, 7, &modulus);
34+
///
35+
/// assert!(!one_1.compare_base(&one_2));
36+
/// ```
37+
fn compare_base(&self, other: &Self) -> bool {
38+
self.get_mod() == other.get_mod()
39+
}
40+
41+
/// Returns an error that gives small explanation how the moduli differ.
42+
///
43+
/// Parameters:
44+
/// - `other`: The other object whose base is compared to `self`
45+
///
46+
/// Returns a MathError of type [MathError::MismatchingModulus].
47+
///
48+
/// # Example
49+
/// ```
50+
/// use qfall_math::{
51+
/// integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq},
52+
/// traits::CompareBase,
53+
/// };
54+
/// use std::str::FromStr;
55+
///
56+
/// let modulus = ModulusPolynomialRingZq::from_str("3 1 0 1 mod 17").unwrap();
57+
/// let one_1 = MatPolynomialRingZq::identity(10, 7, &modulus);
58+
/// let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 23").unwrap();
59+
/// let one_2 = MatPolynomialRingZq::identity(10, 7, &modulus);
60+
///
61+
/// assert!(one_1.call_compare_base_error(&one_2).is_some());
62+
/// ```
63+
fn call_compare_base_error(&self, other: &Self) -> Option<MathError> {
64+
Some(MathError::MismatchingModulus(format!(
65+
"The moduli of the matrices mismatch. One of them is {} and the other is {}.
66+
The desired operation is not defined and an error is returned.",
67+
self.get_mod(),
68+
other.get_mod()
69+
)))
70+
}
71+
}
72+
73+
/// Test that the [`CompareBase`] trait uses an actual implementation.
74+
#[cfg(test)]
75+
mod test_compare_base {
76+
use crate::{
77+
integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq},
78+
traits::CompareBase,
79+
};
80+
use std::str::FromStr;
81+
82+
/// Ensures that the [`CompareBase`] trait uses an actual implementation.
83+
#[test]
84+
fn different_base() {
85+
let modulus = ModulusPolynomialRingZq::from_str("3 1 0 1 mod 17").unwrap();
86+
let one_1 = MatPolynomialRingZq::identity(10, 7, &modulus);
87+
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 23").unwrap();
88+
let one_2 = MatPolynomialRingZq::identity(10, 7, &modulus);
89+
90+
assert!(!one_1.compare_base(&one_2));
91+
assert!(one_1.call_compare_base_error(&one_2).is_some())
92+
}
93+
94+
/// Ensures that the same base return `true`.
95+
#[test]
96+
fn same_base() {
97+
let modulus = ModulusPolynomialRingZq::from_str("3 1 0 1 mod 17").unwrap();
98+
let one_1 = MatPolynomialRingZq::identity(10, 7, &modulus);
99+
let one_2 = MatPolynomialRingZq::identity(29, 3, &modulus);
100+
101+
assert!(one_1.compare_base(&one_2));
102+
}
103+
}

src/integer_mod_q/mat_polynomial_ring_zq/concat.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use super::MatPolynomialRingZq;
1212
use crate::{
1313
error::MathError,
1414
integer::MatPolyOverZ,
15-
traits::{Concatenate, MatrixDimensions},
15+
traits::{CompareBase, Concatenate, MatrixDimensions},
1616
};
1717
use flint_sys::fmpz_poly_mat::{fmpz_poly_mat_concat_horizontal, fmpz_poly_mat_concat_vertical};
1818

@@ -60,12 +60,8 @@ impl Concatenate for &MatPolynomialRingZq {
6060
)));
6161
}
6262

63-
if self.modulus != other.modulus {
64-
return Err(MathError::MismatchingModulus(format!(
65-
"Tried to concatenate matrices with different moduli {} and {}.",
66-
self.get_mod(),
67-
other.get_mod(),
68-
)));
63+
if !self.compare_base(other) {
64+
return Err(self.call_compare_base_error(other).unwrap());
6965
}
7066

7167
let mut matrix = MatPolyOverZ::new(
@@ -126,12 +122,8 @@ impl Concatenate for &MatPolynomialRingZq {
126122
)));
127123
}
128124

129-
if self.modulus != other.modulus {
130-
return Err(MathError::MismatchingModulus(format!(
131-
"Tried to concatenate matrices with different moduli {} and {}.",
132-
self.get_mod(),
133-
other.get_mod(),
134-
)));
125+
if !self.compare_base(other) {
126+
return Err(self.call_compare_base_error(other).unwrap());
135127
}
136128

137129
let mut matrix = MatPolyOverZ::new(

src/integer_mod_q/mat_polynomial_ring_zq/set.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use super::MatPolynomialRingZq;
1212
use crate::integer_mod_q::PolynomialRingZq;
1313
use crate::macros::for_others::implement_for_owned;
14-
use crate::traits::{MatrixSetSubmatrix, MatrixSwaps};
14+
use crate::traits::{CompareBase, MatrixSetSubmatrix, MatrixSwaps};
1515
use crate::utils::index::evaluate_indices_for_matrix;
1616
use crate::{error::MathError, integer::PolyOverZ, traits::MatrixSetEntry};
1717
use flint_sys::{fmpz_poly::fmpz_poly_set, fmpz_poly_mat::fmpz_poly_mat_entry};
@@ -250,12 +250,8 @@ impl MatrixSetSubmatrix for MatPolynomialRingZq {
250250
other: &Self,
251251
col_1: impl TryInto<i64> + Display,
252252
) -> Result<(), MathError> {
253-
if self.modulus != other.modulus {
254-
return Err(MathError::MismatchingModulus(format!(
255-
"set_column requires the moduli to be equal, but {} differs from {}",
256-
self.get_mod(),
257-
other.get_mod()
258-
)));
253+
if !self.compare_base(other) {
254+
return Err(self.call_compare_base_error(other).unwrap());
259255
}
260256

261257
self.matrix.set_column(col_0, &other.matrix, col_1)
@@ -299,12 +295,8 @@ impl MatrixSetSubmatrix for MatPolynomialRingZq {
299295
other: &Self,
300296
row_1: impl TryInto<i64> + Display,
301297
) -> Result<(), MathError> {
302-
if self.modulus != other.modulus {
303-
return Err(MathError::MismatchingModulus(format!(
304-
"set_row requires the moduli to be equal, but {} differs from {}",
305-
self.get_mod(),
306-
other.get_mod()
307-
)));
298+
if !self.compare_base(other) {
299+
return Err(self.call_compare_base_error(other).unwrap());
308300
}
309301

310302
self.matrix.set_row(row_0, &other.matrix, row_1)

src/integer_mod_q/mat_polynomial_ring_zq/tensor.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use super::MatPolynomialRingZq;
1212
use crate::{
1313
error::MathError,
1414
integer::PolyOverZ,
15-
traits::{MatrixDimensions, MatrixGetEntry, Tensor},
15+
traits::{CompareBase, MatrixDimensions, MatrixGetEntry, Tensor},
1616
};
1717
use flint_sys::{fmpz_poly_mat::fmpz_poly_mat_entry, fq::fq_mul};
1818

@@ -81,12 +81,8 @@ impl MatPolynomialRingZq {
8181
/// [`MismatchingModulus`](MathError::MismatchingModulus) if the
8282
/// moduli of the provided matrices mismatch.
8383
pub fn tensor_product_safe(&self, other: &Self) -> Result<Self, MathError> {
84-
if self.modulus != other.modulus {
85-
return Err(MathError::MismatchingModulus(format!(
86-
"Tried to compute tensor product of matrices with moduli '{}' and '{}'.",
87-
self.get_mod(),
88-
other.get_mod()
89-
)));
84+
if !self.compare_base(other) {
85+
return Err(self.call_compare_base_error(other).unwrap());
9086
}
9187

9288
let mut out = MatPolynomialRingZq::new(

0 commit comments

Comments
 (0)