qfall_math/integer/poly_over_z/
coefficient_embedding.rs

1// Copyright © 2023 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 to transform a [`PolyOverZ`]
10//! into a [`MatZ`] and reverse by using the coefficient embedding.
11
12use crate::{
13    integer::{MatZ, PolyOverZ},
14    traits::{
15        FromCoefficientEmbedding, GetCoefficient, IntoCoefficientEmbedding, MatrixDimensions,
16        MatrixGetEntry, MatrixSetEntry, SetCoefficient,
17    },
18};
19
20impl IntoCoefficientEmbedding<MatZ> for &PolyOverZ {
21    /// Computes the coefficient embedding of the polynomial
22    /// in a [`MatZ`] as a column vector, where the i-th entry
23    /// of the vector corresponds to the i-th coefficient.
24    /// It inverts the operation of [`PolyOverZ::from_coefficient_embedding`].
25    ///
26    /// Parameters:
27    /// - `size`: determines the number of rows of the embedding. It has to be larger
28    ///   than the degree of the polynomial.
29    ///
30    /// Returns a coefficient embedding as a column vector if `size` is large enough.
31    ///
32    /// # Examples
33    /// ```
34    /// use std::str::FromStr;
35    /// use qfall_math::{
36    ///     integer::{MatZ, PolyOverZ},
37    ///     traits::IntoCoefficientEmbedding,
38    /// };
39    ///
40    /// let poly = PolyOverZ::from_str("3  17 3 -5").unwrap();
41    /// let vector = poly.into_coefficient_embedding(4);
42    /// let cmp_vector = MatZ::from_str("[[17],[3],[-5],[0]]").unwrap();
43    /// assert_eq!(cmp_vector, vector);
44    /// ```
45    ///
46    /// # Panics ...
47    /// - if `size` is not larger than the degree of the polynomial, i.e.
48    ///   not all coefficients can be embedded.
49    fn into_coefficient_embedding(self, size: impl Into<i64>) -> MatZ {
50        let size = size.into();
51        let length = self.get_degree() + 1;
52        assert!(
53            size >= length,
54            "The polynomial can not be embedded in the vector, \
55            as the length of the polynomial ({length}) is larger than \
56            the provided size ({size})."
57        );
58        let mut out = MatZ::new(size, 1);
59        for j in 0..size {
60            let coeff = unsafe { self.get_coeff_unchecked(j) };
61            unsafe { out.set_entry_unchecked(j, 0, coeff) };
62        }
63
64        out
65    }
66}
67
68impl FromCoefficientEmbedding<&MatZ> for PolyOverZ {
69    /// Computes a polynomial from a vector.
70    /// The first i-th entry of the column vector is taken
71    /// as the coefficient of the polynomial.
72    /// It inverts the operation of
73    /// [`PolyOverZ::into_coefficient_embedding`](#method.into_coefficient_embedding).
74    ///
75    /// Parameters:
76    /// - `embedding`: the column vector that encodes the embedding
77    ///
78    /// Returns a polynomial that corresponds to the embedding.
79    ///
80    /// # Examples
81    /// ```
82    /// use std::str::FromStr;
83    /// use qfall_math::{
84    ///     integer::{MatZ, PolyOverZ},
85    ///     traits::FromCoefficientEmbedding,
86    /// };
87    ///
88    /// let vector = MatZ::from_str("[[17],[3],[-5]]").unwrap();
89    /// let poly = PolyOverZ::from_coefficient_embedding(&vector);
90    /// let cmp_poly = PolyOverZ::from_str("3  17 3 -5").unwrap();
91    /// assert_eq!(cmp_poly, poly);
92    /// ```
93    ///
94    /// # Panics ...
95    /// - if the provided embedding is not a column vector.
96    fn from_coefficient_embedding(embedding: &MatZ) -> Self {
97        assert!(
98            embedding.is_column_vector(),
99            "This is no valid embedding, since the matrix is no column vector."
100        );
101        let mut out = PolyOverZ::default();
102        for i in 0..embedding.get_num_rows() {
103            unsafe { out.set_coeff_unchecked(i, embedding.get_entry_unchecked(i, 0)) }
104        }
105        out
106    }
107}
108
109#[cfg(test)]
110mod test_into_coefficient_embedding {
111    use crate::{
112        integer::{MatZ, PolyOverZ},
113        traits::IntoCoefficientEmbedding,
114    };
115    use std::str::FromStr;
116
117    /// Ensure that the embedding works with large entries.
118    #[test]
119    fn large_entries() {
120        let poly = PolyOverZ::from_str(&format!("3  17 {} {}", i64::MAX, i64::MIN)).unwrap();
121
122        let vector = poly.into_coefficient_embedding(3);
123
124        let cmp_vector = MatZ::from_str(&format!("[[17],[{}],[{}]]", i64::MAX, i64::MIN)).unwrap();
125        assert_eq!(cmp_vector, vector);
126    }
127
128    /// Ensure that the function panics if the the provided size is too small.
129    #[test]
130    #[should_panic]
131    fn size_too_small() {
132        let poly = PolyOverZ::from_str("3  17 12 -1").unwrap();
133
134        let _ = poly.into_coefficient_embedding(2);
135    }
136}
137
138#[cfg(test)]
139mod test_from_coefficient_embedding {
140    use crate::{
141        integer::{MatZ, PolyOverZ},
142        traits::FromCoefficientEmbedding,
143    };
144    use std::str::FromStr;
145
146    /// Ensure that the embedding works with large entries.
147    #[test]
148    fn large_entries() {
149        let vector = MatZ::from_str(&format!("[[17],[{}],[{}]]", i64::MAX, i64::MIN)).unwrap();
150
151        let poly = PolyOverZ::from_coefficient_embedding(&vector);
152
153        let cmp_poly = PolyOverZ::from_str(&format!("3  17 {} {}", i64::MAX, i64::MIN)).unwrap();
154        assert_eq!(cmp_poly, poly);
155    }
156
157    /// Ensure that the function panics if the provided matrix is not a column vector.
158    #[test]
159    #[should_panic]
160    fn not_column_vector() {
161        let vector = MatZ::from_str("[[17, 1],[-17, -1],[5, 9]]").unwrap();
162
163        let _ = PolyOverZ::from_coefficient_embedding(&vector);
164    }
165}