Skip to content

Commit

Permalink
Merge pull request #166 from tcbrindle/pr/cartesian_docs
Browse files Browse the repository at this point in the history
Add documentation for cartesian adaptors
  • Loading branch information
tcbrindle authored Feb 1, 2024
2 parents bbfb1d4 + 50cb491 commit 6610792
Show file tree
Hide file tree
Showing 7 changed files with 283 additions and 3 deletions.
151 changes: 150 additions & 1 deletion docs/reference/adaptors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,129 @@ You can pass a reference to a sequence into an adaptor using :func:`flux::ref` o
* - :concept:`const_iterable_sequence`
- :var:`Seq` is bounded and const-iterable (passthrough)

``cartesian_power``
^^^^^^^^^^^^^^^^^^^

.. function::
template <distance_t N> \
requires (N >= 0) \
auto cartesian_power(multipass_sequence auto seq) -> multipass_sequence auto;

Returns a sequence object giving the :var:`N` th `Cartesian power <https://en.wikipedia.org/wiki/Cartesian_product#n-ary_Cartesian_power>`_ of the elements of :var:`seq`. It is equivalent to :var:`N` nested ``for`` loops each iterating over :var:`seq`.

The element type of the returned sequence is an :var:`N`-tuple of the elements of :var:`seq`. The number of elements is :math:`S^N`, where :math:`S` is :expr:`count(seq)`.

Equivalent to :expr:`cartesian_product(seq, seq, ...)`, but stores only a single copy of :var:`seq`.

:tparam N: The cartesian power

:param seq: A multipass sequence

:returns: A multipass sequence yielding :var:`N`-tuples of all combinations of elements of :var:`seq`

:example:

.. literalinclude:: ../../example/docs/cartesian_power.cpp
:language: cpp
:dedent:
:lines: 15-25

:models:

.. list-table::
:align: left
:header-rows: 1

* - Concept
- When
* - :concept:`multipass_sequence`
- Always
* - :concept:`bidirectional_sequence`
- :var:`seq` is bidirectional
* - :concept:`random_access_sequence`
- :var:`seq` is random-access
* - :concept:`contiguous_sequence`
- Never
* - :concept:`bounded_sequence`
- :var:`seq` is bounded
* - :concept:`sized_sequence`
- :var:`seq` is sized
* - :concept:`infinite_sequence`
- Never
* - :concept:`read_only_sequence`
- :var:`seq` is read-only
* - :concept:`const_iterable_sequence`
- :var:`seq` is const-iterable

:see also:

* `std::views::cartesian_product <https://en.cppreference.com/w/cpp/ranges/cartesian_product_view>`_ (C++23)
* :func:`cartesian_power_map`
* :func:`cartesian_product`


``cartesian_power_map``
^^^^^^^^^^^^^^^^^^^^^^^

.. function::
template <distance_t N> \
requires (N >= 0) \
auto cartesian_power_map(multipass_sequence auto seq, auto func) -> multipass_sequence auto;

Returns a sequence adaptor which applies the :var:`N`-ary function :var:`func` to the :var:`N` th `Cartesian power <https://en.wikipedia.org/wiki/Cartesian_product#n-ary_Cartesian_power>`_ of the elements of :var:`seq`.

The total number of elements in the returned sequence is :math:`S^N`, where :math:`S` is :expr:`count(seq)`.

Equivalent to :expr:`cartesian_power<N>(seq, unpack(func))`, but avoids forming an intermediate tuple.

:tparam N: The cartesian power

:param seq: A multipass sequence

:param func: An :var:`N`-ary function callable with the cartesian product of the elements of :var:`seq`

:returns: A multipass sequence whose elements are the result of applying :var:`func` to :var:`N` elements of :var:`seq`

:example:

.. literalinclude:: ../../example/docs/cartesian_power_map.cpp
:language: cpp
:dedent:
:lines: 17-25

:models:

.. list-table::
:align: left
:header-rows: 1

