Permutator
It provides different way to get permutation of data.
TLDR
Easiest generic use case
use ;
let domains : & = &;
domains.cart_prod.for_each;
Get a permutation at specific point, not an iterator style.
It provides 2 functions to get a cartesian product or k-permutation:
- get_cartesian_for
- get_permutation_for It also provide utilities functions like:
- get_cartesian_size
- get_permutation_size
Get a cartesian product over a set itself multiple times
There are two distinct implementation to get cartesian product.
- Iterator that return product
- Function that call callback function to return product
Iterator
This crate provides SelfCartesianProductIterator, SelfCartesianProductCellIter, and SelfCartesianProductRefIter structs that implement
Iterator, IteratorReset, ExactSizeIterator traits. Each struct serves different use cases:-
SelfCartesianProductIteratorcan be used in any case that performance is least concern.SelfCartesianProductCellItercan be used in case performance is important as well as safety.SelfCartesianProductRefItercan be used in case performance is critical and safety will be handle by caller. Every structs implementsIteratorResettrait.- use
resetfunction instead of creating a new Iterator everytime you need to re-iterate.
Trait
This crate provides CartesianProduct trait which add function cart_prod that return an Iterator to generate a Cartesian Product over a set itself multiple times. The types that currently support are:
- (&'a [T], usize) - Generate cartesian product over 'first paramter' for 'second paramater' times.
- (&'a [T], usize, Rc<RefCell<&'a mut [&'a T]>>) - Similar to above but keep overwrite the product into 'third parameter'
- (&'a [T], usize, *mut [&'a T]) - Similar to above but use unsafe pointer to store value.
Each type above return different Iterator. For example (&'a [T], usize) return
SelfCartesianProductIteratorbut on (&'a [T], usize, *mut [&'a T]) returnSelfCartesianProductRefIter.
Callback function
This crate provides 4 functions that serve different usecase.
self_cartesian_productfunction that return product as callback parameterself_cartesian_product_cellfunction that return product into Rc<RefCell<>> given in function parameterself_cartesian_product_syncfunction that return product into Arc<RwLock<>> given in function parameterunsafe_self_cartesian_productunsafe function that return product into mutable pointer given in function parameter
Get a cartesian product over multiple sets
There are two distinct implementation to get cartesian product.
- Iterator that return product
- Function that call callback function to return product
Iterator
This crate provides CartesianProductIterator, CartesianProductCellIter, and CartesianProductRefIter structs that implement
Iterator, IteratorReset, ExactSizeIterator traits. Each struct serves different use cases:-
CartesianProductIteratorcan be used in any case that performance is least concern.CartesianProductCellItercan be used in case performance is important as well as safety.CartesianProductRefItercan be used in case performance is critical and safety will be handle by caller. Every structs implementsIteratorResettrait.- use
resetfunction instead of creating a new Iterator everytime you need to re-iterate.
Trait
This crate provides CartesianProduct trait and basic implementation various types such as generic slice of slices, generic Vec of slices, tuple of (&'a [&'a [T]], Rc<RefCell<&'a mut[&'a T]>>), and tuple of (&'a [&'a [T]], *mut [&'a T]).
It add cart_prod() function to it and return required iterator based on type of data. For example on generic Vec of slices return CartesianProductIterator but on (&'a [&'a [T]], *mut [&'a T]) return CartesianProductRefIter.
Callback function
This crate provides 4 functions that serve different usecase.
cartesian_productfunction that return product as callback parametercartesian_product_cellfunction that return product into Rc<RefCell<>> given in function parametercartesian_product_syncfunction that return product into Arc<RwLock<>> given in function parameterunsafe_cartesian_productunsafe function that return product into mutable pointer given in function parameter
Get a combination from data
There are three distinct implementation to get k-combinations of n set.
- Iterator that return each combination on each iteration
- Trait that add function to slice, Vec, Rc<RefCell<&mut[&T]>>, etc.
- Function that call callback function to return product
Iterator
This crate provides GosperCombinationIterator, GosperCombinationCellIter, and GosperCombinationRefIter structs that implement
IntoIterator traits. Each struct serves different use cases:-
GosperCombinationIteratorcan be used in any case that performance is least concern.GosperCombinationCellItercan be used in case performance is important as well as safety.GosperCombinationRefItercan be used in case performance is critical and safety will be handle by caller.- These struct isn't implement Iterator itself but it still provide
resetfunction to reset state of the object instead of creating a new object. It's also providesCombinationIterator,CombinationCellIter, andCombinationRefIterstructs that implementIterator,IteratorReset,ExactSizeIteratortraits which is anIteratorrepresentation of each respectivelyGosperCombinationstructs Every structs implementsIteratorResettrait. - use
resetfunction instead of creating a new Iterator everytime you need to re-iterate.
Trait
This crate provides Combination trait and basic implementation various types such as generic slice, generic Vec, tuple of (&'a [T], Rc<RefCell<&'a mut[&'a T]>>), and tuple of (&'a [T], * mut[&'a T]).
It add combination(usize) function to it and return required iterator based on type of data. For example on generic Vec return CombinationIterator but on (&'a [T], * mut[&'a T]) return CombinationRefIter.
Note:
- It doesn't return
GosperCombinationfamily of structs but return a directIteratorimplemented object.
Callback function
This crate provide 4 functions that serve different usecase.
combinationfunction that return product as callback parametercombination_cellfunction that return product into Rc<RefCell<>> given in function parametercombination_syncfunction that return product into Arc<RwLock<>> given in function parameterunsafe_combinationunsafe function that return product into mutable pointer given in function parameter
Get a permutation from data
There are three distinct implementation to get permutation.
- Iterator that do permutation on data
- Trait that add function to slice, Vec, etc.
- Function that call callback function to return each permutation
Iterator
This crate provides HeapPermutationIterator, HeapPermutationCellIter, and HeapPermutationRefIter structs that implement
Iterator, IteratorReset, ExactSizeIterator traits. Each struct serves different use cases:-
HeapPermutationIteratorcan be used in any case that performance is least concern.HeapPermutationCellItercan be used in case performance is important as well as safety.HeapPermutationRefItercan be used in case performance is critical and safety will be handle by caller. Every structs implementsIteratorResettrait.- use
resetfunction instead of creating a new Iterator everytime you need to re-iterate.
Trait
This crate provides Permutation trait and basic implementation various types such as generic slice, generic Vec, tuple of (&'a mut[T], Rc<RefCell<&'a mut[T]>>, and more type but used for k-permutation.
It add permutation() function to it and return required iterator based on type of data. For example on generic Vec return HeapPermutationIterator but on (&'a mut [T], Rc<RefCell<&'a mut[T]>>) return HeapPermutationCellIter.
Callback function
This crate provide 3 functions that serve different usecase.
heap_permutationfunction that return product as callback parameterheap_permutation_cellfunction that return product into Rc<RefCell<>> given in function parameterheap_permutation_syncfunction that return product into Arc<RwLock<>> given in function parameter
Get a k-permutation from data
There are three implementation to get k-permutations of n set.
- Iterator that return product
- Trait that add functionality to some specific tuple.
- Function that call callback function to return product
Iterator
This crate provides KPermutationIterator, KPermutationCellIter, and KPermutationRefIter structs that implement
Iterator, IteratorReset, ExactSizeIterator traits. Each struct serves different use cases:-
KPermutationIteratorcan be used in any case that performance is least concern.KPermutationCellItercan be used in case performance is important as well as safety.KPermutationRefItercan be used in case performance is critical and safety will be handle by caller. Every structs implementsIteratorResettrait.- use
resetfunction instead of creating a new Iterator everytime you need to re-iterate.
Trait
This crate provides Permutation trait that can be used to perform on tuple of (&'a [T], usize), tuple of (&'a [T], usize, Rc<RefCell<&'a mut [&'a T]>>), and (&'a [T], usize, *mut [&'a T]) to create different type of iterator.
It add permutation() function to it and return required iterator based on type of data. For example on (&'a [T], usize) return KPermutationIterator but on (&'a [T], usize, *mut [&'a T]) return KPermutationRefIter.
Callback function
This crate provide 4 functions that serve different usecase.
k_permutationfunction that return product as callback parameterk_permutation_cellfunction that return product into Rc<RefCell<>> given in function parameterk_permutation_syncfunction that return product into Arc<RwLock<>> given in function parameterunsafe_k_permutationunsafe function that return product into mutable pointer given in function parameter
Notes
Struct with RefIter and CellIter suffix return empty Item on each Iteration
Struct like CartesianProductIterator, CombinationIterator, HeapPermutationIterator, KPermutationIterator return fresh new Vec on each iteration. All other structs that have other way to return value will return empty tuple on each iteration. For example, CartesianProductCellIter, CombinationRefIter, HeapPermutationCellIter, and KPermutationRefIter all return empty tuple on each iteration. It return result via parameter specified when instantiate an object. For example, method new on CartesianProductCellIter require Rc<RefCell<&mut [&T]>> parameter which will be used to store each cartesian product from each iteration.
It's important to keep in mind that these struct with suffix RefIter and CellIter overwrite the result of previous iteration on every iteration. If every result from each iteration need to be kept, consider using non-suffix version. For example, instead of using KPermutationRefIter and clone/copy every result into Vec, consider using KPermutationIterator instead.
Performance concern
- Generally speaking, the standard callback function give highest throughput but the return result is a borrowed data with lifetime valid only in that callback scope.
- The crate provides three built-in methods to share result.
- callback function with "_cell" suffix.
- A struct with
CellIterandRefItersuffix. - Iterator that return an owned value.
The callback with "_cell" suffix way is about 10%-20% slower than using
CellItersuffix method. The return owned value method is slowest but most versatile. It's about 700%-1000% slower than usingCellItersuffix object. However, it is still faster than using standard callback function then convert it to owned value to share result.
- This crate provides two built-in methods to send result to other threads.
- callback function with "_sync" suffix.
- Iterator that return an owned value. The fastest and safest way to send result to other threads is to use an Iterator that return owned value. It's about 50%-200% faster than using callback function.
Mutating result is dangerous
Most of sharing result use interior mutability so that the function/struct only borrow the sharing result. It'll mutably borrow only when it's going to mutate result and drop the mutable borrow immediately before calling a callback or return result from iteration. This mean that the result is also mutable on user side. However, doing so may result in undesired behavior. For example: heap_permutation_cell function swap a pair of element inside Rc<RefCell<>> in place. If user swap value inside result, some permutation return in the future may duplicate with the already return one. If user remove some value inside result, it'll panic because inside the heap_permutation_cell function unrecognize the size changed.
Send result to other thread is complicated
This crate provides two built-in methods to send result across thread. The two usecase is strongly against each other in term of performance. The callback with "_sync" suffix store borrowed result into Arc<RwLock<>> which reduce the cost of allocating additional memory and copy/clone the result into it. Each thread that read borrowed content may need additional overhead of communication especially if it cannot miss any of the data send to it. In such case, the following scenario is applied
- The function generate new result
- The function send notification via channel to every threads that new result is available.
- The function block until every thread send notification back that they are all done with the data.
Another way is to use Iterator that return an owned value then clone that value on each thread. This is much simpler to implement but require more memory. It'll simplify the scenario above to:
- The iterator return new result.
- It send notification with new data via channel to every threads. The performance observed in uncontrolled test environment show that the iterator way is faster than the callback by at least 50%.
Unsafe way is fastest and hardest
It's because all "unsafe_" prefix function and struct with RefIter suffix return result throught mutable pointer that
make it has lowest cost to send result back. It leave everything else to user to do the work.
To use it, make sure that the memory is return when it no longer use, synchronization, initialization
is properly done. The original variable owner outlive both user and generator.
Example
Get a permutation at specific point examples
To get into 'n' specific lexicographic permutation,
use get_cartesian_size;
get_cartesian_size; // return 9.
get_cartesian_size; // return 27.
use get_cartesian_for;
let nums = ;
get_cartesian_for; // Return Ok([1, 1])
get_cartesian_for; // Return Ok([2, 1])
get_cartesian_for; // Return Ok([3, 3])
get_cartesian_for; // Return Err("Parameter `i` is out of bound")
get_cartesian_for; // Return Err("Parameter `degree` cannot be larger than size of objects")
use get_permutation_size;
get_permutation_size; // return = 6
get_permutation_size; // return = 12
use get_permutation_for;
let nums = ;
get_permutation_for; // return Result([1, 2])
get_permutation_for; // return Result([1, 2, 3])
get_permutation_for; // return Result([2, 4])
get_permutation_for; // return Result([4, 3])
get_permutation_for; // return Err("parameter x is outside a possible length")
get_permutation_for; // return Err("Insufficient number of object in parameters objects for given parameter degree")
Cartesian product of multiple sets of data
To get cartesian product from 3 set of data.
use cartesian_product;
cartesian_product;
Or do it in iterative style
use CartesianProductIterator
use Instant;
let data : & = &;
let cart = new;
let mut counter = 0;
let timer = now;
for p in cart
assert_eq!;
println!;
Import trait then skipping all object instantiation altogether.
use Instant;
use CartesianProduct;
let data : & = &;
let mut counter = 0;
let timer = now;
data.cart_prod.for_each;
assert_eq!;
println!;
Combination Iterator examples
The struct offer two ways to get a combination. First it can be used as Iterator. Second manually call next with borrowed mut variable that will store the next combination.
// Combination iterator
use GosperCombinationIterator;
use ;
let data = ;
let gosper = new;
let mut counter = 0;
let timer = now;
for combination in gosper
println!;
use Combination;
use ;
let data = ;
let mut counter = 0;
let timer = now;
data.combination.for_each
Iterator style permutation example
There's HeapPermutationIterator and KPermutationIterator struct that can do
permutation. Below is an example of HeapPermutationIterator.
use HeapPermutationIterator;
use ;
let data = &mut ;
println!;
let mut permutator = new;
let timer = now;
let mut counter = 1;
for permutated in permutator
// or use iterator related functional approach like line below.
// permutator.into_iter().for_each(|permutated| {counter += 1;});
println!;
Iterator into Rc<RefCell<>>
There's HeapPermutationCellIter and KPermutationCellIter struct that offer
such functionality. Below is an example of HeapPermutationCellIter
use HeapPermutationCellIter;
use RefCell;
use Rc;
use ;
let data = &mut ;
let result = new;
// print original data before permutation
// println!("0:{:?}", &*result.borrow());
let mut permutator = new;
let timer = now;
let mut counter = 1;
for _ in permutator
println!;
The KPermutationCellIter example show below
use KPermutationCellIter;
use RefCell;
use Rc;
let k = 3;
let data = &;
let mut result = vec!;
let shared = new;
let mut kperm = new;
for _ in kperm
Traits that add new function to various types
CartesianProduct trait add cart_prod function.
The function take no parameter. The function return the same Iterator that also return by
the provided struct
so it can be used like this example
use CartesianProduct;
let data : &= &;
data.cart_prod.for_each;
or
use CartesianProduct;
let data : &= &;
let mut result = vec!;
let shared = new;
// shared can be owned by anyone who want to get cartesian product.
.cart_prod.for_each;
Combination trait add combination function.
The function take 1 parameter. It's a size of combination frame, AKA k, r, etc.
The function return the same Iterator that also return by
the provided struct
so it can be used like this example
use Combination;
let data = ;
data.combination.for_each;
or
use Combination;
let data = ;
let k = 3;
let mut result = vec!;
let shared = new;
// shared can be owned by anyone who want to get combinations.
.combination.for_each;
Permutation trait add permutation function.
It permute the [T], Vec<T>, or Rc<RefCell<&mut [T]>> in place.
The function return the same Iterator that also return by the either
this provided struct or this provided struct
depending on what types does this method is called upon
so it can be used like this example
or this example or following example:
use Permutation;
let mut data = ;
data.permutation.for_each;
// The `data` at this point will also got permuted.
// It'll print the last permuted value twice.
println!;
use Permutation;
let mut data = ;
let shared = new;
// shared can be owned by anyone that want to get a permutation
clone.permutation.for_each;
// The same goes as previous example, the data inside shared on every owner will now has last permuted value.
or k-permutation into Rc<RefCell<>>
use KPermutationCellIter;
use RefCell;
use Rc;
let k = 3;
let data = &;
let mut result = vec!;
let shared = new;
.permutation.for_each;
Unsafe way for faster share result
In some circumstance, the combination result need to be shared but the safe function don't allow you to share the result except copy/clone the result for each share. When that's the case, using Iterator may answer such situation.
Another approach is to use CellIer suffix struct or callback function
with _cell suffix. As long as each iteration doesn't reuse previous
result and result owner treat result as immutable data then it's safe
to use this approach.
Another way, if safety is less concern than performance, there's an
unsafe side implementation that take a mutable pointer to store result.
There's more thing to keep in mind than using struct with CellIter suffix
and callback function _cell suffix. For example:
- Pointer need to outlive the entire operation
- The object that pointer is pointed to need to be release.
- Result synchronization, both in single and multiple thread(s).
- ...
- All other unsafe Rust conditions applied
Example:
- unsafe callback function
use unsafe_combination;
let data = ;
let r = 3;
let mut counter = 0;
let mut result = vec!;
let result_ptr = result.as_mut_slice as *mut ;
unsafe
assert_eq!;
- unsafe Iterator object
use GosperCombinationRefIter;
let data = ;
let r = 3;
let mut counter = 0;
let mut result = vec!;
let result_ptr = result.as_mut_slice as *mut ;
unsafe
assert_eq!;
Share with multiple object from callback function
An example showing the built-in feature that save new cartesian product into Rc<RefCell<>> so it can be easily share to other. This example use two worker objects that read each cartesian product and print it.
use Debug;
use Rc;
use RefCell;
use cartesian_product_cell;
let data : & = &;
let mut result = vec!;
let shared = new;
let worker1 = Worker1 ;
let worker2 = Worker2 ;
let consumers : = vec!;
start_cartesian_product_process;
Iterator that send data to other threads
This example generates a k-permutation and send it to multiple threads by using KPermutation iterator.
The main thread will keep generating a new k-permutation and send it to every thread while all other threads read new k-permutation via channel. In this example, it use sync_channel with size 0. It doesn't hold anything inside the buffer. The sender will block until the receiver read the data.
use KPermutation;
use mpsc;
let k = 5;
let data : & = &;
// workter thread 1
let = ;
spawn;
// worker thread 2
let = ;
spawn;
let channels = vec!;
// main thread that generate result
spawn.join.unwrap;
Callback function send data to other thread
This example generates a k-permutation and send it to multiple threads by using a callback approach k_permutation_sync function.
The main thread will keep generating a new k-permutation and send it to every thread while all other threads read new k-permutation via channel. In this example, it use sync_channel with size 0. It doesn't hold anything inside the buffer. The sender will block until the receiver read the data.
use ;
use mpsc;
use ;
let k = 5;
let data = &;
let result = vec!;
let result_sync = new;
// workter thread 1
let = ;
let = sync_channel;
let t1_local = main_send.clone;
let t1_dat = clone;
spawn;
// worker thread 2
let = ;
let t2_dat = clone;
let t2_local = main_send.clone;
spawn;
// main thread that generate result
spawn.join.unwrap;
Breaking change from 0.1.6 to 0.2.0
Version 0.2.0 has major overhaul on entire crate to make use case more consistent on each other functionalities. There are now only 2 major distinct styles. 1. Callback function 2. Iterator object. The Iterator object has 2 sub-style. 1. Plain Iterator style. 2. Shared Iterator style. The shared Iterator style has both safe and unsafe kind of share which is similar to callback style counterpart. It need to rename every structs. It add one more trait and some more types.
More detail on breaking change:
- An iterator style
next_into_cellhas been refactored into their own struct. Now it can be used like simple Iterator with slightly different way to return value. - A mimic iterator style
nextthat took&mut[&T]parameter has been refactored into their own struct. Now it can be used like simple Iterator with slightly different way to return value. CartesianProductstruct is renamed toCartesianProductIteratorHeapPermutationstruct is renamed toHeapPermutationIteratorGosperCombinationstruct is renamed toGosperCombinationIteratorKPermutationstruct is renamed toKPermutationIteratorCombinationandPermutationtraits now use associated typecombinatorandpermutatorrespectively to define the struct that will be used to perform combination/permutation on slice/array/Vec and Rc<RefCell<&mut [T]>> instead of fixed return type. Now, all trait return an object that implementIteratortrait. It doesn't constrait the associated typeItemdefined inIteratorthought. The trait now take <'a> lifetime parameter and no longer take generic typeT. Thecombinationfunction change signature fromcombination(&mut self)tocombination(&'a mut self). Thepermutationfunction change signature frompermutation(&mut self)topermutation(&'a mut self).
Migration guide from 0.1.6 to 0.2.0
- The mimic iterator style function now moved into it own iterator struct that have suffix "RefIter" in its' name. All of its become
unsafeto use. Following is the list of such structs.- CartesianProductRefIter
- CombinationRefIter
- GosperCombinationRefIter
- HeapPermutationRefIter
- KPermutationRefIter
- All
next_into_cellfunction now moved into it own iterator struct that have suffix "CellIter" in its' name. Following is the list of such structs.- CartesianProductCellIter
- CombinationCellIter
- GosperCombinationCellIter
- HeapPermutationCellIter
- KPermutationCellIter
- Rename all structs. Following is the renamed structs.
CartesianProductstruct is renamed toCartesianProductIteratorHeapPermutationstruct is renamed toHeapPermutationIteratorGosperCombinationstruct is renamed toGosperCombinationIteratorKPermutationstruct is renamed toKPermutationIterator
- Any implementation on other type for
CombinationandPermutationtraits need to define the associated type as well as changecombinationandpermutationfunction signature from taking&selfto&'a selfand&mut selfto&'a mut selfrespectively.
Example:
New Permutation trait now look like this.
// instead of this old implementation
// impl Permutation<T> for [T] {
// fn permutation(&mut self) -> HeapPermutation<T> {
// HeapPermutation {
// c : vec![0; self.len],
// data : self,
// i : 0
// }
// }
// }
// now it become..
The added complexity make this trait applicable to wider type.
Here's new implemention on Rc<RefCell<&mut [T]>> which return HeapPermutationCell.