一、JML理论基础及相关工具链

1.JML理论基础

该部分梳理本单元作业中涉及到的JML知识。

1.1注释结构

JML采用javadoc注释的方式来表示规格,且每行以@开头。通过使用//@annotation来进行行注释,使用/*@annotaion@*/来进行块注释。

1.2JML表达式

1.2.1原子表达式
  • \result表达式,在方法规格中使用,通过\result来指代返回值。在谓词中使用\result,来表达放回值的限制条件。

  • \old(expr)表达式,返回表达式expr在方法执行之前的值。
  • \not_assigned(x,y,...)表达式,该表达式为一谓词,当括号中变量在方法执行过程中未被赋值返回true,否则返回false。
  • \not_modified(x,y,...)表达式,该表示为一谓词,当括号中变量在方法执行过程取值为变化返回true,否则返回false。
1.2.2量化表达式
  • \forall表达式。表达式格式为\formall V; P1; P2。其中V定义了在该表达式中要使用的变量,谓词P1、P2为变量需要满足的条件。一般P1表示变量的范围,P2表示变量需要满足的其他条件。该表达式整体也为一个谓词,当V定义的变量的所有满足P1的取值都满足P2时返回true,否则返回false。
  • \exists表达式。表达式格式为\exists V; P1; P2。其中V,P1,P2与\forall表达式中的相同。该表达式整体为一个谓词,当V定义的变量存在一个满足P1的取值也满足P2时返回true,否则返回false。
  • \sum表达式。表达式格式为\sum V; P; N。其中V定义了表达式中要使用的变量,谓词P限制了变量的范围,N表示每一个满足P的情况下的增量。表达式最终返回所有增量的加和。
1.2.3操作符
  • 推理操作符==>,使用格式P1 ==> P2。P1、P2为谓词,整个表达式也为一谓词。当P1为true,P2为false时该谓词返回false,否则返回true。
  • 变量引用操作符。\nothing表示空集,\everything表示全集。

1.3数据规格

1.3.1规格变量

在本单元作业中,通过在接口中定义规格变量,来规定要管理的数据。

例如//@public instance model non_null int id;定义了一个规格可见的、引用不为空的、int型实例变量。同理将instance改为static可定义一个静态变量。

1.3.2 /*@spec_public@*/

通过对类中的字段添加/*@spec_public@*/可以指定该变量为规格可见。

1.1.3不变式invariant

//@invariant P;其中P为一个谓词。该语句规定在所有可见状态下,规格所管理的数据都必须满足谓词P。

1.1.4状态变化约束constraint

//@constraint P;其中P为一个谓词。该语句规定数据在前序可见状态与当前可见状态之间需要满足的约束。

1.4方法规格

1.4.1/*@pure@*/

通过对方法修饰/*@ pure @*/,表示该方法仅为查询方法,不会对类的数据做任何修改,使得该方法为规格内可见。

1.4.2行为

一个方法可以有多个行为,行为分为正常行为与异常行为。一个方法也也可以有多个正常行为与异常行为,但他们的前置条件之间不能有交集。正常行为用normal_behavior表示,异常行为用exceptional_behavior表示。多个行为之间用also连接。

1.4.3前置条件

通过使用requires语句实现。格式为requires P。P为一谓词,表示调用该方法时需要满足的限制。一个行为可以有多个requires语句,这些语句之间为且关系,在该行为下需全部被满足。

1.4.4后置条件

通过使用ensures语句实现。格式为ensures P。P为一谓词,表示该方法调用结束时需要满足的限制。一个行为可以有多个ensures语句,这些语句之间为且关系,在该行为下需全部被满足。

1.4.5副作用范围限定

通过assignable语句或者modifiable语句实现。格式为assignable/modifiable v。其中v表示可以被赋值/修改的变量。特别的,当v为\nothing时表示不能赋值\修改任何变量。

1.4.6 signals

signals语句使用在异常行为下。格式为signals E P。E为要抛出的异常包括异常类型与异常变量名称。P为一谓词,表示当谓词满足时抛出异常。当P与该行为前置条件的P相同时,可简化该语句为signals_only E。

2.相关工具链

2.1OpenJML

2.1.1介绍

