OO_JAVA_JML系列作业_单元总结

(1)梳理JML语言的理论基础、应用工具链情况

简单梳理

以下三者是jml规格里的核心,对一个方法功能和属性的限制:

  1. requires子句:规定方法的前置条件(precondition);
  2. assignable子句:方法的副作用范围限定;
  3. ensures子句:规定方法的后置条件(post condition)。

简单运用

采用OpenJML工具check第一次JML官方开源库代码得到如下结果:

对比第一次和第二次JML规格官方源码:

第一次:

    /*@ public normal_behavior
@ requires path != null && path.isValid() && \old(containsPath(path));
@ assignable pList, pidList;
@ ensures containsPath(path) == false;
@ ensures (pidList.length == pList.length);
@ ensures (\exists int i; 0 <= i && i < \old(pList.length); \old(pList[i].equals(path)) &&
@ \result == \old(pidList[i]));
@ also
@ public exceptional_behavior
@ assignable \nothing;
@ signals (PathNotFoundException e) path == null;
@ signals (PathNotFoundException e) path.isValid()==false;
@ signals (PathNotFoundException e) !containsPath(path);
@*/
public int removePath(Path path) throws PathNotFoundException;

第二次:

    /*@ public normal_behavior
@ requires path != null && path.isValid() && containsPath(path);
@ assignable pList, pidList;
@ ensures containsPath(path) == false;
@ ensures (\exists int i; 0 <= i && i < \old(pList.length); \old(pList[i].equals(path)) &&
@ \result == \old(pidList[i]));
@ ensures (\forall int i; 0 <= i && i < \old(pList.length) && \old(pList[i].equals(path) == false);
@ containsPath(\old(pList[i])) && containsPathId(\old(pidList[i])));
@ also
@ public exceptional_behavior
@ assignable \nothing;
@ signals (PathNotFoundException e) path == null;
@ signals (PathNotFoundException e) path.isValid() == false;
@ signals (PathNotFoundException e) !containsPath(path);
@*/
public int removePath(Path path) throws PathNotFoundException;

发现问题根源在于requires判据本身就发生在该方法执行前,\old条件无法在此应用,因为,requires执行时就已经是old的数据了。

(2)部署SMT Solver,至少选择3个主要方法来尝试进行验证,报告结果,有可能要补充JML规格

(3)部署JMLUnitNG/JMLUnit,针对Graph接口的实现自动生成测试用例, 并结合规格对生成的测试用例和数据进行简要分析

对自己编写的graph接口的实现类MyGraph运行JMLUnitNG结果是这样:

