Skip to main content

malachite_base/
vector.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::conversion::traits::ExactFrom;
10use alloc::vec;
11use alloc::vec::Vec;
12use core::mem::take;
13
14/// What every vector type has in common: a vector of a fixed dimension, stored as its elements in
15/// order.
16///
17/// The functions here are the ones whose meaning does not depend on what the elements are. Each
18/// implementation documents its own complexity and gives its own examples.
19pub trait Vector: Sized {
20    /// The type of an element.
21    type Element;
22
23    /// What [`pivot`](Self::pivot) returns.
24    ///
25    /// This is a reference to an [`Element`](Self::Element) when the vector holds elements that are
26    /// expensive to copy, and an [`Element`](Self::Element) itself when one is cheap to copy.
27    type ElementOutput<'a>
28    where
29        Self: 'a;
30
31    /// Converts a slice to a vector, cloning the elements.
32    ///
33    /// The vector's dimension is the length of the slice. Every slice is a valid vector, so this
34    /// cannot fail; the empty slice gives the 0-dimensional vector.
35    fn from_elements(xs: &[Self::Element]) -> Self
36    where
37        Self::Element: Clone;
38
39    /// Converts a [`Vec`] to a vector, taking ownership of it.
40    ///
41    /// The vector's dimension is the length of the [`Vec`]. Every [`Vec`] is a valid vector, so
42    /// this cannot fail, and nothing is copied or allocated.
43    fn from_owned_elements(xs: Vec<Self::Element>) -> Self;
44
45    /// Returns the zero vector of a given dimension: a vector of `dimension` zeros.
46    fn zero(dimension: u64) -> Self;
47
48    /// Returns a standard basis vector: the vector of a given dimension whose element at `index` is
49    /// 1 and whose other elements are 0.
50    fn standard_basis_vector(dimension: u64, index: u64) -> Self;
51
52    /// Appends an element to the end of a vector, increasing its dimension by 1.
53    fn push(&mut self, x: Self::Element);
54
55    /// Sets the dimension of a vector, removing elements from the end if the new dimension is
56    /// smaller, and appending zeros if it is larger.
57    fn set_dimension(&mut self, dimension: u64);
58
59    /// Sets every element of a vector to zero, keeping its dimension.
60    fn set_zero(&mut self);
61
62    /// Sorts the elements of a vector in ascending order, keeping its dimension.
63    fn sort(&mut self);
64
65    /// Returns a vector's elements as a [`Vec`], cloning them.
66    fn to_elements(&self) -> Vec<Self::Element>
67    where
68        Self::Element: Clone;
69
70    /// Returns a vector's elements as a [`Vec`], taking ownership of the vector.
71    ///
72    /// The [`Vec`] is what [`from_owned_elements`](Self::from_owned_elements) would take back.
73    fn into_elements(self) -> Vec<Self::Element>;
74
75    /// Returns a reference to a vector's elements, as a slice.
76    fn elements_ref(&self) -> &[Self::Element];
77
78    /// Returns the dimension of a vector: the number of its elements.
79    fn dimension(&self) -> u64;
80
81    /// Determines whether every element of a vector is zero. This includes the 0-dimensional
82    /// vector, which has no elements.
83    fn is_zero(&self) -> bool;
84
85    /// Returns the pivot of a vector: its first nonzero element.
86    ///
87    /// This is the element that leads the vector when it is a row of a matrix in echelon form.
88    /// Returns `None` if every element is zero, which includes the 0-dimensional vector.
89    fn pivot(&self) -> Option<Self::ElementOutput<'_>>;
90
91    /// Returns the index of the pivot of a vector: the position of its first nonzero element.
92    ///
93    /// Indices start at 0, as they do for [`Index`](core::ops::Index). Returns `None` if every
94    /// element is zero, which includes the 0-dimensional vector. When it returns `Some(i)`,
95    /// [`pivot`](Self::pivot) is the element at `i`.
96    fn pivot_index(&self) -> Option<u64>;
97
98    /// Returns the index of an element of largest height: the first one, when several share it.
99    ///
100    /// The height of an integer is its absolute value, and the height of a rational number $p/q$ in
101    /// lowest terms is $\max(|p|, q)$. Returns `None` for the 0-dimensional vector.
102    fn height_index(&self) -> Option<u64>;
103
104    /// Determines whether a vector is a standard basis vector, returning the index of its 1 if it
105    /// is.
106    ///
107    /// A standard basis vector has a single element equal to 1 and every other element 0, as
108    /// [`standard_basis_vector`](Self::standard_basis_vector) builds. Returns `None` for every
109    /// other vector, including the zero vectors and the 0-dimensional vector. When it returns
110    /// `Some(i)`, `i` is also the [`pivot_index`](Self::pivot_index), and the vector equals
111    /// `standard_basis_vector(self.dimension(), i)`.
112    fn standard_basis_index(&self) -> Option<u64>;
113
114    /// Returns the number of significant bits of a vector's height, together with whether any of
115    /// its elements is negative.
116    ///
117    /// The bit count is the largest bit length of any element's height, or 0 for the 0-dimensional
118    /// vector; it is what `Height::height_significant_bits` returns.
119    fn max_bits(&self) -> (u64, bool);
120
121    /// Returns the number of significant bits of a vector's $\ell^1$ norm, the sum of the absolute
122    /// values of its elements, together with the number of significant bits of its height.
123    ///
124    /// The counts are what `L1Norm::l1_norm_significant_bits` and `Height::height_significant_bits`
125    /// return, computed together in one pass where possible. The height of the 0-dimensional vector
126    /// is 0, and so, for integer elements, is its norm.
127    fn sum_max_bits(&self) -> (u64, u64);
128}
129
130/// Selects coordinates of a vector by index: the result's element $j$ is the original's element
131/// `indices[j]`.
132///
133/// The indices may repeat and may appear in any order, so this covers projection onto some of the
134/// coordinates (strictly increasing indices), permutation, and duplication of coordinates. The
135/// result's dimension is the number of indices.
136pub trait SelectCoordinates {
137    type Output;
138
139    fn select_coordinates(self, indices: &[u64]) -> Self::Output;
140}
141
142/// Selects coordinates of a vector by index, in place: afterwards, element $j$ of the vector is
143/// what element `indices[j]` was before.
144pub trait SelectCoordinatesAssign {
145    fn select_coordinates_assign(&mut self, indices: &[u64]);
146}
147
148fn check_index(index: u64, dimension: usize) -> usize {
149    let index = usize::exact_from(index);
150    assert!(
151        index < dimension,
152        "index {index} is out of range for a vector of dimension {dimension}"
153    );
154    index
155}
156
157// The elements of `xs` at `indices`, cloned. Panics if an index is out of range.
158#[doc(hidden)]
159#[inline]
160pub fn select_elements<T: Clone>(xs: &[T], indices: &[u64]) -> Vec<T> {
161    indices
162        .iter()
163        .map(|&i| xs[check_index(i, xs.len())].clone())
164        .collect()
165}
166
167// Replaces `xs` with its elements at `indices`, cloning as few as possible. Panics if an index is
168// out of range.
169//
170// When the indices are strictly increasing, the selected elements are swapped into place and the
171// rest truncated away, so nothing is cloned or allocated. Otherwise each element is moved out at
172// its last use and cloned at any earlier one, so an element is cloned once for each extra time it
173// is selected, which is as few clones as any method needs.
174#[doc(hidden)]
175pub fn select_elements_in_place<T: Clone + Default>(xs: &mut Vec<T>, indices: &[u64]) {
176    let n = xs.len();
177    if indices.windows(2).all(|w| w[0] < w[1]) {
178        if let Some(&last) = indices.last() {
179            check_index(last, n);
180        }
181        for (j, &i) in indices.iter().enumerate() {
182            let i = usize::exact_from(i);
183            if i != j {
184                xs.swap(j, i);
185            }
186        }
187        xs.truncate(indices.len());
188        return;
189    }
190    let mut last_use = vec![usize::MAX; n];
191    for (j, &i) in indices.iter().enumerate() {
192        last_use[check_index(i, n)] = j;
193    }
194    let mut selected = Vec::with_capacity(indices.len());
195    for (j, &i) in indices.iter().enumerate() {
196        let i = usize::exact_from(i);
197        selected.push(if last_use[i] == j {
198            take(&mut xs[i])
199        } else {
200            xs[i].clone()
201        });
202    }
203    *xs = selected;
204}