standing_relations/convenience/
map.rs

1use std::{
2    collections::{BTreeMap, HashMap},
3    convert::identity,
4    fmt::Debug,
5    iter,
6    ops::Neg,
7};
8
9use crate::{pair::Pair, Op, Op_, Relation};
10
11pub type KVMap<K, V> = HashMap<K, HashMap<V, isize>>;
12pub type ExtremaMap<K, V> = BTreeMap<K, HashMap<V, isize>>;
13
14impl<C: Op_> Relation<C> {
15    pub fn map_<Y, F: Fn(C::T) -> Y>(self, f: F) -> Relation<impl Op_<T = Y>> {
16        self.flat_map_(move |x| iter::once(f(x)))
17    }
18    pub fn debug(self, name: &'static str) -> Relation<impl Op_<T = C::T>>
19    where
20        C::T: Debug,
21    {
22        self.map_(move |x| {
23            log::debug!("{}: {:?}", name, x);
24            x
25        })
26        .hidden()
27    }
28}
29
30impl<C: Op> Relation<C> {
31    pub fn flat_map<I: IntoIterator>(
32        self,
33        f: impl Fn(C::D) -> I,
34    ) -> Relation<impl Op<D = I::Item>> {
35        self.flat_map_(move |(x, count)| f(x).into_iter().map(move |y| (y, count)))
36    }
37    pub fn flatten(self) -> Relation<impl Op<D = <C::D as IntoIterator>::Item>>
38    where
39        C::D: IntoIterator,
40    {
41        self.flat_map(identity).type_named("flatten")
42    }
43    pub fn map<Y>(self, f: impl Fn(C::D) -> Y) -> Relation<impl Op<D = Y>> {
44        self.flat_map(move |x| iter::once(f(x))).type_named("map")
45    }
46
47    pub fn map_h<Y>(self, f: impl Fn(C::D) -> Y) -> Relation<impl Op<D = Y>> {
48        self.map(f).hidden()
49    }
50
51    pub fn filter(self, f: impl Fn(&C::D) -> bool) -> Relation<impl Op<D = C::D>> {
52        self.flat_map(move |x| if f(&x) { Some(x) } else { None })
53            .type_named("filter")
54    }
55
56    pub fn map_counts(self, f: impl Fn(isize) -> isize) -> Relation<impl Op<D = C::D>> {
57        self.flat_map_(move |(x, count)| iter::once((x, f(count))))
58            .type_named("map_counts")
59    }
60
61    pub fn negate(self) -> Relation<impl Op<D = C::D>> {
62        self.map_counts(Neg::neg).type_named("negate")
63    }
64}
65
66impl<A, B, C: Op<D = (A, B)>> Relation<C> {
67    pub fn fsts(self) -> Relation<impl Op<D = A>> {
68        self.map_h(Pair::fst)
69    }
70    pub fn snds(self) -> Relation<impl Op<D = B>> {
71        self.map_h(Pair::snd)
72    }
73    pub fn swaps(self) -> Relation<impl Op<D = (B, A)>> {
74        self.map_h(Pair::swap)
75    }
76}