一种快速的复杂逻辑表达式求取方法

简介: 背景最简单的逻辑表达式求取方法是求取所有每个子表达式的值,然后再带入复杂逻辑表达式依次计算得到最终结果,时间复杂度较高。简单的“或运算”和“与运算”,以短路方式实现,不需要计算所有的子表达式的值,计算效率较高。但是,以“或运算”、“与运算”、“否运算”和“嵌套运算”等子表达式组成的复杂逻辑表达式,不能简单的套用短路运算。本专利,通过“构建逻辑表达式树”及“逐级向上触发树节点”的方式,实现了一种快速

背景

最简单的逻辑表达式求取方法是求取所有每个子表达式的值,然后再带入复杂逻辑表达式依次计算得到最终结果,时间复杂度较高。简单的“或运算”和“与运算”,以短路方式实现,不需要计算所有的子表达式的值,计算效率较高。但是,以“或运算”、“与运算”、“否运算”和“嵌套运算”等子表达式组成的复杂逻辑表达式,不能简单的套用短路运算。

本专利,通过“构建逻辑表达式树”及“逐级向上触发树节点”的方式,实现了一种快速的复杂逻辑表达式求取方法。

怎么实现的?

本文提出一种快速的复杂逻辑表达式求取方法,采用“构建逻辑表达式树”及“逐级向上触发树节点”的方式,在保证计算结果正确性的前提下,避免了不必要的子表达式计算,执行时间较短,求值性能较高。系统模块设计分为三部分:解析复杂逻辑表达式、构建逻辑表达式树、逐级向上触发树节点。

   A)解析复杂逻辑表达式,用于解析“复杂逻辑表达式字符串”为“抽象语法树”。

编写词法语法解析工具Antlr4配套的语法文件,此语法文件支持“或运算”、“与运算”、“否运算”和“嵌套运算”四种基本逻辑运算单元。其中,“或运算”表示为“||”或“or”,“与运算”表示为“&&”或“and”,“否运算”表示为“!”或“not”。通过Antlr4处理复杂逻辑字符串可以解析得到相应的抽象语法树。例如:复杂逻辑表达式字符串“a && b and c or d or !e”会被解析为((a) && (b) and (c)) or (d) or (!(e))。

   B)构建逻辑表达式树,利用已解析得到的“抽象语法树”构建逻辑表达式树。

根据抽象语法树的层级嵌套关系构造“逻辑表达式树”。“基础运算单元”转换为PatternElement,“或运算”转换为LogicOrExpression,“与运算”转换为LogicOrExpression,“否运算”转换为LogicOrExpression,“嵌套运算”采用“逻辑表达式树LogicExpresssionTree”的层级关系表示。

 

   C)逐级向上触发树节点。计算“基础运算单元”,并逐级向上触发父节点,直到确定“逻辑表达式树”根节点结果。

将“基础运算单元”的结果带入“逻辑表达树”,并根据触发条件确定是否需要继续触发父节点,执行过程中尽可能的实现逻辑短路,最后求取的确定根节点值,即为“复杂逻辑表达式”的值。

(1)如果得到某个“基础运算单元”的计算结果,则判断此基础运算单元的“计算版本computeVersion”是否最新。

如果不是最新,则更新“计算版本computeVersion”,设置“计算结果hitResult”,如果“父节点parentComputableUnit”存在,则向上触发父节点。

如果最新,则直接返回,无需重复触发。

(2)如果“或运算”被触发,则判断此或运算的“计算版本computeVersion”是否最新。

如果不是最新,则更新“计算版本computeVersion”,设置“是否已触发triggered”为false,重置“已触发的孩子计算单元数量triggeredChildComputalbeUnitCount”为0,重置 “孩子计算单元是否已触发数组childComputalbeUnitTriggeredArray”的元素全部为false。

如果“是否已触发triggered”为true,则直接返回,无需重复触发。

如果“此次触发的子表达式的计算结果hitResult”为true,则设置此或运算的“计算结果hitResult”为true,设置“是否已触发triggered”为true,如果“父节点parentComputableUnit”存在,则向上触发父节点。

如果“此次触发的子表达式的计算结果hitResult”为false,且“此次触发的子表达式”在或运算中的索引位置没有触发,则“已触发的孩子计算单元数量triggeredChildComputalbeUnitCount”加1。

此时,如果或运算的所有子表达式均已全部触发,则设置此或运算的“计算结果hitResult”为false,设置“是否已触发triggered”为true,如果“父节点parentComputableUnit”存在,则向上触发父节点。此时,如果或运算的所有子表达式均没有全部触发,则设置此次触发的子表达式对应的“孩子计算单元是否已触发数组childComputalbeUnitTriggeredArray”的元素为true。

(3)如果“与运算”被触发,则判断此与运算的“计算版本computeVersion”是否最新。

如果不是最新,则更新“计算版本computeVersion”,设置“是否已触发triggered”为false,重置“已触发的孩子计算单元数量triggeredChildComputalbeUnitCount”为0,重置 “孩子计算单元是否已触发数组childComputalbeUnitTriggeredArray”的元素全部为false。

如果“是否已触发triggered”为true,则直接返回,无需重复触发。

