Skip to main content

malachite_nz/integer_vector/arithmetic/
content_chained.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::Integer;
10use crate::integer_vector::IntegerVector;
11use crate::natural::Natural;
12use malachite_base::num::arithmetic::traits::{ContentChained, Gcd, GcdAssign};
13use malachite_base::num::basic::traits::One;
14
15// Returns the GCD of `gcd` and the absolute values of the elements of `xs`, where `abs` gives the
16// absolute value of an element.
17//
18// This is equivalent to `_fmpz_vec_content_chained` from `fmpz_vec/content_chained.c`, FLINT 3.6.0.
19pub(crate) fn content_chained_helper<T>(
20    xs: &[T],
21    abs: impl Fn(&T) -> &Natural,
22    mut gcd: Natural,
23) -> Natural {
24    // Zeros make no difference, so they are skipped at both ends.
25    let Some(start) = xs.iter().position(|c| *abs(c) != 0u32) else {
26        return gcd;
27    };
28    let end = xs.iter().rposition(|c| *abs(c) != 0u32).unwrap();
29    let mut xs = &xs[start..=end];
30    // An element of absolute value 1 makes the GCD 1. Only the ends are checked, since for the
31    // coefficients of a polynomial they are the likeliest to be ±1.
32    if let [first, .., last] = xs
33        && (*abs(first) == 1u32 || *abs(last) == 1u32)
34    {
35        return Natural::ONE;
36    }
37    // The elements are taken in pairs from both ends, stopping as soon as the GCD reaches 1.
38    while gcd != 1u32
39        && let [first, middle @ .., last] = xs
40    {
41        gcd.gcd_assign(abs(first).gcd(abs(last)));
42        xs = middle;
43    }
44    if gcd != 1u32
45        && let [middle] = xs
46    {
47        gcd.gcd_assign(abs(middle));
48    }
49    gcd
50}
51
52// Returns the GCD of `x` and the absolute values of the elements of `xs`.
53//
54// This is equivalent to `_fmpz_vec_content_chained` from `fmpz_vec/content_chained.c`, FLINT 3.6.0.
55#[doc(hidden)]
56#[inline]
57pub fn integers_content_chained(xs: &[Integer], x: &Natural) -> Natural {
58    content_chained_helper(xs, Integer::unsigned_abs_ref, x.clone())
59}
60
61impl ContentChained<Natural> for IntegerVector {
62    type Output = Natural;
63
64    /// Computes the GCD of `x` and the elements of an [`IntegerVector`], taking the vector by value
65    /// and `x` by value.
66    ///
67    /// The GCD of `x` and the elements of the 0-dimensional vector, or of a vector of zeros, is
68    /// `x`. The computation stops as soon as the GCD reaches 1.
69    ///
70    /// $$
71    /// f(v, x) = \gcd(x, v_0, v_1, \ldots, v_{n-1}),
72    /// $$
73    ///
74    /// where $n$ is the dimension of $v$.
75    ///
76    /// # Worst-case complexity
77    /// $T(n) = O(n (\log n)^2 \log\log n)$
78    ///
79    /// $M(n) = O(n)$
80    ///
81    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
82    /// elements and of `x`.
83    ///
84    /// # Examples
85    /// ```
86    /// use core::str::FromStr;
87    /// use malachite_base::num::arithmetic::traits::ContentChained;
88    /// use malachite_base::num::basic::traits::Zero;
89    /// use malachite_nz::integer_vector::IntegerVector;
90    /// use malachite_nz::natural::Natural;
91    ///
92    /// let v = IntegerVector::from_str("(-6, 4, -10)").unwrap();
93    /// assert_eq!(v.clone().content_chained(Natural::from(4u32)), 2u32);
94    /// assert_eq!(v.content_chained(Natural::ZERO), 2u32);
95    /// let v = IntegerVector::from_str("()").unwrap();
96    /// assert_eq!(v.content_chained(Natural::from(6u32)), 6u32);
97    /// ```
98    ///
99    /// This is equivalent to `_fmpz_vec_content_chained` from `fmpz_vec/content_chained.c`, FLINT
100    /// 3.6.0.
101    #[inline]
102    fn content_chained(self, x: Natural) -> Natural {
103        content_chained_helper(&self.elements, Integer::unsigned_abs_ref, x)
104    }
105}
106
107impl ContentChained<&Natural> for IntegerVector {
108    type Output = Natural;
109
110    /// Computes the GCD of `x` and the elements of an [`IntegerVector`], taking the vector by value
111    /// and `x` by reference.
112    ///
113    /// The GCD of `x` and the elements of the 0-dimensional vector, or of a vector of zeros, is
114    /// `x`. The computation stops as soon as the GCD reaches 1.
115    ///
116    /// $$
117    /// f(v, x) = \gcd(x, v_0, v_1, \ldots, v_{n-1}),
118    /// $$
119    ///
120    /// where $n$ is the dimension of $v$.
121    ///
122    /// # Worst-case complexity
123    /// $T(n) = O(n (\log n)^2 \log\log n)$
124    ///
125    /// $M(n) = O(n)$
126    ///
127    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
128    /// elements and of `x`.
129    ///
130    /// # Examples
131    /// ```
132    /// use core::str::FromStr;
133    /// use malachite_base::num::arithmetic::traits::ContentChained;
134    /// use malachite_base::num::basic::traits::Zero;
135    /// use malachite_nz::integer_vector::IntegerVector;
136    /// use malachite_nz::natural::Natural;
137    ///
138    /// let v = IntegerVector::from_str("(-6, 4, -10)").unwrap();
139    /// assert_eq!(v.clone().content_chained(&Natural::from(4u32)), 2u32);
140    /// assert_eq!(v.content_chained(&Natural::ZERO), 2u32);
141    /// let v = IntegerVector::from_str("()").unwrap();
142    /// assert_eq!(v.content_chained(&Natural::from(6u32)), 6u32);
143    /// ```
144    ///
145    /// This is equivalent to `_fmpz_vec_content_chained` from `fmpz_vec/content_chained.c`, FLINT
146    /// 3.6.0.
147    #[inline]
148    fn content_chained(self, x: &Natural) -> Natural {
149        content_chained_helper(&self.elements, Integer::unsigned_abs_ref, x.clone())
150    }
151}
152
153impl ContentChained<Natural> for &IntegerVector {
154    type Output = Natural;
155
156    /// Computes the GCD of `x` and the elements of an [`IntegerVector`], taking the vector by
157    /// reference and `x` by value.
158    ///
159    /// The GCD of `x` and the elements of the 0-dimensional vector, or of a vector of zeros, is
160    /// `x`. The computation stops as soon as the GCD reaches 1.
161    ///
162    /// $$
163    /// f(v, x) = \gcd(x, v_0, v_1, \ldots, v_{n-1}),
164    /// $$
165    ///
166    /// where $n$ is the dimension of $v$.
167    ///
168    /// # Worst-case complexity
169    /// $T(n) = O(n (\log n)^2 \log\log n)$
170    ///
171    /// $M(n) = O(n)$
172    ///
173    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
174    /// elements and of `x`.
175    ///
176    /// # Examples
177    /// ```
178    /// use core::str::FromStr;
179    /// use malachite_base::num::arithmetic::traits::ContentChained;
180    /// use malachite_base::num::basic::traits::Zero;
181    /// use malachite_nz::integer_vector::IntegerVector;
182    /// use malachite_nz::natural::Natural;
183    ///
184    /// let v = IntegerVector::from_str("(-6, 4, -10)").unwrap();
185    /// assert_eq!((&v).content_chained(Natural::from(4u32)), 2u32);
186    /// assert_eq!((&v).content_chained(Natural::ZERO), 2u32);
187    /// let v = IntegerVector::from_str("()").unwrap();
188    /// assert_eq!((&v).content_chained(Natural::from(6u32)), 6u32);
189    /// ```
190    ///
191    /// This is equivalent to `_fmpz_vec_content_chained` from `fmpz_vec/content_chained.c`, FLINT
192    /// 3.6.0.
193    #[inline]
194    fn content_chained(self, x: Natural) -> Natural {
195        content_chained_helper(&self.elements, Integer::unsigned_abs_ref, x)
196    }
197}
198
199impl ContentChained<&Natural> for &IntegerVector {
200    type Output = Natural;
201
202    /// Computes the GCD of `x` and the elements of an [`IntegerVector`], taking the vector by
203    /// reference and `x` by reference.
204    ///
205    /// The GCD of `x` and the elements of the 0-dimensional vector, or of a vector of zeros, is
206    /// `x`. The computation stops as soon as the GCD reaches 1.
207    ///
208    /// $$
209    /// f(v, x) = \gcd(x, v_0, v_1, \ldots, v_{n-1}),
210    /// $$
211    ///
212    /// where $n$ is the dimension of $v$.
213    ///
214    /// # Worst-case complexity
215    /// $T(n) = O(n (\log n)^2 \log\log n)$
216    ///
217    /// $M(n) = O(n)$
218    ///
219    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
220    /// elements and of `x`.
221    ///
222    /// # Examples
223    /// ```
224    /// use core::str::FromStr;
225    /// use malachite_base::num::arithmetic::traits::ContentChained;
226    /// use malachite_base::num::basic::traits::Zero;
227    /// use malachite_nz::integer_vector::IntegerVector;
228    /// use malachite_nz::natural::Natural;
229    ///
230    /// let v = IntegerVector::from_str("(-6, 4, -10)").unwrap();
231    /// assert_eq!((&v).content_chained(&Natural::from(4u32)), 2u32);
232    /// assert_eq!((&v).content_chained(&Natural::ZERO), 2u32);
233    /// let v = IntegerVector::from_str("()").unwrap();
234    /// assert_eq!((&v).content_chained(&Natural::from(6u32)), 6u32);
235    /// ```
236    ///
237    /// This is equivalent to `_fmpz_vec_content_chained` from `fmpz_vec/content_chained.c`, FLINT
238    /// 3.6.0.
239    #[inline]
240    fn content_chained(self, x: &Natural) -> Natural {
241        content_chained_helper(&self.elements, Integer::unsigned_abs_ref, x.clone())
242    }
243}