Skip to main content

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}