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
//! A mesh partitioning library that implements multithreaded, composable geometric algorithms.
//!
//! # Crate Layout
//!
//! Coupe exposes a [`Partition`] trait, which is in turn implemented by
//! algorithms.  See its documentation for more details.  The trait is generic around its input, which means algorithms
//! can partition different type of collections (e.g. 2D and 3D meshes).
//!
//! # Available algorithms
//!
//! ## Partitioner algorithms
//!
//! - Space filling curves:
//!   + [Z-curve][ZCurve]
//!   + [Hilbert curve][HilbertCurve]
//! - [Recursive Coordinate Bisection][Rcb]
//! - [Recursive Inertial Bisection][Rib]
//! - [Multi jagged][MultiJagged]
//! - Number partitioning:
//!   + [Greedy][Greedy]
//!   + [Karmarkar-Karp][KarmarkarKarp] and its [complete][CompleteKarmarkarKarp] version
//!
//! ## Partition improving algorithms
//!
//! - [K-means][KMeans]
//! - Number partitioning:
//!   + [VN-Best][VnBest]
//!   + [VN-First][VnFirst]
//! - [Fiduccia-Mattheyses][FiducciaMattheyses]
//! - [Kernighan-Lin][KernighanLin]

#![cfg_attr(feature = "avx512", feature(stdsimd))]
#![warn(
    missing_copy_implementations,
    missing_debug_implementations,
    rust_2018_idioms
)]

mod algorithms;
mod average;
mod cartesian;
mod defer;
mod geometry;
pub mod imbalance;
mod nextafter;
mod real;
mod topology;
mod work_share;

pub use crate::algorithms::*;
pub use crate::average::Average;
pub use crate::cartesian::*;
pub use crate::geometry::BoundingBox;
pub use crate::geometry::{Point2D, Point3D, PointND};
pub use crate::nextafter::nextafter;
pub use crate::real::Real;
pub use crate::topology::Topology;

pub use nalgebra;
pub use num_traits;
pub use rayon;
pub use sprs;

use std::cmp::Ordering;
use std::mem;
use std::sync::atomic::AtomicUsize;

/// 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`.
    ///
    /// Part IDs must be contiguous and start from zero, meaning the number of
    /// parts is one plus the maximum of `part_ids`.  If a lower ID does not
    /// appear in the array, the part is assumed to be empty.
    fn partition(&mut self, part_ids: &mut [usize], data: M)
        -> Result<Self::Metadata, Self::Error>;
}

fn partial_cmp<W>(a: &W, b: &W) -> Ordering
where
    W: PartialOrd,
{
    if a < b {
        Ordering::Less
    } else {
        Ordering::Greater
    }
}

/// Transmute a mutable slice of [`usize`] into an immutable slice of
/// [`AtomicUsize`].
///
/// # Panics
///
/// Panics on platforms wher `usize` and `AtomicUsize` do not have the same
/// byte representation (size and alignment).
fn as_atomic(p: &mut [usize]) -> &[AtomicUsize] {
    assert_eq!(mem::size_of::<usize>(), mem::size_of::<AtomicUsize>());
    assert_eq!(mem::align_of::<usize>(), mem::align_of::<AtomicUsize>());

    unsafe {
        // While we could use [slice::align_to], their doc says:
        //
        // > The method may make the middle slice the greatest length possible
        // > for a given type and input slice, but only your algorithm’s
        // > performance should depend on that, not its correctness.
        //
        // So we have to use [mem::transmute] to ensure all the slice is
        // converted.
        mem::transmute::<&mut [usize], &[AtomicUsize]>(p)
    }
}