Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Legalization #476

Open
wants to merge 98 commits into
base: main
Choose a base branch
from
Open

Legalization #476

wants to merge 98 commits into from

Conversation

hibenj
Copy link
Collaborator

@hibenj hibenj commented Jul 17, 2024

Description

Adds the following .hpp and .cpp files:

  • check_planarity: For a given network with a rank view, check for planarity
  • virtual_pi_network: stores additional PIs, which are duplicates of other pis. These are called virtual PIs and are stored with a map to their origin PI
  • extended_rank_view: the extended rank_view allows for a more easy modification of ranks and also adds another constructor from an array of nodes. (This might also be more error prone)
  • node_suplication_planarization: Constucts an H-graph (as in "Fabricatable Interconnect and
    Molecular QCA Circuits") in order to duplicate nodes on a given PO order. The output is a extended_rank_view of a virtual_pi_network

Fixes # (issue)

Checklist:

  • The pull request only contains commits that are related to it.
  • I have added appropriate tests and documentation.
  • I have added a changelog entry.
  • I have created/adjusted the Python bindings for any new or updated functionality.
  • I have made sure that all CI jobs on GitHub pass.
  • The pull request introduces no new warnings and follows the project's style guidelines.

hibenj and others added 30 commits June 12, 2024 10:41
…es have to be written as indicated in the ToDo)
…equivalence checking inside the extended rank view.
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 25 out of 91. Check the log or trigger a new build to see more.

experiments/legalization/legalization.cpp Show resolved Hide resolved
experiments/legalization/legalization.cpp Outdated Show resolved Hide resolved
experiments/legalization/legalization.cpp Outdated Show resolved Hide resolved
experiments/legalization/legalization.cpp Show resolved Hide resolved
experiments/legalization/legalization.cpp Show resolved Hide resolved
experiments/legalization/legalization.cpp Outdated Show resolved Hide resolved
experiments/legalization/legalization.cpp Show resolved Hide resolved
experiments/legalization/legalization.cpp Show resolved Hide resolved
experiments/legalization/legalization.cpp Show resolved Hide resolved
experiments/legalization/legalization.cpp Outdated Show resolved Hide resolved
if ((node_pair_cur.pair.first == node_pair_last.pair.second &&
node_pair_last.delay + 1 < node_pair_cur.delay))
{
node_pair_cur.fanin_pair = &node_pair_last;

Check warning

Code scanning / CodeQL

Local variable address stored in non-local memory

A stack address ([source](1)) may be assigned to a non-local variable.
// If there is no connection between the two node pairs the delay is calculated like this
else if (node_pair_last.delay + 2 < node_pair_cur.delay)
{
node_pair_cur.fanin_pair = &node_pair_last;

Check warning

Code scanning / CodeQL

Local variable address stored in non-local memory

A stack address ([source](1)) may be assigned to a non-local variable.
{
if (f0 == f1)
{
node_pair_cur.fanin_pair = &node_pair_last;

Check warning

Code scanning / CodeQL

Local variable address stored in non-local memory

A stack address ([source](1)) may be assigned to a non-local variable.
github-actions[bot]

This comment was marked as duplicate.

github-actions[bot]

This comment was marked as duplicate.

hibenj and others added 2 commits September 23, 2024 13:00
…on_planarization.hpp. The function has no use in any other context (so far).
Signed-off-by: GitHub Actions <actions@github.com>
github-actions[bot]

This comment was marked as duplicate.

hibenj and others added 2 commits September 23, 2024 18:12
Signed-off-by: GitHub Actions <actions@github.com>
github-actions[bot]

This comment was marked as duplicate.

github-actions[bot]

This comment was marked as duplicate.

github-actions[bot]

This comment was marked as duplicate.

@Drewniok
Copy link
Collaborator

@hibenj No worries, the CI fails on Mac because you accidentally updated the submodules. You should revert those changes to fix this :)

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 25 out of 51. Check the log or trigger a new build to see more.

// check equivalence
mockturtle::equivalence_checking_stats st;
const auto cec_m = mockturtle::equivalence_checking(
*fiction::virtual_miter<fiction::technology_network>(benchmark_network, planarized_b), {}, &st);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

            *fiction::virtual_miter<fiction::technology_network>(benchmark_network, planarized_b), {}, &st);
             ^

fiction::clocked_layout<fiction::tile_based_layout<fiction::cartesian_layout<fiction::offset::ucoord_t>>>>;
auto layout = fiction::orthogonal<gate_layout>(planarized_b, {}, &stats);

fiction::gate_level_drv_params ps_d{};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'ps_d' of type 'fiction::gate_level_drv_params' can be declared 'const' [misc-const-correctness]

Suggested change
fiction::gate_level_drv_params ps_d{};
fiction::gate_level_drv_params const ps_d{};

mockturtle::equivalence_checking_stats st_o;

const auto ce = mockturtle::equivalence_checking(*miter, {}, &st_o);
eq = ce.value();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

            eq            = ce.value();
                            ^

// log results
wiring_reduction_exp(benchmark, benchmark_network.num_pis(), planarized_b.num_virtual_pis(),
benchmark_network.num_pos(), benchmark_network.num_gates(), b.num_gates(),
planarized_b.num_gates(), is_planar, cec_m.value(), eq);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

                             planarized_b.num_gates(), is_planar, cec_m.value(), eq);
                                                                  ^

wiring_reduction_exp.table();
}

