• OO第三单元作业——魔教规格

    • JML的理论基础和相关工具


    •  

        JML(Java Modeling Language,Java建模语言),在Java代码种增加了一些符号,这些符号用来标志一个方法是干什么的,但是不关心它的具体实现。通过使用JML,在实现代码前,我们可以描述一个方法的预期功能,而尽可能地忽略实现,从而把过程性思考一直延迟到方法设计的层面。

        如果仅仅是描述方法的功能,那么自然语言一样可以做到,但是,使用JML语言的好处是,相比于容易产生歧义的自然语言,以前置条件、副作用、异常行为、作用域、后置条件等为标准规格的JML规格语言能减少歧义的产生。

      此外,只要有了一套规范的语言,就代表有可能实现形式化验证,也就是说,给定一组输入和输出,就一定可以判定这一组输入和输出是否符合规格要求。而这带来的好处就是,在智能的配套工具链下可能可以实现自动化测试。自动化测试是在由机器自动生成合理且覆盖性强的测试数据来判断是否符合规格要求,这样做可以进一步解放人的时间,还可以避免人思维的死角JML的核心是用表达式,对于方法规格,类型规格进行控制的一种语言。

      • 这里面就涉及到了三个要素,什么是JML表达式,什么是方法规格,什么是类型规格。

        • (1)表达式

          \result表示非void的返回值,

          \forall表示全称量词,给定范围,全部满足约束

          \exist表示存在量词,给定范围,存在一个满足约束

          \max表示给定范围最大值

          \min表示给定范围最小值

          \not_assigned(x,y,...)括号内没赋值就是true,反之false

          \nothing 表示空集

          \everything 表示全集

          (2)方法规格

          方法规格的核心就是,满足什么条件达成什么样的结果。特别强调的是,方法规格只规定了满足什么条件,和产生什么结果。不关心产生结果的过程。

          在这句核心的基础之上,生发出来各种各样的约束,

          前置条件(@require):调用者应当保证的前提

          后置条件(@ensure):实现者需要保证的结果

          副作用(@assignable):允许你的方法对什么进行成员修改,避免产生调用者不知道的其他影响

          异常(@exceptional_behavior,@signal:满足什么条件,需要你去抛出什么样的异常(使用signal 标注出异常类型)

          这样可以很好的实现权责分明,如果让实现者考虑所有可能的输入并且一一检查和判断的话将会产生巨大的工作量以及许多遗漏,而程序的输入往往是决定于调用者的,这样的分工使得工作量的分担更加均匀,也减少了无用功

          (3)类型规格

          类型规格的核心是变与不变,不变式(invariant)就是告诉你,在方法执行前,完成等可见状态下某种数据变量的要求。与之相对的约束就是状态变化约束(constraint),如果要变化,怎么变,描述变前变后的关系。

  • JML工具链
  • (1) openjml与solver
  • 部署好Solver和openjml包后将自己的Person类进行测试,发现除了一堆warning啥都没有,一开始我以为“没有错误就是正确”,这也是Windows等系统在设计命令行的时候所遵循的一个宗旨,但是当我故意把自己Person类改错了一些地方后发现还是只有一堆warning,于是我只能转向网上在线的OpenJML。

  • 同时,我在故意将getAge函数改错以后,发现网页果然报错了。
  • 这说明openJML是可以初步进行测试的,但是openJML也有缺陷,比如为了优化将数据结构变得较为复杂(如采用Hashmap、Hashset等)时便无法进行检查。
  • 不过这也难为机器了,毕竟它无法读懂注释,也没法真正理解代码的含义只能机械比对,被各种数据结构绕晕也可以原谅。

  • (2)JMLUNITNG

  • 在阅读完这个工具的简介以后我是如获至宝的,毕竟Junit单元测试只能自动搭建一个框架,具体的实现还需要你来写测试数据以及assert来完成正确性的判断,而这个工具可以实现全自动测试。部署好JMLUnitNG以后,在命令行输入test指令,果然生成了一堆测试文件:

  • 进行编译并导入jar包后也一切正常。

  • 然而最后的结果却让我哭笑不得:

  • 自动生成的所谓边界数据竟然就是一堆null,真让人大跌眼镜。无奈之下只好重新改动了MyGroup使得它符合测试的条件,并且成功测试了大部分方法。

  • 但是它只测试了边界的条件,有的边界数据不合法(age是负数或者一个很大的正数),有的输入依然是null,因此这个覆盖是不完备的,同时也是低效的。

  • 三次作业架构设计


     第一次作业

  • (1)架构设计

    (2)算法分析

    所有的数组都是采用ArrayList实现,每当寻找需要的数据便直接遍历寻找。对于isCircle方法我采用的是bfs,这样不像dfs让系统维护栈,运行效率高,同时便于寻找最短路径,具有一定的可扩展性。

    (3)复杂度分析


    • 第二次作业

    • (1)架构设计

      (2)算法分析

      本次作业在理解了各个变量的基础上,将ArrayList均变更为Hashmap,这样虽然在遍历的时候会慢一些但是所有查找的时间复杂度都降低至O(1)。此外,由于强测数据量较大,因此设置了缓存机制来防止少量加入、大量查询导致的超时。

      (3)复杂度分析

    • 第三次作业

    • (1)架构设计

      (2)算法分析

      本次作业保留了上一次作业的缓存思想,同时对于isCircle操作以及queryBlockSum操作,通过并查集的方式进行了优化,将查询的时间复杂度降低到了O(1);对于queryMinPath方法,由于我们的图在顶点数最多是800而边数最多的5000,因此采用堆优化后的dijkstra算法(时间复杂度是O(mlogm),其中m为边数)比使用dijkstra算法(时间复杂度是O(n2),n为顶点数)更加省时间;在queryStrongLink方法中,我采用的是删点法,即如果两个人不是直接连接,就采取每次删除一个人,遍历删除所有人的每一个,之后判断起点终点是否可达的方法。如果两个人因为删除一个人无法连通,就不是强连通。但是有一种特殊情况,当两个人直接link的时候,这种做法是无效的,此时只需要寻找到一条长度大于2的路径即可判定强连通为此需要有一个记录路径的bfs来缩小暴力删点范围,以及一个能够接受删点的bfs遍历,还有一个忽略起点终点直接相连路径的bfs,因此我专门建立了一个bfs类来管理不同的bfs。总体而言,我的时间复杂度控制的非常好,仅queryStrongLink方法时间复杂度达到了O(n2),其他方法均不超过线性的复杂度。

      (3)复杂度分析

    • bug分析


      第一次作业:在强测和互测中均未被发现BUG,也未在互测中发现他人的BUG。

       第二次作业:在强测和互测中均未被发现BUG,在互测中只要单一方法时间复杂度达到O(n2)即可构造数据来使得程序运行超时,比较典型的超时例如求方差的时候平均数没有提前求好而是每次都代入计算,没有缓存导致relationSum需要二重遍历,以及bfs使用数组而非链表导致每次删除数组第一位时时间复杂度都是O(n),这样总体的时间复杂度便上升为O(n2)

      第三次作业:在强测中由于int溢出问题WA了两个测试点,互测中未被发现BUG,在互测中利用对拍器发现他人一个缓存不当导致的WA,一个dijkstra写错导致的TLE和一个强连通判断有误的WA。

      对于我自己的Bug,我当时想到了可能出现的int溢出,于是将total变量改成了long,但是我忽略了中间计算过程中还可能存在的溢出导致最后出错。同时,我没有做好边界测试导致这个BUG没有在强测开始前被发现,这样的数据仅仅通过对拍器随机生成是难以查出的。这次的惨痛教训告诉我们,设计上要小心再小心,测试上要严密再严密。

      心得体会


      对于JML的感悟 

    • 跟别的同学介绍JML的时候,我开玩笑说JML是一个程序员写给另一个程序员的情书,情书是假,给对方分配任务是真。那为什么要用JML这种晦涩难懂的语言来描述呢?

    • 有一个笑话,程序员的妻子对程序员说:“你去菜市场买两个苹果,看到西瓜就买一个。”过了一会儿,程序员拿着一个苹果回来了......
    • 还有一个笑话,程序员的妻子对加班到很晚才回家的程序员说:“你明天提早点回来吧!”第二天程序员没有回家,第三天一大早,他手里拎着早餐回到了家......
    • 这说明自然语言有许多局限性,首先它容易产生歧义,其次由于程序员的国界不同语言不同很难跨国交流。
    • 但是JML语言消除这种歧义,逻辑严密,同时它又是一种通用的语言,不受国界影响。

    • (2)启发和感悟

    • 本单元的作业对我的能力是有提高的,首先在阅读JML规格的时候,如何从一串复杂的\forall、\exist和循环中读懂要求并转化成自己的语言是第一个考验,如何确保自己的提取和原规格等价以及发现边界条件和特殊情况是第二个考验,同时由于JML规格只负责描述任务而不关心具体实现,因此如何选择合适的数据结构来简化实现过程是第三个考验,最后为了程序的性能还要使用各种各样的算法进行优化是第四个考验。无论是哪一关出现了问题都会导致最终的结果错误,因此这是一个很好的锻炼过程。

    • 通过本单元的学习,我对容器的选择有了更深刻的理解,对于抽象和具体的转化能力有了进一步的提高,对于程序运行时间的估计和时间复杂度的控制也有了明显的提升,对于架构的把握和接口的管理也颇有收获。

    • 最后,希望OO课程能够越来越好!

OO第三单元作业——魔教规格的更多相关文章

  1. OO第三单元作业总结

    OO第三单元作业总结--JML 第三单元的主题是JML规格的学习,其中的三次作业也是围绕JML规格的实现所展开的(虽然感觉作业中最难的还是如何正确适用数据结构以及如何正确地对于时间复杂度进行优化). ...

  2. 【OO学习】OO第三单元作业总结

    [OO学习]OO第三单元作业总结 第三单元,我们学习了JML语言,用来进行形式化设计.本单元包括三次作业,通过给定的JML来实行了一个对路径的管理系统,最后完成了一个地铁系统,来管理不同的线路,求得关 ...

  3. OO第三单元作业(JML)总结

    OO第三单元作业(JML)总结 目录 OO第三单元作业(JML)总结 JML语言知识梳理 使用jml的目的 jml注释结构 jml表达式 方法规格 类型规格 SMT Solver 部署JMLUnitN ...

  4. OO第三单元作业小结

    一.JML理论基础及应用工具链情况 理论基础 1.JML表达式 \result:表示方法执行后的返回值. \old(expr):表示一个表达式expr在相应方法执行前的取值. \foall:全称量词修 ...

  5. 2019北航OO第三单元作业总结

    1.梳理JML语言的理论基础.应用工具链情况 JML基础理论: JML(Java Modeling Language)是用于对Java程序进行规格化设计的一种表示语言.JML是一种行为接口规格语言,基 ...

  6. 北航OO第三单元作业总结(3.1~3.3)

    JML简介及相关工具链使用 1.JML规格描述语言介绍 本单元学习的内容是JML规格描述语言.我们知道,面向对象方法是一个抽象过程,需求者仅需关注方法的规格.规格是对一个方法/类/程序的外部可感知行为 ...

  7. OO第三单元作业分析

    一.JML的理论基础应用工具链 JML是用于对Java程序进行规格化设计的一种表示语言.基于Larch方法构建. (1)注释 JML以javadoc注释的方式来表示规格,每行都以@起头.有两种注释方式 ...

  8. BUAA OO 2019 第三单元作业总结

    目录 总 JML规格化设计 理论基础 工具链 规格验证 验证代码 代码静态检查 自动生成测试样例 生成结果 错误分析 作业设计 第九次作业 架构 代码实现 第十次作业 架构 代码实现 第十一次作业 架 ...

  9. 规格化设计——OO第三单元总结

    规格化设计--OO第三单元总结 一.JML语言理论基础.应用工具链 1.1 JML语言 ​ JML(java modeling language)是一种描述代码行为的语言,包括前置条件.副作用等等.J ...

随机推荐

  1. vue2.0用法以及环境配置

    一.配置环境搭建 1.安装node.js (可以去官网看) 2.安装git (推荐看廖雪峰文章,点击查看) 3.安装vue: cmd:npm install vue //最新稳定版本 npm inst ...

  2. 去中心化预言机如何助力NGK DeFi 项目发展?

    早在 2014 年前后,协议智能合约就已经出现了,最初协议很笨重,包含了许多不同的部分,每个部分都是一个单独的智能合约,你需要在区块链本身的协议中添加不同的智能合约,这需要几个月甚至几年的时间,而之后 ...

  3. Github Action 快速上手指南

    前言 各位读者,新年快乐,我是过了年匆忙赶回上海努力搬砖的蛮三刀. Github之前更新了一个Action功能(应该是很久以前了),可以实现很多自动化操作.用来替代用户自己设置的自动化脚本(比如:钩子 ...

  4. canal数据同步的环境配置

    canal数据同步的环境配置:(适用于mysql) 前提:在linux和windows系统的mysql数据库中创建相同结构的数据库和表,我的linux中mysql是用docker实现的(5.7版本), ...

  5. 水墨屏开发设备,旧 Kindle 改造而成

    原文地址:Turning an old Amazon Kindle into a eink development platform 原文作者:adq 译者 & 校正:HelloGitHub- ...

  6. deepin 340 USB转console线驱动安装及使用

    刚换DEEPIN系统, 有个路由器要做调整,的确是没windows友好,查了网上资料,归总一下. zhaodong@zhaodong-PC:sudo find / -name serial 进入 zh ...

  7. JavaScript实现动态添加员工

    html代码: <div id="empAdd"> <fieldset> <legend><strong>添加员工</stro ...

  8. Codeforces 1167c(ccpc wannafly camp day1) News Distribution 并查集模板

    题目: In some social network, there are nn users communicating with each other in mm groups of friends ...

  9. pytorch(00)

    pytorch入门到项目(-) 一.pytorch的环境 本身项目采用win10系统+pycharm+anaconda+cuda. 其中版本为 python 3.7 anaconda 5.3.1 cu ...

  10. Vmware虚拟机CentOS7、Ubuntu20系统设置静态IP,且主机和虚拟机系统能相互ping通。

    目录 前言 一.VMware虚拟系统centos7设置静态IP 1.1 打开VMware虚拟网络配置窗口 1.2 方法1:通过DHCP服务给主机动态分配IP,同时设置centos静态IP 1.2.1 ...