Skip to main content

malachite_nz/integer_vector/arithmetic/
canonical_primitive_part.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 crate::integer_vector::arithmetic::content::{content, normalize_in_place, normalized};
11use crate::natural::Natural;
12use malachite_base::num::arithmetic::traits::{
13    CanonicalPrimitivePart, CanonicalPrimitivePartAssign, ContentAndCanonicalPrimitivePart,
14};
15use malachite_base::vector::Vector;
16
17// Whether the canonical primitive part must be negated: when the pivot, the first nonzero element,
18// is negative.
19fn negate(v: &IntegerVector) -> bool {
20    v.pivot().is_some_and(|x| !x.sign)
21}
22
23impl CanonicalPrimitivePart for IntegerVector {
24    type Output = Self;
25
26    /// Computes the canonical primitive part of an [`IntegerVector`], taking the vector by value.
27    ///
28    /// This is the
29    /// [`primitive_part`](malachite_base::num::arithmetic::traits::PrimitivePart::primitive_part),
30    /// negated if its first nonzero element is negative, so that the first nonzero element is
31    /// positive. A vector and its negation have the same canonical primitive part. The canonical
32    /// primitive part of a vector of zeros is itself, keeping its dimension.
33    ///
34    /// $$
35    /// v = \pm \operatorname{cont}(v) \operatorname{cpp}(v).
36    /// $$
37    ///
38    /// # Worst-case complexity
39    /// $T(n) = O(n (\log n)^2 \log\log n)$
40    ///
41    /// $M(n) = O(1)$
42    ///
43    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
44    /// elements.
45    ///
46    /// # Examples
47    /// ```
48    /// use core::str::FromStr;
49    /// use malachite_base::num::arithmetic::traits::CanonicalPrimitivePart;
50    /// use malachite_nz::integer_vector::IntegerVector;
51    ///
52    /// let v = IntegerVector::from_str("(-6, 4, -10)").unwrap();
53    /// assert_eq!(v.canonical_primitive_part().to_string(), "(3, -2, 5)");
54    ///
55    /// // Leading zeros are skipped: the first nonzero element is made positive.
56    /// let v = IntegerVector::from_str("(0, -2, 4)").unwrap();
57    /// assert_eq!(v.canonical_primitive_part().to_string(), "(0, 1, -2)");
58    /// ```
59    #[inline]
60    fn canonical_primitive_part(mut self) -> Self {
61        self.canonical_primitive_part_assign();
62        self
63    }
64}
65
66impl CanonicalPrimitivePart for &IntegerVector {
67    type Output = IntegerVector;
68
69    /// Computes the canonical primitive part of an [`IntegerVector`], taking the vector by
70    /// reference.
71    ///
72    /// This is the
73    /// [`primitive_part`](malachite_base::num::arithmetic::traits::PrimitivePart::primitive_part),
74    /// negated if its first nonzero element is negative, so that the first nonzero element is
75    /// positive. A vector and its negation have the same canonical primitive part. The canonical
76    /// primitive part of a vector of zeros is itself, keeping its dimension.
77    ///
78    /// $$
79    /// v = \pm \operatorname{cont}(v) \operatorname{cpp}(v).
80    /// $$
81    ///
82    /// # Worst-case complexity
83    /// $T(n) = O(n (\log n)^2 \log\log n)$
84    ///
85    /// $M(n) = O(n)$
86    ///
87    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
88    /// elements.
89    ///
90    /// # Examples
91    /// ```
92    /// use core::str::FromStr;
93    /// use malachite_base::num::arithmetic::traits::CanonicalPrimitivePart;
94    /// use malachite_nz::integer_vector::IntegerVector;
95    ///
96    /// let v = IntegerVector::from_str("(-6, 4, -10)").unwrap();
97    /// assert_eq!((&v).canonical_primitive_part().to_string(), "(3, -2, 5)");
98    /// ```
99    #[inline]
100    fn canonical_primitive_part(self) -> IntegerVector {
101        let content = content(&self.elements);
102        IntegerVector {
103            elements: normalized(&self.elements, &content, negate(self)),
104        }
105    }
106}
107
108impl CanonicalPrimitivePartAssign for IntegerVector {
109    /// Replaces an [`IntegerVector`] with its canonical primitive part.
110    ///
111    /// See [`canonical_primitive_part`](CanonicalPrimitivePart::canonical_primitive_part).
112    ///
113    /// # Worst-case complexity
114    /// $T(n) = O(n (\log n)^2 \log\log n)$
115    ///
116    /// $M(n) = O(1)$
117    ///
118    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
119    /// elements.
120    ///
121    /// # Examples
122    /// ```
123    /// use core::str::FromStr;
124    /// use malachite_base::num::arithmetic::traits::CanonicalPrimitivePartAssign;
125    /// use malachite_nz::integer_vector::IntegerVector;
126    ///
127    /// let mut v = IntegerVector::from_str("(-6, 4, -10)").unwrap();
128    /// v.canonical_primitive_part_assign();
129    /// assert_eq!(v.to_string(), "(3, -2, 5)");
130    /// ```
131    #[inline]
132    fn canonical_primitive_part_assign(&mut self) {
133        let content = content(&self.elements);
134        let negate = negate(self);
135        normalize_in_place(&mut self.elements, &content, negate);
136    }
137}
138
139impl ContentAndCanonicalPrimitivePart for IntegerVector {
140    type Content = Natural;
141    type CanonicalPrimitivePart = Self;
142
143    /// Computes the content and the canonical primitive part of an [`IntegerVector`] together,
144    /// taking the vector by value.
145    ///
146    /// See [`content`](malachite_base::num::arithmetic::traits::Content::content) and
147    /// [`canonical_primitive_part`](CanonicalPrimitivePart::canonical_primitive_part); the content
148    /// is found once rather than twice.
149    ///
150    /// # Worst-case complexity
151    /// $T(n) = O(n (\log n)^2 \log\log n)$
152    ///
153    /// $M(n) = O(1)$
154    ///
155    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
156    /// elements.
157    ///
158    /// # Examples
159    /// ```
160    /// use core::str::FromStr;
161    /// use malachite_base::num::arithmetic::traits::ContentAndCanonicalPrimitivePart;
162    /// use malachite_nz::integer_vector::IntegerVector;
163    ///
164    /// let v = IntegerVector::from_str("(-6, 4, -10)").unwrap();
165    /// let (content, primitive_part) = v.content_and_canonical_primitive_part();
166    /// assert_eq!(content, 2u32);
167    /// assert_eq!(primitive_part.to_string(), "(3, -2, 5)");
168    /// ```
169    #[inline]
170    fn content_and_canonical_primitive_part(mut self) -> (Natural, Self) {
171        let content = content(&self.elements);
172        let negate = negate(&self);
173        normalize_in_place(&mut self.elements, &content, negate);
174        (content, self)
175    }
176}
177
178impl ContentAndCanonicalPrimitivePart for &IntegerVector {
179    type Content = Natural;
180    type CanonicalPrimitivePart = IntegerVector;
181
182    /// Computes the content and the canonical primitive part of an [`IntegerVector`] together,
183    /// taking the vector by reference.
184    ///
185    /// See [`content`](malachite_base::num::arithmetic::traits::Content::content) and
186    /// [`canonical_primitive_part`](CanonicalPrimitivePart::canonical_primitive_part); the content
187    /// is found once rather than twice.
188    ///
189    /// # Worst-case complexity
190    /// $T(n) = O(n (\log n)^2 \log\log n)$
191    ///
192    /// $M(n) = O(n)$
193    ///
194    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
195    /// elements.
196    ///
197    /// # Examples
198    /// ```
199    /// use core::str::FromStr;
200    /// use malachite_base::num::arithmetic::traits::ContentAndCanonicalPrimitivePart;
201    /// use malachite_nz::integer_vector::IntegerVector;
202    ///
203    /// let v = IntegerVector::from_str("(-6, 4, -10)").unwrap();
204    /// let (content, primitive_part) = (&v).content_and_canonical_primitive_part();
205    /// assert_eq!(content, 2u32);
206    /// assert_eq!(primitive_part.to_string(), "(3, -2, 5)");
207    /// ```
208    #[inline]
209    fn content_and_canonical_primitive_part(self) -> (Natural, IntegerVector) {
210        let content = content(&self.elements);
211        let elements = normalized(&self.elements, &content, negate(self));
212        (content, IntegerVector { elements })
213    }
214}