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}