use crate::array::{Array, ArrayKind, NaturalArray, OrdArray};
use crate::finite_function::FiniteFunction;
use crate::indexed_coproduct::{HasLen, IndexedCoproduct};
use num_traits::{One, Zero};
pub fn converse<K: ArrayKind>(
r: &IndexedCoproduct<K, FiniteFunction<K>>,
) -> IndexedCoproduct<K, FiniteFunction<K>>
where
K::Type<K::I>: NaturalArray<K>,
{
let values_table = {
let arange = K::Index::arange(&K::I::zero(), &r.sources.len());
let unsorted_values = r.sources.table.repeat(arange.get_range(..));
unsorted_values.sort_by(&r.values.table)
};
let sources_table =
(r.values.table.as_ref() as &K::Type<K::I>).bincount(r.values.target.clone());
let sources = FiniteFunction::new(sources_table, r.values.table.len() + K::I::one()).unwrap();
let values = FiniteFunction::new(values_table, r.len()).unwrap();
IndexedCoproduct::new(sources, values).unwrap()
}