orx_v/cardinality/card.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
use crate::{Dim, NVec};
/// Cardinality of a vector.
///
/// Note that cardinality of a vector of dimension `D` is capable of providing the
/// number of elements of all lower dimension children of the vector.
///
/// Consider, for instance a jagged vector of dimension `D2`, say `v2`, including
/// two vectors of lengths 4 and 6. Then its cardinality is capable of creating all
/// relevant cardinality information:
/// * `v.card([])` is 2
/// * `v.card([0])` is 4
/// * `v.card([1])` is 6
pub trait Card<D: Dim> {
/// Returns true if the cardinality is bounded and rectangular; i.e,
/// * children of a particular dimension have the same number of children.
///
/// The following are example multi-dimensional vectors with rectangular cardinality:
/// * All `D1` vectors.
/// * `D2` vector representing n-by-m matrices such that `card([])` is n and `card([i])`
/// is m for all i in 0..n.
/// * Similarly, higher dimensional vectors representing higher dimensional matrices
/// such as a `D3` vector representing n-by-m-by-p matrix such that `card([])` is n,
/// `card([i])` is m for all i, and `card([i, j])` os p for all (i,j).
/// * Empty vector of any dimension.
fn is_rectangular(&self) -> bool;
/// Returns the cardinality of the child of the vector at the given `idx`.
fn cardinality_of(&self, idx: impl Into<D::CardIdx>) -> usize;
/// Returns the cardinality of the child of this vector at the given
/// `left_most_idx`.
fn child_card(&self, left_most_idx: D::ChildIdx) -> impl Card<D::PrevDim>;
/// Creates a function, say `new_fun`, which applies the first of the indices to
/// `left_most_index` such that:
///
/// `new_fun([i, j, k])` returns `fun([left_most_idx, i, j, k])`
fn child_fun<T, F>(
&self,
left_most_idx: D::ChildIdx,
fun: F,
) -> impl Fn(<D::PrevDim as Dim>::Idx) -> T
where
F: Fn(D::Idx) -> T;
/// Returns an iterator over all elements of the `vec` provided that this is its
/// cardinality.
fn vec_all<'a, T, N>(&'a self, vec: &'a N) -> impl Iterator<Item = T>
where
N: NVec<D, T> + 'a;
/// Returns an iterator over all elements of the `vec` together with their corresponding
/// indices provided that this is its cardinality.
fn vec_enumerate_all<'a, T, N>(&'a self, vec: &'a N) -> impl Iterator<Item = (D::Idx, T)>
where
N: NVec<D, T> + 'a;
}
// impl ref
impl<D: Dim, C: Card<D>> Card<D> for &C {
fn is_rectangular(&self) -> bool {
<C as Card<D>>::is_rectangular(self)
}
fn cardinality_of(&self, idx: impl Into<<D as Dim>::CardIdx>) -> usize {
<C as Card<D>>::cardinality_of(self, idx)
}
fn child_card(&self, left_most_idx: D::ChildIdx) -> impl Card<<D as Dim>::PrevDim> {
<C as Card<D>>::child_card(self, left_most_idx)
}
fn child_fun<T, F>(
&self,
left_most_idx: D::ChildIdx,
fun: F,
) -> impl Fn(<<D as Dim>::PrevDim as Dim>::Idx) -> T
where
F: Fn(<D as Dim>::Idx) -> T,
{
<C as Card<D>>::child_fun(self, left_most_idx, fun)
}
fn vec_all<'a, T, N>(&'a self, vec: &'a N) -> impl Iterator<Item = T>
where
N: NVec<D, T> + 'a,
{
<C as Card<D>>::vec_all(self, vec)
}
fn vec_enumerate_all<'a, T, N>(
&'a self,
vec: &'a N,
) -> impl Iterator<Item = (<D as Dim>::Idx, T)>
where
N: NVec<D, T> + 'a,
{
<C as Card<D>>::vec_enumerate_all(self, vec)
}
}
// helpers
pub(super) fn child_fun_unchecked<D, T, F>(
i: D::ChildIdx,
fun: F,
) -> impl Fn(<D::PrevDim as Dim>::Idx) -> T
where
D: Dim,
F: Fn(D::Idx) -> T,
{
let i: usize = i.into();
move |idx: <D::PrevDim as Dim>::Idx| {
let idx = D::left_join_from_lower_dim(i, idx);
(fun)(idx)
}
}
#[allow(clippy::panic)]
pub(crate) fn panic_on_all_when_udd(is_udd: bool) {
if is_udd {
panic!(
"Called `all` or `enumerate_all` on an unbounded vector. \
You may use `all_in` to iterate over explicit indices. \
Alternatively, you may transform the vector into a bounded vector by \
calling `bounded`, `with_rectangular_bounds` or `with_variable_bounds` \
methods."
);
}
}