pub struct BitDistributor { /* private fields */ }
Expand description

Helps generate tuples exhaustively.

Think of counter as the bits of an integer. It’s initialized to zero (all falses), and as it’s repeatedly incremented, it eventually takes on every 64-bit value.

output_types is a list of $n$ configuration structs that, together, specify how to generate an n-element tuple of unsigned integers. Calling get_output repeatedly, passing in 0 through $n - 1$ as index, distributes the bits of counter into a tuple.

This is best shown with an example. If output_types is set to [BitDistributorOutputType::normal(1); 2], the distributor will generate all pairs of unsigned integers. A pair may be extracted by calling get_output(0) and get_output(1); then counter may be incremented to create the next pair. In this case, the pairs will be $(0, 0), (0, 1), (1, 0), (1, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 0), (2, 1), \ldots$.

If you think of these pairs as coordinates in the $xy$-plane, they are traversed along a Z-order curve. Every pair of unsigned integers will be generated exactly once.

In general, setting output_types to [BitDistributorOutputType::normal(1); n] will generate $n$-tuples. The elements of the tuples will be very roughly the same size, in the sense that each element will grow as $O(\sqrt[n]{i})$, where $i$ is the counter. Sometimes we want the elements to grow at different rates. To accomplish this, we can change the weights of the output types. For example, if we set output_types to [BitDistributorOutputType::normal(1), BitDistributorOutputType::normal(2)], the first element of the generated pairs will grow as $O(\sqrt[3]{i})$ and the second as $O(i^{2/3})$. In general, if the weights are $w_0, w_1, \ldots, w_{n-1}$, then the $k$th element of the output tuples will grow as $O(i^{w_i/\sum_{j=0}^{n-1}w_j})$.

Apart from creating normal output types with different weights, we can create tiny output types, which indicate that the corresponding tuple element should grow especially slowly. If output_types contains $m$ tiny output types, each tiny tuple element grows as $O(\sqrt[m]{\log i})$. The growth of the other elements is unaffected. Having only tiny types in output_types is disallowed.

The above discussion of growth rates assumes that max_bits is not specified for any output type. But if max_bits is set to $b$, then the corresponding element will start growing just as if max_bits wasn’t specified, but will stop growing once it reaches $2^b-1$.

Implementations§

source§

impl BitDistributor

source

pub fn new(output_types: &[BitDistributorOutputType]) -> BitDistributor

Creates a new BitDistributor.

§Worst-case complexity

$T(n) = O(n)$

$M(n) = O(n)$

where $T$ is time, $M$ is additional memory, and $n$ is output_types.len().

§Examples
use malachite_base::iterators::bit_distributor::{
    BitDistributor, BitDistributorOutputType,
};

BitDistributor::new(&[
    BitDistributorOutputType::normal(2),
    BitDistributorOutputType::tiny(),
]);
source

pub fn bit_map_as_slice(&self) -> &[usize]

Returns a reference to the internal bit map as a slice.

The bit map determines which output gets each bit of the counter. For example, if the bit map is $[0, 1, 0, 1, 0, 1, \ldots]$, then the first element of the output pair gets the bits with indices $0, 2, 4, \ldots$ and the second element gets the bits with indices $1, 3, 5, \ldots$.

§Worst-case complexity

Constant time and additional memory.

§Examples
use malachite_base::iterators::bit_distributor::{
    BitDistributor, BitDistributorOutputType,
};

let bd = BitDistributor::new(&[
    BitDistributorOutputType::normal(2),
    BitDistributorOutputType::tiny(),
]);
assert_eq!(
    bd.bit_map_as_slice(),
    &[
        1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 1
    ][..]
);
source

pub fn set_max_bits(&mut self, output_type_indices: &[usize], max_bits: usize)

Sets the maximum bits for several outputs.

Given slice of output indices, sets the maximum bits for each of the outputs and rebuilds the bit map.

§Worst-case complexity

$T(n) = O(n)$

$M(n) = O(1)$

where $T$ is time, $M$ is additional memory, and $n$ is output_type_indices.len().

§Panics

Panics if max_bits is 0 or if any index is greater than or equal to self.output_types.len().

§Examples
use malachite_base::iterators::bit_distributor::{
    BitDistributor, BitDistributorOutputType,
};