return EXIT_SUCCESS;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "EXIT_SUCCESS" is directly included [misc-include-cleaner]

experiments/legalization/legalization.cpp:30:

- #include <filesystem>
+ #include <cstdlib>
+ #include <filesystem>

*
* @return Width of the widest rank in the network.
*/
uint32_t width() const noexcept
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'width' should be marked [[nodiscard]] [modernize-use-nodiscard]

Suggested change
uint32_t width() const noexcept
[[nodiscard]] uint32_t width() const noexcept

{
for (auto l = 0; l < ranks.size(); ++l)
{
foreach_node_in_rank(l, std::forward<Fn>(fn));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: implicit conversion changes signedness: 'int' to 'uint32_t' (aka 'unsigned int') [clang-diagnostic-sign-conversion]

            foreach_node_in_rank(l, std::forward<Fn>(fn));
                                 ^
Additional context

include/fiction/utils/network_utils.hpp:274: in instantiation of function template specialization 'fiction::extended_rank_view<fiction::virtual_pi_networkfiction::technology_network>::foreach_node<(lambda at /github/workspace/include/fiction/utils/network_utils.hpp:276:9)>' requested here

    ntk.foreach_node(
        ^

include/fiction/algorithms/physical_design/orthogonal.hpp:686: in instantiation of function template specialization 'fiction::has_high_degree_fanin_nodes<fiction::extended_rank_view<fiction::virtual_pi_networkfiction::technology_network>>' requested here

or input degree
                        ^

experiments/legalization/legalization.cpp:128: in instantiation of function template specialization 'fiction::orthogonal<fiction::gate_level_layout<fiction::clocked_layout<fiction::tile_based_layout<fiction::cartesian_layout<>>>>, fiction::extended_rank_view<fiction::virtual_pi_networkfiction::technology_network>>' requested here

        auto layout = fiction::orthogonal<gate_layout>(planarized_b, {}, &stats);
                               ^

{
for (auto l = 0; l < ranks.size(); ++l)
{
foreach_gate_in_rank(l, std::forward<Fn>(fn));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: implicit conversion changes signedness: 'int' to 'uint32_t' (aka 'unsigned int') [clang-diagnostic-sign-conversion]

            foreach_gate_in_rank(l, std::forward<Fn>(fn));
                                 ^
Additional context

include/fiction/networks/virtual_pi_network.hpp:391: in instantiation of function template specialization 'fiction::extended_rank_view<fiction::virtual_pi_networkfiction::technology_network>::foreach_gate<(lambda at /github/workspace/include/fiction/networks/virtual_pi_network.hpp:393:13)>' requested here

        ntk_topo.foreach_gate(
                 ^

include/fiction/networks/virtual_pi_network.hpp:560: in instantiation of member function 'fiction::detail::delete_virtual_pis_impl<fiction::extended_rank_view<fiction::virtual_pi_networkfiction::technology_network>>::run' requested here

    auto result = p.run();
                    ^

include/fiction/algorithms/verification/virtual_miter.hpp:23: in instantiation of function template specialization 'fiction::delete_virtual_pis<fiction::extended_rank_view<fiction::virtual_pi_networkfiction::technology_network>>' requested here

        return delete_virtual_pis(network);
               ^

experiments/legalization/legalization.cpp:122: in instantiation of function template specialization 'fiction::virtual_miter<fiction::technology_network, mockturtle::names_viewfiction::technology_network, fiction::extended_rank_view<fiction::virtual_pi_networkfiction::technology_network>>' requested here

            *fiction::virtual_miter<fiction::technology_network>(benchmark_network, planarized_b), {}, &st);
                      ^

std::vector<std::vector<node>> ranks;
uint32_t max_rank_width;

std::shared_ptr<typename mockturtle::network_events<Ntk>::add_event_type> add_event;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "mockturtle::network_events" is directly included [misc-include-cleaner]

include/fiction/networks/views/extended_rank_view.hpp:8:

- #include <mockturtle/traits.hpp>
+ #include <mockturtle/networks/events.hpp>
+ #include <mockturtle/traits.hpp>

void insert_in_rank(const node& n)
{
auto& rank = ranks[this->level(n)];
rank_pos[n] = rank.size();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: implicit conversion loses integer precision: 'size_type' (aka 'unsigned long') to 'value_type' (aka 'unsigned int') [clang-diagnostic-shorten-64-to-32]

        rank_pos[n] = rank.size();
                           ^
Additional context

include/fiction/networks/views/extended_rank_view.hpp:471: in instantiation of member function 'fiction::extended_rank_view<fiction::virtual_pi_networkfiction::technology_network>::insert_in_rank' requested here

        insert_in_rank(n);
        ^

include/fiction/networks/views/extended_rank_view.hpp:142: in instantiation of member function 'fiction::extended_rank_view<fiction::virtual_pi_networkfiction::technology_network>::on_add' requested here

        add_event = Ntk::events().register_add_event([this](auto const& n) { on_add(n); });
                                                                             ^

include/fiction/algorithms/network_transformation/node_duplication_planarization.hpp:647: in instantiation of member function 'fiction::extended_rank_view<fiction::virtual_pi_networkfiction::technology_network>::extended_rank_view' requested here

        return extended_rank_view(virtual_ntk, ntk_lvls_new);
               ^

include/fiction/algorithms/network_transformation/node_duplication_planarization.hpp:706: in instantiation of member function 'fiction::detail::node_duplication_planarization_implfiction::technology_network::run' requested here

    auto result = p.run(ntk_lvls_new);
                    ^

experiments/legalization/legalization.cpp:114: in instantiation of function template specialization 'fiction::node_duplication_planarizationfiction::technology_network' requested here

        const auto planarized_b = fiction::node_duplication_planarization<fiction::technology_network>(b);
                                           ^

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 25 out of 46. Check the log or trigger a new build to see more.

// check equivalence
mockturtle::equivalence_checking_stats st;
const auto cec_m = mockturtle::equivalence_checking(
*fiction::virtual_miter<fiction::technology_network>(benchmark_network, planarized_b), {}, &st);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

            *fiction::virtual_miter<fiction::technology_network>(benchmark_network, planarized_b), {}, &st);
             ^

fiction::clocked_layout<fiction::tile_based_layout<fiction::cartesian_layout<fiction::offset::ucoord_t>>>>;
auto layout = fiction::orthogonal<gate_layout>(planarized_b, {}, &stats);

fiction::gate_level_drv_params ps_d{};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'ps_d' of type 'fiction::gate_level_drv_params' can be declared 'const' [misc-const-correctness]

Suggested change
fiction::gate_level_drv_params ps_d{};
fiction::gate_level_drv_params const ps_d{};

mockturtle::equivalence_checking_stats st_o;

const auto ce = mockturtle::equivalence_checking(*miter, {}, &st_o);
eq = ce.value();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

            eq            = ce.value();
                            ^

// log results
wiring_reduction_exp(benchmark, benchmark_network.num_pis(), planarized_b.num_virtual_pis(),
benchmark_network.num_pos(), benchmark_network.num_gates(), b.num_gates(),
planarized_b.num_gates(), is_planar, cec_m.value(), eq);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

                             planarized_b.num_gates(), is_planar, cec_m.value(), eq);
                                                                  ^

wiring_reduction_exp.table();
}

return EXIT_SUCCESS;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "EXIT_SUCCESS" is directly included [misc-include-cleaner]

experiments/legalization/legalization.cpp:30:

- #include <filesystem>
+ #include <cstdlib>
+ #include <filesystem>

{
assert(rank_level < ranks.size());
auto& rank = ranks[rank_level];
rank_pos[n] = rank.size();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: implicit conversion loses integer precision: 'size_type' (aka 'unsigned long') to 'value_type' (aka 'unsigned int') [clang-diagnostic-shorten-64-to-32]

        rank_pos[n] = rank.size();
                           ^
Additional context

include/fiction/networks/views/extended_rank_view.hpp:521: in instantiation of member function 'fiction::extended_rank_view<fiction::virtual_pi_networkfiction::technology_network>::insert_in_rank' requested here

                    insert_in_rank(n, i);
                    ^

include/fiction/networks/views/extended_rank_view.hpp:140: in instantiation of member function 'fiction::extended_rank_view<fiction::virtual_pi_networkfiction::technology_network>::init_ranks' requested here

        init_ranks(ranks);
        ^

include/fiction/algorithms/network_transformation/node_duplication_planarization.hpp:647: in instantiation of member function 'fiction::extended_rank_view<fiction::virtual_pi_networkfiction::technology_network>::extended_rank_view' requested here

        return extended_rank_view(virtual_ntk, ntk_lvls_new);
               ^

include/fiction/algorithms/network_transformation/node_duplication_planarization.hpp:706: in instantiation of member function 'fiction::detail::node_duplication_planarization_implfiction::technology_network::run' requested here

    auto result = p.run(ntk_lvls_new);
                    ^

experiments/legalization/legalization.cpp:114: in instantiation of function template specialization 'fiction::node_duplication_planarizationfiction::technology_network' requested here

        const auto planarized_b = fiction::node_duplication_planarization<fiction::technology_network>(b);
                                           ^

* @param fn The function to be applied to each primary input.
*/
template <typename Fn>
void foreach_virtual_pi(Fn&& fn) const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: forwarding reference parameter 'fn' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward]

    void foreach_virtual_pi(Fn&& fn) const
                                 ^

* @param fn The function to be applied to each primary input.
*/
template <typename Fn>
void foreach_virtual_ci(Fn&& fn) const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: forwarding reference parameter 'fn' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward]

    void foreach_virtual_ci(Fn&& fn) const
                                 ^


#if (PROGRESS_BARS)
// initialize a progress bar
mockturtle::progress_bar bar{static_cast<uint32_t>(ntk.num_gates()), "[i] network conversion: |{0}|"};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no type named 'progress_bar' in namespace 'mockturtle' [clang-diagnostic-error]

        mockturtle::progress_bar bar{static_cast<uint32_t>(ntk.num_gates()), "[i] network conversion: |{0}|"};
                    ^

Ntk ntk;
TopoNtkSrc ntk_topo;

[[nodiscard]] std::pair<Ntk, mockturtle::node_map<mockturtle::signal<Ntk>, Ntk>>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "mockturtle::node_map" is directly included [misc-include-cleaner]

include/fiction/networks/virtual_pi_network.hpp:11:

- #include <mockturtle/views/topo_view.hpp>
+ #include <mockturtle/utils/node_map.hpp>
+ #include <mockturtle/views/topo_view.hpp>

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 25 out of 44. Check the log or trigger a new build to see more.

// check equivalence
mockturtle::equivalence_checking_stats st;
const auto cec_m = mockturtle::equivalence_checking(
*fiction::virtual_miter<fiction::technology_network>(benchmark_network, planarized_b), {}, &st);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

            *fiction::virtual_miter<fiction::technology_network>(benchmark_network, planarized_b), {}, &st);
             ^

fiction::clocked_layout<fiction::tile_based_layout<fiction::cartesian_layout<fiction::offset::ucoord_t>>>>;
auto layout = fiction::orthogonal<gate_layout>(planarized_b, {}, &stats);

fiction::gate_level_drv_params ps_d{};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'ps_d' of type 'fiction::gate_level_drv_params' can be declared 'const' [misc-const-correctness]

Suggested change
fiction::gate_level_drv_params ps_d{};
fiction::gate_level_drv_params const ps_d{};

mockturtle::equivalence_checking_stats st_o;

const auto ce = mockturtle::equivalence_checking(*miter, {}, &st_o);
eq = ce.value();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

            eq            = ce.value();
                            ^

// log results
wiring_reduction_exp(benchmark, benchmark_network.num_pis(), planarized_b.num_virtual_pis(),
benchmark_network.num_pos(), benchmark_network.num_gates(), b.num_gates(),
planarized_b.num_gates(), is_planar, cec_m.value(), eq);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

                             planarized_b.num_gates(), is_planar, cec_m.value(), eq);
                                                                  ^

