├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── readme.md └── src ├── copy └── mod.rs └── lib.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Build 13 | run: cargo build --verbose 14 | - name: Run tests 15 | run: cargo test --verbose 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "autocfg" 7 | version = "0.1.7" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" 10 | 11 | [[package]] 12 | name = "num" 13 | version = "0.2.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db" 16 | dependencies = [ 17 | "num-bigint", 18 | "num-complex", 19 | "num-integer", 20 | "num-iter", 21 | "num-rational", 22 | "num-traits", 23 | ] 24 | 25 | [[package]] 26 | name = "num-bigint" 27 | version = "0.2.3" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "f9c3f34cdd24f334cb265d9bf8bfa8a241920d026916785747a92f0e55541a1a" 30 | dependencies = [ 31 | "autocfg", 32 | "num-integer", 33 | "num-traits", 34 | ] 35 | 36 | [[package]] 37 | name = "num-complex" 38 | version = "0.2.3" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | checksum = "fcb0cf31fb3ff77e6d2a6ebd6800df7fdcd106f2ad89113c9130bcd07f93dffc" 41 | dependencies = [ 42 | "autocfg", 43 | "num-traits", 44 | ] 45 | 46 | [[package]] 47 | name = "num-integer" 48 | version = "0.1.41" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" 51 | dependencies = [ 52 | "autocfg", 53 | "num-traits", 54 | ] 55 | 56 | [[package]] 57 | name = "num-iter" 58 | version = "0.1.39" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e" 61 | dependencies = [ 62 | "autocfg", 63 | "num-integer", 64 | "num-traits", 65 | ] 66 | 67 | [[package]] 68 | name = "num-rational" 69 | version = "0.2.2" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "f2885278d5fe2adc2f75ced642d52d879bffaceb5a2e0b1d4309ffdfb239b454" 72 | dependencies = [ 73 | "autocfg", 74 | "num-bigint", 75 | "num-integer", 76 | "num-traits", 77 | ] 78 | 79 | [[package]] 80 | name = "num-traits" 81 | version = "0.2.10" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" 84 | dependencies = [ 85 | "autocfg", 86 | ] 87 | 88 | [[package]] 89 | name = "permutator" 90 | version = "0.4.3" 91 | dependencies = [ 92 | "num", 93 | ] 94 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "permutator" 3 | categories = ["algorithms"] 4 | description = "Get a lexicographic cartesian product and lexicographic permutation at any specific index from data. Generate complete lexicographic cartesian product from single or multiple set of data. Generate complete lexicographic combination from data. Generate non-lexicographic permutation and k-permutation." 5 | documentation = "https://docs.rs/permutator/0.4.2/" 6 | keywords = ["cartesian", "permutation", "combination", "multiple", "k-permutation"] 7 | license = "BSD-3-Clause" 8 | readme = "readme.md" 9 | repository = "https://github.com/NattapongSiri/permutator" 10 | version = "0.4.3" 11 | authors = ["Nattapong Sirilappanich "] 12 | edition = "2018" 13 | 14 | [lib] 15 | name = "permutator" 16 | crate-type = ["rlib"] 17 | 18 | [features] 19 | default = [] 20 | 21 | [dependencies] 22 | num = "^0.2" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, Nattapong Sirilappanich 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Permutator 2 | It provides multiple way to get permutation of data. 3 | ## TLDR 4 | Easiest generic use case 5 | ```Rust 6 | use permutator::{CartesianProduct, Combination, Permutation}; 7 | let domains : &[&[i32]] = &[&[1, 2], &[3, 4, 5], &[6], &[7, 8], &[9, 10, 11]]; 8 | domains.cart_prod().for_each(|cp| { 9 | // each cp will be &[&i32] with length equals to domains.len() which in this case 5 10 | 11 | // It's k-permutation of size 3 over data. 12 | cp.combination(3).for_each(|mut c| { // need mut 13 | // each `c` is not &[&&i32] 14 | // print the first 3-combination over data 15 | // No longer need this line from verion 0.4.0 onward 16 | // println!("{:?}", c); 17 | 18 | // start permute the 3-combination 19 | c.permutation().for_each(|p| { 20 | // each `p` is not &[&&&i32] 21 | // print each permutation of the 3-combination. 22 | println!("{:?}", p); 23 | }); 24 | 25 | // It'll print the last 3-permutation again because permutation permute the value in place. 26 | println!("{:?}", c); 27 | }) 28 | }); 29 | ``` 30 | Notice that each nested level get deeper reference. 31 | If such behavior is undesired, use `copy` module. 32 | Here's an example: 33 | ```Rust 34 | use permutator::copy::{CartesianProduct, Combination, Permutation}; 35 | let domains : &[&[i32]] = &[&[1, 2], &[3, 4, 5], &[6], &[7, 8], &[9, 10, 11]]; 36 | domains.cart_prod().for_each(|cp| { 37 | // each cp will be &[i32] with length equals to domains.len() which in this case 5 38 | 39 | // It's k-permutation of size 3 over data. 40 | cp.combination(3).for_each(|mut c| { // need mut 41 | // each `c` is not &[i32] 42 | // print the first 3-combination over data 43 | // No longer need this line from verion 0.4.0 onward 44 | // println!("{:?}", c); 45 | 46 | // start permute the 3-combination 47 | c.permutation().for_each(|p| { 48 | // each `p` is not &[i32] 49 | // print each permutation of the 3-combination. 50 | println!("{:?}", p); 51 | }); 52 | 53 | // It'll print the last 3-permutation again because permutation permute the value in place. 54 | println!("{:?}", c); 55 | }) 56 | }); 57 | ``` 58 | ## The `copy` module 59 | This crate split into two modules. One is root module which can be used in most of the case. Another is `copy` module which require that the type implement `Copy` trait. The root module return value as a collection of `&T`, except all Heap permutaiton family. The `copy` module always return value as a collection of `T`. There's no Heap permutation in `copy` module because it did permutation in place. There's no copy nor create any reference. 60 | ## Get a permutation at specific point, not an iterator style. 61 | It crate provides 2 functions to get a cartesian product or k-permutation: 62 | - get_cartesian_for 63 | - get_permutation_for 64 | It perform mathematically calculation and return the result at that position. It doesn't skip the iteration. It useful when the domains is very large. Otherwise, simply skip the iteration may be faster. For example, in uncontrol test environment, heap_permutation function compile with --release flag can permute about 88 million permutations per second. 65 | 66 | This crate also provides utilities functions like: 67 | - get_cartesian_size 68 | - get_permutation_size 69 | ## Get a cartesian product over a set itself multiple times 70 | There are two distinct implementation to get cartesian product. 71 | - Iterator that return product 72 | - Function that call callback function to return product 73 | ### Iterator 74 | This crate provides `SelfCartesianProductIterator`, `SelfCartesianProductCellIter`, and `SelfCartesianProductRefIter` structs that implement `Iterator`, `IteratorReset`, `ExactSizeIterator` traits. Each struct serves different use cases:- 75 | - `SelfCartesianProductIterator` can be used in any case that performance is least concern. 76 | - `SelfCartesianProductCellIter` can be used in case performance is important as well as safety. 77 | - `SelfCartesianProductRefIter` can be used in case performance is critical and safety will be handle by caller. 78 | Every structs implements `IteratorReset` trait. 79 | - use `reset` function instead of creating a new Iterator everytime you need to re-iterate. 80 | ### Trait 81 | This crate provides `CartesianProduct` trait in both root module and `copy` module 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: 82 | - `(&'a [T], usize)` - Generate cartesian product over 'first paramter' for 'second paramater' times. 83 | - `(&'a [T], usize, Rc>)` - Similar to above but keep overwrite the product into 'third parameter'. **This type require trait from root module.** 84 | - `(&'a [T], usize, *mut [&'a T])` - Similar to above but use unsafe pointer to store value. **This type require trait from root module.** Each type above return different Iterator. For example `(&'a [T], usize)` return `SelfCartesianProductIterator` but on `(&'a [T], usize, *mut [&'a T])` return `SelfCartesianProductRefIter`. 85 | - `(&'a [T], usize, Rc>)` - Similar to above but keep overwrite the product into 'third parameter'. **This type require trait from `copy` module.** 86 | - `(&'a [T], usize, *mut [T])` - Similar to above but use unsafe pointer to store value. **This type require trait from `copy` module.** 87 | Each type above return different Iterator. For example `(&'a [T], usize)` return `copy::SelfCartesianProductIterator` but on `(&'a [T], usize, *mut [T])` return `copy::SelfCartesianProductRefIter`. 88 | ### Callback function 89 | This crate provides 4 functions that serve different usecase. 90 | - `self_cartesian_product` function that return product as callback parameter 91 | - `self_cartesian_product_cell` function that return product into Rc> given in function parameter 92 | - `self_cartesian_product_sync` function that return product into Arc> given in function parameter 93 | - `unsafe_self_cartesian_product` unsafe function that return product into mutable pointer given in function parameter 94 | ## Get a cartesian product over multiple sets 95 | There are three distinct implementation to get cartesian product. 96 | - Iterator that return product 97 | - Function that call callback function to return product 98 | - `CartesianProduct` trait that add `cart_prod` function to `&[&[T]]`, `(&[&[T]], Rc>)` 99 | ### Iterator 100 | This crate provides `CartesianProductIterator`, `CartesianProductCellIter`, and `CartesianProductRefIter` structs that implement 101 | `Iterator`, `IteratorReset`, `ExactSizeIterator` traits. Each struct serves different use cases:- 102 | - `CartesianProductIterator` can be used in any case that performance is least concern. 103 | - `CartesianProductCellIter` can be used in case performance is important as well as safety. 104 | - `CartesianProductRefIter` can be used in case performance is critical and safety will be handle by caller. 105 | Every structs implements `IteratorReset` trait. 106 | - use `reset` function instead of creating a new Iterator everytime you need to re-iterate. 107 | ### Trait 108 | This crate provides `CartesianProduct` trait in both root module and `copy` module. It is implemented on various types such as generic slice of slices, generic Vec of slices, tuple of `(&'a [&'a [T]], Rc>)`, and tuple of `(&'a [&'a [T]], *mut [&'a T])`. 109 | 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`. 110 | ### Callback function 111 | This crate provides 4 similar functions on 2 modules that serve different usecase. 112 | These 4 functions in root module: 113 | - `cartesian_product` function that return product as callback parameter 114 | - `cartesian_product_cell` function that return product into `Rc>` given in function parameter 115 | - `cartesian_product_sync` function that return product into `Arc>` given in function parameter 116 | - `unsafe_cartesian_product` unsafe function that return product into mutable pointer given in function 117 | and all 4 functions in `copy` module which do exactly the same except that each element is `T` rather than `&T` 118 | ## Get a combination from data 119 | There are three distinct implementation to get k-combinations of n set. 120 | - Iterator that return each combination on each iteration 121 | - Trait that add function to slice, `Vec`, `Rc>`, etc. 122 | - Function that call callback function to return product 123 | ### Iterator 124 | This crate provides `LargeCombinationIterator`, `LargeCombinationCellIter`, and `LargeCombinationRefIter` structs in two modules that implement `Iterator`, `IteratorReset`, and `ExactSizeIterator` traits. Each struct serves different use cases:- 125 | - `LargeCombinationIterator` can be used in any case that performance is least concern. 126 | - `LargeCombinationCellIter` can be used in case performance is important as well as safety. 127 | - `LargeCombinationRefIter` can be used in case performance is critical and safety will be handle by caller. 128 | All 3 structs in two modules are only different on the return type. The root module has `&T` element in result while `copy` module has copied `T` element in result. 129 | Every structs implements `IteratorReset` trait. 130 | - use `reset` function instead of creating a new Iterator everytime you need to re-iterate. 131 | ### Trait 132 | This crate provides `Combination` trait in both root module and `copy` module. It provides basic implementation on various types such as generic slice, generic `Vec`, tuple of `(&'a [T], Rc>)`, and tuple of `(&'a [T], * mut[&'a T])`. 133 | It add `combination(usize)` function to it and return required iterator based on type of data. For example on generic Vec return `LargeCombinationIterator` but on `(&'a [T], * mut[&'a T])` return `LargeCombinationRefIter`. 134 | ### Callback function 135 | This crate provide 4 functions in 2 modules that serve different usecase. 136 | - `large_combination` function that return product as callback parameter 137 | - `large_combination_cell` function that return product into `Rc>` given in function parameter 138 | - `large_combination_sync` function that return product into `Arc>` given in function parameter 139 | - `unsafe_large_combination` unsafe function that return product into mutable pointer given in function parameter 140 | The different between root module and `copy` module is that the product contains `&T` in root module while in `copy` module contains copied `T`. 141 | ## Get a permutation from data 142 | This crate provide two different algorithms. One generate lexicographically ordered permutation. Another generate non-lexicographically ordered permutation but faster. 143 | 144 | There are three distinct implementation to get permutation. 145 | - Iterator that do permutation on data 146 | - Trait that add function to slice, Vec, etc. 147 | - Function that call callback function to return each permutation 148 | ### Iterator 149 | This crate provides `HeapPermutationIterator`, `HeapPermutationCellIter`, `HeapPermutationRefIter`, `XPermutationIterator`, `XPermutationCellIter`, and `XPermutationRefIter` structs in both root module and `copy` module that implement `Iterator`, `IteratorReset`, `ExactSizeIterator` traits. Each struct serves different use cases:- 150 | - `HeapPermutationIterator` can be used in any case that order is not important and performance is least concern. This iterator doesn't return original value as first value. 151 | - `XPermutationIterator` can be used in any case that order is important and performance is least concern. 152 | - `HeapPermutationCellIter` can be used in case that order is not important and performance is important as well as safety. This iterator doesn't return original value as first value. 153 | - `XPermutationCellIter` can be used in case that order is important and performance is important as well as safety. 154 | - `HeapPermutationRefIter` can be used in case that order is not important, performance is critical and safety will be handle by caller. This iterator doesn't return original value as first value. 155 | - `XPermutationRefIter` can be used in case that order is important, performance is critical and safety will be handle by caller. 156 | The different between root module and `copy` module is that in `copy` module type `T` need to implement `Copy` trait. 157 | Every structs implements `IteratorReset` trait. 158 | - use `reset` function instead of creating a new Iterator everytime you need to re-iterate. 159 | ### Trait 160 | This crate provides `Permutation` trait in root module and `copy` module. It provide basic implementation various types such as generic slice, generic Vec, tuple of `(&'a mut[T], Rc>`, and more type but used for [k-permutation](#get-a-k-permutation-from-data). 161 | 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>)` return `HeapPermutationCellIter`. 162 | The trait never return lexicographically ordered permutation iterator. 163 | It add one more benefit since version 0.4.0. Unlike constructing an iterator, it return a chained iterator. The chained is just a two iterator chained together. The first iterator return only one value, the original value. The second iterator return all the rest permutation. 164 | ### Callback function 165 | This crate provides 3 functions in root module that return non-lexicographically ordered result which serve different usecase. 166 | - `heap_permutation` function that return product as callback parameter 167 | - `heap_permutation_cell` function that return product into Rc> given in function parameter 168 | - `heap_permutation_sync` function that return product into Arc> given in function parameter 169 | 170 | ~~**There is no heap permutation function family in `copy` module.**~~ 171 | 172 | **Since version 0.4.0 onward all heap permutation family including all Iterator style isn't in `copy` module.** This is because Iterator need to return owned value and `HeapPermutationIterator` use `T` directly, not `&T`, so `T` need to implement `Clone`. This make implementation in `copy` module duplicate of the one in root module. 173 | 174 | This crate provides 4 functions in both root module and `copy` module that return lexicographically ordered result which serve different usecase. 175 | - `x_permutation` function that return lexicographically ordered product as callback parameter 176 | - `x_permutation_cell` function that return lexicographically ordered product into Rc> given in function parameter 177 | - `x_permutation_sync` function that return lexicographically ordered product into Arc> given in function parameter 178 | - `unsafe_x_permutation` unsafe function that return product into mutable pointer given in function parameter 179 | ## Get a k-permutation from data 180 | There are three implementation to get k-permutations. 181 | - Iterator that return product 182 | - Trait that add functionality to some specific tuple. 183 | - Function that call callback function to return product 184 | ### Iterator 185 | This crate provides `KPermutationIterator`, `KPermutationCellIter`, and `KPermutationRefIter` structs in root module and `copy` module that implement `Iterator`, `IteratorReset`, `ExactSizeIterator` traits. Each struct serves different use cases:- 186 | - `KPermutationIterator` can be used in any case that performance is least concern. 187 | - `KPermutationCellIter` can be used in case performance is important as well as safety. 188 | - `KPermutationRefIter` can be used in case performance is critical and safety will be handle by caller. 189 | The different between root module produces collection of `&T` but `copy` module produces collection of copied `T` 190 | Every structs implements `IteratorReset` trait. 191 | - use `reset` function instead of creating a new Iterator everytime you need to re-iterate. 192 | ### Trait 193 | This crate provides `Permutation` trait in root module that can be used to perform k-permutation on tuple of `(&'a [T], usize)`, tuple of `(&'a [T], usize, Rc>)`, and `(&'a [T], usize, *mut [&'a T])` to create different type of iterator. 194 | The `Permutation` trait in `copy` module can be used to perform k-permutation on tuple of `(&'a [T], usize)`, tuple of `(&'a [T], usize, Rc>)`, and `(&'a [T], usize, *mut [T])` to create different type of iterator. 195 | 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`. 196 | ### Callback function 197 | This crate provide 4 functions in both root module and `copy` module that serve different usecase. 198 | - `k_permutation` function that return product as callback parameter 199 | - `k_permutation_cell` function that return product into Rc> given in function parameter 200 | - `k_permutation_sync` function that return product into Arc> given in function parameter 201 | - `unsafe_k_permutation` unsafe function that return product into mutable pointer given in function parameter 202 | The different between root module and `copy` module is that the root module return a collection of `&T` while the `copy` module return collection of `T` 203 | ## Notes 204 | ### Struct with `RefIter` and `CellIter` suffix return empty Item on each Iteration 205 | 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` in root module requires `Rc>` parameter which will be used to store each cartesian product from each iteration. 206 | 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. 207 | ### Performance concern 208 | - For primitive data type, module `copy` and root module performance is roughly equivalent. 209 | - For complex data type, module `copy` performance will depend on the implementation of `Copy` trait. 210 | - 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. 211 | - The crate provides three built-in methods to share result. 212 | 1. callback function with "_cell" suffix. 213 | 2. A struct with `CellIter` and `RefIter` suffix. 214 | 3. Iterator that return an owned value. 215 | The callback with "_cell" suffix way is about 10%-20% slower than using `CellIter` suffix method. 216 | The return owned value method is slowest but most versatile. It's about 700%-1000% slower than using 217 | `CellIter` suffix object. However, it is still faster than using standard callback function then 218 | convert it to owned value to share result. 219 | - This crate provides two built-in methods to send result to other threads. 220 | 1. callback function with "_sync" suffix. 221 | 2. Iterator that return an owned value. 222 | 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 with "_sync" suffix. 223 | ### Mutating result is dangerous 224 | 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 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>` 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. 225 | ### Send result to other thread is complicated 226 | This crate provides two built-in methods to send result across thread. The two usecase is strongly 227 | against each other in term of performance. The callback with "_sync" suffix store borrowed result into Arc> 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 228 | 1. The function generate new result 229 | 2. The function send notification via channel to every threads that new result is available. 230 | 3. The function block until every thread send notification back that they are all done with the data. 231 | 232 | Another way is to use Iterator that return an owned value then clone that value on each thread. 233 | This is much simpler to implement but require more memory. It'll simplify the scenario above to: 234 | 1. The iterator return new result. 235 | 2. It send notification with new data via channel to every threads. 236 | The performance observed in uncontrolled test environment show that the iterator way 237 | is faster than the callback by at least 50%. 238 | ### Unsafe way is fastest and hardest 239 | 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. 240 | # Example 241 | ## Get a permutation at specific point examples 242 | To get into 'n' specific lexicographic permutation, 243 | ```Rust 244 | use permutator::get_cartesian_size; 245 | 246 | get_cartesian_size(3, 2); // return 9. 247 | get_cartesian_size(3, 3); // return 27. 248 | 249 | use permutator::get_cartesian_for; 250 | 251 | let nums = [1, 2, 3]; 252 | get_cartesian_for(&nums, 2, 0); // Return Ok([1, 1]) 253 | get_cartesian_for(&nums, 2, 3); // Return Ok([2, 1]) 254 | get_cartesian_for(&nums, 2, 8); // Return Ok([3, 3]) 255 | get_cartesian_for(&nums, 2, 9); // Return Err("Parameter `i` is out of bound") 256 | get_cartesian_for(&nums, 4, 0); // Return Err("Parameter `degree` cannot be larger than size of objects") 257 | 258 | use permutator::get_permutation_size; 259 | 260 | get_permutation_size(3, 2); // return = 6 261 | get_permutation_size(4, 2); // return = 12 262 | 263 | use permutator::get_permutation_for; 264 | 265 | let nums = [1, 2, 3, 4]; 266 | get_permutation_for(&nums, 2, 0); // return Result([1, 2]) 267 | get_permutation_for(&nums, 3, 0); // return Result([1, 2, 3]) 268 | get_permutation_for(&nums, 2, 5); // return Result([2, 4]) 269 | get_permutation_for(&nums, 2, 11); // return Result([4, 3]) 270 | get_permutation_for(&nums, 2, 12); // return Err("parameter x is outside a possible length") 271 | get_permutation_for(&nums, 5, 0); // return Err("Insufficient number of object in parameters objects for given parameter degree") 272 | ``` 273 | ## Cartesian product of multiple sets of data 274 | To get cartesian product from 3 set of data. 275 | ```Rust 276 | use permutator::cartesian_product; 277 | 278 | cartesian_product(&[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]], |product| { 279 | println!("{:?}", product); 280 | }); 281 | ``` 282 | Or do it in iterative style 283 | ```Rust 284 | use permutator::CartesianProductIterator 285 | use std::time::Instant; 286 | let data : &[&[usize]] = &[&[1, 2, 3], &[4, 5, 6], &[7, 8, 9]]; 287 | let cart = CartesianProductIterator::new(&data); 288 | let mut counter = 0; 289 | let timer = Instant::now(); 290 | 291 | for p in cart { 292 | // println!("{:?}", p); 293 | counter += 1; 294 | } 295 | 296 | assert_eq!(data.iter().fold(1, |cum, domain| {cum * domain.len()}), counter); 297 | println!("Total {} products done in {:?}", counter, timer.elapsed()); 298 | ``` 299 | Import trait then skipping all object instantiation altogether. 300 | ```Rust 301 | use std::time::Instant; 302 | use permutator::CartesianProduct; 303 | let data : &[&[usize]] = &[&[1, 2], &[3, 4, 5, 6], &[7, 8, 9]]; 304 | let mut counter = 0; 305 | let timer = Instant::now(); 306 | 307 | data.cart_prod.for_each(|p| { 308 | // println!("{:?}", p); 309 | counter += 1; 310 | }); 311 | 312 | assert_eq!(data.iter().fold(1, |cum, domain| {cum * domain.len()}), counter); 313 | println!("Total {} products done in {:?}", counter, timer.elapsed()); 314 | ``` 315 | ## Combination Iterator examples 316 | The struct offer two ways to get a combination. 317 | First it can be used as Iterator. Second 318 | manually call next with borrowed mut variable that 319 | will store the next combination. 320 | ```Rust 321 | // Combination iterator 322 | use permutator::LargeCombinationIterator; 323 | use std::time::{Instant}; 324 | let data = [1, 2, 3, 4, 5]; 325 | let combinations = LargeCombinationIterator::new(&data, 3); 326 | let mut counter = 0; 327 | let timer = Instant::now(); 328 | 329 | for combination in combinations { 330 | // uncomment a line below to print each combination 331 | println!("{}:{:?}", counter, combination); 332 | counter += 1; 333 | } 334 | 335 | println!("Total {} combinations in {:?}", counter, timer.elapsed()); 336 | ``` 337 | ```Rust 338 | use permutator::Combination; 339 | use std::time::{Instant}; 340 | 341 | let data = [1, 2, 3, 4, 5]; 342 | let mut counter = 0; 343 | 344 | let timer = Instant::now(); 345 | 346 | data.combination(3).for_each(|combination| { 347 | // uncomment a line below to print each combination 348 | println!("{}:{:?}", counter, combination); 349 | counter += 1; 350 | } 351 | 352 | println!("Total {} combinations in {:?}", counter, timer.elapsed()); 353 | ``` 354 | ## Iterator style permutation example 355 | There's `HeapPermutationIterator` and `KPermutationIterator` struct that can do 356 | permutation. Below is an example of `HeapPermutationIterator`. 357 | ```Rust 358 | use permutator::HeapPermutationIterator; 359 | use std::time::{Instant}; 360 | let data = &mut [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 361 | println!("0:{:?}", data); 362 | let mut permutator = HeapPermutationIterator::new(data); 363 | let timer = Instant::now(); 364 | let mut counter = 1; 365 | 366 | for permutated in permutator { 367 | println!("{}:{:?}", counter, permutated); 368 | counter += 1; 369 | } 370 | 371 | // or use iterator related functional approach like line below. 372 | // permutator.into_iter().for_each(|permutated| {counter += 1;}); 373 | 374 | println!("Done {} permutations in {:?}", counter, timer.elapsed()); 375 | ``` 376 | ## Iterator into Rc> 377 | There's `HeapPermutationCellIter` and `KPermutationCellIter` struct that offer 378 | such functionality. Below is an example of `HeapPermutationCellIter` 379 | ```Rust 380 | use permutator::HeapPermutationCellIter; 381 | use std::cell::RefCell; 382 | use std::rc::Rc; 383 | use std::time::{Instant}; 384 | 385 | let data = &mut [1, 2, 3, 4]; 386 | let result = Rc::new(RefCell::new(data)); 387 | // print original data before permutation 388 | println!("0:{:?}", &*result.borrow()); 389 | let mut permutator = HeapPermutationCellIter::new(Rc::clone(&result)); 390 | let timer = Instant::now(); 391 | let mut counter = 1; 392 | 393 | for _ in permutator { 394 | // uncomment the line below to print all possible permutation 395 | println!("{}:{:?}", counter, &*result.borrow()); 396 | counter += 1; 397 | } 398 | 399 | println!("Done {} permutations in {:?}", counter, timer.elapsed()); 400 | ``` 401 | The `KPermutationCellIter` example show below 402 | ```Rust 403 | use permutator::KPermutationCellIter; 404 | use std::cell::RefCell; 405 | use std::rc::Rc; 406 | 407 | let k = 3; 408 | let data = &[1, 2, 3, 4, 5]; 409 | let mut result = vec![&data[0]; k]; 410 | let shared = Rc::new(RefCell::new(result.as_mut_slice())); 411 | 412 | let mut kperm = KPermutationCellIter::new(data, k, Rc::clone(&shared)); 413 | for _ in kperm { 414 | // each permutation will be stored in `shared` 415 | println!("{:?}", &*shared.borrow()); 416 | } 417 | ``` 418 | ## Lexicographically ordered operation 419 | Generate ordered cartesian product between [1, 2, 3], [4, 5], [6, 7], [8, 9], and [10] then make ordered k-permutation where k = 3 from each cartesian product. 420 | ```Rust 421 | use permutator::{CartesianProduct, LargeCombinationIterator, x_permutation}; 422 | 423 | let data : &[&[u8]] = &[&[1, 2, 3], &[4, 5], &[6, 7], &[8, 9], &[10]]; 424 | let k = 3; 425 | 426 | data.cart_prod().for_each(|cp| { 427 | // lexicographically ordered cartesian product in `cp` 428 | LargeCombinationIterator::new(&cp, k).for_each(|co| { 429 | // lexicographically ordered combination of length 3 430 | x_permutation(&co, |_| true, |p| { 431 | // lexicographically ordered permutation 432 | println!("{:?}", p); 433 | }); 434 | }); 435 | }); 436 | ``` 437 | Generate ordered cartesian product between [1, 2, 3], [4, 5], [6, 7], [8, 9], and [10] then make ordered k-permutation where k = 3 from each cartesian product. Additionally, filter out all permutation that the first element is odd number. 438 | ```Rust 439 | use permutator::{CartesianProduct, LargeCombinationIterator, x_permutation}; 440 | 441 | let data : &[&[u8]] = &[&[1, 2, 3], &[4, 5], &[6, 7], &[8, 9], &[10]]; 442 | let k = 3; 443 | 444 | data.cart_prod().for_each(|cp| { 445 | // lexicographically ordered cartesian product in `cp` 446 | LargeCombinationIterator::new(&cp, k).for_each(|co| { 447 | // lexicographically ordered combination of length 3 448 | x_permutation( 449 | &co, 450 | // first bit == 1 mean it's odd number 451 | // notice *** in front of v ? 452 | // that's because the root module always return borrowed value. 453 | // to get rid of this, use all operation from `copy` module 454 | |v| ***v[0] & 1 != 1, 455 | |p| 456 | { 457 | // lexicographically ordered permutation 458 | println!("{:?}", p); 459 | }); 460 | }); 461 | }); 462 | ``` 463 | ## Traits that add new function to various types 464 | `CartesianProduct` trait add `cart_prod` function. 465 | The function take no parameter. The function return the same Iterator that also return by 466 | the [provided struct](#iterator) 467 | so it can be used like [this example](#cartesian-product-of-multiple-sets-of-data) 468 | ```Rust 469 | use permutator::CartesianProduct; 470 | let data : &[&[i32]]= &[&[1, 2, 3], &[4, 5]]; 471 | 472 | data.cart_prod().for_each(|p| { 473 | // print all product like [1, 4], [1, 5], ... 474 | println!("{:?}", p); 475 | }); 476 | ``` 477 | or 478 | ```Rust 479 | use permutator::CartesianProduct; 480 | let data : &[&[i32]]= &[&[1, 2, 3], &[4, 5]]; 481 | let mut result = vec![&data[0][0]; data.len()]; 482 | let shared = Rc::new(RefCell::new(result.as_mut_slice())); 483 | // shared can be owned by anyone who want to get cartesian product. 484 | (&data, Rc::clone(&shared)).cart_prod().for_each(|_| { 485 | // print all product like [1, 4], [1, 5], ... 486 | println!("{:?}", &*shared.borrow()); 487 | // and notify all owner of shared object so they know that new product is available. 488 | }); 489 | ``` 490 | `Combination` trait add `combination` function. 491 | The function take 1 parameter. It's a size of combination frame, AKA `k`, `r`, etc. 492 | The function return the same Iterator that also return by 493 | the [provided struct](#iterator-1) 494 | so it can be used like [this example](#combination-iterator-examples) 495 | ```Rust 496 | use permutator::Combination; 497 | let data = [1, 2, 3, 4, 5]; 498 | data.combination(3).for_each(|comb| { 499 | // print all combination like [1, 2, 3], [1, 2, 4], ... 500 | println!("{:?}", comb); 501 | }); 502 | ``` 503 | or 504 | ```Rust 505 | use permutator::Combination; 506 | let data = [1, 2, 3, 4, 5]; 507 | let k = 3; 508 | let mut result = vec![&data[0]; k]; 509 | let shared = Rc::new(RefCell::new(result.as_mut_slice())); 510 | // shared can be owned by anyone who want to get combinations. 511 | (&data, Rc::clone(&shared)).combination(k).for_each(|_| { 512 | // print all combination like [1, 2, 3], [1, 2, 4], ... 513 | println!("{:?}", &*shared.borrow()); 514 | // and notify all owner of shared object so they know that new combination is available. 515 | }); 516 | ``` 517 | `Permutation` trait add `permutation` function. 518 | It permute the `[T]`, `Vec`, or Rc> in place. 519 | The function return the same Iterator that also return by the either 520 | this [provided struct](#iterator-2) or this [provided struct](#iterator-3) 521 | depending on what types does this method is called upon 522 | so it can be used like [this example](#iterator-style-permutation-example) 523 | or [this example](#iterator-into-rcrefcell) or following example: 524 | ```Rust 525 | use permutator::Permutation; 526 | let mut data = [1, 2, 3]; 527 | data.permutation().for_each(|p| { 528 | // print all the permutation. 529 | println!("{:?}", p); 530 | }); 531 | // The `data` at this point will also got permuted. 532 | // It'll print the last permuted value twice. 533 | println!("{:?}", data); 534 | ``` 535 | ```Rust 536 | use permutator::Permutation; 537 | let mut data = [1, 2, 3]; 538 | let shared = Rc::new(RefCell::new(&mut data)); 539 | // shared can be owned by anyone that want to get a permutation 540 | Rc::clone(&shared).permutation().for_each(|_| { 541 | // print all the permutation. 542 | println!("{:?}", &*shared.borrow()); 543 | // and notify all owner of shared object so they know that new permutation is available. 544 | }); 545 | // The same goes as previous example, the data inside shared on every owner will now has last permuted value. 546 | ``` 547 | or k-permutation into Rc> 548 | ```Rust 549 | use permutator::KPermutationCellIter; 550 | use std::cell::RefCell; 551 | use std::rc::Rc; 552 | 553 | let k = 3; 554 | let data = &[1, 2, 3, 4, 5]; 555 | let mut result = vec![&data[0]; k]; 556 | let shared = Rc::new(RefCell::new(result.as_mut_slice())); 557 | 558 | (data, k, Rc::clone(&shared)).permutation().for_each(|_| { 559 | // each permutation will be stored in `shared` 560 | println!("{:?}", &*shared.borrow()); 561 | }); 562 | ``` 563 | ## Unsafe way for faster share result 564 | In some circumstance, the combination result need to be shared but 565 | the safe function don't allow you to share the result except copy/clone 566 | the result for each share. When that's the case, using Iterator may answer 567 | such situation. 568 | 569 | Another approach is to use `CellIer` suffix struct or callback function 570 | with `_cell` suffix. As long as each iteration doesn't reuse previous 571 | result and result owner treat result as immutable data then it's safe 572 | to use this approach. 573 | 574 | Another way, if safety is less concern than performance, there's an 575 | unsafe side implementation that take a mutable pointer to store result. 576 | There's more thing to keep in mind than using struct with `CellIter` suffix 577 | and callback function `_cell` suffix. For example: 578 | 1. Pointer need to outlive the entire operation 579 | 2. The object that pointer is pointed to need to be release. 580 | 3. Result synchronization, both in single and multiple thread(s). 581 | 4. ... 582 | 5. All other unsafe Rust conditions may applied 583 | 584 | Example: 585 | - unsafe callback function 586 | ```Rust 587 | use permutator::unsafe_combination; 588 | let data = [1, 2, 3, 4, 5]; 589 | let r = 3; 590 | let mut counter = 0; 591 | let mut result = vec![&data[0]; r]; 592 | let result_ptr = result.as_mut_slice() as *mut [&usize]; 593 | 594 | unsafe { 595 | unsafe_combination(&data, r, result_ptr, || { 596 | println!("{:?}", result); 597 | counter += 1; 598 | }); 599 | } 600 | 601 | assert_eq!(counter, divide_factorial(data.len(), data.len() - r) / factorial(r)); 602 | ``` 603 | - unsafe Iterator object 604 | ```Rust 605 | use permutator::LargeCombinationRefIter; 606 | let data = [1, 2, 3, 4, 5]; 607 | let r = 3; 608 | let mut counter = 0; 609 | let mut result = vec![&data[0]; r]; 610 | let result_ptr = result.as_mut_slice() as *mut [&usize]; 611 | 612 | unsafe { 613 | let comb = LargeCombinationRefIter::new(&data, r, result_ptr); 614 | for _ in comb { 615 | println!("{:?}", result); 616 | counter += 1; 617 | }); 618 | } 619 | 620 | assert_eq!(counter, divide_factorial(data.len(), data.len() - r) / factorial(r)); 621 | ``` 622 | ## Share with multiple object from callback function 623 | An example showing the built-in feature that save new cartesian product into 624 | Rc> so it can be easily share to other. 625 | This example use two worker objects that read each cartesian product 626 | and print it. 627 | ```Rust 628 | use std::fmt::Debug; 629 | use std::rc::Rc; 630 | use std::cell::RefCell; 631 | 632 | use permutator::cartesian_product_cell; 633 | 634 | trait Consumer { 635 | fn consume(&self); 636 | } 637 | struct Worker1<'a, T : 'a> { 638 | data : Rc> 639 | } 640 | impl<'a, T : 'a + Debug> Consumer for Worker1<'a, T> { 641 | fn consume(&self) { 642 | println!("Work1 has {:?}", self.data); 643 | } 644 | } 645 | struct Worker2<'a, T : 'a> { 646 | data : Rc> 647 | } 648 | impl<'a, T : 'a + Debug> Consumer for Worker2<'a, T> { 649 | fn consume(&self) { 650 | println!("Work2 has {:?}", self.data); 651 | } 652 | } 653 | 654 | fn start_cartesian_product_process<'a>(data : &'a[&'a[i32]], cur_result : Rc>, consumers : Vec>) { 655 | cartesian_product_cell(data, cur_result, || { 656 | consumers.iter().for_each(|c| { 657 | c.consume(); 658 | }) 659 | }); 660 | } 661 | 662 | let data : &[&[i32]] = &[&[1, 2], &[3, 4, 5], &[6]]; 663 | let mut result = vec![&data[0][0]; data.len()]; 664 | 665 | let shared = Rc::new(RefCell::new(result.as_mut_slice())); 666 | let worker1 = Worker1 { 667 | data : Rc::clone(&shared) 668 | }; 669 | let worker2 = Worker2 { 670 | data : Rc::clone(&shared) 671 | }; 672 | let consumers : Vec> = vec![Box::new(worker1), Box::new(worker2)]; 673 | start_cartesian_product_process(data, shared, consumers); 674 | ``` 675 | ## Iterator that send data to other threads 676 | This example generates a k-permutation and send it to multiple threads 677 | by using KPermutation iterator. 678 | 679 | The main thread will keep generating a new k-permutation and send it to 680 | every thread while all other threads read new k-permutation via channel. 681 | In this example, it use sync_channel with size 0. It doesn't hold anything 682 | inside the buffer. The sender will block until the receiver read the data. 683 | ```Rust 684 | use permutator::KPermutation; 685 | use std::sync::mpsc; 686 | let k = 5; 687 | let data : &[i32] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 688 | 689 | // workter thread 1 690 | let (t1_send, t1_recv) = mpsc::sync_channel::>>(0); 691 | 692 | thread::spawn(move || { 693 | while let Some(c) = t1_recv.recv().unwrap() { 694 | let result : Vec<&i32> = c; 695 | println!("Thread1: {:?}", result); 696 | } 697 | println!("Thread1 is done"); 698 | }); 699 | 700 | // worker thread 2 701 | let (t2_send, t2_recv) = mpsc::sync_channel::>>(0); 702 | thread::spawn(move || { 703 | while let Some(c) = t2_recv.recv().unwrap() { 704 | let result : Vec<&i32> = c; 705 | println!("Thread2: {:?}", result); 706 | } 707 | println!("Thread2 is done"); 708 | }); 709 | 710 | let channels = vec![t1_send, t2_send]; 711 | // main thread that generate result 712 | thread::spawn(move || { 713 | use std::time::Instant; 714 | let timer = Instant::now(); 715 | let mut counter = 0; 716 | let kperm = KPermutation::new(data, k); 717 | 718 | kperm.into_iter().for_each(|c| { 719 | channels.iter().for_each(|t| {t.send(Some(c.to_owned())).unwrap();}); 720 | counter += 1; 721 | }); 722 | channels.iter().for_each(|t| {t.send(None).unwrap()}); 723 | println!("Done {} combinations in {:?}", counter, timer.elapsed()); 724 | }).join().unwrap(); 725 | ``` 726 | ## Callback function send data to other thread 727 | This example generates a k-permutation and send it to multiple threads by 728 | using a callback approach k_permutation_sync function. 729 | 730 | The main thread will keep generating a new k-permutation and send it to 731 | every thread while all other threads read new k-permutation via channel. 732 | In this example, it use sync_channel with size 0. It doesn't hold anything 733 | inside the buffer. The sender will block until the receiver read the data. 734 | ```Rust 735 | use std::sync::{Arc, RwLock}; 736 | use std::sync::mpsc; 737 | use std::sync::mpsc::{Receiver, SyncSender}; 738 | fn start_k_permutation_process<'a>(data : &'a[i32], cur_result : Arc>>, k : usize, notifier : Vec>>, release_recv : Receiver<()>) { 739 | use std::time::Instant; 740 | let timer = Instant::now(); 741 | let mut counter = 0; 742 | k_permutation_sync(data, k, cur_result, || { 743 | notifier.iter().for_each(|n| { 744 | n.send(Some(())).unwrap(); // notify every thread that new data available 745 | }); 746 | 747 | for _ in 0..notifier.len() { 748 | release_recv.recv().unwrap(); // block until all thread reading data notify on read completion 749 | } 750 | 751 | counter += 1; 752 | }); 753 | 754 | notifier.iter().for_each(|n| {n.send(None).unwrap()}); // notify every thread that there'll be no more data. 755 | 756 | println!("Done {} combinations with 2 workers in {:?}", counter, timer.elapsed()); 757 | } 758 | let k = 5; 759 | let data = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 760 | let result = vec![&data[0]; k]; 761 | let result_sync = Arc::new(RwLock::new(result)); 762 | 763 | // workter thread 1 764 | let (t1_send, t1_recv) = mpsc::sync_channel::>(0); 765 | let (main_send, main_recv) = mpsc::sync_channel(0); 766 | let t1_local = main_send.clone(); 767 | let t1_dat = Arc::clone(&result_sync); 768 | thread::spawn(move || { 769 | while let Some(_) = t1_recv.recv().unwrap() { 770 | let result : &Vec<&i32> = &*t1_dat.read().unwrap(); 771 | // println!("Thread1: {:?}", result); 772 | t1_local.send(()).unwrap(); // notify generator thread that reference is no longer neeed. 773 | } 774 | println!("Thread1 is done"); 775 | }); 776 | 777 | // worker thread 2 778 | let (t2_send, t2_recv) = mpsc::sync_channel::>(0); 779 | let t2_dat = Arc::clone(&result_sync); 780 | let t2_local = main_send.clone(); 781 | thread::spawn(move || { 782 | while let Some(_) = t2_recv.recv().unwrap() { 783 | let result : &Vec<&i32> = &*t2_dat.read().unwrap(); 784 | // println!("Thread2: {:?}", result); 785 | t2_local.send(()).unwrap(); // notify generator thread that reference is no longer neeed. 786 | } 787 | println!("Thread2 is done"); 788 | }); 789 | 790 | // main thread that generate result 791 | thread::spawn(move || { 792 | start_k_permutation_process(data, result_sync, k, vec![t1_send, t2_send], main_recv); 793 | }).join().unwrap(); 794 | ``` 795 | ## Breaking change from 0.3.x to 0.4 796 | trait `Permutation`, functions `heap_permutation`, `heap_permutation_cell`, and `heap_permutation_sync` now return the unpermuted value first instead of returning permuted once first. 797 | ```Rust 798 | use permutator::{ 799 | heap_permutation, 800 | Permutation 801 | }; 802 | let arr = &[1, 2, 3]; 803 | // no longer need to `println!("{:?}", arr);` first 804 | 805 | heap_permutation(arr, |perm| { 806 | // now it print [1, 2, 3], [2, 1, 3], ... 807 | println!("{:?}", perm); 808 | }); 809 | 810 | arr.permutation().for_each(|perm| { 811 | // now it print [1, 2, 3], [2, 1, 3], ... 812 | println!("{:?}", perm); 813 | }); 814 | ``` 815 | All usage on `permutator::copy::HeapPermutationIterator` shall become `permutator::HeapPermutationIterator` 816 | ## Breaking change from 0.2.x to 0.3.x 817 | `combination` from root module and `copy` module now return "Large" combination family. 818 | ### Rationale 819 | All "Gosper" combination family is supersede by "Large" combination family. It doesn't mark those family deprecated yet. There's only Rust document that state it being deprecated. This is because the reason for being deprecated is that the implementation in this crate is inefficient. Each time that gosper algorithm generate new value, it copied all value or create new ref for that combination. In contrast to "Large" family that only copy or create new ref when the combination at that position changed. This make "Large" family combination faster over 10 times. So unless more efficient implementation is available, after sometime, the "Gosper" family function may officially mark deprecated. There's also "Gosper" combination family limitation that it can generate combination as many as bits of variable that support fast bit operation, which Rust currently is capped to 128 bits so source be as large as 128 elements slice. In practical, this is more than enough on most case. But in some edge case, "Large" combination family permit a combination on data as many as `usize` max value, which is 2^32 on 32 bits platform and 2^64 on 64 bits platform. The result from "Large" combination family is lexicographic ordered if the source is lexicographic ordered. 820 | 821 | Internally, k-permutation family are all migrated to use "Large" combination family instead of "Gosper" family. 822 | ## Migration guide from 0.2.x to 0.3.x 823 | - `combination*` functions become `large_combination*` functions. 824 | - `GosperCombination*` structs become `LargeCombination*` structs. 825 | For example: 826 | ```Rust 827 | // This line will be error in 0.3.0 828 | let combinations : GosperCombinationIterator = [1, 2, 3, 4, 5].combination(3); 829 | ``` 830 | Become 831 | ```Rust 832 | let combinations : LargeCombinationIterator = [1, 2, 3, 4, 5].combination(3); 833 | ``` 834 | ## Breaking change from 0.1.6 to 0.2.0 835 | 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. 836 | More detail on breaking change: 837 | - An iterator style `next_into_cell` has been refactored into their own struct. Now it can be used like simple Iterator with slightly different way to return value. 838 | - A mimic iterator style `next` that 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. 839 | - `CartesianProduct` struct is renamed to `CartesianProductIterator` 840 | - `HeapPermutation` struct is renamed to `HeapPermutationIterator` 841 | - `GosperCombination` struct is renamed to `GosperCombinationIterator` 842 | - `KPermutation` struct is renamed to `KPermutationIterator` 843 | - `Combination` and `Permutation` traits now use associated type `combinator` and `permutator` respectively to define the struct that will be used to perform combination/permutation on slice/array/Vec and Rc> instead of fixed return type. Now, all trait return an object that implement `Iterator` trait. It doesn't constrait the associated type `Item` defined in `Iterator` thought. The trait now take <'a> lifetime parameter and no longer take generic type `T`. The `combination` function change signature from `combination(&mut self)` to `combination(&'a mut self)`. The `permutation` function change signature from `permutation(&mut self)` to `permutation(&'a mut self)`. 844 | ## Migration guide from 0.1.6 to 0.2.0 845 | - The mimic iterator style function now moved into it own iterator struct that have suffix "RefIter" in its' name. All of its become `unsafe` to use. Following is the list of such structs. 846 | - CartesianProductRefIter 847 | - CombinationRefIter 848 | - GosperCombinationRefIter 849 | - HeapPermutationRefIter 850 | - KPermutationRefIter 851 | - All `next_into_cell` function now moved into it own iterator struct that have suffix "CellIter" in its' name. Following is the list of such structs. 852 | - CartesianProductCellIter 853 | - CombinationCellIter 854 | - GosperCombinationCellIter 855 | - HeapPermutationCellIter 856 | - KPermutationCellIter 857 | - Rename all structs. Following is the renamed structs. 858 | - `CartesianProduct` struct is renamed to `CartesianProductIterator` 859 | - `HeapPermutation` struct is renamed to `HeapPermutationIterator` 860 | - `GosperCombination` struct is renamed to `GosperCombinationIterator` 861 | - `KPermutation` struct is renamed to `KPermutationIterator` 862 | - Any implementation on other type for `Combination` and `Permutation` traits need to define the associated type as well as change `combination` and `permutation` function signature from taking `&self` to `&'a self` and `&mut self` to `&'a mut self` respectively. 863 | 864 | Example: 865 | New `Permutation` trait now look like this. 866 | ```Rust 867 | // instead of this old implementation 868 | // impl Permutation for [T] { 869 | // fn permutation(&mut self) -> HeapPermutation { 870 | // HeapPermutation { 871 | // c : vec![0; self.len], 872 | // data : self, 873 | // i : 0 874 | // } 875 | // } 876 | // } 877 | // now it become.. 878 | impl<'a, T> Permutation<'a> for [T] where T : 'a { 879 | type Permutator = HeapPermutation<'a, T>; // This struct implement `Iterator` 880 | 881 | fn permutation(&'a mut self) -> HeapPermutation { 882 | HeapPermutation { 883 | c : vec![0; self.len()], 884 | data : self, 885 | i : 0 886 | } 887 | } 888 | } 889 | ``` 890 | The added complexity make this trait applicable to wider type. 891 | Here's new implemention on `Rc>` which return `HeapPermutationCell`. 892 | ```Rust 893 | impl<'a, T> Permutation<'a> for Rc> where T :'a { 894 | type Permutator = HeapPermutationCell<'a, T>; // This struct also implement `Iterator` 895 | 896 | fn permutation(&'a mut self) -> HeapPermutationCell { 897 | HeapPermutationCell { 898 | c : vec![0; self.borrow().len()], 899 | data : Rc::clone(self), 900 | i : 0 901 | } 902 | } 903 | } 904 | ``` --------------------------------------------------------------------------------