OO_JML系列_单元总结

概述:

  面向对象第三单元的任务是根据JML规格,继承相应的接口,实现相应的类。其中涉及一系列的算法以及数据结构的选择问题,高效的算法和合适的数据结构能够减少CPU时间、运行时间和运行内存,使得程序得到优化。

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

1、理论基础

  Java建模语言是用于对Java程序进行规格化设计的一种表示语言。在Java代码中增加了一些符号,这些符号用来标识一个方法是干什么的,却并不关心它的实现。

  JML规格大致包含以下内容:

public model instance JMLObjectBag elementsInQueue;(模型域)

public normal_behavior(方法正常功能)

public exceptional_behavior(方法异常功能)

requires(前置条件)

ensures(后置条件)

assignable(副作用范围限定)

JML表达式(\result \old()  \forall  \exists \nothing\everything <=!=> <==> ==>等)

invariant(不变式)

constraint(状态变化约束)

 

2、应用工具链

openjml测试JML语言的正确性

Junit4生成模板,构造测试样例,单独测试每个函数是否符合JML

JMLUnitNG自动生成测试样例

二、部署SMTSolver,至少选择3个主要方法来尝试进行验证,报告结果

 环境为IDEA+openjml插件+openjml,对第9次作业的MyPathContainer.java进行测试,第一次运行结果如下:

Start OpenJML/ESC with file MyPathContainer.java
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:66: 错误: A \old token with no label may not be present in a requires clause
@ requires path != null && path.isValid() && \old(containsPath(path));
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:82: 错误: A \old token with no label may not be present in a requires clause
@ requires \old(containsPathId(pathId));
^
2 个错误

 

报告了两个规格的错误,修改之后再次运行,报了更多的错误......如下:

