Skip to main content

malachite_nz/integer_vector/comparison/
entrywise_min.rs

1// Copyright © 2026 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::integer_vector::IntegerVector;
10use core::cmp::min;
11use malachite_base::num::arithmetic::traits::{EntrywiseMin, EntrywiseMinAssign};
12
13fn assert_same_dimension(v: &IntegerVector, w: &IntegerVector) {
14    assert_eq!(
15        v.elements.len(),
16        w.elements.len(),
17        "cannot take the entrywise minimum of vectors of different dimensions"
18    );
19}
20
21impl EntrywiseMin<Self> for IntegerVector {
22    type Output = Self;
23
24    /// Takes the entrywise minimum of two [`IntegerVector`]s, taking the first by value and the
25    /// second by value.
26    ///
27    /// Every element of the result is the smaller of the corresponding elements of the two vectors,
28    /// so the result has the same dimension as both.
29    ///
30    /// $$
31    /// f(v, w) = (\min(v_0, w_0), \min(v_1, w_1), \ldots, \min(v_{n-1}, w_{n-1})).
32    /// $$
33    ///
34    /// # Worst-case complexity
35    /// $T(n) = O(n)$
36    ///
37    /// $M(n) = O(1)$
38    ///
39    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
40    /// elements of both vectors.
41    ///
42    /// # Panics
43    /// Panics if `self` and `other` have different dimensions.
44    ///
45    /// # Examples
46    /// ```
47    /// use core::str::FromStr;
48    /// use malachite_base::num::arithmetic::traits::EntrywiseMin;
49    /// use malachite_nz::integer_vector::IntegerVector;
50    ///
51    /// let v = IntegerVector::from_str("(1, -5, 3)").unwrap();
52    /// let w = IntegerVector::from_str("(-4, 2, 3)").unwrap();
53    /// assert_eq!(v.entrywise_min(w).to_string(), "(-4, -5, 3)");
54    /// ```
55    ///
56    /// This is equivalent to `_fmpz_vec_min` from `fmpz_vec/min.c`, FLINT 3.6.0.
57    #[inline]
58    fn entrywise_min(mut self, other: Self) -> Self {
59        self.entrywise_min_assign(other);
60        self
61    }
62}
63
64impl EntrywiseMin<&Self> for IntegerVector {
65    type Output = Self;
66
67    /// Takes the entrywise minimum of two [`IntegerVector`]s, taking the first by value and the
68    /// second by reference.
69    ///
70    /// See the documentation for the [`EntrywiseMin`] implementation that takes both vectors by
71    /// value for details.
72    ///
73    /// # Worst-case complexity
74    /// $T(n) = O(n)$
75    ///
76    /// $M(n) = O(1)$
77    ///
78    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
79    /// elements of both vectors.
80    ///
81    /// # Panics
82    /// Panics if `self` and `other` have different dimensions.
83    ///
84    /// # Examples
85    /// ```
86    /// use core::str::FromStr;
87    /// use malachite_base::num::arithmetic::traits::EntrywiseMin;
88    /// use malachite_nz::integer_vector::IntegerVector;
89    ///
90    /// let v = IntegerVector::from_str("(1, -5, 3)").unwrap();
91    /// let w = IntegerVector::from_str("(-4, 2, 3)").unwrap();
92    /// assert_eq!(v.entrywise_min(&w).to_string(), "(-4, -5, 3)");
93    /// ```
94    ///
95    /// This is equivalent to `_fmpz_vec_min` from `fmpz_vec/min.c`, FLINT 3.6.0.
96    #[inline]
97    fn entrywise_min(mut self, other: &Self) -> Self {
98        self.entrywise_min_assign(other);
99        self
100    }
101}
102
103impl EntrywiseMin<IntegerVector> for &IntegerVector {
104    type Output = IntegerVector;
105
106    /// Takes the entrywise minimum of two [`IntegerVector`]s, taking the first by reference and the
107    /// second by value.
108    ///
109    /// See the documentation for the [`EntrywiseMin`] implementation that takes both vectors by
110    /// value for details.
111    ///
112    /// # Worst-case complexity
113    /// $T(n) = O(n)$
114    ///
115    /// $M(n) = O(1)$
116    ///
117    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
118    /// elements of both vectors.
119    ///
120    /// # Panics
121    /// Panics if `self` and `other` have different dimensions.
122    ///
123    /// # Examples
124    /// ```
125    /// use core::str::FromStr;
126    /// use malachite_base::num::arithmetic::traits::EntrywiseMin;
127    /// use malachite_nz::integer_vector::IntegerVector;
128    ///
129    /// let v = IntegerVector::from_str("(1, -5, 3)").unwrap();
130    /// let w = IntegerVector::from_str("(-4, 2, 3)").unwrap();
131    /// assert_eq!((&v).entrywise_min(w).to_string(), "(-4, -5, 3)");
132    /// ```
133    ///
134    /// This is equivalent to `_fmpz_vec_min` from `fmpz_vec/min.c`, FLINT 3.6.0.
135    #[inline]
136    fn entrywise_min(self, mut other: IntegerVector) -> IntegerVector {
137        // The minimum is symmetric, so the owned vector can hold the result.
138        other.entrywise_min_assign(self);
139        other
140    }
141}
142
143impl EntrywiseMin<&IntegerVector> for &IntegerVector {
144    type Output = IntegerVector;
145
146    /// Takes the entrywise minimum of two [`IntegerVector`]s, taking the first by reference and the
147    /// second by reference.
148    ///
149    /// See the documentation for the [`EntrywiseMin`] implementation that takes both vectors by
150    /// value for details.
151    ///
152    /// # Worst-case complexity
153    /// $T(n) = O(n)$
154    ///
155    /// $M(n) = O(n)$
156    ///
157    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
158    /// elements of both vectors.
159    ///
160    /// # Panics
161    /// Panics if `self` and `other` have different dimensions.
162    ///
163    /// # Examples
164    /// ```
165    /// use core::str::FromStr;
166    /// use malachite_base::num::arithmetic::traits::EntrywiseMin;
167    /// use malachite_nz::integer_vector::IntegerVector;
168    ///
169    /// let v = IntegerVector::from_str("(1, -5, 3)").unwrap();
170    /// let w = IntegerVector::from_str("(-4, 2, 3)").unwrap();
171    /// assert_eq!((&v).entrywise_min(&w).to_string(), "(-4, -5, 3)");
172    /// ```
173    ///
174    /// This is equivalent to `_fmpz_vec_min` from `fmpz_vec/min.c`, FLINT 3.6.0.
175    fn entrywise_min(self, other: &IntegerVector) -> IntegerVector {
176        assert_same_dimension(self, other);
177        IntegerVector {
178            elements: self
179                .elements
180                .iter()
181                .zip(&other.elements)
182                .map(|(x, y)| min(x, y).clone())
183                .collect(),
184        }
185    }
186}
187
188impl EntrywiseMinAssign<Self> for IntegerVector {
189    /// Replaces an [`IntegerVector`] by its entrywise minimum with another [`IntegerVector`],
190    /// taking the other by value.
191    ///
192    /// Every element becomes the smaller of itself and the corresponding element of `other`.
193    ///
194    /// # Worst-case complexity
195    /// $T(n) = O(n)$
196    ///
197    /// $M(n) = O(1)$
198    ///
199    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
200    /// elements of both vectors.
201    ///
202    /// # Panics
203    /// Panics if `self` and `other` have different dimensions.
204    ///
205    /// # Examples
206    /// ```
207    /// use core::str::FromStr;
208    /// use malachite_base::num::arithmetic::traits::EntrywiseMinAssign;
209    /// use malachite_nz::integer_vector::IntegerVector;
210    ///
211    /// let mut v = IntegerVector::from_str("(1, -5, 3)").unwrap();
212    /// let w = IntegerVector::from_str("(-4, 2, 3)").unwrap();
213    /// v.entrywise_min_assign(w);
214    /// assert_eq!(v.to_string(), "(-4, -5, 3)");
215    /// ```
216    ///
217    /// This is equivalent to `_fmpz_vec_min_inplace` from `fmpz_vec/min.c`, FLINT 3.6.0.
218    fn entrywise_min_assign(&mut self, other: Self) {
219        assert_same_dimension(self, &other);
220        for (x, y) in self.elements.iter_mut().zip(other.elements) {
221            if y < *x {
222                *x = y;
223            }
224        }
225    }
226}
227
228impl EntrywiseMinAssign<&Self> for IntegerVector {
229    /// Replaces an [`IntegerVector`] by its entrywise minimum with another [`IntegerVector`],
230    /// taking the other by reference.
231    ///
232    /// Every element becomes the smaller of itself and the corresponding element of `other`.
233    ///
234    /// # Worst-case complexity
235    /// $T(n) = O(n)$
236    ///
237    /// $M(n) = O(n)$
238    ///
239    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
240    /// elements of both vectors.
241    ///
242    /// # Panics
243    /// Panics if `self` and `other` have different dimensions.
244    ///
245    /// # Examples
246    /// ```
247    /// use core::str::FromStr;
248    /// use malachite_base::num::arithmetic::traits::EntrywiseMinAssign;
249    /// use malachite_nz::integer_vector::IntegerVector;
250    ///
251    /// let mut v = IntegerVector::from_str("(1, -5, 3)").unwrap();
252    /// let w = IntegerVector::from_str("(-4, 2, 3)").unwrap();
253    /// v.entrywise_min_assign(&w);
254    /// assert_eq!(v.to_string(), "(-4, -5, 3)");
255    /// ```
256    ///
257    /// This is equivalent to `_fmpz_vec_min_inplace` from `fmpz_vec/min.c`, FLINT 3.6.0.
258    fn entrywise_min_assign(&mut self, other: &Self) {
259        assert_same_dimension(self, other);
260        for (x, y) in self.elements.iter_mut().zip(&other.elements) {
261            if y < x {
262                x.clone_from(y);
263            }
264        }
265    }
266}