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}