qfall_math/
traits.rs

1// Copyright © 2023 Marvin Beckmann, Marcel Luca Schmidt
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//! Definitions of traits implemented and used in this crate.
10//!
11//! This module contains basic traits for this library. These include
12//! specific traits for matrices and polynomials.
13
14use crate::{
15    error::MathError,
16    utils::index::{evaluate_index, evaluate_index_for_vector, evaluate_indices_for_matrix},
17};
18use flint_sys::fmpz::fmpz;
19use std::fmt::Display;
20
21/// Is implemented by every type where a base-check might be needed.
22/// This also includes every type of matrix, because it allows for geneceric implementations.
23/// Per default, a basecheck simply returs that the bases match and no error is returned.
24pub trait CompareBase<T = Self> {
25    /// Compares the base elements of the objects and returns true if they match
26    /// and an operation between the two provided types is possible.
27    ///
28    /// Parameters:
29    /// - `other`: The other object whose base is compared to `self`
30    ///
31    /// Returns true if the bases match and false otherwise.
32    /// The default implementation just returns true.
33    #[allow(unused_variables)]
34    fn compare_base(&self, other: &T) -> bool {
35        true
36    }
37
38    /// Calls an error that gives small explanation how the base elements differ.
39    /// This function only calls the error and does not check if the two actually differ.
40    ///
41    /// Parameters:
42    /// - `other`: The other object whose base is compared to `self`
43    ///
44    /// Returns a MathError, typically [MathError::MismatchingModulus].
45    /// The default implementation just returns `None`.
46    #[allow(unused_variables)]
47    fn call_compare_base_error(&self, other: &T) -> Option<MathError> {
48        None
49    }
50}
51
52/// Is implemented by polynomials to evaluate them for a certain input.
53pub trait Evaluate<T, U> {
54    /// Evaluates the object, e.g. polynomial or a matrix of polynomials,
55    /// for a given input value.
56    ///
57    /// Parameters:
58    /// - `value`: the value with which to evaluate the object.
59    ///
60    /// Returns the evaluation of the object.
61    fn evaluate(&self, value: T) -> U;
62}
63
64/// Is implemented by polynomials to get a coefficient.
65pub trait GetCoefficient<T> {
66    /// Returns a coefficient of the given object, e.g. a polynomial,
67    /// for a given index.
68    ///
69    /// Parameters:
70    /// - `index`: the index of the coefficient
71    ///
72    /// # Errors and Failures
73    /// - Returns a [`MathError`] of type
74    ///   [`OutOfBounds`](MathError::OutOfBounds) if either the index is negative
75    ///   or does not fit into an [`i64`].
76    /// - Returns a [`MathError`] of type
77    ///   [`MismatchingModulus`](MathError::MismatchingModulus) if the base types are
78    ///   not compatible. This can only happen if the base types themselves can mismatch.
79    fn get_coeff(&self, index: impl TryInto<i64> + Display) -> Result<T, MathError> {
80        let index = evaluate_index(index)?;
81        Ok(unsafe { self.get_coeff_unchecked(index) })
82    }
83
84    /// Returns a coefficient of the given object, e.g. a polynomial,
85    /// for a given index.
86    ///
87    /// Parameters:
88    /// - `index`: the index of the coefficient
89    ///
90    /// Returns the coefficient of the polynomial.
91    ///
92    /// # Safety
93    /// To use this function safely, make sure that the selected index
94    /// is greater or equal than `0`.
95    unsafe fn get_coeff_unchecked(&self, index: i64) -> T;
96}
97
98/// Is implemented by polynomials to set a coefficient.
99pub trait SetCoefficient<T>
100where
101    Self: CompareBase<T>,
102{
103    /// Sets coefficient of the object, e.g. polynomial,
104    /// for a given input value and a index.
105    ///
106    /// Parameters:
107    /// - `index`: the coefficient to be set.
108    /// - `value`: the value the coefficient is set to.
109    ///
110    /// # Errors and Failures
111    /// - Returns a [`MathError`] of type
112    ///   [`OutOfBounds`](MathError::OutOfBounds) if either the index is negative
113    ///   or does not fit into an [`i64`].
114    /// - Returns a [`MathError`] of type [`MismatchingModulus`](MathError::MismatchingModulus) if the base types are
115    ///   not compatible. This can only happen if the base types themselves can mismatch.
116    fn set_coeff(&mut self, index: impl TryInto<i64> + Display, value: T) -> Result<(), MathError> {
117        let index = evaluate_index(index)?;
118        if !self.compare_base(&value) {
119            return Err(self.call_compare_base_error(&value).unwrap());
120        }
121        unsafe {
122            self.set_coeff_unchecked(index, value);
123        }
124        Ok(())
125    }
126
127    /// Sets coefficient of the object, e.g. polynomial,
128    /// for a given input value and a index.
129    ///
130    /// Parameters:
131    /// - `index`: the coefficient to be set.
132    /// - `value`: the value the coefficient is set to.
133    ///
134    /// # Safety
135    /// To use this function safely, make sure that the selected index
136    /// is greater or equal than `0` and that the provided value has
137    /// the same base so that they have a matching base.
138    unsafe fn set_coeff_unchecked(&mut self, index: i64, value: T);
139}
140
141/// Is implemented by matrices to get the number of rows and number of columns of the matrix.
142pub trait MatrixDimensions {
143    /// Returns the number of rows of a matrix.
144    fn get_num_rows(&self) -> i64;
145
146    /// Returns the number of columns of a matrix.
147    fn get_num_columns(&self) -> i64;
148}
149
150/// Is implemented by matrices to get entries.
151pub trait MatrixGetEntry<T>
152where
153    Self: MatrixDimensions + Sized,
154    T: std::clone::Clone,
155{
156    /// Returns the value of a specific matrix entry.
157    ///
158    /// Parameters:
159    /// - `row`: specifies the row in which the entry is located.
160    /// - `column`: specifies the column in which the entry is located.
161    ///
162    /// Negative indices can be used to index from the back, e.g., `-1` for
163    /// the last element.
164    ///
165    /// Errors can occur if the provided indices are not within the dimensions of the provided matrices,
166    /// the bases of the matrix and value are not compatible, e.g. different modulus.
167    ///
168    /// # Errors and Failures
169    /// - Returns a [`MathError`] of type [`MathError::OutOfBounds`]
170    ///   if `row` or `column` do not define an entry in the mtrix
171    /// - Returns a [`MathError`] of type [`MathError::MismatchingModulus`]
172    ///   if the moduli are different.
173    fn get_entry(
174        &self,
175        row: impl TryInto<i64> + Display,
176        column: impl TryInto<i64> + Display,
177    ) -> Result<T, MathError> {
178        let (row, column) = evaluate_indices_for_matrix(self, row, column)?;
179        Ok(unsafe { self.get_entry_unchecked(row, column) })
180    }
181
182    /// Returns the value of a specific matrix entry
183    /// without performing any checks, e.g. checking whether the entry is
184    /// part of the matrix.
185    ///
186    /// Parameters:
187    /// - `row`: specifies the row in which the entry is located.
188    /// - `column`: specifies the column in which the entry is located.
189    ///
190    /// # Safety
191    /// To use this function safely, make sure that the selected entry is part
192    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
193    /// occur.
194    unsafe fn get_entry_unchecked(&self, row: i64, column: i64) -> T;
195
196    /// Outputs a [`Vec<Vec<T>>`] containing all entries of the matrix s.t.
197    /// any entry in row `i` and column `j` can be accessed via `entries[i][j]`
198    /// if `entries = matrix.get_entries`.
199    ///
200    /// # Examples
201    /// ```
202    /// use qfall_math::{integer::{MatZ, Z}, traits::*};
203    /// let matrix = MatZ::sample_uniform(3, 3, 0, 16).unwrap();
204    ///
205    /// let entries = matrix.get_entries();
206    /// let mut added_entries = Z::default();
207    /// for row in entries {
208    ///     for entry in row {
209    ///         added_entries += entry;
210    ///     }
211    /// }
212    /// ```
213    fn get_entries(&self) -> Vec<Vec<T>> {
214        let mut entries =
215            vec![Vec::with_capacity(self.get_num_columns() as usize); self.get_num_rows() as usize];
216
217        for i in 0..self.get_num_rows() {
218            for j in 0..self.get_num_columns() {
219                let entry = unsafe { self.get_entry_unchecked(i, j) };
220                entries[i as usize].push(entry);
221            }
222        }
223
224        entries
225    }
226
227    /// Outputs a [`Vec<T>`] containing all entries of the matrix in a row-wise order, i.e.
228    /// a matrix `[[2, 3, 4],[5, 6, 7]]` can be accessed via this function in this order `[2, 3, 4, 5, 6, 7]`.
229    ///
230    /// # Examples
231    /// ```
232    /// use qfall_math::{integer::{MatZ, Z}, traits::*};
233    /// let matrix = MatZ::sample_uniform(3, 3, 0, 16).unwrap();
234    ///
235    /// let entries = matrix.get_entries_rowwise();
236    /// let mut added_entries = Z::default();
237    /// for entry in entries {
238    ///     added_entries += entry;
239    /// }
240    /// ```
241    fn get_entries_rowwise(&self) -> Vec<T> {
242        let mut entries =
243            Vec::with_capacity((self.get_num_rows() * self.get_num_columns()) as usize);
244
245        for i in 0..self.get_num_rows() {
246            for j in 0..self.get_num_columns() {
247                let entry = unsafe { self.get_entry_unchecked(i, j) };
248                entries.push(entry);
249            }
250        }
251
252        entries
253    }
254
255    /// Outputs a [`Vec<T>`] containing all entries of the matrix in a column-wise order, i.e.
256    /// a matrix `[[2, 3, 4],[5, 6, 7]]` can be accessed via this function in this order `[2, 5, 3, 6, 4, 7]`.
257    ///
258    /// # Examples
259    /// ```
260    /// use qfall_math::{integer::{MatZ, Z}, traits::*};
261    /// let matrix = MatZ::sample_uniform(3, 3, 0, 16).unwrap();
262    ///
263    /// let entries = matrix.get_entries_columnwise();
264    /// let mut added_entries = Z::default();
265    /// for entry in entries {
266    ///     added_entries += entry;
267    /// }
268    /// ```
269    fn get_entries_columnwise(&self) -> Vec<T> {
270        let mut entries =
271            Vec::with_capacity((self.get_num_rows() * self.get_num_columns()) as usize);
272
273        for j in 0..self.get_num_columns() {
274            for i in 0..self.get_num_rows() {
275                let entry = unsafe { self.get_entry_unchecked(i, j) };
276                entries.push(entry);
277            }
278        }
279
280        entries
281    }
282}
283
284/// Is implemented by Matrices to get submatrices such as rows, columns, etc.
285pub trait MatrixGetSubmatrix
286where
287    Self: Sized + MatrixDimensions,
288{
289    /// Outputs the row vector of the specified row.
290    ///
291    /// Parameters:
292    /// - `row`: specifies the row of the matrix to return
293    ///
294    /// Negative indices can be used to index from the back, e.g., `-1` for
295    /// the last element.
296    ///
297    /// Returns a row vector of the matrix at the position of the given
298    /// `row` or an error if specified row is not part of the matrix.
299    ///
300    /// # Errors and Failures
301    /// - Returns a [`MathError`] of type [`OutOfBounds`](MathError::OutOfBounds)
302    ///   if specified row is not part of the matrix.
303    fn get_row(&self, row: impl TryInto<i64> + Display + Clone) -> Result<Self, MathError> {
304        let row = evaluate_index_for_vector(row, self.get_num_rows())?;
305        Ok(unsafe { self.get_row_unchecked(row) })
306    }
307
308    /// Outputs the row vector of the specified row.
309    ///
310    /// Parameters:
311    /// - `row`: specifies the row of the matrix to return
312    ///
313    /// Returns a row vector of the matrix at the position of the given
314    /// `row`.
315    ///
316    /// # Safety
317    /// To use this function safely, make sure that the selected row is part
318    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
319    /// occur.
320    unsafe fn get_row_unchecked(&self, row: i64) -> Self {
321        unsafe { self.get_submatrix_unchecked(row, row + 1, 0, self.get_num_columns()) }
322    }
323
324    /// Outputs the column vector of the specified column.
325    ///
326    /// Parameters:
327    /// - `column`: specifies the column of the matrix to return
328    ///
329    /// Negative indices can be used to index from the back, e.g., `-1` for
330    /// the last element.
331    ///
332    /// Returns a column vector of the matrix at the position of the given
333    /// `column` or an error if specified column is not part of the matrix.
334    ///
335    /// # Errors and Failures
336    /// - Returns a [`MathError`] of type [`OutOfBounds`](MathError::OutOfBounds)
337    ///   if specified column is not part of the matrix.
338    fn get_column(&self, column: impl TryInto<i64> + Display + Clone) -> Result<Self, MathError> {
339        let column = evaluate_index_for_vector(column, self.get_num_columns())?;
340        Ok(unsafe { self.get_column_unchecked(column) })
341    }
342
343    /// Outputs the column vector of the specified column.
344    ///
345    /// Parameters:
346    /// - `column`: specifies the row of the matrix to return
347    ///
348    /// Returns a column vector of the matrix at the position of the given
349    /// `column`.
350    ///
351    /// # Safety
352    /// To use this function safely, make sure that the selected column is part
353    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
354    /// occur.
355    unsafe fn get_column_unchecked(&self, column: i64) -> Self {
356        unsafe { self.get_submatrix_unchecked(0, self.get_num_rows(), column, column + 1) }
357    }
358
359    /// Returns a deep copy of the submatrix defined by the given parameters.
360    /// All entries starting from `(row_1, col_1)` to `(row_2, col_2)`(inclusively) are collected in
361    /// a new matrix.
362    /// Note that `row_1 >= row_2` and `col_1 >= col_2` must hold after converting negative indices.
363    /// Otherwise the function will panic.
364    ///
365    /// Parameters:
366    /// `row_1`: the starting row of the specified submatrix
367    /// `row_2`: the ending row of the specified submatrix
368    /// `col_1`: the starting column of the specified submatrix
369    /// `col_2`: the ending column of the specified submatrix
370    ///
371    /// Negative indices can be used to index from the back, e.g., `-1` for
372    /// the last element.
373    ///
374    /// Returns the submatrix from `(row_1, col_1)` to `(row_2, col_2)`(inclusively)
375    /// or an error if any provided row or column is larger than the matrix.
376    ///
377    /// # Errors and Failures
378    /// - Returns a [`MathError`] of type [`MathError::OutOfBounds`]
379    ///   if any provided row or column is larger than the matrix.
380    ///
381    /// # Panics ...
382    /// - if `col_1 > col_2` or `row_1 > row_2`.
383    fn get_submatrix(
384        &self,
385        row_1: impl TryInto<i64> + Display,
386        row_2: impl TryInto<i64> + Display,
387        col_1: impl TryInto<i64> + Display,
388        col_2: impl TryInto<i64> + Display,
389    ) -> Result<Self, MathError> {
390        let (row_1, col_1) = evaluate_indices_for_matrix(self, row_1, col_1)?;
391        let (row_2, col_2) = evaluate_indices_for_matrix(self, row_2, col_2)?;
392
393        assert!(
394            row_2 >= row_1,
395            "The number of rows must be positive, i.e. row_2 ({row_2}) must be greater or equal row_1 ({row_1})"
396        );
397
398        assert!(
399            col_2 >= col_1,
400            "The number of columns must be positive, i.e. col_2 ({col_2}) must be greater or equal col_1 ({col_1})"
401        );
402
403        // increase both values to have an inclusive capturing of the matrix entries
404        let (row_2, col_2) = (row_2 + 1, col_2 + 1);
405        Ok(unsafe { self.get_submatrix_unchecked(row_1, row_2, col_1, col_2) })
406    }
407
408    /// Returns a deep copy of the submatrix defined by the given parameters
409    /// and does not check the provided dimensions.
410    /// There is also a safe version of this function that checks the input.
411    ///
412    /// Parameters:
413    /// `row_1`: the starting row of the submatrix
414    /// `row_2`: the ending row of the submatrix
415    /// `col_1`: the starting column of the submatrix
416    /// `col_2`: the ending column of the submatrix
417    ///
418    /// Returns the submatrix from `(row_1, col_1)` to `(row_2, col_2)`(exclusively).
419    ///
420    /// # Safety
421    /// To use this function safely, make sure that the selected submatrix is part
422    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
423    /// occur.
424    unsafe fn get_submatrix_unchecked(
425        &self,
426        row_1: i64,
427        row_2: i64,
428        col_1: i64,
429        col_2: i64,
430    ) -> Self;
431
432    /// Outputs a [`Vec`] containing all rows of the matrix in order.
433    /// Use this function for simple iteration over the rows of the matrix.
434    ///
435    /// # Example
436    /// ```
437    /// use qfall_math::{integer::MatZ, traits::MatrixGetSubmatrix};
438    /// let matrix = MatZ::sample_uniform(3, 3, 0, 16).unwrap();
439    ///
440    /// let mut added_rows = MatZ::new(1, 3);
441    /// for row in matrix.get_rows() {
442    ///     added_rows = added_rows + row;
443    /// }
444    /// ```
445    ///
446    /// If an index is required, use `.iter().enumerate()`, e.g. in this case.
447    /// ```
448    /// use qfall_math::{integer::MatZ, traits::*};
449    /// let mut matrix = MatZ::sample_uniform(3, 3, 0, 16).unwrap();
450    ///
451    /// let mut added_rows = MatZ::new(1, 3);
452    /// for (i, row) in matrix.get_rows().iter().enumerate() {
453    ///     added_rows = added_rows + row;
454    ///     matrix.set_row(i, &added_rows, 0).unwrap();
455    /// }
456    /// ```
457    fn get_rows(&self) -> Vec<Self> {
458        let mut rows = Vec::with_capacity(self.get_num_rows() as usize);
459
460        for i in 0..self.get_num_rows() {
461            let entry = unsafe { self.get_row_unchecked(i) };
462            rows.push(entry);
463        }
464
465        rows
466    }
467
468    /// Outputs a [`Vec`] containing all columns of the matrix in order.
469    /// Use this function for simple iteration over the columns of the matrix.
470    ///
471    /// # Example
472    /// ```
473    /// use qfall_math::{integer::MatZ, traits::MatrixGetSubmatrix};
474    /// let matrix = MatZ::sample_uniform(3, 3, 0, 16).unwrap();
475    ///
476    /// let mut added_columns = MatZ::new(3, 1);
477    /// for column in matrix.get_columns() {
478    ///     added_columns = added_columns + column;
479    /// }
480    /// ```
481    ///
482    /// If an index is required, use `.iter().enumerate()`, e.g. in this case.
483    /// ```
484    /// use qfall_math::{integer::MatZ, traits::*};
485    /// let mut matrix = MatZ::sample_uniform(3, 3, 0, 16).unwrap();
486    ///
487    /// let mut added_columns = MatZ::new(3, 1);
488    /// for (i, column) in matrix.get_columns().iter().enumerate() {
489    ///     added_columns = added_columns + column;
490    ///     matrix.set_column(i, &added_columns, 0).unwrap();
491    /// }
492    /// ```
493    fn get_columns(&self) -> Vec<Self> {
494        let mut columns = Vec::with_capacity(self.get_num_columns() as usize);
495
496        for i in 0..self.get_num_columns() {
497            let entry = unsafe { self.get_column_unchecked(i) };
498            columns.push(entry);
499        }
500
501        columns
502    }
503}
504
505/// Is implemented by matrices to set entries.
506pub trait MatrixSetEntry<T>
507where
508    Self: CompareBase<T> + MatrixDimensions + Sized,
509{
510    /// Sets the value of a specific matrix entry according to a given value.
511    ///
512    /// Parameters:
513    /// - `row`: specifies the row in which the entry is located.
514    /// - `column`: specifies the column in which the entry is located.
515    /// - `value`: specifies the value to which the entry is set.
516    ///
517    /// Negative indices can be used to index from the back, e.g., `-1` for
518    /// the last element, but after conversion they must be within the matrix dimensions.
519    ///
520    /// Errors can occur if the provided indices are not within the dimensions of the provided matrices,
521    /// the bases of the matrix and value are not compatible, e.g. different modulus.
522    ///
523    /// # Errors and Failures
524    /// - Returns a [`MathError`] of type [`MathError::OutOfBounds`]
525    ///   if `row` or `column` do not define an entry in the mtrix
526    /// - Returns a [`MathError`] of type [`MathError::MismatchingModulus`]
527    ///   if the moduli are different.
528    fn set_entry(
529        &mut self,
530        row: impl TryInto<i64> + Display,
531        column: impl TryInto<i64> + Display,
532        value: T,
533    ) -> Result<(), MathError> {
534        if !self.compare_base(&value) {
535            return Err(self.call_compare_base_error(&value).unwrap());
536        }
537        let (row, column) = evaluate_indices_for_matrix(self, row, column)?;
538        unsafe {
539            self.set_entry_unchecked(row, column, value);
540        }
541        Ok(())
542    }
543
544    /// Sets the value of a specific matrix entry according to a given value
545    /// without performing any checks, e.g. checking whether the entry is
546    /// part of the matrix or if the moduli of the matrices match.
547    ///
548    /// Parameters:
549    /// - `row`: specifies the row in which the entry is located.
550    /// - `column`: specifies the column in which the entry is located.
551    /// - `value`: specifies the value to which the entry is set.
552    ///
553    /// # Safety
554    /// To use this function safely, make sure that the selected entry is part
555    /// of the matrix. If it is not, memory leaks, unexpected panics, etc. might
556    /// occur.
557    unsafe fn set_entry_unchecked(&mut self, row: i64, column: i64, value: T);
558}
559
560/// Is implemented by matrices to set more than a single entry of the matrix.
561pub trait MatrixSetSubmatrix
562where
563    Self: Sized + MatrixDimensions + CompareBase,
564{
565    /// Sets a row of the given matrix to the provided row of `other`.
566    ///
567    /// Parameters:
568    /// - `row_0`: specifies the row of `self` that should be modified
569    /// - `other`: specifies the matrix providing the row replacing the row in `self`
570    /// - `row_1`: specifies the row of `other` providing
571    ///   the values replacing the original row in `self`
572    ///
573    /// Negative indices can be used to index from the back, e.g., `-1` for
574    /// the last element, but after conversion they must be within the matrix dimensions.
575    ///
576    /// Returns an empty `Ok` if the action could be performed successfully.
577    /// Otherwise, a [`MathError`] is returned if one of the specified rows is not part of its matrix
578    /// or if the number of columns differs.
579    ///
580    /// # Errors and Failures
581    /// - Returns a [`MathError`] of type [`MathError::OutOfBounds`]
582    ///   if the provided row index is not defined within the margins of the matrix.
583    /// - Returns a [`MathError`] of type [`MismatchingMatrixDimension`](MathError::MismatchingMatrixDimension)
584    ///   if the number of columns of `self` and `other` differ.
585    /// - Returns a [`MathError`] of type [`MismatchingModulus`](MathError::MismatchingModulus) if the base types are
586    ///   not compatible. This can only happen if the base types themselves can mismatch.
587    fn set_row(
588        &mut self,
589        row_0: impl TryInto<i64> + Display,
590        other: &Self,
591        row_1: impl TryInto<i64> + Display,
592    ) -> Result<(), MathError> {
593        if !self.compare_base(other) {
594            return Err(self.call_compare_base_error(other).unwrap());
595        }
596
597        let num_cols_0 = self.get_num_columns();
598        let num_cols_1 = other.get_num_columns();
599        if num_cols_0 != num_cols_1 {
600            return Err(MathError::MismatchingMatrixDimension(format!(
601                "as set_row was called on two matrices with different number of rows/columns {num_cols_0} and {num_cols_1}",
602            )));
603        }
604
605        let row_0 = evaluate_index_for_vector(row_0, self.get_num_rows())?;
606        let row_1 = evaluate_index_for_vector(row_1, other.get_num_rows())?;
607
608        unsafe {
609            self.set_row_unchecked(row_0, other, row_1);
610        }
611
612        Ok(())
613    }
614    /// Sets a row of the given matrix to the provided row of `other`.
615    ///
616    /// Parameters:
617    /// - `row_0`: specifies the row of `self` that should be modified
618    /// - `other`: specifies the matrix providing the row replacing the row in `self`
619    /// - `row_1`: specifies the row of `other` providing
620    ///   the values replacing the original row in `self`
621    ///
622    /// # Safety
623    /// To use this function safely, make sure that the selected rows are part
624    /// of the matrices, the columns are of the same length and the base types are the same.
625    /// If not, memory leaks, unexpected panics, etc. might occur.
626    unsafe fn set_row_unchecked(&mut self, row_0: i64, other: &Self, row_1: i64) {
627        unsafe {
628            self.set_submatrix_unchecked(
629                row_0,
630                0,
631                row_0 + 1,
632                self.get_num_columns(),
633                other,
634                row_1,
635                0,
636                row_1 + 1,
637                other.get_num_columns(),
638            );
639        }
640    }
641
642    /// Sets a column of the given matrix to the provided column of `other`.
643    ///
644    /// Parameters:
645    /// - `col_0`: specifies the column of `self` that should be modified
646    /// - `other`: specifies the matrix providing the column replacing the column in `self`
647    /// - `col_1`: specifies the column of `other` providing
648    ///   the values replacing the original column in `self`
649    ///
650    /// Negative indices can be used to index from the back, e.g., `-1` for
651    /// the last element, but after conversion they must be within the matrix dimensions.
652    ///
653    /// Returns an empty `Ok` if the action could be performed successfully.
654    /// Otherwise, a [`MathError`] is returned if one of the specified columns is not part of its matrix
655    /// or if the number of rows differs.
656    ///
657    /// # Errors and Failures
658    /// - Returns a [`MathError`] of type [`MathError::OutOfBounds`]
659    ///   if the provided column index is not defined within the margins of the matrix.
660    /// - Returns a [`MathError`] of type [`MismatchingMatrixDimension`](MathError::MismatchingMatrixDimension)
661    ///   if the number of rows of `self` and `other` differ.
662    /// - Returns a [`MathError`] of type [`MismatchingModulus`](MathError::MismatchingModulus) if the base types are
663    ///   not compatible. This can only happen if the base types themselves can mismatch.
664    fn set_column(
665        &mut self,
666        col_0: impl TryInto<i64> + Display,
667        other: &Self,
668        col_1: impl TryInto<i64> + Display,
669    ) -> Result<(), MathError> {
670        if !self.compare_base(other) {
671            return Err(self.call_compare_base_error(other).unwrap());
672        }
673
674        let num_rows_0 = self.get_num_rows();
675        let num_rows_1 = other.get_num_rows();
676        if num_rows_0 != num_rows_1 {
677            return Err(MathError::MismatchingMatrixDimension(format!(
678                "as set_row was called on two matrices with different number of rows/columns {num_rows_0} and {num_rows_1}",
679            )));
680        }
681
682        let col_0 = evaluate_index_for_vector(col_0, self.get_num_columns())?;
683        let col_1 = evaluate_index_for_vector(col_1, other.get_num_columns())?;
684
685        unsafe {
686            self.set_column_unchecked(col_0, other, col_1);
687        }
688
689        Ok(())
690    }
691
692    /// Sets a column of the given matrix to the provided column of `other`.
693    ///
694    /// Parameters:
695    /// - `col_0`: specifies the column of `self` that should be modified
696    /// - `other`: specifies the matrix providing the column replacing the column in `self`
697    /// - `col_1`: specifies the column of `other` providing
698    ///   the values replacing the original column in `self`
699    ///
700    /// # Safety
701    /// To use this function safely, make sure that the selected columns are part
702    /// of the matrices, the columns are of the same length and the base types are the same.
703    /// If not, memory leaks, unexpected panics, etc. might occur.
704    unsafe fn set_column_unchecked(&mut self, col_0: i64, other: &Self, col_1: i64) {
705        unsafe {
706            self.set_submatrix_unchecked(
707                0,
708                col_0,
709                self.get_num_rows(),
710                col_0 + 1,
711                other,
712                0,
713                col_1,
714                self.get_num_rows(),
715                col_1 + 1,
716            );
717        }
718    }
719
720    /// Sets the matrix entries in `self` to entries defined in `other`.
721    /// The entries in `self` starting from `(row_self_start, col_self_start)` are set to be
722    /// the entries from the submatrix from `other` defined by `(row_other_start, col_other_start)`
723    /// to `(row_other_end, col_other_end)` (inclusively).
724    /// The original matrix must have sufficiently many entries to contain the defined submatrix.
725    ///
726    /// Parameters:
727    /// `row_self_start`: the starting row of the matrix in which to set a submatrix
728    /// `col_self_start`: the starting column of the matrix in which to set a submatrix
729    /// `other`: the matrix from where to take the submatrix to set
730    /// `row_other_start`: the starting row of the specified submatrix
731    /// `col_other_start`: the starting column of the specified submatrix
732    /// `row_other_end`: the ending row of the specified submatrix
733    /// `col_other_end`:the ending column of the specified submatrix
734    ///
735    /// Negative indices can be used to index from the back, e.g., `-1` for
736    /// the last element, but after conversion they must be within the matrix dimensions.
737    ///
738    /// Sets the submatrix of `self`, starting from the specified starting row and column
739    /// to the submatrix defined in `other` by the provided indices (inclusively).
740    /// Errors can occur if the provided indices are not within the dimensions of the provided matrices,
741    /// the bases of the matrices are not compatible, e.g. different modulus or if the `self` can not
742    /// contain the specified submatrix from `other`.
743    ///
744    /// # Errors and Failures
745    /// - Returns a [`MathError`] of type [`MathError::OutOfBounds`]
746    ///   if any provided row or column is larger than the matrix or if entries of `self` would have to be
747    ///   set that are not within `self`.
748    /// - Returns a [`MathError`] of type [`MismatchingModulus`](MathError::MismatchingModulus) if the base types are
749    ///   not compatible. This can only happen if the base types themselves can mismatch.
750    ///
751    /// # Panics ...
752    /// - if `row_other_start > row_other_end` or `col_other_start > col_other_end`.
753    #[allow(clippy::too_many_arguments)]
754    fn set_submatrix(
755        &mut self,
756        row_self_start: impl TryInto<i64> + Display,
757        col_self_start: impl TryInto<i64> + Display,
758        other: &Self,
759        row_other_start: impl TryInto<i64> + Display,
760        col_other_start: impl TryInto<i64> + Display,
761        row_other_end: impl TryInto<i64> + Display,
762        col_other_end: impl TryInto<i64> + Display,
763    ) -> Result<(), MathError> {
764        if !self.compare_base(other) {
765            return Err(self.call_compare_base_error(other).unwrap());
766        }
767
768        let (row_self_start, col_self_start) =
769            evaluate_indices_for_matrix(self, row_self_start, col_self_start)?;
770        let (row_other_start, col_other_start) =
771            evaluate_indices_for_matrix(other, row_other_start, col_other_start)?;
772        let (row_other_end, col_other_end) =
773            evaluate_indices_for_matrix(other, row_other_end, col_other_end)?;
774
775        assert!(
776            row_other_end >= row_other_start,
777            "The number of rows must be positive, i.e. row_other_end ({row_other_end}) must be greater or equal row_other_start ({row_other_start})"
778        );
779
780        assert!(
781            col_other_end >= col_other_start,
782            "The number of columns must be positive, i.e. col_other_end ({col_other_end}) must be greater or equal col_other_start ({col_other_start})"
783        );
784
785        // increase both values to have an inclusive capturing of the matrix entries
786        let nr_rows = row_other_end - row_other_start;
787        let nr_cols = col_other_end - col_other_start;
788        // check if all entries that have to be set are contained in `self`
789        let row_self_end =
790            evaluate_index_for_vector(row_self_start + nr_rows, self.get_num_rows())?;
791        let col_self_end =
792            evaluate_index_for_vector(col_self_start + nr_cols, self.get_num_columns())?;
793        let (row_other_end, col_other_end) = (row_other_end + 1, col_other_end + 1);
794        let (row_self_end, col_self_end) = (row_self_end + 1, col_self_end + 1);
795
796        unsafe {
797            self.set_submatrix_unchecked(
798                row_self_start,
799                col_self_start,
800                row_self_end,
801                col_self_end,
802                other,
803                row_other_start,
804                col_other_start,
805                row_other_end,
806                col_other_end,
807            );
808        }
809
810        Ok(())
811    }
812
813    /// Sets the matrix entries in `self` to entries defined in `other`.
814    /// The entries in `self` starting from `(row_self_start, col_self_start)` up to
815    /// `(row_self_end, col_self_end)`are set to be
816    /// the entries from the submatrix from `other` defined by `(row_other_start, col_other_start)`
817    /// to `(row_other_end, col_other_end)` (exclusively).
818    ///
819    /// Parameters:
820    /// `row_self_start`: the starting row of the matrix in which to set a submatrix
821    /// `col_self_start`: the starting column of the matrix in which to set a submatrix
822    /// `other`: the matrix from where to take the submatrix to set
823    /// `row_other_start`: the starting row of the specified submatrix
824    /// `col_other_start`: the starting column of the specified submatrix
825    /// `row_other_end`: the ending row of the specified submatrix
826    /// `col_other_end`:the ending column of the specified submatrix
827    ///
828    /// # Safety
829    /// To use this function safely, make sure that the selected submatrices are part
830    /// of the matrices, the submatrices are of the same dimensions and the base types are the same.
831    /// If not, memory leaks, unexpected panics, etc. might occur.
832    #[allow(clippy::too_many_arguments)]
833    unsafe fn set_submatrix_unchecked(
834        &mut self,
835        row_self_start: i64,
836        col_self_start: i64,
837        row_self_end: i64,
838        col_self_end: i64,
839        other: &Self,
840        row_other_start: i64,
841        col_other_start: i64,
842        row_other_end: i64,
843        col_other_end: i64,
844    );
845}
846
847pub trait MatrixSwaps {
848    /// Swaps two entries of the specified matrix.
849    ///
850    /// Parameters:
851    /// - `row_0`: specifies the row, in which the first entry is located
852    /// - `col_0`: specifies the column, in which the first entry is located
853    /// - `row_1`: specifies the row, in which the second entry is located
854    /// - `col_1`: specifies the column, in which the second entry is located
855    ///
856    /// Returns an empty `Ok` if the action could be performed successfully.
857    /// Otherwise, a [`MathError`] is returned if one of the specified entries is not part of the matrix.
858    ///
859    /// # Errors and Failures
860    /// - Returns a [`MathError`] of type [`MathError::OutOfBounds`]
861    ///   if row or column are greater than the matrix size.
862    fn swap_entries(
863        &mut self,
864        row_0: impl TryInto<i64> + Display,
865        col_0: impl TryInto<i64> + Display,
866        row_1: impl TryInto<i64> + Display,
867        col_1: impl TryInto<i64> + Display,
868    ) -> Result<(), MathError>;
869
870    /// Swaps two rows of the specified matrix.
871    ///
872    /// Parameters:
873    /// - `row_0`: specifies the first row which is swapped with the second one
874    /// - `row_1`: specifies the second row which is swapped with the first one
875    ///
876    /// Returns an empty `Ok` if the action could be performed successfully.
877    /// Otherwise, a [`MathError`] is returned if one of the specified rows is not part of the matrix.
878    ///
879    /// # Errors and Failures
880    /// - Returns a [`MathError`] of type [`OutOfBounds`](MathError::OutOfBounds)
881    ///   if one of the given rows is not in the matrix.
882    fn swap_rows(
883        &mut self,
884        row_0: impl TryInto<i64> + Display,
885        row_1: impl TryInto<i64> + Display,
886    ) -> Result<(), MathError>;
887
888    /// Swaps two columns of the specified matrix.
889    ///
890    /// Parameters:
891    /// - `col_0`: specifies the first column which is swapped with the second one
892    /// - `col_1`: specifies the second column which is swapped with the first one
893    ///
894    /// Returns an empty `Ok` if the action could be performed successfully.
895    /// Otherwise, a [`MathError`] is returned if one of the specified columns is not part of the matrix.
896    ///
897    /// # Errors and Failures
898    /// - Returns a [`MathError`] of type [`OutOfBounds`](MathError::OutOfBounds)
899    ///   if one of the given columns is not in the matrix.
900    fn swap_columns(
901        &mut self,
902        col_0: impl TryInto<i64> + Display,
903        col_1: impl TryInto<i64> + Display,
904    ) -> Result<(), MathError>;
905}
906
907/// Is implemented by matrices to compute the tensor product.
908pub trait Tensor {
909    /// Computes the tensor product of `self` with `other`
910    ///
911    /// Parameters:
912    /// - `other`: the value with which the tensor product is computed.
913    ///
914    /// Returns the tensor product
915    fn tensor_product(&self, other: &Self) -> Self;
916}
917
918/// Is implemented by matrices to concatenate them.
919pub trait Concatenate {
920    type Output;
921
922    /// Concatenates `self` with `other` vertically.
923    ///
924    /// Parameters:
925    /// - `other`: the other matrix to concatenate with `self`
926    ///
927    /// # Errors and Failures
928    /// - Returns a [`MathError`] of type
929    ///   [`MismatchingMatrixDimension`](MathError::MismatchingMatrixDimension)
930    ///   if the matrices can not be concatenated due to mismatching dimensions
931    fn concat_vertical(self, other: Self) -> Result<Self::Output, MathError>;
932
933    /// Concatenates `self` with `other` horizontally.
934    ///
935    /// Parameters:
936    /// - `other`: the other matrix to concatenate with `self`
937    ///
938    /// # Errors and Failures
939    /// - Returns a [`MathError`] of type
940    ///   [`MismatchingMatrixDimension`](MathError::MismatchingMatrixDimension)
941    ///   if the matrices can not be concatenated due to mismatching dimensions
942    fn concat_horizontal(self, other: Self) -> Result<Self::Output, MathError>;
943}
944
945/// Is implemented by basic types to calculate distances.
946pub trait Distance<T = Self> {
947    type Output;
948
949    /// Computes the absolute distance between two values.
950    ///
951    /// Parameters:
952    /// - `other`: specifies the value whose distance is calculated to `self`
953    ///
954    /// Returns the absolute difference, i.e. distance between the two given values
955    /// as a new instance.
956    fn distance(&self, other: T) -> Self::Output;
957}
958
959/// Is implemented by [`Z`](crate::integer::Z) instances to compute the `lcm`.
960pub trait Lcm<T = Self> {
961    type Output;
962
963    /// Outputs the least common multiple (lcm) of the two given values
964    /// with `lcm(a, 0) = 0`.
965    ///
966    /// Parameters:
967    /// - `other`: specifies one of the values of which the `lcm` is computed
968    ///
969    /// Returns the least common multiple of `self` and `other` as a new value.
970    fn lcm(&self, other: T) -> Self::Output;
971}
972
973/// Is implemented by basic types to raise a value to the power of another.
974pub trait Pow<T> {
975    type Output;
976
977    /// Raises the value of `self` to the power of an `exp`.
978    ///
979    /// Parameters:
980    /// - `exp`: specifies the exponent to which the value is raised
981    ///
982    /// Returns the value of `self` powered by `exp` as a new `Output` instance.
983    fn pow(&self, exp: T) -> Result<Self::Output, MathError>;
984}
985
986/// Is implemented by [`Z`](crate::integer::Z) instances to calculate the `gcd`
987pub trait Gcd<T = Self> {
988    type Output;
989
990    /// Outputs the greatest common divisor (gcd) of the two given values
991    /// with `gcd(a, 0) = |a|`.
992    ///
993    /// Parameters:
994    /// - `other`: specifies one of the values of which the gcd is computed
995    ///
996    /// Returns the greatest common divisor of `self` and `other`.
997    fn gcd(&self, other: T) -> Self::Output;
998}
999
1000/// Is implemented by [`Z`](crate::integer::Z) instances to calculate the
1001/// extended `gcd`
1002pub trait Xgcd<T = Self> {
1003    type Output;
1004
1005    /// Outputs the extended greatest common divisor (xgcd) of the two given values,
1006    /// i.e. a triple `(gcd(a, b), x, y)`, where `a*x + b*y = gcd(a, b)*`.
1007    ///
1008    /// Parameters:
1009    /// - `other`: specifies one of the values of which the gcd is computed
1010    ///
1011    /// Returns a triple `(gcd(a, b), x, y)` containing the greatest common divisor,
1012    /// `x`, and `y` s.t. `gcd(a, b) = a*x + b*y`.
1013    fn xgcd(&self, other: T) -> Self::Output;
1014}
1015
1016/// This is a trait to abstract Integers.
1017///
1018/// It is implemented by [`Z`](crate::integer::Z), [`Zq`](crate::integer_mod_q::Zq),
1019/// [`Modulus`](crate::integer_mod_q::Modulus),
1020/// and rust's 8, 16, 32, and 64 bit signed and unsigned integers.
1021/// The implementations exist for their owned and borrowed variants.
1022///
1023/// # Safety
1024/// Handling [`fmpz`] directly requires thinking about memory issues.
1025/// Read the documentation of the functions carefully before you use them.
1026pub(crate) unsafe trait AsInteger {
1027    /// Returns an [`fmpz`] representing the value.
1028    /// Data about the original object might not be contained in the return value.
1029    /// For example, [`Zq`](crate::integer_mod_q::Zq)'s return value does not
1030    /// contain Information about the modulus.
1031    ///
1032    /// # Safety
1033    /// The caller has to ensure that the returned [`fmpz`] is cleared properly.
1034    /// This is not happening automatically.
1035    /// Not clearing the [`fmpz`] is a memory leak.
1036    unsafe fn into_fmpz(self) -> fmpz;
1037
1038    /// Returns a reference to an internal [`fmpz`] that represents the value.
1039    /// If the data type does not contain an [`fmpz`] completely [`None`] is returned.
1040    ///
1041    /// It is intended to be used when a read only [`fmpz`] reference is required
1042    /// for a Flint function call.
1043    /// If the data type does not contain an [`fmpz`], [`into_fmpz`](AsInteger::into_fmpz)
1044    /// can be used instead.
1045    fn get_fmpz_ref(&self) -> Option<&fmpz> {
1046        None
1047    }
1048}
1049
1050/// Is implemented by polynomials to receive a matrix representation of their coefficients.
1051pub trait IntoCoefficientEmbedding<T> {
1052    /// Returns a canonical coefficient embedding of the value,
1053    /// e.g. a matrix representation of the coefficients of a polynomial.
1054    ///
1055    /// Parameters:
1056    /// - `size`: determines the length of the object in which the coefficients are
1057    ///   embedded, e.g. length of the vector
1058    fn into_coefficient_embedding(self, size: impl Into<i64>) -> T;
1059}
1060
1061/// Is implemented by polynomials to reverse the coefficient embedding.
1062pub trait FromCoefficientEmbedding<T> {
1063    /// Reverses the coefficient embedding, e.g. takes as input a vector and
1064    /// returns a polynomial.
1065    ///
1066    /// Parameters:
1067    /// - `embedding`: the coefficient embedding
1068    fn from_coefficient_embedding(embedding: T) -> Self;
1069}