[][src]Crate voracious_radix_sort

Voracious sort

Voracious sort is a sort algorithm, like Rust standard sort or Rust unstable sort. However it is a radix sort, it is a non comparative sort. It is a very fast sort which compares very well against Rust standard and unstable sorts or others state of the art sorting algorithms (see runtimes below).

Voracious sort can sort a vector or a slice of:

Vocarious sort can only sort in ascending order. You can call the reverse method if desired.

Because of Rust Orphan Rule, we chose not to support tuple sorting. You can use Struct instead.

Version

Last version tested/used:

  • Rustc: 1.41.1 stable
  • Rustfmt: 1.4.11 stable
  • Cargo: 1.41.0 stable
  • Clippy: 0.0.212

License

See the license file.

How to use it

Add in Cargo.toml:

[dependencies]
voracious_radix_sort = "0.1.0"

Environment variable

To fully benefit from Voracious sort, it is better to add the environment variable:

export RUSTFLAGS="-C target-cpu=native"

When the Crate is imported, two methods are added to vectors and slices:

  • voracious_sort() (single thread).
  • voracious_stable_sort() (single thread).

Example

use voracious_radix_sort::*;

let mut array = vec![2, 45, 8, 7, 9, 65, 8, 74, 1, 2, 56, 9, 7, 41];

array.voracious_sort();

assert_eq!(array, vec![1, 2, 2, 7, 7, 8, 8, 9, 9, 41, 45, 56, 65, 74]);

let mut array = vec![2, 45, 8, 7, 9, 65, 8, 74, 1, 2, 56, 9, 7, 41];

array.voracious_stable_sort();

assert_eq!(array, vec![1, 2, 2, 7, 7, 8, 8, 9, 9, 41, 45, 56, 65, 74]);

Implementing a custom struct

Let's do it through an example.

use std::cmp::Ordering;

// We need a struct
// We want, for example, to sort these structs by the key = value
// This struct must implement the Copy and Clone traits, we can just derive them.
#[derive(Copy, Clone, Debug)]
pub struct Custom {
    value: f32,
    other: usize,
}
impl PartialOrd for Custom {
    fn partial_cmp(&self, other: &Custom) -> Option<Ordering> {
        self.value.partial_cmp(&other.value)
    }
}
impl PartialEq for Custom {
    fn eq(&self, other: &Self) -> bool {
        self.value == other.value
    }
}

And then we have to implement the Radixable trait:

use voracious_radix_sort::*;

impl Radixable<f32> for Custom {
    type Key = f32;
    #[inline]
    fn key(&self) -> Self::Key {
        self.value
    }
}

See more implementation examples on our GitHub

When it is done, we can run a test:

use voracious_radix_sort::*;

let mut array = vec![
    Custom { value: 5.7, other: 29 },
    Custom { value: 2.7, other: 23 },
    Custom { value: 14.7, other: 17 },
    Custom { value: 4.7, other: 35 },
];

array.voracious_sort();

assert_eq!(array, vec![
    Custom { value: 2.7, other: 23 },
    Custom { value: 4.7, other: 35 },
    Custom { value: 5.7, other: 29 },
    Custom { value: 14.7, other: 17 },
]);

let mut array = vec![
    Custom { value: 5.7, other: 29 },
    Custom { value: 2.7, other: 23 },
    Custom { value: 14.7, other: 17 },
    Custom { value: 4.7, other: 35 },
];

array.voracious_stable_sort();

assert_eq!(array, vec![
    Custom { value: 2.7, other: 23 },
    Custom { value: 4.7, other: 35 },
    Custom { value: 5.7, other: 29 },
    Custom { value: 14.7, other: 17 },
]);

Panics

For f32 and f64 , if there is a NaN value or an INFINITY or a NEG_INFINITY in the vector or the slice, the behavior is not guaranteed.

It might panic or not sort correctly the array.

Dependencies

There is no dependency.

Performances

  • All tests have been done on a i5 7500 3.4GHz 6MB cache L3 with 40GB DDR4 RAM (November 2019) with RUSTFLAGS="-C target-cpu=native".

  • Only one run has been done by test.

  • For more runtimes, please visit our GitHub.

  • Times are in micro seconde.

  • In order to have a very user friendly crate, sorts might be a little less faster than dedicated sort by type.

  • CAUTION: Performance tests have been done on a previous version of the code.

  • *RdxSort version 0.3.0

  • *AfSort version 0.3.1

For u64 100_000_000 integers

DistributionVoraciousDLSDRust StdRust UnstableRdxSort*AFSort*
Uniform1_969_9841_393_20610_124_1033_372_091 2_842_6704_060_710
Zipf352_6841_315_7135_584_313331_3305_587_2662_155_202
Normal (SD 10^6)1_863_5363_008_3359_675_9112_454_2083_874_5214_482_161

For f64 100_000_000 floats

DistributionVoraciousDLSDRust StdRust UnstableRdxSort*AFSort*
Uniform2_358_0322_873_76814_247_5517_108_8424_548_991N/A
Zipf2_198_0491_221_6606_435_186805_0886_242_734N/A
Normal (SD 10^6)2_357_6972_334_54114_049_2257_109_5804_309_830N/A

For i64 100_000_000 integers

DistributionVoraciousDLSDRust StdRust UnstableRdxSort*AFSort*
Uniform2_037_4791_347_1689_932_9123_516_6093_302_737N/A
Zipf401_9471_287_5345_499_072320_0385_807_618N/A
Normal (SD 10^6)1_856_7293_039_1949_821_6702_602_0984_225_584N/A

For char 100_000_000 chars

DistributionVoraciousDLSDRust StdRust UnstableRdxSort*AFSort*
Uniform777_537802_9396_116_9851_813_0571_933_041N/A
All Equal47_91447_92947_48841_2122_229_338N/A
Small CharSet114_896394_6166_197_632689_7382_006_239N/A
Medium CharSet113_521622_1846_144_734629_9891_982_256N/A
Big CharSet867_986857_8846_169_368727_7492_029_007N/A

For Developers and Researchers

Logic

  • Voracious sort is a MSD radix sort. It is an improvement of the Ska sort and it uses the Verge sort pre-processing heuristic. Depending on the type and the input size, another sort might be choosen (LSD sort, Counting sort, etc...). The purpose is to implement a multithread radix sort (see Regions sort and the article).

  • DLSD (Diverting LSD radix sort) is a simpler version of the DFR sort with a different diversion and a variable radix (see article).

  • All sorts fallback on the PDQ sort (Rust Unstable sort) for very small inputs (or Rust stable sort).

Future work

  • Add multithread sort.
  • Improve k-way-merge algorithm.
  • Add more generators (for tests).
  • Add a sort for String.

Re-exports

pub use traits::dispatcher::Dispatcher;
pub use traits::radix_key::RadixKey;
pub use traits::radixable::Radixable;
pub use traits::radixsort::RadixSort;

Modules

traits

Functions

american_flag_sort

American flag sort

boolean_sort

Boolean sort

counting_sort

Counting sort

ded_lsd_radixsort
dlsd_radixsort

DLSD sort: Diverting LSD sort

insertion_sort

Insertion sort

lsd_radixsort

LSD sort

msd_radixsort

MSD sort

msd_stable_radixsort

MSD stable sort

ska_sort

Ska sort

thiel_radixsort

Thiel sort

voracious_sort

Voracious sort