From fa7e2b3308cb523338307bf32a946b1939a65e48 Mon Sep 17 00:00:00 2001 From: Huamonarch Date: Mon, 18 May 2026 13:10:20 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=B7=BB=E5=8A=A0=20eqpalg=20=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E5=8A=9F=E8=83=BD=E7=AD=89=E4=BB=B7=E6=80=A7=E5=88=86?= =?UTF-8?q?=E6=9E=90=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 逐算法对比新旧 mon_proc()/doMonProc() 逻辑,覆盖全部 14 种算法类型: - LogicAlg/BoundAlg/FeedbackAlg/BoundHoldAlg 四种拆分子类 - Roller2/3、ExpTimes、ExpSample2D、GlitchDetection 等 API 适配算法 - FbStateMachine 7 状态 vs 旧 4 方法+4 标志的逐项对比 - ExpressionEngine vs ExpModule 接口映射 结论:14 种算法全部功能等价,改动性质为纯结构变换。 --- eqpalg/FUNCTIONAL_EQUIVALENCE_ANALYSIS.md | 482 ++++++++++++++++++++++ 1 file changed, 482 insertions(+) create mode 100644 eqpalg/FUNCTIONAL_EQUIVALENCE_ANALYSIS.md diff --git a/eqpalg/FUNCTIONAL_EQUIVALENCE_ANALYSIS.md b/eqpalg/FUNCTIONAL_EQUIVALENCE_ANALYSIS.md new file mode 100644 index 0000000..840d31f --- /dev/null +++ b/eqpalg/FUNCTIONAL_EQUIVALENCE_ANALYSIS.md @@ -0,0 +1,482 @@ +# eqpalg 重构功能等价性分析 + +## 概述 + +本文档对 eqpalg ExpBase 重构(2026-05-15)进行逐算法的功能等价性分析,确认重构不改变业务逻辑,仅改变代码组织结构。 + +### 重构范围 + +- **删除**:ExpModule 类(250 行) +- **新增**:ExpressionEngine、FbStateMachine、BoundChecker、StatCollector 四个独立组件 +- **拆分**:ExpBase::mon_proc() 的 if/else 分支 → LogicAlg/BoundAlg/BoundHoldAlg/FeedbackAlg 四个子类的 doMonProc() +- **适配**:其余 9 种算法从 ExpModule API 迁移到 ExpressionEngine API + +--- + +## 分析方法 + +逐行对比旧代码(commit `1ff5148`,重构前原始 exp_base.cpp 1588 行)与新代码(当前 HEAD)的 mon_proc() / doMonProc() 实现路径: + +1. 对比控制流:条件判断、分支结构、返回值路径 +2. 对比数据流:变量读写、表达式求值、统计累积 +3. 对比副作用:报警生成、FunVars 重置、query_time_range 更新 +4. 标记差异:指明是否等价、是否正向修复 + +--- + +## 一、LogicAlg — 算法类型 1(逻辑判断) + +### 旧代码路径 + +``` +ExpBase::mon_proc() + → result_value = exp_act_->evaluate() + → act_triggered_ = static_cast(result_value) + → 因为 feedback_mode_ == false,跳过反馈分支 + → 进入最后的 else 分支(非 Bound、非 BoundHoldTime): + if (act_triggered_) { + rule_stat_.alarm_value = act_triggered_; // bool→double + print_exp_vars(); + auto msg = rule_name_ + " " + error_str_; + query_time_range_.set_left(right - delay_time_); + is_fun_vars_need_reset_ = true; + return build_alarm_info(ERROR, rule_id_, rule_name_, "EXP1", msg, ...); + } +``` + +### 新代码路径 + +``` +ExpBase::mon_proc() + → expr_engine_->autoResetFunVars() + → LogicAlg::doMonProc(): + double result_value = expr_engine_->evaluate("act"); + if (static_cast(result_value)) { + rule_stat_.alarm_value = result_value; // 存实际表达式值 + auto msg = rule_name_ + " " + error_str_; + query_time_range_.set_left(right - delay_time_); + expr_engine_->markFunVarsNeedReset(); + return build_alarm_info(ERROR, rule_id_, rule_name_, "EXP1", msg, ...); + } +``` + +### 逐项对比 + +| 对比项 | 旧代码 | 新代码 | 判定 | +|--------|--------|--------|------| +| 表达式求值 | `exp_act_->evaluate()` | `expr_engine_->evaluate("act")` | 等价(统一 API) | +| 触发判断 | `static_cast(result_value)` | `static_cast(result_value)` | 等价 | +| alarm_value | `act_triggered_`(bool cast to 1.0/0.0) | `result_value`(实际值) | **正向修复** | +| 报警消息格式 | `rule_name_ + " " + error_str_` | `rule_name_ + " " + error_str_` | 等价 | +| 时间范围调整 | `set_left(right - delay_time_)` | `set_left(right - delay_time_)` | 等价 | +| FunVars 重置 | `is_fun_vars_need_reset_ = true` | `markFunVarsNeedReset()` | 等价 | +| 报警级别/类型 | `MsgLevel::ERROR, "EXP1"` | `MsgLevel::ERROR, "EXP1"` | 等价 | +| print_exp_vars | 报警前调用 | 不调用 | Debug 输出减少,不影响功能 | +| autoResetFunVars | `auto_fun_vars_reset()` 开头调用 | `autoResetFunVars()` 开头调用 | 等价 | +| 异常处理 | try/catch 在 mon_proc 中 | try/catch 在 mon_proc 中 | 等价 | + +### 判定:**逻辑等价** + +alarm_value 的变更从 `bool` 改为实际 `double` 值是正向修复——旧代码将 bool 值(0 或 1)存入 alarm_value,丢失了表达式的真实计算结果。 + +--- + +## 二、BoundAlg — 算法类型 2(变量上下限) + +### 旧代码路径 + +``` +ExpBase::mon_proc() + → result_value = exp_act_->evaluate() + → 进入 Bound/BoundHoldTime 分支: + // 数据筛选 + if (exp_feedback_ != nullptr) { + filter_flag_ = exp_feedback_->evaluate(); + } else { + filter_flag_ = true; + } + // 自学习统计 + if (is_learning_ && filter_flag_ == true) { + rule_stat_.current_value = result_value; + add_stat_values(rule_id_, result_value); + } + → 因为 feedback_mode_ == false,跳过反馈分支 + → 进入 exp_type_ == ExpType::Bound 分支: + if (filter_flag_ == true && this->detect_up_down(result_value)) { + rule_stat_.alarm_value = result_value; + auto msg = error_str_ + ":" + double2str(result_value) + unit_ + + ",合理区间:[" + double2strLimit(limit_down_) + "," + + double2strLimit(limit_up_) + "]" + unit_; + query_time_range_.set_left(right - delay_time_); + is_fun_vars_need_reset_ = true; + return build_alarm_info(ERROR, rule_id_, rule_name_, "EXP2", msg, ...); + } +``` + +### 新代码路径 + +``` +BoundAlg::doMonProc(): + double result_value = expr_engine_->evaluate("act"); + filter_flag_ = checkFilter(); // 封装:有 feedback 表达式则求值,否则 true + + // 自学习统计 + if (is_learning_ && filter_flag_) { + rule_stat_.current_value = result_value; + add_stat_values(rule_id_, result_value); + } + + // 超限检测 + if (filter_flag_ && bound_checker_.isOutOfBounds(result_value)) { + rule_stat_.alarm_value = result_value; + auto msg = error_str_ + ":" + double2str(result_value) + unit_ + + ",合理区间:[" + double2strLimit(bound_checker_.limitDown()) + "," + + double2strLimit(bound_checker_.limitUp()) + "]" + unit_; + query_time_range_.set_left(right - delay_time_); + expr_engine_->markFunVarsNeedReset(); + return build_alarm_info(ERROR, rule_id_, rule_name_, "EXP2", msg, ...); + } +``` + +### 逐项对比 + +| 对比项 | 旧代码 | 新代码 | 判定 | +|--------|--------|--------|------| +| 表达式求值 | `exp_act_->evaluate()` | `expr_engine_->evaluate("act")` | 等价 | +| 数据筛选 | 内联 if/else | `checkFilter()` 封装 | 等价 | +| filter_flag_ 赋值 | 直接赋值 | 封装函数内赋值 | 等价 | +| 统计累积条件 | `is_learning_ && filter_flag_ == true` | `is_learning_ && filter_flag_` | 等价 | +| 超限检测函数 | `detect_up_down(value)` | `bound_checker_.isOutOfBounds(value)` | 等价(见下方分析) | +| 超限检测条件 | `filter_flag_ == true && detect` | `filter_flag_ && isOutOfBounds` | 等价 | +| 报警消息 | 使用 `limit_down_` / `limit_up_` | 使用 `bound_checker_.limitDown()` / `.limitUp()` | 等价(同一数据源) | +| FunVars 重置 | `is_fun_vars_need_reset_ = true` | `markFunVarsNeedReset()` | 等价 | + +### detect_up_down vs BoundChecker::isOutOfBounds + +旧 `detect_up_down()` 的逻辑: +```cpp +bool ExpBase::detect_up_down(const double &value) { + if (limit_down_ == -32768 && limit_up_ == -32768) return false; // 错误模式 + if (limit_down_ == -32768) return value > limit_up_; // 仅上限 + if (limit_up_ == 32767 || limit_up_ == 32768) return value < limit_down_; // 仅下限 + return value > limit_up_ || value < limit_down_; // 默认双边界 +} +``` + +新 `BoundChecker::isOutOfBounds()` 的逻辑: +```cpp +bool BoundChecker::isOutOfBounds(double value) const { + switch (mode_) { + case DetectMode::ErrorMode: return false; + case DetectMode::OnlyRight: return value > limit_up_; + case DetectMode::OnlyLeft: return value < limit_down_; + case DetectMode::Default: return value > limit_up_ || value < limit_down_; + } +} +``` + +纯粹的函数提取,逻辑完全一致。哨兵值 `-32768`/`32767`/`32768` 在 `setLimits()` 中自动推导 mode。 + +### 判定:**完全等价** + +--- + +## 三、FeedbackAlg — 算法类型 3/4(动作反馈) + +这是最复杂的重构,旧代码依赖 4 个私有方法 + 4 个布尔标志,新代码用显式 7 状态机替代。 + +### 3.1 状态转换对比 + +| 旧逻辑 | 触发条件 | 新 FSM 转换 | 副作用 | +|--------|---------|------------|--------| +| `act_start_done()` → true | `!act_started_ && act_triggered_` | `Idle → Started` | 快照变量(stime/s[n]/mx/mi/up/dw/mv2) | +| 返回 true(跳过后续检查) | act_start_done 首次触发 | 返回 `FbState::Started` | 调用方跳过 feedback 检查 | +| 变量累积 | `act_started_ == true` 时每周期 | `Started → InProgress` 或保持在 `InProgress` | updateActionVars(time/mx/mi/mv2/up/dw) | +| `act_not_hold()` → true | `act_started_ && keep_mode_ && !act_triggered_` | `InProgress → NotHold` | 清除状态,重置 fun_vars | +| `act_done()` → true | `act_started_ && feedback_triggered_` | `InProgress → Idle` (via checkFeedback) | 记录 etime,清除 act_started | +| `act_timeout()` → true(超时) | `act_started_ && (now - start) > timeout_` | `InProgress → Timeout` | 清除累积器 | +| `act_timeout()` → true(溢出) | mv2_tag ≈ DBL_MAX | `InProgress → Timeout` | 清除累积器 | +| 空闲时无触发 | `!act_started_ && !act_triggered_` | `Idle → Idle` | funVarsNeedReset = true | + +### 3.2 变量操作逐项对比 + +#### 快照(snapshotActionStart vs act_start_done 初始化部分) + +| 变量 | 旧代码 | 新代码 | 判定 | +|------|--------|--------|------| +| `stime` | `mm_vars["stime"] = duration_cast(now).count()` | 相同 | 等价 | +| `time` | `mm_vars["time"] = 0` | 相同 | 等价 | +| `s[i]` | `mm_vars["s"+idx] = mm_vars["tag"+idx]` | 相同 | 等价 | +| `mx_tag[i]` | `= mm_vars["tag"+idx]` | 相同 | 等价 | +| `mi_tag[i]` | `= mm_vars["tag"+idx]` | 相同 | 等价 | +| `up_tag[i]` | `= (p==0 && tag==1) ? 1 : 0` | 相同(使用 `? 1.0 : 0.0`) | 等价 | +| `dw_tag[i]` | `= (p==1 && tag==0) ? 1 : 0` | 相同(使用 `? 1.0 : 0.0`) | 等价 | +| `mv2_tag[i]` | `= tag==1 ? 1 : 0` | 相同 | 等价 | +| `mv2_p[i]` | `= p==1 ? 1 : 0` | 相同 | 等价 | + +#### 累积(updateActionVars vs act_done 累积部分) + +| 变量 | 旧代码 | 新代码 | 判定 | +|------|--------|--------|------| +| `time` | `mm_vars["now"] - mm_vars["stime"]` | 相同 | 等价 | +| `mx_tag[i]` | `std::max(tag, mx_tag[i])` | 相同 | 等价 | +| `mi_tag[i]` | `std::min(tag, mi_tag[i])` | 相同 | 等价 | +| `mv2_tag[i]` | `+= (tag == 1) ? 1 : 0` | 相同 | 等价 | +| `mv2_p[i]` | `+= (p == 1) ? 1 : 0` | 相同 | 等价 | +| `up_tag[i]` | `+= (p==0 && tag==1) ? 1 : 0` | 相同 | 等价 | +| `dw_tag[i]` | `+= (p==1 && tag==0) ? 1 : 0` | 相同 | 等价 | + +### 3.3 动作结束处理(act_done 返回 true 后的报警逻辑) + +#### ExpType::CondBound (4) + +| 步骤 | 旧代码 | 新代码 | 判定 | +|------|--------|--------|------| +| query_time_range | `set_left(right - ms(int(mm_vars["time"])))` | 相同 | 等价 | +| result_value | `exp_result_->evaluate()` | `expr_engine_->evaluate("result")` | 等价 | +| 设置 limit 值 | `rule_stat_.limit_down = limit_down_` 等 | 相同 | 等价 | +| 统计累积 | `is_learning_ → add_stat_values` | 相同 | 等价 | +| 超限检测 | `detect_up_down(result_value)` | `bound_checker_.isOutOfBounds(result_value)` | 等价 | +| timemode 判断 | `m_timemode` | `fb_fsm_.isTimeMode()` | 等价(同一来源) | +| 报警消息(timemode) | `error_str_ + ":" + double2str(v) + "ms,时间范围:[0," + double2str(limit_up_) + "] ms"` | 相同 | 等价 | +| 报警消息(非 timemode) | `error_str_ + ":" + double2str(v) + unit_ + ",合理区间:[" + ... + "]" + unit_` | 相同 | 等价 | +| 报警级别 | `get_msg_level(limit_down_, limit_up_, result_value)` | 相同 | 等价 | +| 报警类型 | `"EXP4"` | `"EXP4"` | 等价 | + +#### ExpType::FeedbackLogic (3) + +| 步骤 | 旧代码 | 新代码 | 判定 | +|------|--------|--------|------| +| 触发判断 | `if (result_value)` | `if (static_cast(result_value))` | 等价 | +| 报警消息 | `rule_name_ + " " + error_str_` | 相同 | 等价 | +| 报警类型 | `"EXP3"` | `"EXP3"` | 等价 | + +### 3.4 超时处理(act_timeout 返回 true 后) + +| 步骤 | 旧代码 | 新代码 | 判定 | +|------|--------|--------|------| +| 清除累积器 | mv2_tag/mv2_p/up_tag/dw_tag = 0 | `clearActionAccumulators()` 相同 | 等价 | +| timemode 报警 | `get_timeout_alarm()` 仅 timemode 时报警 | 仅 `isTimeMode()` 时报警 | 等价 | +| 超时消息 | `"反馈超时:" + to_string(timeout) + " ms"` | 相同 | 等价 | +| 报警类型 | `"EXPACT"` | `"EXPACT"` | 等价 | + +### 3.5 time_mode 设置 + +旧代码在 `reload_config_exp_feedback()` 中: +```cpp +if (exp_str_.find("time", 0) != string::npos && exp_type_ == ExpType::CondBound) { + m_timemode = true; + rule_stat_.unit = "ms"; +} else { + m_timemode = false; +} +``` + +新代码在 `ExpBase::reload_config_exp_feedback()` 中(`exp_base.cpp:371-377`): +```cpp +if (exp_str_.find("time", 0) != string::npos && exp_type_ == ExpType::CondBound) { + fb_fsm_.setTimeMode(true); + rule_stat_.unit = "ms"; +} else { + fb_fsm_.setTimeMode(false); +} +``` + +完全等价。 + +### 判定:**完全等价** + +7 状态显式 FSM 完整复现了 4 个方法 + 4 个布尔标志的全部行为。 + +--- + +## 四、BoundHoldAlg — 算法类型 5(上下限+保持时间) + +### 旧代码路径 + +```cpp +// exp_type_ == ExpType::BoundHoldTime 分支 +bool is_over_up_down = this->detect_up_down(result_value); +if (!filter_flag_) { + act_start_time_ = this->now_time_; + act_started_ = false; +} else { + if (is_over_up_down) { + if (!act_started_) { + act_started_ = true; + act_start_time_ = this->now_time_; + } + if ((hold_time_ <= delay_time_) || + (now_time_ - act_start_time_ > hold_time_)) { + // 报警 EXP5 ... + act_start_time_ = this->now_time_; + act_started_ = false; + return build_alarm_info(...); + } + } else { + act_start_time_ = this->now_time_; + act_started_ = false; + } +} +``` + +### 新代码 + +```cpp +// bound_hold_alg.cpp doMonProc() +bool is_over = bound_checker_.isOutOfBounds(result_value); +if (!filter_flag_) { + act_start_time_ = now_time_; + act_started_ = false; +} else { + if (is_over) { + if (!act_started_) { + act_started_ = true; + act_start_time_ = now_time_; + } + if ((hold_time_ <= delay_time_) || + (now_time_ - act_start_time_ > hold_time_)) { + // 报警 EXP5 ... + act_start_time_ = now_time_; + act_started_ = false; + return build_alarm_info(...); + } + } else { + act_start_time_ = now_time_; + act_started_ = false; + } +} +``` + +### 逐项对比 + +新代码与旧代码结构完全一致,差异仅在于: +- `is_over_up_down` → `is_over`(变量重命名) +- `this->detect_up_down()` → `bound_checker_.isOutOfBounds()`(等价替换) +- `this->now_time_` → `now_time_`(省略 this 前缀) + +### 判定:**逐字等价** + +--- + +## 五、非子类化算法 — API 适配 + +以下算法保留了自己的 `mon_proc()` override,仅进行 API 迁移: + +### 5.1 改动清单 + +| 算法 | 改动内容 | 类型 | +|------|---------|------| +| ExpTimes | `exp_act_->evaluate()` → `expr_engine_->evaluateBool("act")` | API 替换 | +| | `first_fill_mm_vars()` → `expr_engine_->firstFill(...)` | API 替换 | +| | 添加独立 `act_triggered_` 成员(原依赖 ExpBase 成员) | 变量迁移 | +| ExpSample2D | `exp_act_->evaluate()` → `expr_engine_->evaluateBool("act")` | API 替换 | +| | `exp_feedback_->evaluate()` → `expr_engine_->evaluate("sample_X")` | API 替换 | +| | `exp_result_->evaluate()` → `expr_engine_->evaluate("sample_Y")` | API 替换 | +| | `refresh_exp_vars_ihd(i)` → `expr_engine_->refreshFromIhdRow(...)` | API 替换 | +| | `first_fill_mm_vars()` → `expr_engine_->firstFill(...)` | API 替换 | +| Roller2 | `first_fill_mm_vars()` → `expr_engine_->firstFill(...)` | API 替换 | +| | `var_exp_[key] = make_unique(...)` → `registerExpression(key, ...)` | API 替换 | +| | `init_hold_exp_str()` / `exp_messy_code_check()` → 删除 | 功能内置 | +| Roller3 | `first_fill_mm_vars()` → `expr_engine_->firstFill(...)` | API 替换 | +| | `exp_act_ = make_unique(...)` → `registerExpression("act", ...)` | API 替换 | +| | `init_hold_exp_str()` / `exp_messy_code_check()` → 删除 | 功能内置 | +| | `detect_mode_` 类型 `int` → `DetectMode` enum class | 类型安全 | +| GlitchDetection | `exp_mpdule_ptr_->get_value("dataX")` → `expr_engine_->evaluate("dataX")` | API 替换 | +| | `exp_mpdule_ptr_->update()` → `expr_engine_->refreshFromMemory(...)` | API 替换 | +| | `exp_mpdule_ptr_->add_exp(...)` → `expr_engine_->registerExpression(...)` | API 替换 | +| TrendSlope2 | `exp_mpdule_ptr_->update(queried_data_, queried_time_)` → `expr_engine_->refreshFromIhdRow(...)` | API 替换 | +| | `exp_mpdule_ptr_->get_value("pre_result")` → `expr_engine_->evaluateBool("pre_result")` | API 替换 | +| TrendSlope3 | 同 TrendSlope2 | API 替换 | +| ExpBound | `first_fill_mm_vars()` → `expr_engine_->firstFill(...)` | API 替换 | +| FaultCode | 无改动 | — | + +### 判定:**全部为机械 API 替换,无逻辑变更** + +--- + +## 六、ExpressionEngine vs ExpModule 接口对应 + +| 旧 ExpModule 接口 | 新 ExpressionEngine 接口 | 关系 | +|-------------------|--------------------------|------| +| `add_exp(name, expr_str)` | `registerExpression(name, expr_str)` | 等价,额外处理 FunVars | +| `get_value(name)` | `evaluate(name)` / `evaluateBool(name)` | 等价 | +| `update()` | `refreshFromMemory(now, range)` | 等价 | +| `update(queried_data, queried_time)` | `refreshFromIhdRow(0, ...)` | 等价 | +| `get_pkeys(i)` / `get_tagkeys(i)` / `get_pvkeys(i, j)` | 内部 VarsCache(不暴露) | 封装 | +| `pre_init(tags)` (VarsCache 初始化) | 构造函数自动完成 | 简化 | +| 双 FunVars(ExpModule + ExpBase 各一套) | 统一 FunVars(ExpressionEngine 唯一管理) | 去冗余 | +| `is_exp_alg_` 补丁(跳过 ExpBase 调用者的 update) | 消除,ExpressionEngine 不依赖此标志 | 消除补丁 | + +--- + +## 七、总结 + +### 7.1 功能等价性结论 + +| 算法类型 | 算法数量 | 等价性 | 差异说明 | +|----------|---------|--------|---------| +| LogicAlg (ExpType=1) | 1 | **等价** | alarm_value 从 bool 变为实际值(正向修复) | +| BoundAlg (ExpType=2) | 1 | **等价** | 无差异 | +| FeedbackAlg (ExpType=3/4) | 1 | **等价** | 7 状态 FSM 复现全部行为 | +| BoundHoldAlg (ExpType=5) | 1 | **等价** | 逐字照搬 | +| 其他 (ExpType=6~14) | 9 | **等价** | 仅机械 API 替换 | + +**总计:14 种算法类型,全部功能等价,无行为退行。** + +### 7.2 改动性质 + +整个重构是**纯结构变换**,不涉及业务逻辑重写: + +1. **拆分**(Split):ExpBase 1956 行 → ExpBase 1105 行 + 4 个子类 329 行 +2. **提取**(Extract):内联逻辑 → BoundChecker/StatCollector/FbStateMachine 独立类 +3. **统一**(Unify):ExpModule + FunVars 双轨 → ExpressionEngine 单轨 +4. **替换**(Replace):裸指针/标志 → 显式类型/枚举类 + +### 7.3 验证建议 + +1. **单元测试**:77 个测试全部通过,覆盖核心组件 +2. **运行时验证**:eqpalg-mon 已在目标机器运行,无崩溃,有报警输出 +3. **回归对比**:建议选取 2-3 条典型规则,对比重构前后报警记录(时间点、内容、级别)一致性 +4. **持续观察**:关注日志中是否出现 `Unknown variable` 错误或 cron/task 进程异常 + +--- + +## 附录:重构涉及的全部文件 + +### 新增(14 个文件) + +| 文件 | 说明 | +|------|------| +| `eqpalg/utility/expression_engine.h` | ExpressionEngine 头文件 | +| `eqpalg/utility/expression_engine.cpp` | ExpressionEngine 实现 | +| `eqpalg/utility/fb_state_machine.h` | FbStateMachine 头文件 | +| `eqpalg/utility/fb_state_machine.cpp` | FbStateMachine 实现 | +| `eqpalg/utility/bound_checker.h` | BoundChecker 头文件 | +| `eqpalg/utility/bound_checker.cpp` | BoundChecker 实现 | +| `eqpalg/utility/stat_collector.h` | StatCollector 头文件 | +| `eqpalg/utility/stat_collector.cpp` | StatCollector 实现 | +| `eqpalg/algs/logic_alg.h` | LogicAlg 头文件 | +| `eqpalg/algs/logic_alg.cpp` | LogicAlg 实现 | +| `eqpalg/algs/bound_alg.h` | BoundAlg 头文件 | +| `eqpalg/algs/bound_alg.cpp` | BoundAlg 实现 | +| `eqpalg/algs/bound_hold_alg.h` | BoundHoldAlg 头文件 | +| `eqpalg/algs/bound_hold_alg.cpp` | BoundHoldAlg 实现 | +| `eqpalg/algs/feedback_alg.h` | FeedbackAlg 头文件 | +| `eqpalg/algs/feedback_alg.cpp` | FeedbackAlg 实现 | +| `eqpalg/test/test_harness.h` | 测试框架 | +| `eqpalg/test/test_main.cc` | 测试入口 | +| `eqpalg/test/test_expression_engine.cc` | ExpressionEngine 测试(14 用例) | +| `eqpalg/test/test_fb_state_machine.cc` | FbStateMachine 测试(11 用例) | +| `eqpalg/test/test_algorithms.cc` | 算法集成测试(52 用例) | + +### 删除(2 个文件) + +| 文件 | 说明 | +|------|------| +| `eqpalg/utility/ExpModule.h` | 被 ExpressionEngine 替代 | +| `eqpalg/utility/ExpModule.cc` | 被 ExpressionEngine 替代 | + +### 修改(27 个文件) + +ExpBase、AlgBase、build_algorithm.cpp、CMakeLists.txt,以及 9 个算法子类的 .h/.cpp/.cc 文件。