* - Concept
- When
* - :concept:`multipass_sequence`
- Always
* - :concept:`bidirectional_sequence`
- :var:`seq` is bidirectional
* - :concept:`random_access_sequence`
- :var:`seq` is random-access
* - :concept:`contiguous_sequence`
- Never
* - :concept:`bounded_sequence`
- :var:`seq` is bounded
* - :concept:`sized_sequence`
- :var:`seq` is sized
* - :concept:`infinite_sequence`
- Never
* - :concept:`read_only_sequence`
- :var:`seq` is read-only
* - :concept:`const_iterable_sequence`
- :var:`seq` is const-iterable and :var:`func` is const-invocable

:see also:

* `std::views::cartesian_product <https://en.cppreference.com/w/cpp/ranges/cartesian_product_view>`_ (C++23)
* :func:`cartesian_power`
* :func:`cartesian_product_map`

``cartesian_product``
^^^^^^^^^^^^^^^^^^^^^

Expand All @@ -222,6 +345,13 @@ You can pass a reference to a sequence into an adaptor using :func:`flux::ref` o

The element type of the returned sequence is a tuple of the element types of the input sequences.

:example:

.. literalinclude:: ../../example/docs/cartesian_product.cpp
:language: cpp
:dedent:
:lines: 17-43

:models:

.. list-table::
Expand Down Expand Up @@ -249,6 +379,12 @@ You can pass a reference to a sequence into an adaptor using :func:`flux::ref` o
* - :concept:`const_iterable_sequence`
- All passed-in sequences are const-iterable

:see also:

* `std::views::cartesian_product <https://en.cppreference.com/w/cpp/ranges/cartesian_product_view>`_ (C++23)
* :func:`cartesian_power`
* :func:`cartesian_product_map`

``cartesian_product_map``
^^^^^^^^^^^^^^^^^^^^^^^^^

Expand All @@ -257,10 +393,17 @@ You can pass a reference to a sequence into an adaptor using :func:`flux::ref` o
requires std::regular_invocable<Func&, element_t<Seq0>, element_t<Seqs>...> \
auto cartesian_product_with(Func func, Seq0 seq0, Seqs... seqs) -> sequence auto;

Given ``N`` input sequences and an ``N``-ary function :var:`func`, applies :var:`func` to the cartesian product of the elements of the input sequences.
Given ``N`` sequences and an ``N``-ary function :var:`func`, applies :var:`func` to the cartesian product of the elements of the input sequences.

Equivalent to :expr:`map(cartesian_product(seq0, seqs...), unpack(func))`, but avoids forming an intermediate tuple.

:example:

.. literalinclude:: ../../example/docs/cartesian_product_map.cpp
:language: cpp
:dedent:
:lines: 17-29

:models:

.. list-table::
Expand Down Expand Up @@ -288,6 +431,12 @@ You can pass a reference to a sequence into an adaptor using :func:`flux::ref` o
* - :concept:`const_iterable_sequence`
- All passed-in sequences are const-iterable and :var:`func` is const-invocable

:see also:

* `std::views::cartesian_product <https://en.cppreference.com/w/cpp/ranges/cartesian_product_view>`_ (C++23)
* :func:`cartesian_power_map`
* :func:`cartesian_product`

``chain``
^^^^^^^^^

Expand Down
4 changes: 4 additions & 0 deletions example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ add_example(example-docs-adjacent docs/adjacent.cpp)
add_example(example-docs-adjacent-filter docs/adjacent_filter.cpp)
add_example(example-docs-all docs/all.cpp)
add_example(example-docs-any docs/any.cpp)
add_example(example-docs-cartesian-power docs/cartesian_power.cpp)
add_example(example-docs-cartesian-power-map docs/cartesian_power_map.cpp)
add_example(example-docs-cartesian-product docs/cartesian_product.cpp)
add_example(example-docs-cartesian-product-map docs/cartesian_product_map.cpp)
add_example(example-docs-compare docs/compare.cpp)
add_example(example-docs-contains docs/contains.cpp)
add_example(example-docs-count docs/count.cpp)
Expand Down
26 changes: 26 additions & 0 deletions example/docs/cartesian_power.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

// Copyright (c) 2024 Tristan Brindle (tcbrindle at gmail dot com)
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)


#include <flux.hpp>

#include "assert.hpp"
#include <iostream>
#include <vector>

