第三单元总结
(1) 分析在本单元自测过程中如何利用JML规格来准备测试数据
在理解JML规格含义及要求的前提下,对JML中的每个normal_behavior和exceptional_behavior设计多组相应的测试数据,尤其是针对边界数据、null等特殊情况的数据,并对相应的后置条件进行检查,并使用repOk判断是否满足不变式和约束。
(2) 梳理本单元的架构设计,分析自己的图模型构建和维护策略
本单元作业以每个人为点,人于人之间的关系为有权值的无向边,用每个人的acquaintance和value维护每个点的相连的点和边权。Group是某些点的集合,在图中并无实际含义。Messege可看作可在图中按边移动的属性。Network是协调点的属性、点之间关系、Group的成员、Message的移动,以及整个图属性的总类。在实现时要对每条边(即关系)进行保存,以便于最小生成树的操作。对于连通性、连通分量的维护用并查集实现。
(3) 按照作业分析代码实现出现的性能问题和修复情况
第一次作业
本次作业以社交网络为背景,对于某些暴力开销较大的方法使用相应的图论算法来改善性能。如此次作业中isCircle和queryBlockSum使用路径压缩并查集维护。维护一个连通分量个数blockSum,每次加人时将该变量加一,有效合并并查集时将该变量减一。对于某些查询量可采用提前计算的方式维护一个量并动态维护,如针对年龄平均值的查询可维护一个年龄总数的变量。
第二次作业
本次作业中新增的queryLeastConnection使用Kruskal最小生成树算法实现。对于Group类中queryGroupValueSum的性能问题,可在每次addToGroup,delFromGroup,addRelation操作中维护每个组的总value,从而改善每条指令的最高性能开销。但对于实际应用来说,getValueSum的调用频率可能不及addToGroup,delFromGroup,addRelation这些方法的调用那么频繁,因此以加权平均性能的指标考量,以上解决方案甚至可能是负优化。
第三次作业
本次作业中新增的sendIndirectMessage使用spfa最短路算法实现。其他新增方法仅需按照规格编写即可。
(4) 请针对下页ppt内容对Network进行扩展,并给出相应的JML规格
假设出现了几种不同的Person
Advertiser:持续向外发送产品广告
Producer:产品生产商,通过Advertiser来销售产品
Customer:消费者,会关注广告并选择和自己偏好匹配的产品来购买 -- 所谓购买,就是直接通过Advertiser给相应Producer发一个购买消息
Person:吃瓜群众,不发广告,不买东西,不卖东西
如此Network可以支持市场营销,并能查询某种商品的销售额和销售路径等 请讨论如何对Network扩展,给出相关接口方法,并选择3个核心业务功能的接口方法撰写JML规格(借鉴所总结的JML规格模式)
Advertiser、Producer、Customer均继承自Person,Advertisement、Product均继承自Message。其中Advertisement的Person1只能为Advertiser,Product中新增price属性,且type只能为0,Person1只能为Advertiser,Person1只能为Customer。新建ProductInfo类用来保存每种产品的相关信息。同时创建抽象模型productInfoList来维护产品的相关信息。
以下分别为发布广告(单发或群发)、购买产品、查询某产品销售额的JML规格
/*@ public normal_behavior
@ requires containsMessage(id) && getMessage(id).getType() == 0 &&
@ getMessage(id) instanceof Advertisement &&
@ getMessage(id).getPerson1().isLinked(getMessage(id).getPerson2()) &&
@ getMessage(id).getPerson1() != getMessage(id).getPerson2();
@ assignable messages;
@ assignable getMessage(id).getPerson1().socialValue;
@ assignable getMessage(id).getPerson2().messages, getMessage(id).getPerson2().socialValue;
@ ensures !containsMessage(id) && messages.length == \old(messages.length) - 1 &&
@ (\forall int i; 0 <= i && i < \old(messages.length) && \old(messages[i].getId()) != id;
@ (\exists int j; 0 <= j && j < messages.length; messages[j].equals(\old(messages[i]))));
@ ensures \old(getMessage(id)).getPerson1().getSocialValue() ==
@ \old(getMessage(id).getPerson1().getSocialValue()) + \old(getMessage(id)).getSocialValue() &&
@ \old(getMessage(id)).getPerson2().getSocialValue() ==
@ \old(getMessage(id).getPerson2().getSocialValue()) + \old(getMessage(id)).getSocialValue();
@ ensures (\forall int i; 0 <= i && i < \old(getMessage(id).getPerson2().getMessages().size());
@ \old(getMessage(id)).getPerson2().getMessages().get(i+1) == \old(getMessage(id).getPerson2().getMessages().get(i)));
@ ensures \old(getMessage(id)).getPerson2().getMessages().get(0).equals(\old(getMessage(id)));
@ ensures \old(getMessage(id)).getPerson2().getMessages().size() == \old(getMessage(id).getPerson2().getMessages().size()) + 1;
also
@ public normal_behavior
@ requires containsMessage(id) && getMessage(id).getType() == 1 &&
@ getMessage(id) instanceof Advertisement &&
@ getMessage(id).getGroup().hasPerson(getMessage(id).getPerson1());
@ assignable people[*].socialValue, people[*].money, messages;
@ ensures !containsMessage(id) && messages.length == \old(messages.length) - 1 &&
@ (\forall int i; 0 <= i && i < \old(messages.length) && \old(messages[i].getId()) != id;
@ (\exists int j; 0 <= j && j < messages.length; messages[j].equals(\old(messages[i]))));
@ ensures (\forall Person p; \old(getMessage(id)).getGroup().hasPerson(p); p.getSocialValue() ==
@ \old(p.getSocialValue()) + \old(getMessage(id)).getSocialValue());
@ ensures (\forall int i; 0 <= i && i < people.length && !\old(getMessage(id)).getGroup().hasPerson(people[i]);
@ \old(people[i].getSocialValue()) == people[i].getSocialValue());
@ also
@ public exceptional_behavior
@ signals (MessageIdNotFoundException e) !containsMessage(id) ||
@ (containsMessage(id) && !getMessage(id) instanceof Advertisement);
@ signals (RelationNotFoundException e) containsMessage(id) && getMessage(id).getType() == 0 &&
@ !(getMessage(id).getPerson1().isLinked(getMessage(id).getPerson2()));
@ signals (PersonIdNotFoundException e) containsMessage(id) && getMessage(id).getType() == 1 &&
@ !(getMessage(id).getGroup().hasPerson(getMessage(id).getPerson1()));
@*/
public void sendAdvertisement(int id) throws
RelationNotFoundException, MessageIdNotFoundException, PersonIdNotFoundException;
/*@ public normal_behavior
@ requires containsMessage(id) && getMessage(id).getType() == 0 &&
@ getMessage(id) instanceof Product &&
@ getMessage(id).getPerson1().isLinked(getMessage(id).getPerson2()) &&
@ getMessage(id).getPerson1() != getMessage(id).getPerson2();
@ assignable messages, productInfoList;
@ assignable getMessage(id).getPerson1().socialValue, getMessage(id).getPerson1().money;
@ assignable getMessage(id).getPerson2().messages, getMessage(id).getPerson2().socialValue, getMessage(id).getPerson2().money;
@ ensures !containsMessage(id) && messages.length == \old(messages.length) - 1 &&
@ (\forall int i; 0 <= i && i < \old(messages.length) && \old(messages[i].getId()) != id;
@ (\exists int j; 0 <= j && j < messages.length; messages[j].equals(\old(messages[i]))));
@ ensures \old(getMessage(id)).getPerson1().getSocialValue() ==
@ \old(getMessage(id).getPerson1().getSocialValue()) + \old(getMessage(id)).getSocialValue() &&
@ \old(getMessage(id)).getPerson2().getSocialValue() ==
@ \old(getMessage(id).getPerson2().getSocialValue()) + \old(getMessage(id)).getSocialValue();
@ ensures (\old(getMessage(id)).getPerson1().getMoney() ==
@ \old(getMessage(id).getPerson1().getMoney()) + ((Product)\old(getMessage(id))).getMoney() &&
@ \old(getMessage(id)).getPerson2().getMoney() ==
@ \old(getMessage(id).getPerson2().getMoney()) - ((Product)\old(getMessage(id))).getMoney());
@ ensures (\forall int i; 0 <= i && i < \old(getMessage(id).getPerson2().getMessages().size());
@ \old(getMessage(id)).getPerson2().getMessages().get(i+1) == \old(getMessage(id).getPerson2().getMessages().get(i)));
@ ensures \old(getMessage(id)).getPerson2().getMessages().get(0).equals(\old(getMessage(id)));
@ ensures \old(getMessage(id)).getPerson2().getMessages().size() == \old(getMessage(id).getPerson2().getMessages().size()) + 1;
@ ensures (\exists int i; 0 <= i && i < productInfoList.length && productInfoList[i].getId() == ((Product)\old(getMessage(id))).getProductId();
@ productInfoList[i].getSaledNum() == \old(productInfoList[i].getSaledNum()) + 1);
@ also
@ public exceptional_behavior
@ signals (MessageIdNotFoundException e) !containsMessage(id) ||
@ (containsMessage(id) && !getMessage(id) instanceof Product);
@ signals (RelationNotFoundException e) containsMessage(id) && getMessage(id).getType() == 0 &&
@ !(getMessage(id).getPerson1().isLinked(getMessage(id).getPerson2()));
@*/
public void buyProduct(int id) throws
RelationNotFoundException, MessageIdNotFoundException;
/*@ public normal_behavior
@ requires (\exists int i; 0 <= i && i < productInfoList.length; productInfoList[i].getId() == id);
@ ensures (\exists int i; 0 <= i && i < productInfoList.length; productInfoList[i].getId() == id &&
@ \result == productInfoList[i].getSaledNum());
@ also
@ public exceptional_behavior
@ requires !(\exists int i; 0 <= i && i < productInfoList.length; productInfoList[i].getId() == id);
@ signals_only ProductIdNotFoundException;
@*/
public int querySaledProductNum(int id) throws ProductIdNotFoundException;
(5) 本单元学习体会
本单元作业最重要的就是要全面地理解JML的操作,并选择合适的容器及算法实现。对于简单易于实现的方法,严格按照JML的描述语言编写代码。对于按JML描述语言不易实现或性能较差的方法,则需在严格遵守JML约束的前提下谨慎选择实现算法。本单元第三次作业就因为Message类的equals方法偷懒用了IDEA自动生成的equals导致Message的id相同的不同子类不能触发EqualMessageIdException,最终未能进入互测(顺便吐槽一波中测难度,太水了)。相对于第二次作业,本单元作业难度明显降低,思考难度几乎没有,也不需要自行架构,仅需要将JML规格翻译成代码,但需要十分细心地编写或大量的测试数据,否则就会因为及其细小的问题惨遭爆零。
posted on 2022-06-03 17:38 hacker_killer 阅读(31) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】