➜  src git:(master) ✗ jmlunitng -cp ~/javalib/specs-homework-2-1.2-raw-jar-with-dependencies.jar container/MyGraph.java
JMLUnitNG exited because of an irrecoverable error:
org.jmlspecs.jmlunitng.JMLUnitNGError: Encountered 100 compilation errors:
/home/relia/Projects/Java/OO/graph_management/src/container/MyGraph.java:21: 错误: 非法的类型开始
private HashMap<SymPair<Integer>, Integer> edges = new HashMap<>();
^
/home/relia/Projects/Java/OO/graph_management/src/container/MyGraph.java:24: 错误: 非法的类型开始
shortestRoutes = new HashMap<>();
^
/home/relia/Projects/Java/OO/graph_management/src/container/MyGraph.java:37: 错误: 非法的类型开始
return edges.containsKey(new SymPair<>(var1, var2));
^
/home/relia/Projects/Java/OO/graph_management/src/container/MyGraph.java:49: 错误: 非法的类型开始
if (!shortestRoutes.containsKey(new SymPair<>(var1, var2))) {
^
/home/relia/Projects/Java/OO/graph_management/src/container/MyGraph.java:52: 错误: 非法的类型开始
return shortestRoutes.containsKey(new SymPair<>(var1, var2));
^
/home/relia/Projects/Java/OO/graph_management/src/container/MyGraph.java:61: 错误: 非法的类型开始
return shortestRoutes.get(new SymPair<>(var1, var2));
^
/home/relia/Projects/Java/OO/graph_management/src/container/MyGraph.java:68: 错误: 需要')'
updateEdges(path, this::edgeAddingConsumer);
^
/home/relia/Projects/Java/OO/graph_management/src/container/MyGraph.java:68: 错误: 非法的表达式开始
updateEdges(path, this::edgeAddingConsumer);
^
/home/relia/Projects/Java/OO/graph_management/src/container/MyGraph.java:68: 错误: 需要';'
updateEdges(path, this::edgeAddingConsumer);
^
/home/relia/Projects/Java/OO/graph_management/src/container/MyGraph.java:76: 错误: 需要')'
updateEdges(path, this::edgeRemovingConsumer);
^
/home/relia/Projects/Java/OO/graph_management/src/container/MyGraph.java:76: 错误: 非法的表达式开始
updateEdges(path, this::edgeRemovingConsumer);
^
/home/relia/Projects/Java/OO/graph_management/src/container/MyGraph.java:76: 错误: 需要';'
updateEdges(path, this::edgeRemovingConsumer); ...

可见的是,JMLUnitNG至少不支持两种特性:

  1. 泛型的自动推断特性,在声明处已经声明的泛型,在new实例化时,不需要填充泛型类型,编译器可以自动推断,但是JMLUnitNG不支持;
  2. 函数式接口的两种形式都不支持,无论是方法引用的双冒号,还是lambda表达式。

不支持上述特性,难以想象其广泛运用。

(4)按照作业梳理自己的架构设计,并特别分析迭代中对架构的重构

第一次作业

说实话,跟大部分人相同,path container采用三个hash map莽到底,规格很简单,功能很简单,正确性容易达成。

第二次作业

这个也没有什么特色,就是BFS能用,便采用这个算法计算最短路径了,想必跟大部分人也是大同小异的设计。

正确性方面还是较为容易达成的,强测和互测都没有发现bug。

第三次作业

联通集计算

通过一个map来保留联通集的信息,其原理在于单个path内部的连通性是可以保障的,就可以在path ID的基础上建立联通集,我也是这么做的,一个pathID映射该path联通的pathID的集合,这样,就可以在线性时间内完成一次path的添加工作,其线性时间,主要依赖path本身的长度,由于我看见大家都是提到DFS能解决连通性的问题,就这么设计了,所以,我在这里大概说一下我的不一样的联通集的设计思路。

作业架构感想

说实话,没有算法,架构只是纸上谈兵,这是我第三次作业的感想,选择了最朴素的分离解耦的思维,但是在算法上,复杂度过高,没有充分考虑可缓存的,没有充分考虑遍历的控制,虽然降低了每个方法的复杂度,但这样的程序,是没有实际价值的,换言之,我大部分是做了无用功;

到现在,我也没设计出自己的完成第三次作业的思路,虽然学习别人的思路是必要的,我还是想弄清楚,怎样的原因导致了我的遍历无法达到想要的效果,然后深刻理解怎样设计遍历算法,这是我想探究的事物。

我对搜索本身有了更深刻的理解,所谓遍历,究其目的,就是寻找要寻找的目标,或者是在确定的线性集合里搜索,或者是在有更加特殊的结构的集合里搜索,为了完成这个任务,就要有无数优化加入其中,最朴素的,就是排序,排序可以极大的加快搜索的过程,放在单纯的线性集合里,排序可以将集合视为二分集,进行二叉树上的搜索,达到最高的静态集合的搜索效率,而在图结构里,搜索单源最短路径,也可以利用类似的方法,即dijkstra算法,每次根据基础集合从待选集合中搜索路径长度最小的一个,加入基础集合,变相地实现了排序的要求,排序的目的,就旨在滤除不需要的数据或数据集合,将其提前排除,加速搜索的过程。

总的来说,对集合的遍历操作十分依赖集合本身的结构,没有排序这样的优化,计算就永远是暴力计算,是不可取的。

(5)按照作业分析代码实现的bug和修复情况

这个。。第一次有一个bug但是比较隐蔽,强测和互测均未发现,最后是我在第二次作业编写中发现的,并且就排除掉了,是两个path compare的函数的错误,第二次作业最后通过了强测和互测,没有发现bug;

第三次作业,至今为止,我还是没有设计出遍历算法或者遍历同时计算的算法,保证计算的完全性的算法,没有这个,计算出的结果,就不能确定是最小值。

目前还在思考修复中,也许如果不采用讨论区大佬提的拆点算法了话,可能暂时修复不出来。

(6)阐述对规格撰写和理解上的心得体会

规格是对方法结果的一种约束,可以作为需求的一种清晰表述,利于针对其进行规范详尽的测试,因为结果都用可证明的形式描述出来,所以针对jml规格,可以采用更加针对性的测试,测试单个函数的功能正确性,并进一步提高junit的测试手段。

有了完善的规格,一定程度上,有利于我们写出更加正确的程序,当然,其作用主要还是测试方面,根据规格可以更加形式化地验证,乃至采用自动化地方法生成测试程序,甚至测试数据,这都是可能的。

OO_JAVA_JML系列作业_单元总结的更多相关文章

  1. OO_JAVA_JML系列第三次作业__架构之谈

    OO_JAVA_JML系列第三次作业 ## ----架构之谈 目录 OO_JAVA_JML系列第三次作业 出发点 操作的可分离性 操作本身的多样性 实现手段:表驱动编程 储存 注册 出发点 操作的可分 ...

  2. NLP系列(2)_用朴素贝叶斯进行文本分类(上)

    作者:龙心尘 && 寒小阳 时间:2016年1月. 出处: http://blog.csdn.net/longxinchen_ml/article/details/50597149 h ...

  3. 面向对象JML系列作业总结

    面向对象JML系列作业总结 一.综述 本单元作业,由简到难地迭代式实现了三种JML需求,主要学习了面向规格的编程方法. 第一次:实现Path类和PathContainer类 第二次:继承PathCon ...

  4. OO_JAVA_表达式求导_单元总结

    OO_JAVA_表达式求导_单元总结 这里引用个链接,是我写的另一份博客,讲的是设计层面的问题,下面主要是对自己代码的单元总结. 程序分析 (1)基于度量来分析自己的程序结构 第一次作业 程序结构大致 ...

  5. NLP系列(5)_从朴素贝叶斯到N-gram语言模型

    作者: 龙心尘 && 寒小阳 时间:2016年2月. 出处: http://blog.csdn.net/longxinchen_ml/article/details/50646528 ...

  6. NLP系列(4)_朴素贝叶斯实战与进阶

    作者: 寒小阳 && 龙心尘 时间:2016年2月. 出处:http://blog.csdn.net/han_xiaoyang/article/details/50629608 htt ...

  7. BZOJ_3809_Gty的二逼妹子序列 && BZOJ_3236_[Ahoi2013]作业 _莫队+分块

    BZOJ_3809_Gty的二逼妹子序列 && BZOJ_3236_[Ahoi2013]作业 _莫队+分块 Description Autumn和Bakser又在研究Gty的妹子序列了 ...

  8. NLP系列(4)_朴素贝叶斯实战与进阶(转)

    http://blog.csdn.net/han_xiaoyang/article/details/50629608 作者: 寒小阳 && 龙心尘 时间:2016年2月. 出处:htt ...

  9. Python全栈day24(面向对象编程作业作业_定义学校老师课程班级学生类)

    面向对象作业 作业_定义学校老师课程班级学生类.py #面向对象编程作业,定义学校老师课程班级学生类 #定义几个类,尽可能定义多的数据属性及函数属性 class School: def __init_ ...

随机推荐

  1. Pytest 系列(24)- allure 环境准备

    如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html allure 和 pytest 相 ...

  2. (1)java Spring Cloud+Spring boot+mybatis企业快速开发架构之微服务是什么?它的优缺点有哪些?

    ​ "微服务"一词来源于 Martin Fowler 的<Microservices>一文.微服务是一种架构风格,即将单体应用划分为小型的服务单元,微服务之间使用 HT ...

  3. 自己用树莓派做了一个电视盒子,还可以看优酷和cctv

    我刚接触树莓派时间不久,安装过raspberry(树莓派官方系统),ubuntu mate,openelec等系统,openelec是一个电视盒子系统,但是我的用的电视机是一个老式的,老是出现闪屏的问 ...

  4. C++快速读入

    使用C++的标准cin进行读入速度比较慢,尤其是在大数据的情况下,所以我们需要使用一种方法,按照字符读入,最后再"组装"成整数.由于字符读入比数字要快,所以这样做可以提高读入速度. ...

  5. nginx proxy_next_upstream 与openresty balancer.set_more_tries的使用

    背景 我们这边网关服务使用的 kong,前段时间上线一个服务,这个服务它报错了,产生了502的错误码,追查这个报错的时候发现了网关服务的两个可疑的地方,第一个疑点是我们在Kong上配置的 Retrie ...

  6. mysql5.7当两个字段名类似,查询时会出错

    excepInfo: select id,describe from iwebshop_student_problem where id=256 order by id desc -- You hav ...

  7. 解决wampserver无法启动问题

    如果无法启动,找不到原因.直接依次点击打开到:控制面板--管理工具--事件查看器--windows日志--应用程序,查看对应进程错误信息对症下药即可. 我这个错误就是8099端口错误,运行cmd命令, ...

  8. 『Python』matplotlib常用图表

    这里简要介绍几种统计图形的绘制方法,其他更多图形可以去matplotlib找examples魔改 1. 柱状图 柱状图主要是应用在定性数据的可视化场景中,或是离散数据类型的分布展示.例如,一个本科班级 ...

  9. 安装redis3.0.5

    首先在官网下载redis-3.0.5.tar.gz 在某一个要安装redis的目录下输入命令 tar xzf redis-3.0.5.tar.gz 实现解压缩 进入解压缩后的redis目录 输入mak ...

  10. P7405-[JOI 2021 Final]雪玉【二分】

    正题 题目链接:https://www.luogu.com.cn/problem/P7405 题目大意 \(n\)个点在坐标轴上,\(q\)次每次所有点向一个方向移动若干步,每个点的权值是它第一次覆盖 ...