standing_relations/convenience/
map.rs1use 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}