(1) 分析在本单元自测过程中如何利用JML规格来准备测试数据
没有用JUNIT测试方法,主要是针对JML规格中的异常出现情况,以及基本的JML大意来构造测试数据。
(2) 梳理本单元的架构设计,分析自己的图模型构建和维护策略
本单元的架构比较明了,就是简单的网络模型——MyNetWork。
其中有Person跟Group,Person即网络中的结点,相连代表彼此之间有关系和社交值。
本单元我的架构设计主要还是根据JML规格完善方法。
维护策略,基本就是用数组来死板地存储person跟group,在queryBlockSum指令撰写时使用并查集方法,利用HashMap<Integer,Integer>来实现。
(3) 按照作业分析代码实现出现的性能问题和修复情况
最后一次作业出现了CPU_TIME_LIMIT_EXCEED的情况,可能是由于我三次作业的存储结构都是用list来存,在查找的时候需要遍历,过于耗费时间。
另外,在一些方法中实现时间复杂度较高,如下:
-
getValueSum (qgvs) ,按照JML死板实现,复杂度为O(N^2)
- sendIndirectMessage ,Dijkstra 算法没有用堆优化,复杂度为O(N^2)
(4) 请针对下页ppt内容对Network进行扩展,并给出相应的JML规格
假设出现了几种不同的Person
- Advertiser:持续向外发送产品广告
- Producer:产品生产商,通过Advertiser来销售产品
- Customer:消费者,会关注广告并选择和自己偏好匹配的产品来购买
-- 所谓购买,就是直接通过Advertiser给相应Producer发一个购买消息 - Person:吃瓜群众,不发广告,不买东西,不卖东西
如此Network可以支持市场营销,并能查询某种商品的销售额和销售路径等
请讨论如何对Network扩展,给出相关接口方法,并选择3个核心业务功能的接口方法撰写JML规格(借鉴所总结的JML规格模式)
答:
advertiser、producer、customer实现person接口
buyMessage、AdvertiseMessage实现Message接口
NetWork中,实现如下接口方法:
queryProductSales
:查询对应ProducerId
的产品的销售额queryProductPath
:查询ProducerId
的产品的所有销售路径- buyMessage2Adv:消费者发送购买信息到广告商
- advMessage2Cus:广告商发送广告消息到消费者
(其实按照我的理解来说,这些发送消息的应该都整合到sendMessage中,所以Producer跟Advertiser的消息传递就不写额外的方法了)
advMessage2Cus
/*@ public normal_behavior
@ requires containsMessage(id) && (getMessage(id) instance of AdvertiseMessage) && getMessage(id).getType() == 0 &&
@ getMessage(id).getPerson1().isLinked(getMessage(id).getPerson2()) &&
@ getMessage(id).getPerson1() != getMessage(id).getPerson2() &&
@ assignable messages;
@ assignable getMessage(id).getPerson2().messages;
@ assignable getMessage(id).getPerson1().socialValue, 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) instance of AdvertiseMessage) && getMessage(id).getType() == 1 &&
@ getMessage(id).getGroup().hasPerson(getMessage(id).getPerson1()) &&
@ assignable people[*].socialValue, messages;
@ assignable people[*].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());
@ ensures (\forall Person p; \old(getMessage(id)).getGroup().hasPerson(p);
@ (\forall int i; 0 <= i && i < \old(p.getMessages().size());
@ p.getMessages().get(i+1) == \old(p.getMessages().get(i)))) &&
@ p.getMessages().get(0).equals(\old(getMessage(id)))
@ && p.getMessages().size() == \old(p.getMessages().size()) + 1);
@ also
@ public exceptional_behavior
@ signals (MessageIdNotFoundException e) !containsMessage(id);
@ signals (NotAdvertiseMessageException e) containsMessage(id) && !(getMessage(id) instance of AdvertiseMessage);
@ signals (RelationNotFoundException e) containsMessage(id) && (getMessage(id) instance of AdvertiseMessage) &&
@ getMessage(id).getType() == 0 && !(getMessage(id).getPerson1().isLinked(getMessage(id).getPerson2()));
@ signals (PersonIdNotFoundException e) containsMessage(id) && (getMessage(id) instance of AdvertiseMessage) &&
@ getMessage(id).getType() == 1 && !(getMessage(id).getGroup().hasPerson(getMessage(id).getPerson1()));
@*/
public void advMessage2Cus(int id) throws NotAdvertiseMessageException,
MessageIdNotFoundException, RelationNotFoundException, PersonIdNotFoundException;
buyMessage2Adv
/*@ public normal_behavior
@ requires containsMessage(id) && (getMessage(id) instance of BuyMessage) && getMessage(id).getType() == 0 &&
@ getMessage(id).getPerson1().isLinked(getMessage(id).getPerson2()) &&
@ getMessage(id).getPerson1() != getMessage(id).getPerson2() &&
@ ((Customer)getMessage(id).getPerson1()).containsPreference((BuyMessage)getMessage(id)).getProductId) &&
@ ((Customer)getMessage(id).getPerson1()).receivedAdv((BuyMessage)getMessage(id)).getProducerId,
@ (BuyMessage)getMessage(id)).getProductId)) &&
@ assignable messages;
@ assignable getMessage(id).getPerson2().messages;
@ assignable getMessage(id).getPerson1().socialValue, getMessage(id).getPerson2().socialValue;
@ assignable getMessage(id).getPerson1().money,getProduct((BuyMessage)getMessage(id)).getProductId)).sales;
@ ensures getProduct((BuyMessage)getMessage(id)).getProductId))).sales == \old(getProduct((BuyMessage)getMessage(id)).getProductId))).sales) + getProduct((BuyMessage)getMessage(id)).getProductId))).productPrice * ((BuyMessage)getMessage(id)).getProductNum);
@ ensures getMessage(id).getPerson1().money == \old(getMessage(id).getPerson1().money) - getProduct((BuyMessage)getMessage(id)).getProductId))).productPrice * ((BuyMessage)getMessage(id)).getProductNum);
@ 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) instance of BuyMessage) && getMessage(id).getType() == 1 &&
@ getMessage(id).getGroup().hasPerson(getMessage(id).getPerson1()) &&
@ ((Customer)getMessage(id).getPerson1()).containsPreference((BuyMessage)getMessage(id)).getProductId) &&
@ ((Customer)getMessage(id).getPerson1()).receivedAdv((BuyMessage)getMessage(id)).getProducerId,
@ (BuyMessage)getMessage(id)).getProductId)) &&
@ assignable people[*].socialValue, messages;
@ assignable people[*].messages;
@ assignable getMessage(id).getPerson1().money,getProduct((BuyMessage)getMessage(id)).getProductId)).sales;
@ ensures getProduct((BuyMessage)getMessage(id)).getProductId))).sales == \old(getProduct((BuyMessage)getMessage(id)).getProductId))).sales) + getMessage(id).getGroup().getSize() * getProduct((BuyMessage)getMessage(id)).getProductId))).productPrice * ((BuyMessage)getMessage(id)).getProductNum);
@ ensures getMessage(id).getPerson1().money == \old(getMessage(id).getPerson1().money) - getMessage(id).getGroup().getSize() * getProduct((BuyMessage)getMessage(id)).getProductId))).productPrice * ((BuyMessage)getMessage(id)).getProductNum);
@ 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());
@ ensures (\forall Person p; \old(getMessage(id)).getGroup().hasPerson(p);
@ (\forall int i; 0 <= i && i < \old(p.getMessages().size());
@ p.getMessages().get(i+1) == \old(p.getMessages().get(i)))) &&
@ p.getMessages().get(0).equals(\old(getMessage(id)))
@ && p.getMessages().size() == \old(p.getMessages().size()) + 1);
@ also
@ public exceptional_behavior
@ signals (MessageIdNotFoundException e) !containsMessage(id);
@ signals (NotBuyMessageException e) containsMessage(id) && !(getMessage(id) instance of BuyMessage);
@ signals (CustomerNotReference) containsMessage(id) && (getMessage(id) instance of BuyMessage) &&
@ !((Customer)getMessage(id).getPerson1()).containsPreference((BuyMessage)getMessage(id)).getProductId)
@ signals (CustomerNotReceivedAdv) containsMessage(id) && (getMessage(id) instance of BuyMessage) &&
@ ((Customer)getMessage(id).getPerson1()).containsPreference((BuyMessage)getMessage(id)).getProductId) &&
@ !((Customer)getMessage(id).getPerson1()).receivedAdv((BuyMessage)getMessage(id)).getProducerId,
@ (BuyMessage)getMessage(id)).getProductId))
@ signals (RelationNotFoundException e) containsMessage(id) && (getMessage(id) instance of BuyMessage) &&
@ ((Customer)getMessage(id).getPerson1()).containsPreference((BuyMessage)getMessage(id)).getProductId) &&
@ ((Customer)getMessage(id).getPerson1()).receivedAdv((BuyMessage)getMessage(id)).getProducerId,
@ (BuyMessage)getMessage(id)).getProductId))
@ getMessage(id).getType() == 0 && !(getMessage(id).getPerson1().isLinked(getMessage(id).getPerson2()));
@ signals (PersonIdNotFoundException e) containsMessage(id) && (getMessage(id) instance of BuyMessage) &&
@ ((Customer)getMessage(id).getPerson1()).containsPreference((BuyMessage)getMessage(id)).getProductId) &&
@ ((Customer)getMessage(id).getPerson1()).receivedAdv((BuyMessage)getMessage(id)).getProducerId,
@ (BuyMessage)getMessage(id)).getProductId))
@ getMessage(id).getType() == 1 && !(getMessage(id).getGroup().hasPerson(getMessage(id).getPerson1()));
@*/
public void buyMessage2Adv(int id) throws NotBuyMessageException,CustomerNotReference,CustomerNotReceivedAdv
MessageIdNotFoundException, RelationNotFoundException, PersonIdNotFoundException;
queryProductSales
/*@ public normal_behavior
@ requires containsProducer(id);
@ assignable \nothing;
@ ensures \result == getProducer(id).sales;
@ also
@ public exceptional_behavior
@ signals (ProducerIdNotFoundException e) !containsProducer(id1));
@*/
public int queryProductSales(int id) throws
ProducerIdNotFoundException;
(5) 本单元学习体会
不能为了追求方便就死板地按照JML描述来实现方法,要从根本去理解JML撰写者的意图,从而在保险和高效之间找到一个平衡点去实现。