From e43d9116fcafbf6d31e22a7da12ecab5759b1820 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Fri, 26 Dec 2025 10:51:43 +0100 Subject: [PATCH 1/4] [fnc] avoid double natural evaluation --- src/core/functions/analytic/codac2_AnalyticFunction.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/functions/analytic/codac2_AnalyticFunction.h b/src/core/functions/analytic/codac2_AnalyticFunction.h index 2a527fbf1..5d41421de 100644 --- a/src/core/functions/analytic/codac2_AnalyticFunction.h +++ b/src/core/functions/analytic/codac2_AnalyticFunction.h @@ -133,7 +133,7 @@ namespace codac2 // If the centered form is not available for this expression... if(x_.da.size() == 0 // .. because some parts have not yet been implemented, || !x_.def_domain) // .. or due to restrictions in the derivative definition domain - return eval(EvalMode::NATURAL, x...); + return x_.a; // natural evaluation else { @@ -311,7 +311,7 @@ namespace codac2 else { fill_from_args(v, x...); - return this->expr()->fwd_eval(v, cart_prod(x...).size(), NATURAL_EVAL); // todo: improve size computation + return this->expr()->fwd_eval(v, this->input_size(), NATURAL_EVAL); } } From 5fe9df5fb281a14609f470426c2bfaf4c4fd8ead Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Fri, 26 Dec 2025 10:53:00 +0100 Subject: [PATCH 2/4] [fnc] improved FunctionArgsList, memorizing total_size() --- .../analytic/codac2_py_AnalyticFunction.h | 13 +++-- src/core/functions/codac2_FunctionArgsList.h | 47 +++++++++++++++---- 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/python/src/core/functions/analytic/codac2_py_AnalyticFunction.h b/python/src/core/functions/analytic/codac2_py_AnalyticFunction.h index 1f970557b..a719717f0 100644 --- a/python/src/core/functions/analytic/codac2_py_AnalyticFunction.h +++ b/python/src/core/functions/analytic/codac2_py_AnalyticFunction.h @@ -154,7 +154,7 @@ using namespace pybind11::literals; inline FunctionArgsList create_FunctionArgsList(const std::vector& l) { - FunctionArgsList args {}; + std::vector> v_args; Index i = 0; for(const auto& li : l) @@ -162,20 +162,19 @@ inline FunctionArgsList create_FunctionArgsList(const std::vector& l i++; if(py::isinstance(li)) - args.push_back(li.cast().arg_copy()); + v_args.push_back(li.cast().arg_copy()); else if(py::isinstance(li)) - args.push_back(li.cast().arg_copy()); + v_args.push_back(li.cast().arg_copy()); else if(py::isinstance(li)) - args.push_back(li.cast().arg_copy()); + v_args.push_back(li.cast().arg_copy()); else throw std::invalid_argument("Argument " + std::to_string(i) + " is invalid. Only variables are accepted."); } - - args.compute_unique_arg_names(); - return args; + + return { v_args }; } template diff --git a/src/core/functions/codac2_FunctionArgsList.h b/src/core/functions/codac2_FunctionArgsList.h index 5c2d13531..91da714ab 100644 --- a/src/core/functions/codac2_FunctionArgsList.h +++ b/src/core/functions/codac2_FunctionArgsList.h @@ -21,15 +21,36 @@ namespace codac2 * \class FunctionArgsList * \brief A container class to manage a collection of function arguments. */ - class FunctionArgsList : public std::vector> + class FunctionArgsList : private std::vector> { + using base = std::vector>; + + public: + + // Expose only selected const (read-only) members of the underlying + // std::vector via `using` to keep iteration/access convenient. + // Mutating operations (push_back/insert/erase/...) are intentionally + // not exposed in order to keep consistency with the _total_args_size value. + + using base::size; + using base::empty; + using base::cbegin; + using base::cend; + using base::crbegin; + using base::crend; + + const std::shared_ptr& operator[](std::size_t i) const { return base::operator[](i); } + const std::shared_ptr& at(std::size_t i) const { return base::at(i); } + + base::const_iterator begin() const noexcept { return base::begin(); } + base::const_iterator end() const noexcept { return base::end(); } + public: /** * \brief Default constructor. It creates an empty list of arguments. */ - FunctionArgsList() - { } + FunctionArgsList() = default; /** * \brief Copy constructor. @@ -43,7 +64,7 @@ namespace codac2 { size_t i = 0; for(const auto& arg : args) - (*this)[i++] = arg->arg_copy(); + base::operator[](i++) = arg->arg_copy(); compute_unique_arg_names(); } @@ -74,6 +95,12 @@ namespace codac2 compute_unique_arg_names(); } + FunctionArgsList(const std::vector>& args) + : std::vector>(args) + { + compute_unique_arg_names(); + } + /** * \brief Calculates the total size of the function arguments, * as the sum of the sizes of each argument. @@ -82,21 +109,23 @@ namespace codac2 */ Index total_size() const { - Index n = 0; - for(const auto& ai : *this) - n += ai->size(); - return n; + return _total_args_size; } + protected: + void compute_unique_arg_names() { std::list var_names; for(const auto& arg : *this) var_names.push_back(arg->name()); + _total_args_size = 0; + int i = 23; // default first variable is x, then y,z, then starting from a... for(auto& arg : *this) { + _total_args_size += arg->size(); if(arg->name() == "?") { std::string new_name; @@ -107,5 +136,7 @@ namespace codac2 } } } + + Index _total_args_size = 0; }; } \ No newline at end of file From 9c25722d8f40cd20f85f5a2942c2059fd2b3a507 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Fri, 26 Dec 2025 10:53:30 +0100 Subject: [PATCH 3/4] [fnc] now thread safe --- src/core/functions/codac2_ExprBase.cpp | 4 ++-- src/core/functions/codac2_ExprBase.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/core/functions/codac2_ExprBase.cpp b/src/core/functions/codac2_ExprBase.cpp index a4ecbbb6f..40b97c2e5 100644 --- a/src/core/functions/codac2_ExprBase.cpp +++ b/src/core/functions/codac2_ExprBase.cpp @@ -12,10 +12,10 @@ using namespace std; using namespace codac2; -Index ExprID::_id_counter = 0; +std::atomic ExprID::_id_counter{0}; ExprID::ExprID() - : _id(ExprID::_id_counter) + : _id(ExprID::_id_counter.fetch_add(1, std::memory_order_relaxed)) { ExprID::_id_counter ++; } diff --git a/src/core/functions/codac2_ExprBase.h b/src/core/functions/codac2_ExprBase.h index 6722aff1e..eb3931929 100644 --- a/src/core/functions/codac2_ExprBase.h +++ b/src/core/functions/codac2_ExprBase.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "codac2_Domain.h" #include "codac2_Index.h" @@ -70,7 +71,7 @@ namespace codac2 protected: const Index _id; //!< unique identifier, cannot be modified after initialization - static Index _id_counter; //!< static counter used to generate unique IDs for each ``ExprID`` object + static std::atomic _id_counter; //!< thread-safe counter used to generate unique IDs }; /** From 8f5c2dca1478e56a02c2d8485f6a820ab0d30606 Mon Sep 17 00:00:00 2001 From: Simon Rohou Date: Fri, 26 Dec 2025 10:53:56 +0100 Subject: [PATCH 4/4] [fnc] minor improvements --- .../functions/analytic/codac2_AnalyticExpr.h | 22 ++++++++++++++----- src/core/functions/set/codac2_SetExpr.h | 6 ++--- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/core/functions/analytic/codac2_AnalyticExpr.h b/src/core/functions/analytic/codac2_AnalyticExpr.h index 35f95507d..3f2aef202 100644 --- a/src/core/functions/analytic/codac2_AnalyticExpr.h +++ b/src/core/functions/analytic/codac2_AnalyticExpr.h @@ -35,17 +35,27 @@ namespace codac2 auto& p = v[unique_id()]; if(!p) + { p = std::make_shared(x); - else - *std::dynamic_pointer_cast(p) = x; + return *static_cast(p.get()); + } - return x; + else + { + auto pt = std::dynamic_pointer_cast(p); + assert(pt && "Type mismatch in ValuesMap for this ExprID"); + *pt = x; + return *pt; + } } T& value(ValuesMap& v) const { - assert(v.find(unique_id()) != v.end() && "argument cannot be found"); - return *std::dynamic_pointer_cast(v[unique_id()]); + auto it = v.find(unique_id()); + assert(it != v.end() && "argument cannot be found"); + auto p = std::dynamic_pointer_cast(it->second); + assert(p && "Type mismatch in ValuesMap for this ExprID"); + return *p; } virtual bool belongs_to_args_list(const FunctionArgsList& args) const = 0; @@ -132,7 +142,7 @@ namespace codac2 { bool b = true; - std::apply([&b,args](auto &&... x) + std::apply([&b,&args](auto &&... x) { ((b &= x->belongs_to_args_list(args)), ...); }, this->_x); diff --git a/src/core/functions/set/codac2_SetExpr.h b/src/core/functions/set/codac2_SetExpr.h index c2555cc7c..1de56481c 100644 --- a/src/core/functions/set/codac2_SetExpr.h +++ b/src/core/functions/set/codac2_SetExpr.h @@ -60,7 +60,7 @@ namespace codac2 { bool b = true; - std::apply([&b,args](auto &&... x) + std::apply([&b,&args](auto &&... x) { ((b &= x->belongs_to_args_list(args)), ...); }, this->_x); @@ -71,7 +71,7 @@ namespace codac2 std::shared_ptr> create_ctc(const FunctionArgsList& args, const std::vector>>& values) const { return std::apply( - [this,values,args](auto &&... x) + [this,&values,&args](auto &&... x) { return C::create_ctc(x->create_ctc(args,values)...); }, @@ -81,7 +81,7 @@ namespace codac2 std::shared_ptr create_sep(const FunctionArgsList& args, const std::vector>& values) const { return std::apply( - [this,values,args](auto &&... x) + [this,&values,&args](auto &&... x) { return C::create_sep(x->create_sep(args,values)...); },