Skip to main content

malachite_base/unsigned_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::num::arithmetic::traits::ContentChained;
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11use crate::unsigned_vector::UnsignedVector;
12
13// Returns the GCD of `gcd` and the elements of `xs`. Zeros at either end are skipped, an element of
14// 1 at either end gives 1 at once, and the rest are taken in pairs from both ends, stopping as soon
15// as the GCD reaches 1.
16//
17// This is equivalent to `_fmpz_vec_content_chained` from `fmpz_vec/content_chained.c`, FLINT 3.6.0.
18pub(crate) fn content_chained<T: PrimitiveUnsigned>(xs: &[T], mut gcd: T) -> T {
19    let Some(start) = xs.iter().position(|&c| c != T::ZERO) else {
20        return gcd;
21    };
22    let end = xs.iter().rposition(|&c| c != T::ZERO).unwrap();
23    let mut xs = &xs[start..=end];
24    if let [first, .., last] = xs
25        && (*first == T::ONE || *last == T::ONE)
26    {
27        return T::ONE;
28    }
29    while gcd != T::ONE
30        && let [first, middle @ .., last] = xs
31    {
32        gcd.gcd_assign(first.gcd(*last));
33        xs = middle;
34    }
35    if gcd != T::ONE
36        && let [middle] = xs
37    {
38        gcd.gcd_assign(*middle);
39    }
40    gcd
41}
42
43impl<T: PrimitiveUnsigned> ContentChained<T> for UnsignedVector<T> {
44    type Output = T;
45
46    /// Computes the GCD of `x` and the elements of an [`UnsignedVector`], taking the vector by
47    /// value.
48    ///
49    /// The GCD of `x` and the elements of the 0-dimensional vector, or of a vector of zeros, is
50    /// `x`. The computation stops as soon as the GCD reaches 1.
51    ///
52    /// $$
53    /// f(v, x) = \gcd(x, v_0, v_1, \ldots, v_{n-1}),
54    /// $$
55    ///
56    /// where $n$ is the dimension of $v$.
57    ///
58    /// # Worst-case complexity
59    /// $T(n) = O(n)$
60    ///
61    /// $M(n) = O(1)$
62    ///
63    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
64    ///
65    /// # Examples
66    /// ```
67    /// use core::str::FromStr;
68    /// use malachite_base::num::arithmetic::traits::ContentChained;
69    /// use malachite_base::unsigned_vector::UnsignedVector;
70    ///
71    /// let v = UnsignedVector::<u8>::from_str("(6, 4, 10)").unwrap();
72    /// assert_eq!(v.clone().content_chained(4), 2);
73    /// assert_eq!(v.content_chained(0), 2);
74    /// let v = UnsignedVector::<u8>::from_str("()").unwrap();
75    /// assert_eq!(v.content_chained(6), 6);
76    /// ```
77    ///
78    /// This is equivalent to `_fmpz_vec_content_chained` from `fmpz_vec/content_chained.c`, FLINT
79    /// 3.6.0.
80    #[inline]
81    fn content_chained(self, x: T) -> T {
82        content_chained(&self.elements, x)
83    }
84}
85
86impl<T: PrimitiveUnsigned> ContentChained<T> for &UnsignedVector<T> {
87    type Output = T;
88
89    /// Computes the GCD of `x` and the elements of an [`UnsignedVector`], taking the vector by
90    /// reference.
91    ///
92    /// The GCD of `x` and the elements of the 0-dimensional vector, or of a vector of zeros, is
93    /// `x`. The computation stops as soon as the GCD reaches 1.
94    ///
95    /// $$
96    /// f(v, x) = \gcd(x, v_0, v_1, \ldots, v_{n-1}),
97    /// $$
98    ///
99    /// where $n$ is the dimension of $v$.
100    ///
101    /// # Worst-case complexity
102    /// $T(n) = O(n)$
103    ///
104    /// $M(n) = O(1)$
105    ///
106    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
107    ///
108    /// # Examples
109    /// ```
110    /// use core::str::FromStr;
111    /// use malachite_base::num::arithmetic::traits::ContentChained;
112    /// use malachite_base::unsigned_vector::UnsignedVector;
113    ///
114    /// let v = UnsignedVector::<u8>::from_str("(6, 4, 10)").unwrap();
115    /// assert_eq!((&v).content_chained(4), 2);
116    /// assert_eq!((&v).content_chained(0), 2);
117    /// let v = UnsignedVector::<u8>::from_str("()").unwrap();
118    /// assert_eq!((&v).content_chained(6), 6);
119    /// ```
120    ///
121    /// This is equivalent to `_fmpz_vec_content_chained` from `fmpz_vec/content_chained.c`, FLINT
122    /// 3.6.0.
123    #[inline]
124    fn content_chained(self, x: T) -> T {
125        content_chained(&self.elements, x)
126    }
127}