eis/eqpalg/utility/StatExp.hpp

369 lines
9.2 KiB
C++
Raw Permalink Normal View History

#pragma once
#include <boost/regex.hpp>
#include <chrono>
#include <functional>
#include <limits>
#include <map>
#include <memory>
#include <mix_cc/json.h>
#include <mix_cc/matheval/matheval.hpp>
#include <string>
#include <vector>
namespace StatExp {
using std::string;
using std::vector;
using namespace std::chrono;
/**
* @brief 仿
*
* 1. keep_time ms
* 2. t1
*/
struct KeepT {
/**
* @brief KeepT(lt,rt)
* @param lt double
* @param rt double
* @return int lt==rt的时间 (ms)
*/
inline int64_t operator()(double lt, double rt) {
if (fabs(lt - rt) > std::numeric_limits<double>::epsilon()) {
t1 = std::chrono::system_clock::now();
keep_time = 0;
return 0;
} else {
keep_time =
duration_cast<milliseconds>(std::chrono::system_clock::now() - t1)
.count();
}
return keep_time;
}
private:
int64_t keep_time = 0;
std::chrono::system_clock::time_point t1 =
std::chrono::system_clock::now();
};
/**
* @brief KeepC 仿
*
* keep_times
*/
struct KeepC {
/**
* @brief KeepC(lt,rt)
* @param lt double
* @param rt double
* @return int lt==rt的次数
*/
inline int operator()(double lt, double rt) {
if (fabs(lt - rt) > std::numeric_limits<double>::epsilon()) {
keep_times = 0;
return 0;
} else {
keep_times += 1;
}
return keep_times;
}
private:
int keep_times = 0;
};
/**
* @brief 沿
*/
struct RiseEdge {
/**
* @brief RiseEdge 沿仿
* @param data
* @param is_reset
* @return int
*/
inline int operator()(double data, double is_reset) {
last_data = now_data;
now_data = (bool)data;
if (keep_times == -1) {
return ++keep_times;
}
keep_times += int(!last_data && now_data);
if (is_reset) {
keep_times = -1;
return 0;
}
return keep_times;
}
private:
bool last_data = false;
bool now_data = false;
int keep_times = -1;
};
/**
* @brief
*
*/
struct Detect {
/**
* @brief Detect 仿
* @param data
* @param is_reset
* @return int
*/
inline int operator()(double data, double is_reset) {
if (is_reset) {
keep_times = 0;
return 0;
}
if (data) {
return ++keep_times;
}
return keep_times;
}
private:
int keep_times = 0;
};
/**
* @brief
*/
struct DelayT {
using Clock = std::chrono::steady_clock;
using Milliseconds = std::chrono::milliseconds;
int operator()(bool data, bool is_reset) {
if (is_reset) {
accumulated_time = 0;
last_data = false;
counting = false;
return 0;
}
if (!last_data && data) {
start_time = Clock::now();
counting = true;
} else if (last_data && !data) {
if (counting) {
auto current_time = Clock::now();
accumulated_time +=
std::chrono::duration_cast<Milliseconds>(current_time - start_time)
.count();
counting = false;
}
}
last_data = data;
if (counting) {
auto current_time = Clock::now();
int current_duration =
std::chrono::duration_cast<Milliseconds>(current_time - start_time)
.count();
return accumulated_time + current_duration;
} else {
return accumulated_time;
}
}
private:
int accumulated_time = 0;
bool last_data = false;
bool counting = false;
Clock::time_point start_time{};
};
using FIDD = std::function<int(double, double)>;
enum class FiddType {
KeepT = 0,
KeepC,
RiseEdge,
Detect
};
const std::map<std::string, FiddType> Fidd2M = {
{"KeepT", FiddType::KeepT},
{"KeepC", FiddType::KeepC},
{"RiseEdge", FiddType::RiseEdge},
{"Detect", FiddType::Detect}};
const std::map<FiddType, std::string> FType2Regex = {
{FiddType::KeepT, "KeepT\\((\\S+?),(\\S+?)\\)"},
{FiddType::KeepC, "KeepC\\((\\S+?),(\\S+?)\\)"},
{FiddType::RiseEdge, "RiseEdge\\((\\S+?),(\\S+?)\\)"},
{FiddType::Detect, "Detect\\((\\S+?),(\\S+?)\\)"}};
const std::map<FiddType, std::string> FType2RegexAll = {
{FiddType::KeepT, "(KeepT\\(\\S+?,\\S+?\\))"},
{FiddType::KeepC, "(KeepC\\(\\S+?,\\S+?\\))"},
{FiddType::RiseEdge, "(RiseEdge\\(\\S+?,\\S+?\\))"},
{FiddType::Detect, "(Detect\\(\\S+?,\\S+?\\))"}};
inline FIDD CreateFIDD(FiddType type) {
switch (type) {
case FiddType::KeepC:
return KeepC{};
break;
case FiddType::KeepT:
return KeepT{};
break;
case FiddType::RiseEdge:
return RiseEdge{};
break;
case FiddType::Detect:
return Detect{};
break;
default:
return KeepT{};
break;
}
}
inline mix_cc::json search_regs(const string &str, const string &reg_str) {
mix_cc::json res;
boost::regex reg(reg_str.c_str());
string::const_iterator start(str.begin()), end(str.end());
boost::match_results<string::const_iterator> what;
int i = 0;
res[i] = reg_str;
while (regex_search(start, end, what, reg, boost::match_default)) {
vector<string> v1;
for (int j = 1; j < what.size(); j++) {
v1.push_back(what[j]);
}
res[i + 1] = v1;
i++;
start = what[0].second;
}
return res;
}
inline std::string regex_str(const string &reg_str, const string &reg_t) {
boost::regex base_regex(("(\\" + reg_t + ")").c_str());
std::string plv;
std::stringstream ss;
ss << R"(\\$1)";
plv = ss.str();
auto ret = boost::regex_replace(reg_str, base_regex, plv);
return ret;
}
inline std::string regex_str(const string &reg_str) {
std::string str2 = reg_str;
std::vector<std::string> rex = {"+", "*", "(", ")", ".", "^", "|"};
for (auto item : rex) {
str2 = StatExp::regex_str(str2, item);
}
return str2;
}
struct BinaryF {
BinaryF() {}
BinaryF(const string &exp_str, std::map<std::string, double> *const mm_vars,
FiddType type) {
ftype = type;
try {
auto res = search_regs(exp_str, FType2Regex.at(type));
var1 = std::make_unique<mix_cc::matheval::Expression>(
res[1][0].get<string>(), mm_vars);
var2 = std::make_unique<mix_cc::matheval::Expression>(
res[1][1].get<string>(), mm_vars);
Fun = CreateFIDD(type);
} catch (const std::exception &e) {
}
}
FIDD Fun;
FiddType ftype;
std::unique_ptr<mix_cc::matheval::Expression> var1;
std::unique_ptr<mix_cc::matheval::Expression> var2;
inline double operator()() {
if (var1 != nullptr && var2 != nullptr) {
switch (ftype) {
case FiddType::RiseEdge:
case FiddType::Detect:
return (double)Fun(
var2->evaluate() ? var1->evaluate() : !var1->evaluate(), 0);
break;
default:
return (double)Fun(var1->evaluate(), var2->evaluate());
break;
}
} else {
return 0;
}
}
};
class FunVars {
public:
FunVars() {}
~FunVars() {}
inline std::pair<bool, std::string>
add_exp_str(const std::string &exp_str,
std::map<std::string, double> *const mm_vars) {
std::string out_str = exp_str;
try {
for (auto item : FType2RegexAll) {
auto res = search_regs(exp_str, item.second);
if (res.size() > 1) {
for (int i = 1; i < res.size(); i++) {
std::string expi = res[i][0].get<string>();
if (exp2fvar.find(expi) == exp2fvar.end()) {
exp2binayF[expi] = BinaryF(expi, mm_vars, item.first);
std::string f_var = pre_var + std::to_string(index++);
exp2fvar[expi] = f_var;
exp2ftype[expi] = item.first;
mm_vars->operator[](f_var) = 0;
out_str = boost::regex_replace(
out_str, boost::regex(regex_str(expi).c_str()),
f_var.c_str());
} else {
std::string f_var = exp2fvar[expi];
out_str = boost::regex_replace(
out_str, boost::regex(regex_str(expi).c_str()),
f_var.c_str());
}
}
}
}
return std::make_pair(true, out_str);
} catch (const std::exception &e) {
return std::make_pair(false, e.what());
}
}
/**
* @brief fun[index]
* @param is_reset bool
* @param mm_vars std::map<std::string, double>* const
* @return true
* @return false
*/
inline bool refresh_fun_vars(bool is_reset,
std::map<std::string, double> *const mm_vars) {
try {
for (auto fi : exp2fvar) {
if (is_reset) {
mm_vars->operator[](fi.second) =
(double)exp2binayF[fi.first].Fun(0.0, 1.0);
} else {
mm_vars->operator[](fi.second) = exp2binayF[fi.first]();
}
}
return true;
} catch (const std::exception &e) {
return false;
}
}
inline bool empty() { return exp2fvar.empty(); }
private:
const std::string pre_var = "fun";
int index = 0;
std::map<std::string, BinaryF> exp2binayF;
std::map<std::string, std::string> exp2fvar;
std::map<std::string, FiddType> exp2ftype;
};
}