let mut bd = BitDistributor::new(&[BitDistributorOutputType::normal(2); 3]);
assert_eq!(
    bd.bit_map_as_slice(),
    &[
        2, 2, 1, 1, 0, 0, 2, 2, 1, 1, 0, 0, 2, 2, 1, 1, 0, 0, 2, 2, 1, 1, 0, 0, 2, 2, 1, 1,
        0, 0, 2, 2, 1, 1, 0, 0, 2, 2, 1, 1, 0, 0, 2, 2, 1, 1, 0, 0, 2, 2, 1, 1, 0, 0, 2, 2,
        1, 1, 0, 0, 2, 2, 1, 1
    ][..]
);

bd.set_max_bits(&[0, 2], 5);
assert_eq!(
    bd.bit_map_as_slice(),
    &[
        2, 2, 1, 1, 0, 0, 2, 2, 1, 1, 0, 0, 2, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
        1, 1, 1, 1, 1, 1, 1, 1
    ][..]
);
source

pub fn increment_counter(&mut self)

Increments the counter in preparation for a new set of outputs.

If the counter is incremented $2^{64}$ times, it rolls back to 0.

§Worst-case complexity

Constant time and additional memory.

§Examples
use malachite_base::iterators::bit_distributor::{
    BitDistributor, BitDistributorOutputType,
};

let mut bd = BitDistributor::new(&[BitDistributorOutputType::normal(1)]);
let mut outputs = Vec::new();
for _ in 0..20 {
    outputs.push(bd.get_output(0));
    bd.increment_counter();
}
assert_eq!(
    outputs,
    &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
);
source

pub fn get_output(&self, index: usize) -> usize

Gets the output at a specified index.

§Worst-case complexity

Constant time and additional memory.

§Panics

Panics if index is greater than or equal to self.output_types.len().

§Examples
use itertools::Itertools;
use malachite_base::iterators::bit_distributor::{
    BitDistributor, BitDistributorOutputType,
};

let mut bd = BitDistributor::new(&[BitDistributorOutputType::normal(1); 2]);
let mut outputs = Vec::new();
for _ in 0..10 {
    outputs.push((0..2).map(|i| bd.get_output(i)).collect_vec());
    bd.increment_counter();
}
let expected_outputs: &[&[usize]] = &[
    &[0, 0],
    &[0, 1],
    &[1, 0],
    &[1, 1],
    &[0, 2],
    &[0, 3],
    &[1, 2],
    &[1, 3],
    &[2, 0],
    &[2, 1],
];
assert_eq!(outputs, expected_outputs);

Trait Implementations§

source§

impl Clone for BitDistributor

source§

fn clone(&self) -> BitDistributor

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for BitDistributor

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Hash for BitDistributor

source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
source§

impl PartialEq for BitDistributor

source§

fn eq(&self, other: &BitDistributor) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl Eq for BitDistributor

source§

impl StructuralPartialEq for BitDistributor

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> CloneToUninit for T
where T: Clone,

source§

unsafe fn clone_to_uninit(&self, dst: *mut T)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. Read more
source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
source§

impl<T, U> ExactFrom<T> for U
where U: TryFrom<T>,

source§

fn exact_from(value: T) -> U

source§

impl<T, U> ExactInto<U> for T
where U: ExactFrom<T>,

source§

fn exact_into(self) -> U

source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> IntoEither for T

source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

impl<T, U> OverflowingInto<U> for T
where U: OverflowingFrom<T>,

source§

impl<T, U> RoundingInto<U> for T
where U: RoundingFrom<T>,

source§

impl<T, U> SaturatingInto<U> for T
where U: SaturatingFrom<T>,

source§

impl<T> ToDebugString for T
where T: Debug,

source§

fn to_debug_string(&self) -> String

Returns the String produced by Ts Debug implementation.

§Examples
use malachite_base::strings::ToDebugString;

assert_eq!([1, 2, 3].to_debug_string(), "[1, 2, 3]");
assert_eq!(
    [vec![2, 3], vec![], vec![4]].to_debug_string(),
    "[[2, 3], [], [4]]"
);
assert_eq!(Some(5).to_debug_string(), "Some(5)");
source§

impl<T> ToOwned for T
where T: Clone,

source§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

source§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T, U> WrappingInto<U> for T
where U: WrappingFrom<T>,

source§

fn wrapping_into(self) -> U