wiring_reduction_exp.table();
}

return EXIT_SUCCESS;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "EXIT_SUCCESS" is directly included [misc-include-cleaner]

experiments/legalization/legalization.cpp:30:

- #include <filesystem>
+ #include <cstdlib>
+ #include <filesystem>

* @param fn The function to be applied to each primary input.
*/
template <typename Fn>
void foreach_virtual_pi(Fn&& fn) const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: forwarding reference parameter 'fn' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward]

    void foreach_virtual_pi(Fn&& fn) const
                                 ^

* @param fn The function to be applied to each primary input.
*/
template <typename Fn>
void foreach_virtual_ci(Fn&& fn) const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: forwarding reference parameter 'fn' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward]

    void foreach_virtual_ci(Fn&& fn) const
                                 ^

Ntk ntk;
TopoNtkSrc ntk_topo;

[[nodiscard]] std::pair<Ntk, mockturtle::node_map<mockturtle::signal<Ntk>, Ntk>>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "mockturtle::node_map" is directly included [misc-include-cleaner]

include/fiction/networks/virtual_pi_network.hpp:11:

- #include <mockturtle/views/topo_view.hpp>
+ #include <mockturtle/utils/node_map.hpp>
+ #include <mockturtle/views/topo_view.hpp>

const auto removed = remove_buffer(tec);

mockturtle::equivalence_checking_stats st;
const auto cec_m = mockturtle::equivalence_checking(*mockturtle::miter<technology_network>(tec, removed), {}, &st);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

    const auto cec_m = mockturtle::equivalence_checking(*mockturtle::miter<technology_network>(tec, removed), {}, &st);
                                                         ^

mockturtle::equivalence_checking_stats st;
const auto cec_m = mockturtle::equivalence_checking(*mockturtle::miter<technology_network>(tec, removed), {}, &st);
REQUIRE(cec_m.has_value());
CHECK(cec_m.value() == 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

    CHECK(cec_m.value() == 1);
          ^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants