From bee7fdeffb6896249df71491f1a408ff930669e3 Mon Sep 17 00:00:00 2001 From: Beojan Stanislaus Date: Thu, 11 Dec 2025 11:25:04 -0800 Subject: [PATCH 1/2] FEAT: Specify input product using producer name Addresses #108 --- phlex/core/edge_creation_policy.hpp | 2 -- phlex/core/product_query.cpp | 7 ++++ phlex/core/product_query.hpp | 6 ++++ test/CMakeLists.txt | 9 +++++ test/anonymous_products.cpp | 56 +++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 test/anonymous_products.cpp diff --git a/phlex/core/edge_creation_policy.hpp b/phlex/core/edge_creation_policy.hpp index b149e3b6..e117dcb3 100644 --- a/phlex/core/edge_creation_policy.hpp +++ b/phlex/core/edge_creation_policy.hpp @@ -45,8 +45,6 @@ namespace phlex::experimental { std::multimap result; for (auto const& [node_name, node] : nodes) { for (auto const& product_name : node->output()) { - if (empty(product_name.name())) - continue; result.emplace( product_name.name(), named_output_port{node_name, &node->sender(), &node->to_output(), product_name.type()}); diff --git a/phlex/core/product_query.cpp b/phlex/core/product_query.cpp index 14fad88e..ab26c749 100644 --- a/phlex/core/product_query.cpp +++ b/phlex/core/product_query.cpp @@ -1,6 +1,8 @@ #include "phlex/core/product_query.hpp" #include "fmt/format.h" +#include "phlex/model/algorithm_name.hpp" +#include "phlex/model/product_specification.hpp" #include #include @@ -23,6 +25,11 @@ namespace phlex::experimental { return fmt::format("{} ϵ {}", spec.full(), layer); } + product_tag from(char const* creator) + { + return {.name = product_specification(algorithm_name(creator), "", type_id())}; + } + product_tag operator""_in(char const* product_name, std::size_t length) { if (length == 0ull) { diff --git a/phlex/core/product_query.hpp b/phlex/core/product_query.hpp index 81a79e4a..9c8c2665 100644 --- a/phlex/core/product_query.hpp +++ b/phlex/core/product_query.hpp @@ -19,6 +19,11 @@ namespace phlex::experimental { struct product_tag { product_specification spec; product_query operator()(std::string layer) &&; + product_query in(std::string layer) && + { + // std::move(*this) required to forward to rvalue ref qualified operator() + return std::move(*this).operator()(std::move(layer)); + } }; using product_queries = std::vector; @@ -26,6 +31,7 @@ namespace phlex::experimental { inline auto& to_name(product_query const& query) { return query.spec.name(); } inline auto& to_layer(product_query& query) { return query.layer; } + product_tag from(char const* creator); product_tag operator""_in(char const* str, std::size_t); bool operator==(product_query const& a, product_query const& b); bool operator!=(product_query const& a, product_query const& b); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3d93011a..6acbb1b6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -110,6 +110,15 @@ cet_test( Boost::json phlex::core ) +cet_test( + anonymous_products + USE_CATCH2_MAIN + SOURCE + anonymous_products.cpp + LIBRARIES + Boost::json + phlex::core + ) cet_test( data_cell_counting USE_CATCH2_MAIN diff --git a/test/anonymous_products.cpp b/test/anonymous_products.cpp new file mode 100644 index 00000000..d196b86a --- /dev/null +++ b/test/anonymous_products.cpp @@ -0,0 +1,56 @@ +#include "phlex/core/framework_graph.hpp" +#include "phlex/model/data_layer_hierarchy.hpp" +#include "phlex/model/product_store.hpp" + +#include "catch2/catch_test_macros.hpp" + +#include +#include +#include + +using namespace phlex::experimental; + +namespace { + auto square_numbers(std::vector const& numbers) + { + std::vector result(size(numbers)); + std::ranges::transform(numbers, begin(result), [](unsigned i) { return i * i; }); + return result; + } + + auto sum_numbers(std::vector const& squared_numbers) + { + std::vector const expected_squared_numbers{0, 1, 4, 9, 16}; + CHECK(squared_numbers == expected_squared_numbers); + return std::accumulate(begin(squared_numbers), end(squared_numbers), 0u); + } + + double sqrt_sum_numbers(unsigned summed_numbers, unsigned offset) + { + CHECK(summed_numbers == 30u); + return std::sqrt(static_cast(summed_numbers + offset)); + } +} + +TEST_CASE("Test resolution without product suffixes", "[programming model]") +{ + auto store = product_store::base(); + store->add_product("numbers", std::vector{0, 1, 2, 3, 4}); + store->add_product("offset", 6u); + framework_graph g{store}; + + g.transform("square_numbers", square_numbers, concurrency::unlimited) + .input_family("numbers"_in("job")) + .output_products(""); + g.transform("sum_numbers", sum_numbers, concurrency::unlimited) + .input_family(from("square_numbers").in("job")) + .output_products(""); + g.transform("sqrt_sum_numbers", sqrt_sum_numbers, concurrency::unlimited) + .input_family(from("sum_numbers").in("job"), "offset"_in("job")) + .output_products("result"); + + // The following is invoked for *each* section above + g.observe("verify_result", [](double actual) { assert(actual == 6.); }) + .input_family("result"_in("job")); + g.execute(); +} From 1016ae60b79bf704c70be6e92930ecceb8783632 Mon Sep 17 00:00:00 2001 From: Beojan Stanislaus Date: Thu, 11 Dec 2025 14:06:28 -0800 Subject: [PATCH 2/2] Adjustments after providers PR --- phlex/core/product_query.cpp | 2 +- test/anonymous_products.cpp | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/phlex/core/product_query.cpp b/phlex/core/product_query.cpp index ab26c749..8beb2677 100644 --- a/phlex/core/product_query.cpp +++ b/phlex/core/product_query.cpp @@ -27,7 +27,7 @@ namespace phlex::experimental { product_tag from(char const* creator) { - return {.name = product_specification(algorithm_name(creator), "", type_id())}; + return {.spec = product_specification(algorithm_name(creator), "", type_id())}; } product_tag operator""_in(char const* product_name, std::size_t length) diff --git a/test/anonymous_products.cpp b/test/anonymous_products.cpp index d196b86a..7d19f764 100644 --- a/test/anonymous_products.cpp +++ b/test/anonymous_products.cpp @@ -34,10 +34,12 @@ namespace { TEST_CASE("Test resolution without product suffixes", "[programming model]") { - auto store = product_store::base(); - store->add_product("numbers", std::vector{0, 1, 2, 3, 4}); - store->add_product("offset", 6u); - framework_graph g{store}; + framework_graph g{data_cell_index::base_ptr()}; + g.provide("provide_numbers", + [](data_cell_index const&) -> std::vector { return {0, 1, 2, 3, 4}; }) + .output_product("numbers"_in("job")); + g.provide("provide_offset", [](data_cell_index const&) -> unsigned { return 6u; }) + .output_product("offset"_in("job")); g.transform("square_numbers", square_numbers, concurrency::unlimited) .input_family("numbers"_in("job"))