malachite_base/unsigned_vector/arithmetic/content.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::num::arithmetic::traits::{
10 Content, ContentAndPrimitivePart, PrimitivePart, PrimitivePartAssign,
11};
12use crate::num::basic::unsigneds::PrimitiveUnsigned;
13use crate::unsigned_vector::UnsignedVector;
14
15// The GCD of the elements. It stops as soon as it reaches 1, since nothing can lower it further.
16pub(crate) fn content<T: PrimitiveUnsigned>(coefficients: &[T]) -> T {
17 let mut gcd = T::ZERO;
18 for &c in coefficients {
19 gcd.gcd_assign(c);
20 if gcd == T::ONE {
21 break;
22 }
23 }
24 gcd
25}
26
27// Divides every element by the content, which divides each of them exactly.
28pub(crate) fn divide_by_content<T: PrimitiveUnsigned>(coefficients: &mut [T], content: T) {
29 if content > T::ONE {
30 for c in coefficients {
31 c.div_exact_assign(content);
32 }
33 }
34}
35
36impl<T: PrimitiveUnsigned> Content for UnsignedVector<T> {
37 type Output = T;
38
39 /// Computes the content of an [`UnsignedVector`], the GCD of its elements, taking the vector by
40 /// value.
41 ///
42 /// The content of the 0-dimensional vector, and of a vector of zeros, is zero. The GCD is taken
43 /// element by element, stopping early once it reaches 1.
44 ///
45 /// $$
46 /// f(v) = \gcd(v_0, v_1, \ldots, v_{n-1}),
47 /// $$
48 ///
49 /// where $n$ is the dimension of $v$.
50 ///
51 /// # Worst-case complexity
52 /// $T(n) = O(n)$
53 ///
54 /// $M(n) = O(1)$
55 ///
56 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
57 ///
58 /// # Examples
59 /// ```
60 /// use core::str::FromStr;
61 /// use malachite_base::num::arithmetic::traits::Content;
62 /// use malachite_base::unsigned_vector::UnsignedVector;
63 ///
64 /// let v = UnsignedVector::<u8>::from_str("(6, 4, 10)").unwrap();
65 /// assert_eq!(v.content(), 2);
66 /// assert_eq!(UnsignedVector::<u8>::from_str("()").unwrap().content(), 0);
67 /// ```
68 ///
69 /// This is equivalent to `_fmpz_vec_content` from `fmpz_vec/content.c`, FLINT 3.6.0.
70 #[inline]
71 fn content(self) -> T {
72 content(&self.elements)
73 }
74}
75
76impl<T: PrimitiveUnsigned> Content for &UnsignedVector<T> {
77 type Output = T;
78
79 /// Computes the content of an [`UnsignedVector`], the GCD of its elements, taking the vector by
80 /// reference.
81 ///
82 /// The content of the 0-dimensional vector, and of a vector of zeros, is zero. The GCD is taken
83 /// element by element, stopping early once it reaches 1.
84 ///
85 /// $$
86 /// f(v) = \gcd(v_0, v_1, \ldots, v_{n-1}),
87 /// $$
88 ///
89 /// where $n$ is the dimension of $v$.
90 ///
91 /// # Worst-case complexity
92 /// $T(n) = O(n)$
93 ///
94 /// $M(n) = O(1)$
95 ///
96 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
97 ///
98 /// # Examples
99 /// ```
100 /// use core::str::FromStr;
101 /// use malachite_base::num::arithmetic::traits::Content;
102 /// use malachite_base::unsigned_vector::UnsignedVector;
103 ///
104 /// let v = UnsignedVector::<u8>::from_str("(6, 4, 10)").unwrap();
105 /// assert_eq!((&v).content(), 2);
106 /// assert_eq!(
107 /// (&UnsignedVector::<u8>::from_str("(0, 0)").unwrap()).content(),
108 /// 0
109 /// );
110 /// ```
111 ///
112 /// This is equivalent to `_fmpz_vec_content` from `fmpz_vec/content.c`, FLINT 3.6.0.
113 #[inline]
114 fn content(self) -> T {
115 content(&self.elements)
116 }
117}
118
119impl<T: PrimitiveUnsigned> PrimitivePart for UnsignedVector<T> {
120 type Output = Self;
121
122 /// Computes the primitive part of an [`UnsignedVector`], taking the vector by value.
123 ///
124 /// This is the vector divided by its content. The elements are non-negative, so this is also
125 /// the [`CanonicalPrimitivePart`](crate::num::arithmetic::traits::CanonicalPrimitivePart).
126 ///
127 /// $$
128 /// v = \operatorname{cont}(v) \operatorname{pp}(v).
129 /// $$
130 ///
131 /// The primitive part of a vector of zeros is itself, keeping its dimension.
132 ///
133 /// # Worst-case complexity
134 /// $T(n) = O(n)$
135 ///
136 /// $M(n) = O(1)$
137 ///
138 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
139 ///
140 /// # Examples
141 /// ```
142 /// use core::str::FromStr;
143 /// use malachite_base::num::arithmetic::traits::PrimitivePart;
144 /// use malachite_base::unsigned_vector::UnsignedVector;
145 ///
146 /// let v = UnsignedVector::<u8>::from_str("(6, 4, 10)").unwrap();
147 /// assert_eq!(v.primitive_part().to_string(), "(3, 2, 5)");
148 /// assert_eq!(
149 /// UnsignedVector::<u8>::from_str("(0, 0)")
150 /// .unwrap()
151 /// .primitive_part()
152 /// .to_string(),
153 /// "(0, 0)"
154 /// );
155 /// ```
156 #[inline]
157 fn primitive_part(mut self) -> Self {
158 self.primitive_part_assign();
159 self
160 }
161}
162
163impl<T: PrimitiveUnsigned> PrimitivePart for &UnsignedVector<T> {
164 type Output = UnsignedVector<T>;
165
166 /// Computes the primitive part of an [`UnsignedVector`], taking the vector by reference.
167 ///
168 /// This is the vector divided by its content. The elements are non-negative, so this is also
169 /// the [`CanonicalPrimitivePart`](crate::num::arithmetic::traits::CanonicalPrimitivePart).
170 ///
171 /// $$
172 /// v = \operatorname{cont}(v) \operatorname{pp}(v).
173 /// $$
174 ///
175 /// The primitive part of a vector of zeros is itself, keeping its dimension.
176 ///
177 /// # Worst-case complexity
178 /// $T(n) = O(n)$
179 ///
180 /// $M(n) = O(n)$
181 ///
182 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
183 ///
184 /// # Examples
185 /// ```
186 /// use core::str::FromStr;
187 /// use malachite_base::num::arithmetic::traits::PrimitivePart;
188 /// use malachite_base::unsigned_vector::UnsignedVector;
189 ///
190 /// let v = UnsignedVector::<u8>::from_str("(6, 4, 10)").unwrap();
191 /// assert_eq!((&v).primitive_part().to_string(), "(3, 2, 5)");
192 /// ```
193 #[inline]
194 fn primitive_part(self) -> UnsignedVector<T> {
195 let content = content(&self.elements);
196 let mut elements = self.elements.clone();
197 divide_by_content(&mut elements, content);
198 UnsignedVector { elements }
199 }
200}
201
202impl<T: PrimitiveUnsigned> PrimitivePartAssign for UnsignedVector<T> {
203 /// Replaces an [`UnsignedVector`] with its primitive part, the vector divided by its content.
204 ///
205 /// See [`primitive_part`](PrimitivePart::primitive_part).
206 ///
207 /// # Worst-case complexity
208 /// $T(n) = O(n)$
209 ///
210 /// $M(n) = O(1)$
211 ///
212 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
213 ///
214 /// # Examples
215 /// ```
216 /// use core::str::FromStr;
217 /// use malachite_base::num::arithmetic::traits::PrimitivePartAssign;
218 /// use malachite_base::unsigned_vector::UnsignedVector;
219 ///
220 /// let mut v = UnsignedVector::<u8>::from_str("(6, 4, 10)").unwrap();
221 /// v.primitive_part_assign();
222 /// assert_eq!(v.to_string(), "(3, 2, 5)");
223 /// ```
224 #[inline]
225 fn primitive_part_assign(&mut self) {
226 let content = content(&self.elements);
227 divide_by_content(&mut self.elements, content);
228 }
229}
230
231impl<T: PrimitiveUnsigned> ContentAndPrimitivePart for UnsignedVector<T> {
232 type Content = T;
233 type PrimitivePart = Self;
234
235 /// Computes the content and the primitive part of an [`UnsignedVector`] together, taking the
236 /// vector by value.
237 ///
238 /// See [`content`](Content::content) and [`primitive_part`](PrimitivePart::primitive_part); the
239 /// content is found once rather than twice.
240 ///
241 /// # Worst-case complexity
242 /// $T(n) = O(n)$
243 ///
244 /// $M(n) = O(1)$
245 ///
246 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
247 ///
248 /// # Examples
249 /// ```
250 /// use core::str::FromStr;
251 /// use malachite_base::num::arithmetic::traits::ContentAndPrimitivePart;
252 /// use malachite_base::unsigned_vector::UnsignedVector;
253 ///
254 /// let v = UnsignedVector::<u8>::from_str("(6, 4, 10)").unwrap();
255 /// let (content, primitive_part) = v.content_and_primitive_part();
256 /// assert_eq!(content, 2);
257 /// assert_eq!(primitive_part.to_string(), "(3, 2, 5)");
258 /// ```
259 #[inline]
260 fn content_and_primitive_part(mut self) -> (T, Self) {
261 let content = content(&self.elements);
262 divide_by_content(&mut self.elements, content);
263 (content, self)
264 }
265}
266
267impl<T: PrimitiveUnsigned> ContentAndPrimitivePart for &UnsignedVector<T> {
268 type Content = T;
269 type PrimitivePart = UnsignedVector<T>;
270
271 /// Computes the content and the primitive part of an [`UnsignedVector`] together, taking the
272 /// vector by reference.
273 ///
274 /// See [`content`](Content::content) and [`primitive_part`](PrimitivePart::primitive_part); the
275 /// content is found once rather than twice.
276 ///
277 /// # Worst-case complexity
278 /// $T(n) = O(n)$
279 ///
280 /// $M(n) = O(n)$
281 ///
282 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
283 ///
284 /// # Examples
285 /// ```
286 /// use core::str::FromStr;
287 /// use malachite_base::num::arithmetic::traits::ContentAndPrimitivePart;
288 /// use malachite_base::unsigned_vector::UnsignedVector;
289 ///
290 /// let v = UnsignedVector::<u8>::from_str("(6, 4, 10)").unwrap();
291 /// let (content, primitive_part) = (&v).content_and_primitive_part();
292 /// assert_eq!(content, 2);
293 /// assert_eq!(primitive_part.to_string(), "(3, 2, 5)");
294 /// ```
295 #[inline]
296 fn content_and_primitive_part(self) -> (T, UnsignedVector<T>) {
297 let content = content(&self.elements);
298 let mut elements = self.elements.clone();
299 divide_by_content(&mut elements, content);
300 (content, UnsignedVector { elements })
301 }
302}