int main()
{
std::string_view str = "ab";
std::vector<std::string> strings;

// cartesian_power<3> gives us 3-tuples which we can destructure
// The total number of elements in this case is size(str)^3 = 8
for (auto [x, y, z] : flux::cartesian_power<3>(str)) {
strings.push_back(std::string{x, y, z});
}

assert((strings == std::vector<std::string>{"aaa", "aab", "aba", "abb",
"baa", "bab", "bba", "bbb"}));
}
26 changes: 26 additions & 0 deletions example/docs/cartesian_power_map.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

// Copyright (c) 2024 Tristan Brindle (tcbrindle at gmail dot com)
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)


#include <flux.hpp>

#include "assert.hpp"
#include <iostream>
#include <vector>

using namespace std::string_view_literals;

int main()
{
std::array nums{1, 2, 3};

// cartesian_power_map<N> takes a sequence and a callable of N arguments
// Here we are using N=2 and the binary function object std::plus
auto sums = flux::cartesian_power_map<2>(nums, std::plus{}).to<std::vector<int>>();

assert((sums == std::vector<int>{1 + 1, 1 + 2, 1 + 3,
2 + 1, 2 + 2, 2 + 3,
3 + 1, 3 + 2, 3 + 3}));
}
44 changes: 44 additions & 0 deletions example/docs/cartesian_product.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@

// Copyright (c) 2024 Tristan Brindle (tcbrindle at gmail dot com)
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)


#include <flux.hpp>

#include "assert.hpp"
#include <iostream>
#include <vector>

using namespace std::string_view_literals;

int main()
{
std::string_view str = "abc";
std::array nums = {1, 2, 3};

// flux::cartesian_product(str, nums) yields all combinations of elements from
// the two sequences as a tuple<char, int>
auto pairs = flux::cartesian_product(str, nums).to<std::vector>();

using P = std::tuple<char, int>;

assert((pairs == std::vector{P{'a', 1}, P{'a', 2}, P{'a', 3},
P{'b', 1}, P{'b', 2}, P{'b', 3},
P{'c', 1}, P{'c', 2}, P{'c', 3}}));

// cartesian_product can take an arbitrary number of sequence arguments
// The number of elements is the product of the sizes of the input sequences
// It is bidirectional and random-access if all the input sequences
// satisfy these concepts
auto seq = flux::cartesian_product("xy"sv,
std::array{1.0, 2.0},
std::vector{111, 222}).reverse();

using T = std::tuple<char, double, int>;

assert(flux::equal(seq, std::vector<T>{{'y', 2.0, 222}, {'y', 2.0, 111},
{'y', 1.0, 222}, {'y', 1.0, 111},
{'x', 2.0, 222}, {'x', 2.0, 111},
{'x', 1.0, 222}, {'x', 1.0, 111}}));
}
30 changes: 30 additions & 0 deletions example/docs/cartesian_product_map.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

// Copyright (c) 2024 Tristan Brindle (tcbrindle at gmail dot com)
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)


#include <flux.hpp>

#include "assert.hpp"
#include <iostream>
#include <vector>

int main()
{
std::array big = {10000L, 20000L};
std::array medium = {100.0f, 200.0f};
std::array small = {1, 2};

auto add3 = [](long a, float b, int c) { return double(a) + b + c; };

// Note that because cartesian_product_map takes a variadic number of
// sequences, the function argument goes first
auto vec = flux::cartesian_product_map(add3, big, medium, small)
.to<std::vector>();

assert((vec == std::vector<double>{10101.0, 10102.0,
10201.0, 10202.0,
20101.0, 20102.0,
20201.0, 20202.0}));
}
5 changes: 3 additions & 2 deletions include/flux/op/cartesian_power.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ struct cartesian_power_fn {
} // end namespace detail

FLUX_EXPORT
template<std::size_t PowN>
inline constexpr auto cartesian_power = detail::cartesian_power_fn<PowN>{};
template<distance_t N>
requires (N >= 0)
inline constexpr auto cartesian_power = detail::cartesian_power_fn<N>{};

} // end namespace flux

Expand Down

0 comments on commit 6610792

Please sign in to comment.