// license:BSD-3-Clause // copyright-holders:Couriersud #ifndef PFUNCTION_H_ #define PFUNCTION_H_ /// /// \file pfunction.h /// #include "pmath.h" #include "pstring.h" #include namespace plib { //============================================================ // function evaluation //============================================================ enum rpn_cmd { ADD, MULT, SUB, DIV, EQ, NE, LT, GT, LE, GE, IF, NEG, // unary minus POW, LOG, SIN, COS, MIN, MAX, RAND, /// random number between 0 and 1 TRUNC, PUSH_CONST, PUSH_INPUT, LP, // Left parenthesis - for infix parsing RP // right parenthesis - for infix parsing }; /// \brief Class providing support for evaluating expressions /// /// \tparam NT Number type, should be float or double /// template class pfunction { struct rpn_inst { constexpr rpn_inst() : m_cmd(ADD) { m_param.val = plib::constants::zero(); } constexpr rpn_inst(rpn_cmd cmd, std::size_t index = 0) : m_cmd(cmd) { m_param.index = index; } constexpr rpn_inst(NT v) : m_cmd(PUSH_CONST) { m_param.val = v; } constexpr const rpn_cmd &cmd() const noexcept { return m_cmd; } constexpr const NT &value() const noexcept { return m_param.val; // NOLINT } constexpr const std::size_t &index() const noexcept { return m_param.index; // NOLINT } private: rpn_cmd m_cmd; union { NT val; std::size_t index; } m_param; }; public: using value_type = NT; using inputs_container = std::vector; using values_container = std::vector; /// \brief Constructor /// pfunction() : m_lfsr(0xace1U) // NOLINT { } /// \brief Constructor with compile /// pfunction(const pstring &expr, const inputs_container &inputs = inputs_container()) : m_lfsr(0xace1U) // NOLINT { compile(expr, inputs); } /// \brief Evaluate the expression /// /// \param values for input variables, e.g. {1.1, 2.2} /// \return value of expression /// value_type operator()(const values_container &values = values_container()) noexcept { return evaluate(values); } /// \brief Compile an expression /// /// \param expr infix or postfix expression. default is infix, postrix /// to be prefixed with rpn, e.g. "rpn:A B + 1.3 /" /// \param inputs Vector of input variables, e.g. {"A","B"} /// void compile(const pstring &expr, const inputs_container &inputs = inputs_container()) noexcept(false); /// \brief Compile a rpn expression /// /// \param expr Reverse polish notation expression, e.g. "A B + 1.3 /" /// \param inputs Vector of input variables, e.g. {"A","B"} /// void compile_postfix(const pstring &expr, const inputs_container &inputs = inputs_container()) noexcept(false); /// \brief Compile an infix expression /// /// \param expr Infix expression, e.g. "(A+B)/1.3" /// \param inputs Vector of input variables, e.g. {"A","B"} /// void compile_infix(const pstring &expr, const inputs_container &inputs = inputs_container()) noexcept(false); /// \brief Evaluate the expression /// /// \param values for input variables, e.g. {1.1, 2.2} /// \return value of expression /// value_type evaluate(const values_container &values = values_container()) noexcept; template void save_state(ST &st) { st.save_item(m_lfsr, "m_lfsr"); } private: void compress(); void compile_postfix(const inputs_container &inputs, const std::vector &cmds, const pstring &expr); std::vector m_precompiled; //!< precompiled expression std::uint16_t m_lfsr; //!< lfsr used for generating random numbers }; extern template class pfunction; extern template class pfunction; extern template class pfunction; #if (PUSE_FLOAT128) extern template class pfunction; #endif } // namespace plib #endif // PEXCEPTION_H_