根据OpenJML官网(http://www.openjml.org/)上的介绍,OpenJML通过使用SMT solver能够为Java程序验证其是否满足JML规格,分为静态(static)检查以及运行时(runtime)检查。

2.2JMLunitng

2.2.1介绍

JMLunitng能通过JML为Java程序提供测试集。

2.2.1本地部署

参考了这篇博客(https://www.cnblogs.com/starmiku/p/10908745.html)的配置。

执行如下指令后

java -jar jmlunitng.jar test/MyGroup.java
javac -cp jmlunitng.jar test/*.java
java -jar openjml.jar -rac test/MyGroup.java
java -cp jmlunitng.jar test.MyGroup_JML_Test

得到如下结果:

总共进行了55次测试,失败了4次。其中3次都是对addPerson传入null参数引起的,但在我们的作业中应当保证了传入的参数不为null。

而测试的样例中集中对边界数据进行了测试。

二、架构设计

1.第一次作业

第一次作业由于对规格不是特别了解,加上对规格的某些语句的工能有所误解,导致第一次作业完全就是按照规格的语句来完成整个设计的。MyPerson中的acquaintance和value,以及MyNetwork中的people都是采用链表结构,对数据的获取和查找基本上都是采用遍历的方式,所以性能较差,担幸好第一次作业在性能上的要求不是十分严格,所以还是逃过了一劫。

1.1类图

2.第二次作业

由于第二次作业比较强调的一点就是性能问题,所以需要对整个作业需要做一次完全的重构。同时将这个社交网络视为以Person为节点,link关系为边,value为边权的无向图。

2.1类图

2.2MyPerson

考虑到acquaintance与value中的数据有一一对应的关系,以及为了提高查找数据的效率,将他们整合成一个以Person为key以value为value的HashMap。

2.3MyGroup

同样为了提高查找效率上的考虑,使用HashSet来作为people数据的组织形式。

对getRelationSum, getValueSum, getConflictSum, getAgeMean, getAgeVar方法,为了不每次调用这些方法都重新遍历一遍数据,所以缓存了realtionSum, valueSum, ageSum, age2Sum(年龄平方和), conflictSum。其中relationSum以及valueSum需要在addPerson以及Network的addRelation时进行更新,其他数据在addPerson时更新即可。另外需要注意的是,ageMean的计算,为了保证与规格中的公式有相同的精确度,需要使用公式ageVar=(age2Sum - 2*mean*ageSum+n*ageSum**2)/n(摘自第十次讨论区乐洋同学的帖子)。

2.4MyNetwork

共用HashMap组织了三个数据:people, groups, peopleInCircle。people以及groups是为了快速通过id查找Person与Group。peopleInCircle无向图的连通分量,peopleInCircle在addRelation时更新。

通过这些储存结构,MyNetwork中大部分方法都只有几个语句,queryCircle方法可以通过查找他们是否在一个连通分量来实现。主要需要注意的方法就是addRelation,当person1与person2在一个Group中的时候需要为为这个Group更新relationSum以及valueSum,并且还需要注意person1与person2是否在同一连通分量,如果不在则需要合并两个连通分量。

3.第三次作业

第三次作业完全基于第二次作业迭代而来。

3.1类图

3.2MyPerson

与第二次作业保持一致。

3.3MyGroup

与第二次作业相比添加了delPerson方法,该方法同时更新people, ageSum, age2Sum, conflictSum, relationSum, valueSum。

3.4MyNetwork

添加了以HashMap组织的money,通过Person的id来查找其money。同时建立了一个内部类Edge来供图算法使用。

queryMinPath使用dijkstra算法,并用优先队列储存边来进行优化。

queryStrongLinked使用tarjan算法来计算点双连通分量以判断两Person是否stronglinked。

三、Bug分析

本单元的bug出现在第三次作业,强测中有两个点出现了CTLE的情况。后来经查看发现这两个点是针对queryMinPath进行测试的,导致CPU时间紧张。

由于自己偷懒就没有再去优化dijkstra算法,于是就选择在Bug修复中直接提交了之前的代码,幸好在评测机资源不紧张的状况下,出现CTLE的两个点都通过了测试。

四、心得体会

由于对JML的阅读还十分有限,所以也谈不上什么心得体会。主要策略就是先界定清楚不同正常行为以及异常行为,然后对每个行为中方法的逻辑进行分析,尝试用规范的逻辑语言去描述它,最后再转化为JML中的语句。

北航OO(2020)第三单元博客作业的更多相关文章

  1. 北航OO(2020)第四单元博客作业暨学期总结

    一.第四单元架构设计 1.第一次作业 我在本次作业中设置了多个储存结构:Directory,ElementsInName,ElementsInId,Cache. Directory: 顾名思义,这是个 ...

  2. oo第三单元博客作业

    JML语言理论基础 Java建模语言(Java Modeling Language,JML)是一种进行详细设计的符号语言,他鼓励你用一种全新的方式来看待Java的类和方法.JML是一种行为接口规格语言 ...

  3. OO第四单元博客作业

    OO第四单元博客作业 BUAA_1706_HugeGun 目录 第四单元作业架构设计 四个单元架构设计及OO方法理解 四个单元测试理解与实践演进 课程收获 一点建议 第四单元作业架构设计 ### 第十 ...

  4. [BUAA OO]第三次博客作业

    OO第三次博客作业 1. 规格化设计的发展 我认为,规格化设计主要源自于软件设计的两次危机.第一次是由于大量存在的goto语句,让当时被广泛应用的面向过程式的编程语言臃肿不堪,在逻辑性上与工程规模上鱼 ...

  5. OO第三次博客作业——规格

    OO第三次博客作业——规格 一.调研结果: 规格的历史: 引自博文链接:http://blog.sina.com.cn/s/blog_473d5bba010001x9.html 传统科学的特点是发现世 ...

  6. [2017BUAA软工]第三次博客作业:案例分析

    第三次博客作业:案例分析 1. 调研和评测 1.1 BUG及设计缺陷描述 主要测试博客园在手机端上的使用情况. [BUG 01] 不能后退到上一界面(IOS) 重现步骤:打开博客首页中任意博文,点击博 ...

  7. 北航OO(2020)第二单元博客作业

    第二单元第一次作业 多线程设计策略 第一次作业的想法是设计三个线程:输入线程,调度器线程以及电梯线程.输入线程获取请求并发送给调度器线程:调度器线程通过查询电梯线程的状态(等待.停靠以及移动),并综合 ...

  8. 第三周博客作业<西北师范大学|李晓婷>

    1.助教博客链接:https://www.cnblogs.com/lxt-/MyComments.html 2.学生作业打分要求:   https://www.cnblogs.com/nwnu-dai ...

  9. OO第三次博客作业(第三单元总结)

    (1)梳理JML语言的理论基础.应用工具链情况 Java 建模语言(JML)将注释添加到 Java 代码中,这样我们就可以确定方法所执行的内容,而不必说明它们如何做到这一点.有了 JML,我们就可以描 ...

随机推荐

  1. GoPath模式和GoMoudle模式的相爱相杀

    相信看我文章的文章的童鞋,golang版本已经是1.3版本以上.如果你的版本还停留在1.3以下,那这篇文章可以做为你的提升之法. go moudle的前世今生 前世-gopath gopath是什么 ...

  2. 【PAT甲级】1119 Pre- and Post-order Traversals(前序后序转中序)

    [题目链接] [题意] 根据二叉树的前序和后序序列,如果中序序列唯一,输出Yes,如果不唯一输出No,并输出这个中序序列. [题解] 众所周知,二叉树是不能够根据前序和中序建立的,为什么呢?首先需要明 ...

  3. JVM之调优及常见场景分析

    JVM调优 GC调优是最后要做的工作,GC调优的目的可以总结为下面两点: 减少对象晋升到老年代的数量 减少FullGC的执行时间 通过监控排查问题及验证优化结果,可以分为: 命令监控:jps.jinf ...

  4. python学习8 文件的操作

    本文拷贝了on testing 的<python之文件操作:文件的读写>,只做学习之用 python的文件读写通过 一.用open函数 二.对文件读写操作 三.读取文件位置定位 1. op ...

  5. KubeEdge云边协同设计原理

    云端组件CloudCore与k8s Master的关系 从黑盒角度看,CloudCore就是k8s的一个插件,它是非侵入的来扩展k8s的一部分功能,将原来云上的节点映射到边缘端进行管理,一个Cloud ...

  6. ON DUPLICATE KEY UPDATE作用

    ON DUPLICATE KEY UPDATE作用 先声明一点,ON DUPLICATE KEY UPDATE为Mysql特有语法,这是个坑 语句的作用,当insert已经存在的记录时,执行Updat ...

  7. oo第四单元暨课程总结

    第四单元架构设计总结 第一次作业 单独写了MyUmlClass.MyUmlInterface.MyUmlOperation三个类对应UML中相应元素,在UML图中这几个元素包含一些下级元素,如Clas ...

  8. SpringBoot(九篇)

    (一) SpringBootCLI安装 (二)SpringBoot开发第一个应用 (三)SpringBoot pom.xml配置文件详解 (四)SpringBoot起步依赖Starters详解 (五) ...

  9. CPU 空闲时在干嘛?

    人在空闲时会发呆会无聊,计算机呢? 假设你正在用计算机浏览网页,当网页加载完成后你开始阅读,此时你没有移动鼠标,没有敲击键盘,也没有网络通信,那么你的计算机此时在干嘛? 有的同学可能会觉得这个问题很简 ...

  10. 浅入Kubernetes(6):CKAD认证中的部署教程

    目录 预设网络 kubeadm 安装 k8s 配置 calico 自动补全工具 状态描述 目前为止,笔者已经写了 5 篇关于 k8s 的文章,这一篇笔者将介绍 CKAD 认证官方课程中,如何部署 k8 ...