Start OpenJML/ESC with file MyPathContainer.java
错误: A catastrophic JML internal error occurred. Please report the bug with as much information as you can.
Reason: Mismatch in number of arguments in accumulateTypeInstantiations
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:54: 警告: The prover cannot establish an assertion (ArithmeticOperationRange) in method addPath: overflow in int sum
id++;
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:57: 警告: The prover cannot establish an assertion (ArithmeticOperationRange) in method addPath: overflow in int sum
sizeall++;
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:49: 警告: The prover cannot establish an assertion (ExceptionalPostcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:58: 注: ) in method addPath
if (path == null || !path.isValid()) {
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:58: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:49: 注:
@ normal_behavior
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:52: 警告: The prover cannot establish an assertion (Postcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:49: 注: ) in method addPath
return pathMap.get(path);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:49: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:52: 注:
@ ensures (pidList.length == pList.length);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:52: 警告: The prover cannot establish an assertion (Postcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:50: 注: ) in method addPath
return pathMap.get(path);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:50: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:52: 注:
@ ensures (\exists int i; 0 <= i && i < pList.length; pList[i] == path &&
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:52: 警告: The prover cannot establish an assertion (Postcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:55: 注: ) in method addPath
return pathMap.get(path);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:55: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:52: 注:
@ ensures (\forall int i; 0 <= i && i < \old(pList.length);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:49: 警告: The prover cannot establish an assertion (ExceptionalPostcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:46: 注: ) in method addPath
if (path == null || !path.isValid()) {
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:46: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:49: 注:
/*@ normal_behavior
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:25: 警告: The prover cannot establish an assertion (Postcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:12: 注: ) in method containsPath
return pathMap.containsKey(path);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:12: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:25: 注:
@ ensures \result == (\exists int i; 0 <= i && i < pList.length;
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:29: 警告: The prover cannot establish an assertion (Postcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:17: 注: ) in method containsPathId
return idMap.containsKey(pathId);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:17: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:29: 注:
/*@ ensures \result == (\exists int i; 0 <= i && i < pidList.length;
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:98: 警告: The prover cannot establish an assertion (Postcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:94: 注: ) in method getDistinctNodeCount
return sizedis;
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:94: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:98: 注:
/*@ ensures (\exists int[] arr; (\forall int i, j; 0 <= i && i < j && j < arr.length; arr[i] != arr[j]);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:33: 警告: The prover cannot establish an assertion (ExceptionalPostcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:22: 注: ) in method getPathById
if (!containsPathId(pathId)) {
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:22: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:33: 注:
/*@ public normal_behavior
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:33: 警告: The prover cannot establish an assertion (ExceptionList: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:30: 注: ) in method getPathById
if (!containsPathId(pathId)) {
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:30: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:33: 注:
@ signals_only PathIdNotFoundException;
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:36: 警告: The prover cannot establish an assertion (Postcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:25: 注: ) in method getPathById
return idMap.get(pathId);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:25: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:36: 注:
@ ensures (pidList.length == pList.length) && (\exists int i; 0 <= i && i < pList.length; pidList[i] == pathId && \result == pList[i]);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:42: 警告: The prover cannot establish an assertion (ExceptionalPostcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:40: 注: ) in method getPathId
throw new PathNotFoundException(path);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:40: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:42: 注:
@ signals (PathNotFoundException e) path == null;
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:44: 警告: The prover cannot establish an assertion (Postcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:37: 注: ) in method getPathId
return pathMap.get(path);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:37: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:44: 注:
@ ensures (pidList.length == pList.length) && (\exists int i; 0 <= i && i < pList.length; pList[i].equals(path) && pidList[i] == \result);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:44: 警告: The prover cannot establish an assertion (Postcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:39: 注: ) in method getPathId
return pathMap.get(path);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:39: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:44: 注:
@ public exceptional_behavior
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:41: 警告: The prover cannot establish an assertion (ExceptionalPostcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:34: 注: ) in method getPathId
if (path == null || !path.isValid() || !containsPath(path)) {
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:34: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:41: 注:
/*@ public normal_behavior
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:65: 警告: The prover cannot establish an assertion (ExceptionalPostcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:75: 注: ) in method removePath
throw new PathNotFoundException(path);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:75: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:65: 注:
@ signals (PathNotFoundException e) path == null;
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:64: 警告: The prover cannot establish an assertion (ExceptionalPostcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:65: 注: ) in method removePath
if (path == null || !path.isValid() || !containsPath(path)) {
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:65: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:64: 注:
/*@ public normal_behavior
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:77: 警告: The prover cannot establish an assertion (ExceptionalPostcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:81: 注: ) in method removePathById
if (!containsPathId(pathId)) {
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:81: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:77: 注:
/*@ public normal_behavior
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:78: 警告: The prover cannot establish an assertion (ExceptionalPostcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:90: 注: ) in method removePathById
throw new PathIdNotFoundException(pathId);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:90: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:78: 注:
@ signals (PathIdNotFoundException e) !containsPathId(pathId);
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:21: 警告: The prover cannot establish an assertion (Postcondition: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:7: 注: ) in method size
return sizeall;
^
C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\PathContainer.java:7: 警告: Associated declaration: C:\Users\Administrator\Desktop\HW09\HW9\src\com\oocourse\specs1\models\MyPathContainer.java:21: 注:
//@ ensures \result == pList.length;
^
1 个错误
42 个警告

 前两个错误是整数溢出。

 

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

对compare函数进行测试,函数内容如下图:

 

 

 

生成的测试文件如下图:

 

 

 

测试过程及运行结果如下图:

 

 

发现自动生成的测试样例是通过判断大数据和零来验证结果的。

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

1、第9次作业架构

 

 

  MyPath.java中用ArrayList和HashSet双容器来存一条路径上的节点,根据下标查找用ArrayList,根据nodeid查找用HashSet。

  MyPathContainer.java中用了两个HashMap分别将Path映射到Pathid和将Pathid映射到Path,增删Path时同时对两个容器操作。寻找不同节点个数时,将Path中所有的node都放到一个HashSet中,计算该HashSet的大小。

 

2、第10次作业架构

 

 

  MyGraph.java中用HashMap<Edge, Integer>来保存每个边出现的次数,其中Edge是一个class,包含(int fromNode,int toNode)代表边上的两个端点。用floyd算法计算出每两个点之间的最短路径,用HashMap<Edge, Integer>存放结果,代表每两个点之间的最短路径,每次增删节点时重新计算一遍。

 

3、第11次作业架构

 

 

  MyRailwaySystem.java中用HashMap将nodeid映射到[0,120),之后根据四个不同的问题分别跑floyd算法。

  最短路径问题,将有边的两个点之间初始化为边的长度,其余的点之间初始化为-1,跑floyd算法,将结果存放在二维数组中。

  最小换乘问题,将每条路径上的每两个点之间初始化为1,其余的点之间初始化为-1,跑floyd算法,将结果存放在二维数组中。

  最低票价问题,将每条路径上的每两点之间初始化为二者之间的最短路径+2,其余的点之间初始化为-1,跑floyd算法,将结果存放在二维数组中。

  最小不满意度问题,将每条路径上的每两点之间初始化为二者之间的最小不满意度+32,其余的点之间初始化为-1,跑floyd算法,将结果存放在二维数组中。

  连通块的个数用并查集来求。

  每次增删path重新计算一遍。

 

五、按照作业分析代码实现的bug和修复情况

  代码的正确性上来讲是没有bug的,但是对于第10次作业,强测中出现了大量的CPU超时。经过分析,超时的原因是,我的代码中实现了一个Edge类(其中包含(int fromNode,int toNode)),类中存了这条边的两个端点,程序中大量的new Edge导致了时间和空间的损失,特别是当nodeid特别大的时候,超时明显。

  为了修复这个bug,我应该将nodeid映射到[0,200),并采用别的数据结构例如静态数组来存放边。

 

六、阐述对规格撰写和理解上的心得体会

  规格的撰写是一个需要大量的思考的过程,应该将每种情况都考虑到,从而保证正确性。

  而规格的解读加代码实现的过程,是一个思维转换的过程,因为规格中的数据结构并不一定是你代码实现的数据结构。规格中的数据结构是为了说明正确性方便,代码中的数据结构要考虑正确性+效率。

 

猜你喜欢

转载自www.cnblogs.com/buaa16231053/p/10890739.html