只要要对对象进行任何服务,我都想更改其服务代码。假设,只要有一个应用于对象的操作,该对象的服务代码将为1,而当执行另一个操作时该服务代码将为2。我想将最新的服务代码保存到每个对象。不幸的是,我无法很好地设计谓词,这就是为什么从合金中获取谓词不一致的信息的原因。
我尝试了一些用于将服务代码分配给每个对象的代码。完整的代码如下所示-
open util/ordering[Environment]
abstract sig Object{
name: String,
serviceCode: Int,
}{
serviceCode >= 0 and serviceCode <= 3
}
// Events
enum Event {Event1, Event2, Event3}
abstract sig Condition{
name: Event,
object: Object
}
abstract sig BaseOperation{
name: Event,
object: Object
// it will have more attributes than Condition later
}
abstract sig Connector{
condition: Condition,
baseOperation: BaseOperation,
}
sig Environment{
ev : set Event
}
pred execute [u:Environment, u':Environment, r:Connector] {
some e: u.ev | {
e = r.condition.name =>
u'.ev = u.ev + r.baseOperation.name
else
u'.ev = u.ev
}
}
fact {
all u:Environment-last, u':u.next, r:Connector {
execute [u, u', r]
}
}
sig Object1 extends Object{
}{
name = "Object1 Object"
}
sig Object2 extends Object{
}{
name = "Object2 Object"
}
sig Condition1 extends Condition{
}{
name = Event1
object = Object2
object.serviceCode = 1
}
sig Operation1 extends BaseOperation{
}{
name = Event2
object = Object1
object.serviceCode = 1
}
sig Operation2 extends BaseOperation{
}{
name = Event3
object = Object1
object.serviceCode = 0
}
one sig Connector1 extends Connector{
}{
condition = Condition1
baseOperation = Operation1
}
one sig Connector2 extends Connector{
}{
condition = Condition1
baseOperation = Operation2
}
fact {
Event3 !in first.ev &&
Event2 !in first.ev
}
run {Event1 in last.ev} for 10
当我只有一个操作链接到一个对象时,以上代码可以正常工作。我已经为其附上了图here。只要进行了多个操作,合金就会找不到实例。在设计合金代码以实现我的目标时需要帮助。
另一种可能的方法可能是-我们可能有一个服务代码列表,而不是一个服务代码。考虑时间戳以及每个服务代码。然后在需要的时候找出最新的服务代码。我们可以使用最大时间戳的服务代码。但是我不确定如何用合金设计。
答案 0 :(得分:0)
我认为您应该看看丹尼尔·杰克逊的书。 Alloy不是具有可变分配的编程语言。基本上,它是关系上的规则引擎,可以生成 instance ,这是与这些规则匹配的一组关系。这意味着,如果需要可变分配,则需要一种表示关系中随时间变化的可变状态的方法。有两种方法:
Time
–使每个字段都有一个Time
列,其中Time
被排序。我觉得这很麻烦。 Electrum项目通过提供一个var
关键字,然后为您维护Time
列,使此操作变得更加容易。Trace
–除了将每个字段与Time
关联之外,还可以将关联置于有序的状态 sig
中。然后,该关系显示了值如何随时间变化。关键问题是您的问题描述与规格几乎完全断开。您先讨论服务,然后再讨论操作,它们是一样的吗? Event
和Connector
进入哪里?您的问题描述中从未提及它们?
让我们一一介绍:
我想更改对象
的服务代码
open util/ordering[Environment]
sig Object {}
enum ServiceCode { _1, _2 }
sig Environment {
object : Object -> ServiceCode
}
通常,您不希望将Ints用于服务代码之类的东西,因为它们会消耗状态空间。
Environment
是我们的状态。我们要为每个环境原子执行一个 Service 。
...只要对其进行了任何服务操作。
sig Service {
serviceCode : ServiceCode
}
pred execute[ e, e' : Environment, o : Object, s : Service ] {
e'.object = e.object ++ o -> s.serviceCode
}
假设,只要适用于 Object
,我就有一个 Operation
不清楚您对 Operation 的含义,我认为这是早期的 Service ?
...该 Object 的服务代码将为1,然后在 另一个 Operation 执行,则 ServiceCode 将为2。 我想将最新的服务代码保存到每个对象。不幸的是
pred trace {
no first.object
all t : Environment-last, t':t.next {
some o: Object, s : Service {
execute[t,t', o, s]
}
}
}
run trace
在表格视图中,您可以:
┌────────────────┐
│this/ServiceCode│
├────────────────┤
│_1⁰ │
├────────────────┤
│_2⁰ │
└────────────────┘
┌───────────┐
│this/Object│
├───────────┤
│Object⁰ │
├───────────┤
│Object¹ │
└───────────┘
┌────────────┬───────────┐
│this/Service│serviceCode│
├────────────┼───────────┤
│Service⁰ │_2⁰ │
├────────────┼───────────┤
│Service¹ │_2⁰ │
├────────────┼───────────┤
│Service² │_1⁰ │
└────────────┴───────────┘
┌────────────────┬───────────┐
│this/Environment│object │
├────────────────┼───────────┤
│Environment⁰ │ │
├────────────────┼───────┬───┤
│Environment¹ │Object¹│_2⁰│
├────────────────┼───────┼───┤
│Environment² │Object⁰│_1⁰│
│ ├───────┼───┤
│ │Object¹│_2⁰│
└────────────────┴───────┴───┘
使用Alloy时,首先要做的就是用简单的英语定义要指定的问题。然后,您可以将本文中的概念转换为Alloy构造。合金规格的目的是使其看起来像散文。