标签:class exp constrain 必须 containe 一个 也有 return 双连通分量
JML(Java Modeling Language)是用于对Java程序进行规格化设计的一种表示语言,即JML限制了各个类的规格。JML是一种行为接口规格语言。我们目前学到的JML仅限于level0,还只是入门级而已。
注释结构
JML表达式
\result
\old(expr)
not_assigned(x, y, ...)
\not_modified(x, y, ...)
\forall
\exists
\sum
等。b_expr1<==>b_expr2
b_expr1==>b_expr2
个人感觉基本和离散数学的感觉差不多。
方法规格
前置条件requires P
表示要求方法的调用者确保表达式P为真;后置条件ensures P
表示要确保方法执行返回结果要保证P为真;normal_behavior
表示正常功能行为;exceptional_behavior
表示异常行为,要用到signals (***Exception e) b_expr
子句,即当b_expr为真时抛出异常。
类型规格
不变式invariant
:要求在所有可见状态下都必须满足的特性。
状态变化约束constraint
:对前序可见状态和当前可见状态的关系进行约束。
下载openJML时候里面就有了各种平台下可用的solver。将openjml.jar,z3-4.7.1.exe,__修改后的__MyPerson.java放在一个文件夹下然后在命令行输入java -jar openjml.jar -exec z3-4.7.1.exe -esc MyPerson.java
,得到一堆警告但至少没有报错(sigh)。
说一下我对MyPerson.java的修改过程。首先openjml检查时,如果类规格里写了MyPerson[] acquaintance
,在实现时就只能同样用数组实现,要么就得改JML,这也实在是openJML的一大恶心之处。改完之后的MyPerson类一窥(省略了很多函数):
public class MyPerson{
private /*@ spec_public @*/ int id;
private /*@ spec_public @*/ MyPerson[] acquaintance = new MyPerson[1000]; //这里为了符合JML无奈之下使用了静态数组
private /*@ spec_public @*/ HashMap<Integer,Integer> value = new HashMap<>();
//@ ensures \result == id;
public /*@ pure @*/ int getId() {
return this.id;
}
/*@ public normal_behavior
@ requires (\exists int i; 0 <= i && i < acquaintance.length;
@ acquaintance[i].getId() == MyPerson.getId());
@ assignable \nothing;
@ ensures (\exists int i; 0 <= i && i < acquaintance.length;
@ acquaintance[i].getId() == MyPerson.getId() && \result == value.get(MyPerson.getId()));
@ also
@ public normal_behavior
@ requires (\forall int i; 0 <= i && i < acquaintance.length;
@ acquaintance[i].getId() != MyPerson.getId());
@ ensures \result == 0;
@*/
//这里规格的第六行把value[i]改成了value.get(MyPerson.getId()))
public int queryValue(MyPerson MyPerson) {
if (value.containsKey(MyPerson.getId())) {
return value.get(MyPerson.getId());
}
return 0;
}
}
JMLUnitNG好就好在可以自动生成测试数据,据我观察其实也就是生成一些极限数据确保程序在极限情况下的正确性。
但是有一点我真的非常疑惑,同样的数据我用Junit测试和代码实际运行都是对的,为什么交给JMLUnitNG这东西就总是fail呢?问过不少同学也有同样的问题,向助教大大请教也没有得到解释,这一点我真的是无可奈何了......
总体上我这次的架构就是按照JML的结构来的。
在求连通块个数时用到了并查集,将并查集相关操作封装在类UnionFindSet 中。用一个HashMap维护并查集(键值为节点(用户)的id,值为节点的祖先),成员函数为即为并查集的常规加点、求祖先、连边等操作。
在求点双连通分量和最短路时没有把相关算法封装到单独的类中而是在MyNetwork类中多写了几个函数,毕竟每个算法只用到了单独一个函数。但是Tarjan算法需要维护全局变量(dfn数组等),就使得MyNetwork类平白无故多了很多成员变量。UML图如下:
标签:class exp constrain 必须 containe 一个 也有 return 双连通分量
原文地址:https://www.cnblogs.com/Locksoyev/p/12939680.html