Malachite for FLINT Users: Integer Vectors
This page maps the functions of FLINT’s integer vector module, fmpz_vec.h, onto their Malachite
counterpart:
IntegerVector,
from the malachite-nz crate. It follows the organization of the fmpz_vec.h
chapter of the FLINT manual, as of FLINT 3.6.0, and is a
companion to Malachite for FLINT Users: Integers, whose
conventions, including word types and aliasing, apply here
as well; the mapping index lists the whole family.
Every section of the chapter is mapped below: 78 rows across 15 sections, of which 60 are ✓, 2 ⚙,
7 ≈, 8 —, and 1 ✗. Functions whose names begin with an underscore are included, since they make
up most of the chapter (see Underscore functions). Two functions that
fmpz_vec.h declares but the chapter does not document, _fmpz_vec_min and
_fmpz_vec_min_inplace, have no rows (see Comparison).
The one ✗ row is _fmpz_vec_dot_general, the dot product with an initial term, a subtraction
flag, and a reversal flag; its note gives the interim way to compute it.
Conventions
Two kinds of vector
Most of fmpz_vec.h works on a bare array: an fmpz * together with a separate slong length,
which the caller allocates, tracks, and frees. Only the Resizable vectors
section has a vector object, fmpz_vec_t, which holds entries, alloc, and length in one
struct.
Malachite has one type for both.
IntegerVector
is a single public field,
elements,
of type
Vec<Integer>, whose pointer,
capacity, and length are the counterparts of entries, alloc, and length. Every
Vec method is therefore available
through the field, and a function that takes an (fmpz *, slong) pair becomes a method on
IntegerVector
or a function on a slice
&[Integer]. The construction and
access methods common to all of Malachite’s vector types are in the
Vector trait.
Underscore functions
The other FLINT pages omit functions whose names begin with an underscore. This page does not: the bare-array functions are most of the chapter, and nearly all of them have underscore names.
Elements that are not Integers
Malachite has four vector types differing only in their elements:
IntegerVector
over \(\mathbb{Z}\),
NaturalVector
over \(\mathbb{N}\),
UnsignedVector
with primitive unsigned elements (in malachite-base), and
RationalVector
over \(\mathbb{Q}\). They are the counterparts of FLINT’s fmpz_vec, fmpz_mod_vec, nmod_vec,
and fmpq_vec modules respectively:
NaturalVector
and
UnsignedVector
also hold residues for the Mod* and ModPowerOf2* traits, which check that their arguments are
reduced. Every row below names the
IntegerVector
version; the memory-management and resizing rows apply unchanged to the other three.
Categories
Each function falls into one of five categories:
| meaning | |
|---|---|
| ✓ | A Malachite function does the same thing. |
| ≈ | A Malachite function serves the same purpose, but its specification differs. The notes say how. |
| ⚙ | Malachite does not expose this algorithm or helper; the Malachite column or the notes say what to call instead. |
| — | No counterpart is needed, either because Rust handles it for you or because it is outside Malachite’s scope. The notes say which. |
| ✗ | Malachite does not fully support this yet, but will in a future version. |
Memory management
| FLINT | Malachite | |
|---|---|---|
| ✓ | fmpz * _fmpz_vec_init(slong len) |
zero |
| — | void _fmpz_vec_clear(fmpz * vec, slong len) |
_fmpz_vec_init returns len zeros (it is a calloc, and a zeroed fmpz is \(0\)), and
fmpz_vec_init does the same for the resizable vector. Both are
zero, the
Vector method
that returns the zero vector of a given dimension: IntegerVector::zero(len). The length travels
with the result, so there is no separate len to keep. _fmpz_vec_clear is
Drop, which runs when the vector goes out of scope.
Resizable vectors
| FLINT | Malachite | |
|---|---|---|
| ✓ | fmpz_vec_struct |
IntegerVector |
| — | fmpz_vec_t |
|
| ✓ | void fmpz_vec_init(fmpz_vec_t vec, slong len) |
zero |
| — | void fmpz_vec_clear(fmpz_vec_t vec) |
|
| ✓ | fmpz * fmpz_vec_entry_ptr(fmpz_vec_t vec, slong i) |
IndexMut |
| ✓ | const fmpz * fmpz_vec_entry_srcptr(const fmpz_vec_t vec, slong i) |
Index |
| ✓ | slong fmpz_vec_length(const fmpz_vec_t vec) |
dimension |
| — | void fmpz_vec_fit_length(fmpz_vec_t vec, slong len) |
|
| ✓ | void fmpz_vec_set_length(fmpz_vec_t vec, slong len) |
set_dimension |
| ✓ | void fmpz_vec_set(fmpz_vec_t res, const fmpz_vec_t src) |
Clone |
| ✓ | void fmpz_vec_append(fmpz_vec_t vec, const fmpz_t f) |
push |
| ✓ | void fmpz_vec_append_ui(fmpz_vec_t vec, ulong f) |
push |
fmpz_vec_t is the pass-by-reference device that & and &mut already are, and
fmpz_vec_clear is Drop. FLINT also
documents that an fmpz_vec_t may be cast to a gr_vec_t, its generic-ring vector; Malachite
has no generic-ring layer, so that has no counterpart.
The two entry functions are v[i], through
IndexMut and
Index with a
usize index. FLINT requires the
index to be in bounds and does not check it; Malachite panics if it is out of bounds.
dimension
returns a u64.
fmpz_vec_set is Clone;
clone_from
reuses the destination’s allocation, as fmpz_vec_set does.
fmpz_vec_append and fmpz_vec_append_ui are
push, the
Vector method that
appends one element, with Integer::from(f) for the
ulong version. To append many
elements, Extend takes them
from any iterator.
fmpz_vec_set_length is
set_dimension,
which pads with zeros when growing and discards the trailing elements when shrinking, as
fmpz_vec_set_length does. fmpz_vec_fit_length, which only reserves room without changing the
length, is a memory-management detail; if it matters,
reserve on the
elements
field does it. fmpz_vec_fit_length(vec, len) takes the total number of elements to make room
for, and reserve takes the number beyond the current length, so the equivalent call is
v.elements.reserve(len.saturating_sub(v.elements.len())).
Randomisation
| FLINT | Malachite | |
|---|---|---|
| ≈ | void _fmpz_vec_randtest(fmpz * f, flint_rand_t state, slong len, flint_bitcnt_t bits) |
random_integer_vectors_with_dimension, random_integer_vectors_with_dimension_from_iterator, striped_random_integer_vectors_with_dimension |
| ≈ | void _fmpz_vec_randtest_unsigned(fmpz * f, flint_rand_t state, slong len, flint_bitcnt_t bits) |
random_natural_vectors_with_dimension, random_natural_vectors_with_dimension_from_iterator, striped_random_natural_vectors_with_dimension |
Both FLINT functions fill a vector of length len and draw each element with
fmpz_randtest or fmpz_randtest_unsigned, which cap
its bit length at bits. Malachite’s counterparts are infinite iterators of vectors of a given
dimension, whose elements come from
random_integers
or
random_naturals
(or their striped forms). Those take a mean bit length, with no cap, so the distributions
differ, as they do for single integers.
The distributions also differ in a second way. Half the time, FLINT makes the vector sparse: it
draws \(s\) uniformly from \(1\) to \(\max(2, \mathit{len})\), and then each element is zero with
probability \(1 - 1/s\). Malachite’s generators have no sparse mode; every element is drawn the
same way. randtest_unsigned is a change of type, to
NaturalVector.
For a hard bound on the elements, pass a bounded element stream to
random_integer_vectors_with_dimension_from_iterator,
which takes the elements of each vector from any iterator. For example,
uniform_random_integer_inclusive_range
with the range \([-(2^{\mathit{bits}} - 1), 2^{\mathit{bits}} - 1]\) caps the bit length at bits,
as FLINT does, though it is uniform over values rather than over bit lengths, so most elements
have close to bits bits. To let the dimension vary as well, use
random_integer_vectors_from_iterator
or
random_integer_vectors
and its siblings, which draw the dimension from a geometric distribution with a given mean.
Bit sizes and norms
| FLINT | Malachite | |
|---|---|---|
| ✓ | slong _fmpz_vec_max_bits(const fmpz * vec, slong len) |
max_bits |
| — | slong _fmpz_vec_max_bits_ref(const fmpz * vec, slong len) |
|
| ✓ | void _fmpz_vec_sum_max_bits(slong * sumabs, slong * maxabs, const fmpz * vec, slong len) |
sum_max_bits |
| — | slong _fmpz_vec_max_limbs(const fmpz * vec, slong len) |
|
| ✓ | void _fmpz_vec_height(fmpz_t height, const fmpz * vec, slong len) |
Height, HeightRef |
| ✓ | slong _fmpz_vec_height_index(const fmpz * vec, slong len) |
height_index |
The height of a vector is the largest absolute value of its elements, its \(\ell^\infty\) norm, and
\(0\) for the 0-dimensional vector. _fmpz_vec_height is
Height’s
to_height,
or
into_height
to move the element out instead of cloning it; HeightRef lends it instead, since the height is the
absolute value of one of the elements. All four vector types implement
Height, as the polynomial types do (see the polynomial
page).
max_bits returns the bit length \(b\) of the height, negated when any element is negative.
max_bits,
a Vector
method, returns the same two facts as a pair, (b, negative); the bit count alone is
height_significant_bits.
Both use FLINT’s method, or-ing together the top limbs of the elements with the most limbs, so no
element’s bit length is computed separately.
sum_max_bits returns two bit lengths: that of the sum of the absolute values (the \(\ell^1\)
norm), and that of the height. It is
sum_max_bits,
which returns them as a pair in the same order. Like FLINT’s, it adds the elements in two words
while each fits in one, and computes the sum exactly only when an element does not. The norm
itself is
to_l1_norm,
and its bit length alone is
l1_norm_significant_bits.
height_index is height_index, a
Vector
method. Both return the index of the first element of largest absolute value when several tie
(the manual does not say which; this is what FLINT’s implementation does). FLINT requires a
nonempty vector, while height_index returns
None for the
0-dimensional one.
max_bits_ref is a slower reference implementation of max_bits, kept for testing. Malachite
keeps reference implementations in its test code rather than its public API. max_limbs is a
memory-estimation helper; limbs are an implementation detail in Malachite.
Input and output
As on the fmpz page, Malachite has no FILE *
functions: formatting and parsing work with any Rust reader or writer.
| FLINT | Malachite | |
|---|---|---|
| ≈ | int _fmpz_vec_fread(FILE * file, fmpz ** vec, slong * len) |
FromStr, Deserialize |
| ≈ | int _fmpz_vec_read(fmpz ** vec, slong * len) |
FromStr, Deserialize |
| ≈ | int _fmpz_vec_fprint(FILE * file, const fmpz * vec, slong len) |
Display, Serialize |
| ≈ | int _fmpz_vec_print(const fmpz * vec, slong len) |
Display, Serialize |
The formats differ, hence ≈. FLINT writes the length, two spaces, and then the elements separated
by single spaces, so \((1, -2, 3)\) is 3 1 -2 3 and the empty vector is 0; this is the same
as fmpz_poly’s plain format. Malachite’s
Display writes (1, -2, 3),
with () for the 0-dimensional vector, and
FromStr reads exactly that
form back, returning an Err on failure where FLINT returns a non-positive value. Neither
writes the length. With the serde feature,
IntegerVector
is serialized as a plain list of its elements.
_fmpz_vec_fread either allocates a vector of the length it reads or, given an existing vector,
fails unless the length read matches. Parsing in Malachite always produces a new vector; to
require a particular dimension, compare
dimension
afterwards. The print/fprint and read/fread splits disappear because
Display writes to any
Formatter, and parsing
works on any string, however it was read.
Conversions
| FLINT | Malachite | |
|---|---|---|
| ✓ | void _fmpz_vec_get_nmod_vec(nn_ptr res, const fmpz * poly, slong len, nmod_t mod) |
Mod |
| ≈ | void _fmpz_vec_set_nmod_vec(fmpz * res, nn_srcptr poly, slong len, nmod_t mod) |
BalancedMod |
| ⚙ | void _fmpz_vec_get_fft(ulong ** coeffs_f, const fmpz * coeffs_m, slong l, slong length) |
Mul |
| ⚙ | void _fmpz_vec_set_fft(fmpz * coeffs_m, slong length, const nn_ptr * coeffs_f, slong limbs, slong sign) |
Mul |
| — | slong _fmpz_vec_get_d_vec_2exp(double * appv, const fmpz * vec, slong len) |
Malachite has no nmod_vec type: a vector of residues modulo a word-sized \(n\) is an
UnsignedVector<u64>
whose elements are less than \(n\). get_nmod_vec reduces each element modulo \(n\) into
\([0, n)\); it is
Mod
with a primitive unsigned modulus, v.mod_op(n), which returns an UnsignedVector of the
modulus’s type. The same reduction modulo a
Natural returns
a
NaturalVector,
and a NaturalVector can be reduced modulo a primitive unsigned modulus in the same way.
set_nmod_vec converts each residue to its balanced representative, as
BalancedMod
does for a single value (see fmpz_set_ui_smod). For
vectors this is BalancedMod on a NaturalVector, which returns an IntegerVector; convert the
UnsignedVector of residues to a NaturalVector with
From first, hence ≈. Unlike
set_nmod_vec, it accepts elements that are not yet reduced. The manual gives the balanced range
as \([-n/2, n/2)\), but the implementation (fmpz_set_ui_smod) keeps \(x\) when \(x \le n/2\), so
the range is \((-n/2, n/2]\), the same as
BalancedMod’s.
The two differ only for even \(n\), where FLINT returns \(n/2\), not \(-n/2\).
get_fft and set_fft convert between integers and the residues modulo a Fermat number
\(2^{wl} + 1\) that Schönhage–Strassen polynomial multiplication works with. They are steps
inside multiplication, and Malachite keeps them internal; multiply the polynomials instead, with
Mul (see the polynomial
page). In FLINT 3.6.0, set_fft gives the
wrong sign to a negative coefficient whose top limb is exactly half the limb range; this was fixed
in FLINT’s development branch after the 3.6.0 release.
get_d_vec_2exp approximates every element by a
f64 scaled by one shared power of
2: it returns the largest element exponent \(e\), and element \(i\) is approximately
\(\mathit{appv}_i \cdot 2^e\) with \(|\mathit{appv}_i| \le 1\). For a single value this is
SciMantissaAndExponent
(see fmpz_get_d_2exp), whose mantissas lie in
\([1, 2)\) rather than FLINT’s \([1/2, 1)\). The shared-exponent vector form is outside
Malachite’s scope, hence —; apply
sci_mantissa_and_exponent
to the absolute value of each element and rescale by the largest exponent.
Assignment and basic manipulation
| FLINT | Malachite | |
|---|---|---|
| ✓ | void _fmpz_vec_set(fmpz * vec1, const fmpz * vec2, slong len2) |
Clone |
| ✓ | void _fmpz_vec_swap(fmpz * vec1, fmpz * vec2, slong len2) |
mem::swap |
| ✓ | void _fmpz_vec_zero(fmpz * vec, slong len) |
set_zero |
| ✓ | void _fmpz_vec_neg(fmpz * vec1, const fmpz * vec2, slong len2) |
Neg, NegAssign |
| ✓ | void _fmpz_vec_scalar_abs(fmpz * vec1, const fmpz * vec2, slong len2) |
EntrywiseAbs, EntrywiseAbsAssign, EntrywiseUnsignedAbs |
_fmpz_vec_set is Clone, as
fmpz_vec_set is in Resizable vectors.
_fmpz_vec_swap exchanges the contents of two vectors of the same length one element at a time;
mem::swap exchanges two
IntegerVectors
of any dimensions in constant time. _fmpz_vec_neg with vec1 equal to vec2 negates in place,
which is
NegAssign;
otherwise it is -&v, or -v when v is no longer needed.
_fmpz_vec_zero sets every element to zero while keeping the dimension, which is
set_zero,
a Vector method.
_fmpz_vec_scalar_abs replaces every element by its absolute value, which is
EntrywiseAbs,
or EntrywiseAbsAssign
when vec1 equals vec2. The name is not
Abs, which for a vector would be its
Euclidean length. Since every absolute value is nonnegative, the result can also be a
NaturalVector,
which is EntrywiseUnsignedAbs,
as UnsignedAbs is for a single
Integer.
Comparison
| FLINT | Malachite | |
|---|---|---|
| ✓ | int _fmpz_vec_equal(const fmpz * vec1, const fmpz * vec2, slong len) |
PartialEq |
| ✓ | int _fmpz_vec_is_zero(const fmpz * vec, slong len) |
is_zero |
| ✓ | void _fmpz_vec_max(fmpz * vec1, const fmpz * vec2, const fmpz * vec3, slong len) |
EntrywiseMax |
| ✓ | void _fmpz_vec_max_inplace(fmpz * vec1, const fmpz * vec2, slong len) |
EntrywiseMaxAssign |
_fmpz_vec_equal compares two arrays over a length the caller supplies;
PartialEq on
IntegerVector
also requires the dimensions to match, so vectors of different dimensions are unequal. The vector
types can also be compared with one another, so an
IntegerVector
equals a
NaturalVector
or
UnsignedVector
with the same elements.
_fmpz_vec_is_zero is true when every element is zero, including for the empty vector. It is
is_zero,
a Vector
method, which agrees on the empty vector. Malachite also has
standard_basis_index,
which FLINT lacks: it returns the index of the 1 in a standard basis vector, and None for any
other vector.
_fmpz_vec_max sets each element of the result to the larger of the corresponding elements of
two vectors, and _fmpz_vec_max_inplace does the same with the result in the first vector. These
are EntrywiseMax and
EntrywiseMaxAssign,
which every vector type implements, in every combination of value and reference. The vectors
must have the same dimension.
fmpz_vec.h also declares the pointwise minimum functions _fmpz_vec_min and
_fmpz_vec_min_inplace, which the chapter does not document; they have no rows here. Their
counterparts are EntrywiseMin and
EntrywiseMinAssign.
Sorting
| FLINT | Malachite | |
|---|---|---|
| ✓ | void _fmpz_vec_sort(fmpz * vec, slong len) |
sort |
_fmpz_vec_sort sorts the elements in ascending order, using the C library’s qsort with
fmpz_cmp. It is
sort,
a Vector
method, which sorts in place with
sort_unstable.
Stability does not matter here: equal integers are indistinguishable.
Addition and subtraction
| FLINT | Malachite | |
|---|---|---|
| ✓ | void _fmpz_vec_add(fmpz * res, const fmpz * vec1, const fmpz * vec2, slong len2) |
Add, AddAssign |
| ✓ | void _fmpz_vec_sub(fmpz * res, const fmpz * vec1, const fmpz * vec2, slong len2) |
Sub, SubAssign |
Both operations work element by element, and Malachite panics if the two vectors have different
dimensions; FLINT assumes, without checking, that both arrays have len2 elements. Calling
_fmpz_vec_add or _fmpz_vec_sub with res equal to vec1 is v += w or v -= w. Each
operator also takes either operand by value or by reference, and taking an operand by value lets
Malachite reuse its storage for the result, as &v - w does.
The modular counterparts, which belong to FLINT’s fmpz_mod_vec and nmod_vec modules, are
ModAdd
and
ModSub
(and their power-of-2 forms) on
NaturalVector
and
UnsignedVector.
Scalar multiplication and division
| FLINT | Malachite | |
|---|---|---|
| ✓ | void _fmpz_vec_scalar_mul_fmpz(fmpz * vec1, const fmpz * vec2, slong len2, const fmpz_t x) |
Mul, MulAssign |
| ✓ | void _fmpz_vec_scalar_mul_si(fmpz * vec1, const fmpz * vec2, slong len2, slong c) |
Mul, MulAssign |
| ✓ | void _fmpz_vec_scalar_mul_ui(fmpz * vec1, const fmpz * vec2, slong len2, ulong c) |
Mul, MulAssign |
| ✓ | void _fmpz_vec_scalar_mul_2exp(fmpz * vec1, const fmpz * vec2, slong len2, ulong exp) |
Shl, ShlAssign |
| ✓ | void _fmpz_vec_scalar_divexact_fmpz(fmpz * vec1, const fmpz * vec2, slong len2, const fmpz_t x) |
DivExact, DivExactAssign |
| ✓ | void _fmpz_vec_scalar_divexact_si(fmpz * vec1, const fmpz * vec2, slong len2, slong c) |
DivExact, DivExactAssign |
| ✓ | void _fmpz_vec_scalar_divexact_ui(fmpz * vec1, const fmpz * vec2, slong len2, ulong c) |
DivExact, DivExactAssign |
| ✓ | void _fmpz_vec_scalar_fdiv_q_fmpz(fmpz * vec1, const fmpz * vec2, slong len2, const fmpz_t c) |
EntrywiseDivRound, EntrywiseDivRoundAssign |
| ✓ | void _fmpz_vec_scalar_fdiv_q_si(fmpz * vec1, const fmpz * vec2, slong len2, slong c) |
EntrywiseDivRound, EntrywiseDivRoundAssign |
| ✓ | void _fmpz_vec_scalar_fdiv_q_ui(fmpz * vec1, const fmpz * vec2, slong len2, ulong c) |
EntrywiseDivRound, EntrywiseDivRoundAssign |
| ✓ | void _fmpz_vec_scalar_fdiv_q_2exp(fmpz * vec1, const fmpz * vec2, slong len2, ulong exp) |
Shr, ShrAssign |
| ✓ | void _fmpz_vec_scalar_fdiv_r_2exp(fmpz * vec1, const fmpz * vec2, slong len2, ulong exp) |
ModPowerOf2 |
| ✓ | void _fmpz_vec_scalar_tdiv_q_fmpz(fmpz * vec1, const fmpz * vec2, slong len2, const fmpz_t c) |
Div, DivAssign |
| ✓ | void _fmpz_vec_scalar_tdiv_q_si(fmpz * vec1, const fmpz * vec2, slong len2, slong c) |
Div, DivAssign |
| ✓ | void _fmpz_vec_scalar_tdiv_q_ui(fmpz * vec1, const fmpz * vec2, slong len2, ulong c) |
Div, DivAssign |
| ✓ | void _fmpz_vec_scalar_tdiv_q_2exp(fmpz * vec1, const fmpz * vec2, slong len2, ulong exp) |
EntrywiseShrRound, EntrywiseShrRoundAssign |
| ✓ | void _fmpz_vec_scalar_addmul_si(fmpz * vec1, const fmpz * vec2, slong len2, slong c) |
AddMul, AddMulAssign |
| ✓ | void _fmpz_vec_scalar_addmul_ui(fmpz * vec1, const fmpz * vec2, slong len2, ulong c) |
AddMul, AddMulAssign |
| ✓ | void _fmpz_vec_scalar_addmul_fmpz(fmpz * vec1, const fmpz * vec2, slong len2, const fmpz_t c) |
AddMul, AddMulAssign |
| ✓ | void _fmpz_vec_scalar_addmul_si_2exp(fmpz * vec1, const fmpz * vec2, slong len2, slong c, ulong exp) |
AddMulShl, AddMulShlAssign |
| ✓ | void _fmpz_vec_scalar_submul_fmpz(fmpz * vec1, const fmpz * vec2, slong len2, const fmpz_t x) |
SubMul, SubMulAssign |
| ✓ | void _fmpz_vec_scalar_submul_si(fmpz * vec1, const fmpz * vec2, slong len2, slong c) |
SubMul, SubMulAssign |
| ✓ | void _fmpz_vec_scalar_submul_si_2exp(fmpz * vec1, const fmpz * vec2, slong len2, slong c, ulong e) |
SubMulShl, SubMulShlAssign |
scalar_mul multiplies every element by one integer. It is
Mul of an
IntegerVector
and an
Integer, with the
scalar on either side, or
MulAssign when vec1 is
vec2;
NaturalVector
and RationalVector
multiply by a Natural
and a Rational in the
same way. Like FLINT’s, the integer version special-cases multiplication by 0, 1, and \(-1\);
the natural and rational versions special-case 0 and 1. scalar_mul_2exp is
Shl (<<) by any primitive unsigned
type, or ShlAssign (<<=) when
vec1 is vec2, implemented by
IntegerVector,
NaturalVector,
and
RationalVector.
scalar_addmul adds \(c\) times vec2 to vec1, which is
AddMulAssign of an
IntegerVector,
another IntegerVector, and an
Integer;
AddMul returns the result instead of updating vec1. scalar_submul
subtracts in the same way, with SubMul and
SubMulAssign. Every combination of value and reference is
implemented, and like FLINT’s, both special-case multiplication by 0, 1, and \(-1\). For
NaturalVector,
AddMul and AddMulAssign take a
Natural scalar.
The _si and _ui forms take an Integer made from the primitive scalar.
scalar_fdiv_q_2exp is
Shr (>>), which takes the floor
of every element, or ShrAssign
(>>=) when vec1 is vec2. scalar_tdiv_q_2exp, which rounds toward zero, is
EntrywiseShrRound
with Down, or
EntrywiseShrRoundAssign
when vec1 is vec2. Its other rounding modes give the remaining quotients; unlike
ShrRound,
it returns no Ordering, since
the elements may round in different directions. All of these take any primitive unsigned or
signed shift amount, a negative one shifting the other way.
scalar_divexact is
DivExact,
or DivExactAssign
when vec1 is vec2; the _si and _ui forms divide by an
Integer made from
the word. Like FLINT’s, the integer version special-cases division by 1 and \(-1\). Neither
library checks that each division is exact. To check, use
DivisibleBy
on each element first.
scalar_tdiv_q, which rounds toward zero, is
Div (/), or
DivAssign (/=) when vec1
is vec2, by an
Integer; the _si
and _ui forms divide by an Integer made from the word. scalar_fdiv_q, which rounds toward
\(-\infty\), is
EntrywiseDivRound
with Floor, or
EntrywiseDivRoundAssign
when vec1 is vec2; its other rounding modes give the remaining quotients. Like
EntrywiseShrRound, it returns no
Ordering, unlike the scalar
DivRound.
The _si_2exp forms of scalar_addmul and scalar_submul multiply by \(c \cdot 2^e\). They
are AddMulShlAssign and
SubMulShlAssign of an IntegerVector, another IntegerVector, an
Integer scalar, and a u64 shift; AddMulShl and
SubMulShl return the result instead. Like FLINT’s, they handle a zero scalar,
a zero shift, and a scalar of \(\pm 1\) directly. NaturalVector implements AddMulShl and
AddMulShlAssign with a Natural scalar, and the scalar traits are implemented for Integer,
Natural (AddMulShl only), and Rational.
scalar_fdiv_r_2exp, the remainder in \([0, 2^e)\), is
ModPowerOf2
on an
IntegerVector.
Every remainder is nonnegative, so it returns a
NaturalVector,
as Mod does for scalar_mod_fmpz (see Reduction mod p).
The si and ui forms disappear, since Malachite’s
Integer
operations take
Integer
operands; convert the scalar once with Integer::from(c).
Sums and products
| FLINT | Malachite | |
|---|---|---|
| ✓ | void _fmpz_vec_sum(fmpz_t res, const fmpz * vec, slong len) |
ElementSum |
| ✓ | void _fmpz_ui_vec_prod(fmpz_t res, nn_srcptr vec, slong len) |
WideningElementProduct |
| ✓ | void _fmpz_vec_prod(fmpz_t res, const fmpz * vec, slong len) |
ElementProduct |
The sum of an empty vector is \(0\) and the product is \(1\). _fmpz_vec_sum is
ElementSum’s
to_element_sum, and _fmpz_vec_prod is
ElementProduct’s
to_element_product; the into_ forms consume the vector.
They are distinct from Sum for the
vector types, which adds vectors to each other.
_fmpz_ui_vec_prod takes an array of words, an
UnsignedVector<u64>
in Malachite, and its product is a
Natural:
WideningElementProduct’s
to_widening_element_product, whose output type is a
parameter so that the product cannot overflow. ElementProduct would return a u64. The same
computation is available for any iterator of unsigned primitive integers through
Product for Natural, as in
Natural::product(xs.iter()).
FLINT computes the products by binary splitting, multiplying the products of the two halves so
that the operands of each multiplication have similar sizes; below 16 words, _fmpz_ui_vec_prod
multiplies one word at a time. ElementProduct multiplies through
Product for
Integer and
Natural, which
does the same, combining the elements in a balanced tree, and stops as soon as it meets a zero.
WideningElementProduct first multiplies adjacent words together while their product fits in a
word, then combines the resulting words in a balanced tree; it also stops at a zero.
Reduction mod p
| FLINT | Malachite | |
|---|---|---|
| ✓ | void _fmpz_vec_scalar_mod_fmpz(fmpz * res, const fmpz * vec, slong len, const fmpz_t p) |
Mod |
| ✓ | void _fmpz_vec_scalar_smod_fmpz(fmpz * res, const fmpz * vec, slong len, const fmpz_t p) |
BalancedMod, BalancedModAssign |
| ✓ | void _fmpz_vec_multi_CRT_ui(fmpz * res, nn_srcptr * residues, slong len, nn_srcptr primes, slong num_primes, int sign) |
NaturalVector::multi_crt, IntegerVector::multi_balanced_crt |
scalar_mod_fmpz reduces each element into \([0, p)\), and scalar_smod_fmpz into
\((-p/2, p/2]\). For a single value these are
Mod
and
BalancedMod.
scalar_mod_fmpz is Mod on an
IntegerVector
with a Natural
modulus. Since every residue in \([0, p)\) is nonnegative, the result is a
NaturalVector,
as Mod on an IntegerPolynomial returns a NaturalPolynomial (see the polynomial
page). scalar_smod_fmpz is
BalancedMod on an IntegerVector with an
Integer
modulus, which keeps the result an IntegerVector; only the modulus’s magnitude matters, so a
negative modulus, which FLINT does not accept, gives the same result as its absolute value.
multi_CRT_ui is given the residues of a vector modulo several word-sized primes, one residue
vector per prime, and reconstructs each element by Chinese remaindering; sign chooses the
representative in \([0, M)\) or in \((-M/2, M/2]\), where \(M\) is the product of the primes.
These are
NaturalVector::multi_crt,
with sign = 0, and
IntegerVector::multi_balanced_crt,
with sign = 1. Each takes the moduli as a slice of
Limbs and the
residues as one
UnsignedVector<Limb>
per modulus, in FLINT’s order. Like FLINT, they precompute once for the moduli and reuse it for
every element; FLINT also splits long vectors across threads, which Malachite does not. They
follow
Natural::multi_crt
and
Integer::multi_balanced_crt
(see Chinese remaindering) in their conventions:
unusable moduli give
None (with one modulus, a
modulus of 0; with more, any 0 or 1, or any pair that is not coprime), the residues must be
reduced, and an empty list of moduli panics, where FLINT returns a vector of zeros of the given
length.
Gaussian content
| FLINT | Malachite | |
|---|---|---|
| ✓ | void _fmpz_vec_content(fmpz_t res, const fmpz * vec, slong len) |
Content |
| ✓ | void _fmpz_vec_content_chained(fmpz_t res, const fmpz * vec, slong len, const fmpz_t input) |
ContentChained |
| ✓ | void _fmpz_vec_lcm(fmpz_t res, const fmpz * vec, slong len) |
ElementLcm |
The content is the GCD of the elements, as a nonnegative
Natural; both
libraries define the content of the empty vector and of a vector of zeros to be \(0\), and both
stop as soon as the GCD reaches \(1\). The same family of traits also gives the vector divided by
its content:
PrimitivePart
and
ContentAndPrimitivePart,
along with canonical forms whose first nonzero element is positive.
content_chained computes the GCD of input and the elements of the vector, which makes it
possible to accumulate the common content of several vectors one at a time, starting from \(0\).
It is ContentChained’s v.content_chained(input), with input a
Natural taken by
value or by reference. Like FLINT’s, it skips zeros at both ends, returns \(1\) at once if an end
element is \(\pm 1\), and otherwise takes the elements in pairs from both ends, stopping as soon as
the GCD reaches \(1\). ContentChained is also implemented for
NaturalVector,
UnsignedVector,
and
RationalVector,
where input is a Rational and the result is the rational GCD.
_fmpz_vec_lcm is ElementLcm’s
to_element_lcm, or
into_element_lcm when the vector is no longer needed. Both
libraries define the LCM of the empty vector to be \(1\) and the LCM of a vector with a zero entry to
be \(0\), stopping at the first zero, and both return the LCM of the absolute values as a nonnegative
number. ElementLcm is implemented for IntegerVector and NaturalVector.
Dot product
| FLINT | Malachite | |
|---|---|---|
| — | void _fmpz_vec_dot_general_naive(fmpz_t res, const fmpz_t initial, int subtract, const fmpz * a, const fmpz * b, int reverse, slong len) |
|
| ✗ | void _fmpz_vec_dot_general(fmpz_t res, const fmpz_t initial, int subtract, const fmpz * a, const fmpz * b, int reverse, slong len) |
|
| ✓ | void _fmpz_vec_dot(fmpz_t res, const fmpz * vec1, const fmpz * vec2, slong len2) |
Dot |
_fmpz_vec_dot is \(\sum_i a_i b_i\). _fmpz_vec_dot_general generalizes it to
\(s \pm \sum_i a_i b_i\), with an optional initial term \(s\), a flag that subtracts the sum instead
of adding it, and a flag that pairs \(a_i\) with \(b_{n-1-i}\), reversing the second vector, as in
the coefficient of a polynomial product. _fmpz_vec_dot_general_naive is a slower reference
implementation of the same function, kept for testing; Malachite keeps reference implementations
in its test code rather than its public API.
_fmpz_vec_dot is Dot’s v.dot(w), for IntegerVector and NaturalVector, with
each vector taken by value or by reference; the vectors must have the same dimension, and the dot
product of two 0-dimensional vectors is \(0\). It uses the same accumulation as FLINT, described
below. The general form has no counterpart yet; until it does, start from the initial term (or
zero) and apply
AddMulAssign
or
SubMulAssign
for each pair of elements, iterating over the second vector in reverse for the reverse form.
FLINT’s _fmpz_vec_dot_general accumulates the small products in three words and the large ones
in two separate limb buffers, one for positive terms and one for negative, so it creates no
intermediate
Integers, and
Dot does the same; the element-by-element fold does not avoid them. Malachite does have a dot product for floating-point
numbers,
Float::dot
and its rounding variants, the counterpart of MPFR’s mpfr_dot.