malachite_base/unsigned_vector/arithmetic/mod_power_of_2_neg.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::{ModPowerOf2IsReduced, ModPowerOf2Neg, ModPowerOf2NegAssign};
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11use crate::unsigned_vector::UnsignedVector;
12
13fn assert_reduced<T: PrimitiveUnsigned>(v: &UnsignedVector<T>, pow: u64) {
14 assert!(
15 pow <= T::WIDTH,
16 "pow must be at most T::WIDTH, but it is {pow}"
17 );
18 assert!(
19 v.mod_power_of_2_is_reduced(pow),
20 "self must be reduced mod 2^pow, but {v} has an element >= 2^{pow}"
21 );
22}
23
24// Negates every element modulo 2^pow.
25fn negate<T: PrimitiveUnsigned>(elements: &mut [T], pow: u64) {
26 for x in elements {
27 *x = x.wrapping_neg().mod_power_of_2(pow);
28 }
29}
30
31impl<T: PrimitiveUnsigned> ModPowerOf2Neg for UnsignedVector<T> {
32 type Output = Self;
33
34 /// Negates an [`UnsignedVector`] modulo $2^k$, taking the vector by value. The elements must
35 /// already be reduced modulo $2^k$.
36 ///
37 /// Each element $x$ becomes $-x \bmod 2^k$: $2^k - x$ if $x$ is nonzero, and 0 if it is zero.
38 /// The dimension is unchanged.
39 ///
40 /// $$
41 /// f(v, k) = -v \bmod 2^k.
42 /// $$
43 ///
44 /// # Worst-case complexity
45 /// $T(n) = O(n)$
46 ///
47 /// $M(n) = O(1)$
48 ///
49 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
50 ///
51 /// # Panics
52 /// Panics if `pow` is greater than `T::WIDTH`, or if any element of `self` is greater than or
53 /// equal to $2^k$.
54 ///
55 /// # Examples
56 /// ```
57 /// use core::str::FromStr;
58 /// use malachite_base::num::arithmetic::traits::ModPowerOf2Neg;
59 /// use malachite_base::unsigned_vector::UnsignedVector;
60 ///
61 /// let v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
62 /// assert_eq!(v.mod_power_of_2_neg(3).to_string(), "(3, 7, 5)");
63 ///
64 /// // A zero element stays zero.
65 /// let v = UnsignedVector::<u8>::from_str("(0, 1)").unwrap();
66 /// assert_eq!(v.mod_power_of_2_neg(8).to_string(), "(0, 255)");
67 /// ```
68 ///
69 /// This is equivalent to `_nmod_vec_neg` from `nmod_vec/neg.c`, FLINT 3.6.0, with the modulus
70 /// $2^k$.
71 #[inline]
72 fn mod_power_of_2_neg(mut self, pow: u64) -> Self {
73 self.mod_power_of_2_neg_assign(pow);
74 self
75 }
76}
77
78impl<T: PrimitiveUnsigned> ModPowerOf2Neg for &UnsignedVector<T> {
79 type Output = UnsignedVector<T>;
80
81 /// Negates an [`UnsignedVector`] modulo $2^k$, taking the vector by reference. The elements
82 /// must already be reduced modulo $2^k$.
83 ///
84 /// Each element $x$ becomes $-x \bmod 2^k$: $2^k - x$ if $x$ is nonzero, and 0 if it is zero.
85 /// The dimension is unchanged.
86 ///
87 /// $$
88 /// f(v, k) = -v \bmod 2^k.
89 /// $$
90 ///
91 /// # Worst-case complexity
92 /// $T(n) = O(n)$
93 ///
94 /// $M(n) = O(n)$
95 ///
96 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
97 ///
98 /// # Panics
99 /// Panics if `pow` is greater than `T::WIDTH`, or if any element of `self` is greater than or
100 /// equal to $2^k$.
101 ///
102 /// # Examples
103 /// ```
104 /// use core::str::FromStr;
105 /// use malachite_base::num::arithmetic::traits::ModPowerOf2Neg;
106 /// use malachite_base::unsigned_vector::UnsignedVector;
107 ///
108 /// let v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
109 /// assert_eq!((&v).mod_power_of_2_neg(3).to_string(), "(3, 7, 5)");
110 /// ```
111 ///
112 /// This is equivalent to `_nmod_vec_neg` from `nmod_vec/neg.c`, FLINT 3.6.0, with the modulus
113 /// $2^k$.
114 #[inline]
115 fn mod_power_of_2_neg(self, pow: u64) -> UnsignedVector<T> {
116 assert_reduced(self, pow);
117 let mut elements = self.elements.clone();
118 negate(&mut elements, pow);
119 UnsignedVector { elements }
120 }
121}
122
123impl<T: PrimitiveUnsigned> ModPowerOf2NegAssign for UnsignedVector<T> {
124 /// Negates an [`UnsignedVector`] modulo $2^k$, in place. The elements must already be reduced
125 /// modulo $2^k$.
126 ///
127 /// See [`mod_power_of_2_neg`](ModPowerOf2Neg::mod_power_of_2_neg).
128 ///
129 /// # Worst-case complexity
130 /// $T(n) = O(n)$
131 ///
132 /// $M(n) = O(1)$
133 ///
134 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
135 ///
136 /// # Panics
137 /// Panics if `pow` is greater than `T::WIDTH`, or if any element of `self` is greater than or
138 /// equal to $2^k$.
139 ///
140 /// # Examples
141 /// ```
142 /// use core::str::FromStr;
143 /// use malachite_base::num::arithmetic::traits::ModPowerOf2NegAssign;
144 /// use malachite_base::unsigned_vector::UnsignedVector;
145 ///
146 /// let mut v = UnsignedVector::<u8>::from_str("(5, 1, 3)").unwrap();
147 /// v.mod_power_of_2_neg_assign(3);
148 /// assert_eq!(v.to_string(), "(3, 7, 5)");
149 /// ```
150 #[inline]
151 fn mod_power_of_2_neg_assign(&mut self, pow: u64) {
152 assert_reduced(self, pow);
153 negate(&mut self.elements, pow);
154 }
155}