如果“此次触发的子表达式的计算结果hitResult”为false,则设置此与运算的“计算结果hitResult”为false,设置“是否已触发triggered”为true,如果“父节点parentComputableUnit”存在,则向上触发父节点。

如果“此次触发的子表达式的计算结果hitResult”为true,且“此次触发的子表达式”在与运算中的索引位置没有触发,则“已触发的孩子计算单元数量triggeredChildComputalbeUnitCount”加1。

此时,如果与运算的所有子表达式均已全部触发,则设置此或运算的“计算结果hitResult”为true,设置“是否已触发triggered”为true,如果“父节点parentComputableUnit”存在,则向上触发父节点。此时,如果与运算的所有子表达式均没有全部触发,则设置此次触发的子表达式对应的“孩子计算单元是否已触发数组childComputalbeUnitTriggeredArray”的元素为true。

(4)如果“否运算”被触发,则判断此否运算的“计算版本computeVersion”是否最新。

如果不是最新,则更新“计算版本computeVersion”,设置“计算结果hitResult”为“此次触发的子表达式的计算结果hitResult”的非值,如果“父节点parentComputableUnit”存在,则向上触发父节点。

如果最新,则直接返回,无需重复触发。

(5)循环执行上述步骤,如果执行完毕时,逻辑表达式树的根节点的“是否已触发triggered”为true,则直接返回“计算结果hitResult”。

为了快速求取所有基础运算单元都没有匹配的情况,需计算复杂逻辑表达的默认值。如果没有匹配成功任何“基础运算单元”,则直接返回此默认值。

有哪些实际价值?

1)逻辑表达式复杂:树形层次结构可以表示与复杂逻辑表达式相同的语义。

2)执行时间快:采用“逐级向上触发树节点”的方式求取根节点的值,避免了不必要的子表达式计算,具有较好的执行性能。

相关文章
|
前端开发 测试技术 API
DDD领域驱动设计实战-分层架构及代码目录结构(上)
DDD领域驱动设计实战-分层架构及代码目录结构
1844 0
DDD领域驱动设计实战-分层架构及代码目录结构(上)
|
Java Spring
动态控制 Spring Boot 中的 @Scheduled 定时任务
Spring Boot 中的 @Scheduled 注解为定时任务提供了一种很简单的实现,只需要在注解中加上一些属性,例如 fixedRate、fixedDelay、cron(最常用)等等,并且在启动类上面加上 @EnableScheduling 注解,就可以启动一个定时任务了。 但是在某些情况下,并没有这么简单,例如项目部署上线之后,我们可能会修改定时任务的执行时间,并且停止、重启定时任务等,因为定时任务是直接写死在程序中的,修改起来不是非常的方便。所以,简单记录一下自己的一些解决方案,仅供参考。
2489 0
|
关系型数据库 MySQL Linux
centos7.0环境下安装MySql_8.0.12
centos7.0环境下安装MySql_8.0.12
|
Python
双端优先级队列(Double-Ended Priority Queue
双端优先级队列(Double-Ended Priority Queue)是一种支持在两端进行插入和删除操作的优先级队列。它可以在 O(log n) 的时间复杂度内完成插入、删除、查询操作。双端优先级队列可以使用二叉堆或线段树等数据结构实现。
608 6
|
传感器 人工智能 JSON
多图、视频首上端!面壁「小钢炮」 MiniCPM-V 2.6 模型重磅上新!魔搭推理、微调、部署实战教程来啦!
该模型基于 SigLip-400M 和 Qwen2-7B 构建,仅 8B 参数,取得 20B 以下单图、多图、视频理解 3 SOTA 成绩,一举将端侧AI多模态能力拉升至全面对标 GPT-4V 水平。
|
JavaScript 前端开发 安全
TypeScript【基础类型】超简洁教程!再也不用看臭又长的TypeScript文档了!
【10月更文挑战第9天】TypeScript【基础类型】超简洁教程!再也不用看臭又长的TypeScript文档了!
|
5G UED
5G NR中的寻呼过程
【8月更文挑战第31天】
431 1
|
前端开发 API Android开发
Android自定义View之Canvas一文搞定
这篇文章介绍了Android自定义View中如何使用Canvas和Paint来绘制图形。Canvas可理解为画布,用于绘制各种形状如文字、点、线、矩形、圆角矩形、圆和弧。常见API包括`drawText()`、`drawPoint()`、`drawLine()`、`drawRect()`等。文章还提到了Canvas的保存、恢复、平移和旋转方法,通过绘制钟表盘的例子展示了如何实际应用。总结关键点:Canvas与Paint结合用于图像绘制,掌握Canvas的基本绘图函数及坐标变换操作是自定义View的关键。
377 0
Android自定义View之Canvas一文搞定
|
数据采集 监控 搜索推荐
ERP系统中的财务指标与绩效评估解析
【7月更文挑战第25天】 ERP系统中的财务指标与绩效评估解析
608 0
|
消息中间件 Kafka 数据处理
了解Kafka位移自动提交的秘密:避免常见陷阱的方法
了解Kafka位移自动提交的秘密:避免常见陷阱的方法
905 1