Merge remote branch 'apache:add-combinatorics'
This closes #2
Signed-off-by: ILYA Khlopotov <iilyak@ca.ibm.com>
diff --git a/src/couch_tests_combinatorics.erl b/src/couch_tests_combinatorics.erl
new file mode 100644
index 0000000..3433362
--- /dev/null
+++ b/src/couch_tests_combinatorics.erl
@@ -0,0 +1,137 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+% http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couch_tests_combinatorics).
+
+-export([
+ powerset/1,
+ permutations/1,
+ product/1,
+ binary_combinations/1,
+ n_combinations/2
+]).
+
+%% @doc powerset(Items)
+%% Generate powerset for a given list of Items
+%% By Hynek - Pichi - Vychodil
+%% For example:
+%% 1> powerset([foo, bar, baz]).
+%% [
+%% [foo],
+%% [foo,baz],
+%% [foo,bar,baz],
+%% [foo,bar],
+%% [bar],
+%% [bar,baz],
+%% [baz],
+%% []
+%% ]
+-spec powerset(Elements :: list()) -> [list()].
+
+powerset([]) ->
+ [[]];
+powerset([H | T]) ->
+ PT = powerset(T),
+ powerset(H, PT, PT).
+
+powerset(_, [], Acc) ->
+ Acc;
+powerset(X, [H | T], Acc) ->
+ powerset(X, T, [[X | H] | Acc]).
+
+%% @doc permutations(Items)
+%% Return all premutations of given list of Items.
+%% from http://erlang.org/doc/programming_examples/list_comprehensions.html
+%% For example:
+%% 1> permutations([foo, bar, baz]).
+%% [
+%% [foo, bar, baz],
+%% [foo, baz, bar],
+%% [bar, foo, baz],
+%% [bar, baz, foo],
+%% [baz, foo, bar],
+%% [baz, bar, foo]
+%% ]
+-spec permutations(Elements :: list()) -> [list()].
+
+permutations([]) ->
+ [[]];
+permutations(L) ->
+ [[H | T] || H <- L, T <- permutations(L -- [H])].
+
+%% @doc product({Items1, Items2, ..., ItemsN})
+%% Return cartesian product of multiple sets represented as list of lists
+%% From: http://stackoverflow.com/a/23886680
+%% For example:
+%% 1> product([[foo, bar], [1,2,3]]).
+%% [
+%% [foo, 1],
+%% [foo, 2],
+%% [foo, 3],
+%% [bar, 1],
+%% [bar, 2],
+%% [bar, 3]
+%% ]
+-spec product(Elements :: list()) -> [list()].
+
+product([H]) ->
+ [[A] || A <- H];
+product([H | T]) ->
+ [[A | B] || A <- H, B <- product(T)].
+
+%% @doc binary_combinations(NBits).
+%% Generate all combinations of true and false for specified number of bits.
+%% For example:
+%% 1> binary_combinations(3).
+%% [
+%% [ false , false , false ],
+%% [ false , false , true ],
+%% [ false , true , false ],
+%% [ false , true , true ],
+%% [ true , false , false ],
+%% [ true , false , true ],
+%% [ true , true , false ],
+%% [ true , true , true ]
+%% ]
+%% 2> length(binary_combinations(3))
+%% 8
+-spec binary_combinations(NBits :: pos_integer()) -> [list(boolean())].
+
+binary_combinations(NBits) ->
+ product(lists:duplicate(NBits, [true, false])).
+
+
+%% @doc combinations(N, Items).
+%% Generate all combinations by choosing N values from a given list of Items
+%% in sorted order. Each combination is sorted and the entire table is sorted.
+%% For example:
+%% 1> couch_tests_combinatorics:n_combinations(2, [mon, tue, wed, thu, fri]).
+%% [
+%% [mon, tue],
+%% [mon, wed],
+%% [mon, thu],
+%% [mon, fri],
+%% [tue, wed],
+%% [tue, thu],
+%% [tue, fri],
+%% [wed, thu],
+%% [wed, fri],
+%% [thu, fri]
+%% ]
+-spec n_combinations(Size :: pos_integer(), Elements :: list()) -> [list()].
+
+n_combinations(0, _) ->
+ [[]];
+n_combinations(_, []) ->
+ [];
+n_combinations(N, [H | T]) ->
+ [[H | L] || L <- n_combinations(N - 1, T)] ++ n_combinations(N, T).