Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework trait system #9

Merged
merged 6 commits into from
Mar 23, 2022
Merged

Rework trait system #9

merged 6 commits into from
Mar 23, 2022

Conversation

hhirtz
Copy link
Member

@hhirtz hhirtz commented Sep 22, 2021

Trait changes

There is now only one Partition trait, which exposes a partition function and two types:

coupe/src/lib.rs

Lines 46 to 66 in 5521e9c

/// The `Partition` trait allows for partitioning data.
///
/// Partitioning algorithms implement this trait.
///
/// The generic argument `M` defines the input of the algorithms (e.g. an
/// adjacency matrix or a 2D set of points).
///
/// The input partition must be of the correct size and its contents may or may
/// not be used by the algorithms.
pub trait Partition<M> {
/// Diagnostic data returned for a specific run of the algorithm.
type Metadata;
/// Error details, should the algorithm fail to run.
type Error;
/// Partition the given data and output the part ID of each element in
/// `part_ids`.
fn partition(&mut self, part_ids: &mut [usize], data: M)
-> Result<Self::Metadata, Self::Error>;
}

Algorithms' input is represented by the generic type M (e.g. &'a [Point2D], or W: IntoIterator or even () for the random partitioning algorithm).

The function now can now mutate algorithm state. I don't know if it's something we want or not, but Random was using a RefCell for the prng state.

The Error type will be used instead of panics. I don't have modified all algorithms yet, and would rather do that in another PR.

Example usage

Implementation of VNBest, which is currently the only algorithm to return diagnostic data (metadata, see #34):

impl<W> crate::Partition<W> for VnBest
where
W: IntoIterator,
W::Item: AddAssign + Sub<Output = W::Item> + Div<Output = W::Item> + Mul<Output = W::Item>,
for<'a> &'a W::Item: Sub<Output = W::Item>,
W::Item: Zero + One,
W::Item: Ord + Copy,
{
type Metadata = usize;
type Error = std::convert::Infallible;
fn partition(
&mut self,
part_ids: &mut [usize],
weights: W,
) -> Result<Self::Metadata, Self::Error> {
let algo_iterations = vn_best_mono::<W, W::Item>(part_ids, weights, self.part_count);
Ok(algo_iterations)
}
}

Example usage of RCB:

let points = [
    Point2D::new(1., 1.),
    Point2D::new(-1., 1.),
    Point2D::new(1., -1.),
    Point2D::new(-1., -1.),
];
let weights = [1; 4];
let mut partition = [0; 4];

// generate a partition of 4 parts
let mut rcb = coupe::Rcb { iter_count: 2 };
rcb.partition(&mut partition, (points, weights)).unwrap();

Limitations

Some implementations cannot be as generic as we'd want, for example k-means:

impl<'a, const D: usize> crate::Partition<(&'a [PointND<D>], &'a [f64])> for KMeans

At first, I wanted k-means to implement Partition for any P: AsRef<[PointND<D>]> and W: AsRef<[f64]> (so that it can also be used with a &Vec<_>), but rust doesn't accept those kind of "loose" constraints on const-generic parameters.

I suppose this will do for now. Surprisingly, RCB, which has looser constraints, is fine:

impl<const D: usize, P, W> crate::Partition<(P, W)> for Rcb
where
P: rayon::iter::IntoParallelIterator<Item = PointND<D>>,
P::Iter: rayon::iter::IndexedParallelIterator,
W: rayon::iter::IntoParallelIterator,
W::Item: Copy + std::fmt::Debug + Default,
W::Item: Add<Output = W::Item> + AddAssign + Sub<Output = W::Item> + Sum + PartialOrd,
W::Item: num::ToPrimitive,
W::Iter: rayon::iter::IndexedParallelIterator,
{

Misc changes

All algorithm structs have been moved in their respective module, to declutter lib.rs.

Constructors/Builder patterns have been removed since they didn't add much (and a fn new with 5 parameters is not that readable). It's simpler to have a Default impl and let the user do Algo { specific_param, ..Algo::default() }.

@hhirtz

This comment was marked as outdated.

@hhirtz
Copy link
Member Author

hhirtz commented Mar 17, 2022

Started from scratch, hopefully this will allow for tools/mesh-part to be simplified.

@hhirtz

This comment was marked as outdated.

@hhirtz hhirtz force-pushed the trait-rework branch 2 times, most recently from e31c07f to ffcdcd0 Compare March 23, 2022 13:57
@hhirtz hhirtz changed the title WIP: Rework trait system Rework trait system Mar 23, 2022
hhirtz added 6 commits March 23, 2022 15:10
This simplifies the family of traits from before into one "Partition"
trait that is generic over the input of the algorithm.

Thus, algorithms can partition points, weights or graphs without
implementing several traits.

The partition function can now mutate algorithm state, which is useful
for PRNG state inside coupe::Random.

Algorithms can now return errors instead of panicking, which is more
FFI-friendly.

Algorithms can now return arbitrary information (e.g. coupe::VnBest
returns its number of iterations), which removes the need for
coupe::RunInfo.

== Limitations ==

Some implementations cannot be as generic as we want (e.g. Kmeans)

At first, I wanted k-means to implement `Partition` for any
`P: AsRef<[PointND<D>]>` and `W: AsRef<[f64]>` (so that it can also be
used with a &Vec<_>), but rust doesn't accept those kind of "loose"
constraints on const-generic parameters.

I suppose this will do for now. Surprisingly, RCB, which has looser
constraints, is fine.

== Misc changes ==

All algorithm structs have been moved in their respective module, to
declutter lib.rs.

Constructors/Builder patterns have been removed since they didn't add
much (and a fn new with 5 parameters is not that readable). It's simpler
to have a Default impl and let the user do
Algo { specific_param, ..Algo::default() }.
All of its items were exported anyway
@hhirtz hhirtz merged commit a345892 into master Mar 23, 2022
@cedricchevalier19 cedricchevalier19 deleted the trait-rework branch June 22, 2022 13:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant