英文:
How to specify "global" frame condition in Alloy6?
问题
玩具示例:
假设我有一个"员工"的概念,他可以登录到"机器",并可以出现在"机器"或"测量室"。"机器"可以处于多个状态之一:未登录,工作和测量。"机器"当前有一个活跃的工具和其他工具,这些工具在模型的不同部分改变活动(只是为了有更大的框架条件而包含在示例中)。
然后我指定了初始状态,在此状态下"员工"处于"未在工作"状态。
fact init {
Employee.location = NotAtWork
no Machine.login
Machine.state = NoLogin
Machine.tools = Tool
no Machine.activeTool
}
最后,不同状态之间的转换(例如,登录,开始测量和结束测量):
pred login {
Machine.state = NoLogin // 保护条件。
// 影响:
Machine.state' = Work
Machine.login' = Employee
Employee.location' = Machine
}
pred measuring_begin {
Machine.state = Work // 保护条件。
// 影响:
Machine.state' = Measuring
Employee.location' = MeasureRoom
// 框架条件 - **如何使这些更简洁?**:
Machine.login' = Machine.login
Machine.tools' = Machine.tools
Machine.activeTool' = Machine.activeTool
}
pred measuring_end {
Machine.state = Measuring // 保护条件。
// 影响:
Machine.state' = Work
Employee.location' = Machine
// 框架条件 - **如何使这些更简洁?**:
Machine.login' = Machine.login
Machine.tools' = Machine.tools
Machine.activeTool' = Machine.activeTool
}
fact transition {
always (
login or measuring_begin or measuring_end
)
}
run example {
eventually measuring_end
}
更具体地说,是否可能编写简洁的框架条件,以确保新状态与先前状态相同,除了影响之外?我理解可能不可能,因为谓词(如果我理解正确)不会改变状态,而只是指定可能未来状态的搜索条件。
英文:
I am trying to model temporal process using for reference Formal Software Design with Alloy 6 - Protocol design chapter. I would like to know how to make frame conditions in predicates less verbose.
Toy example:
Let's say that I have concept of Employee who can be logged into Machine and can be present at Machine or in MeasureRoom. Machine can be in one of multiple states: NoLogin, Work and Measuring. Machine has currently active Tool and other Tools, which change activity in different part of model (included in example just to have bigger frame conditions).
enum MachineState { NoLogin, Work, Measuring }
abstract sig Location {}
some sig Tool {}
one sig Machine extends Location {
var login: lone Employee,
var state: one MachineState,
var tools: some Tool,
var activeTool: lone Tool
}
one sig NotAtWork extends Location {}
one sig MeasureRoom extends Location {}
one sig Employee {
var location: one Location
}
Then I specify initial state, in which Employee is NotAtWork.
fact init {
Employee.location = NotAtWork
no Machine.login
Machine.state = NoLogin
Machine.tools = Tool
no Machine.activeTool
}
Finally transitions between different states (for example, login, measuring_begin and measuring_end):
pred login {
Machine.state = NoLogin // Guard condition.
// Effects:
Machine.state' = Work
Machine.login' = Employee
Employee.location' = Machine
}
pred measuring_begin {
Machine.state = Work // Guard condition.
// Effects:
Machine.state' = Measuring
Employee.location' = MeasureRoom
// Frame conditions - **how to make these less verbose?**:
Machine.login' = Machine.login
Machine.tools' = Machine.tools
Machine.activeTool' = Machine.activeTool
}
pred measuring_end {
Machine.state = Measuring // Guard condition.
// Effects:
Machine.state' = Work
Employee.location' = Machine
// Frame conditions - **how to make these less verbose?**:
Machine.login' = Machine.login
Machine.tools' = Machine.tools
Machine.activeTool' = Machine.activeTool
}
fact transition {
always (
login or measuring_begin or measuring_end
)
}
run example {
eventually measuring_end
}
So more concretely, is it possible to write concise frame condition, that would ensure that new state is identical to previous one except for effects? I understand it may not be possible, since predicates (if I understand correctly), do not mutate state, but just specify search criteria for possible future states.
答案1
得分: 2
你说得对,谓词(对事件进行编码)只是约束了未来的状态。由于约束可以是任意公式,因此似乎不可能从效果中推断出帧条件。一个解决方案,目前在Alloy中尚未实现,并且会大幅改变语言,是以某种方式限制效果的语法,使所述推断成为可能。
与此同时,有一些简化帧条件的方法。例如,你可以依赖于宏来定义一个unchanged
关键字(宏是一种脆弱的、无类型的、带参数的表达式或约束)。例如:
let unchanged[r] { ((r) = (r)') } // 注意括号
pred measuring_begin {
...
// 帧条件
unchanged[Machine.login]
unchanged[Machine.tools]
unchanged[Machine.activeTool]
}
在你的情况下,因为只有一个Machine
,你甚至可以摆脱Machine.
部分,直接写成unchanged
。
另一种方法是依赖于Reiter风格的帧条件(参见例如Daniel Jackson的这些幻灯片(在Alloy 4中))。在这种方法中,你可以在全局事实中编写帧条件,说明如果关系r
发生变化,那只能是因为这个或那个事件。例如对于login
:
fact {
always {
(unchanged[Machine.login] or login)
(unchanged[state] or login or measuring_begin or measuring_end)
...
}
}
根据事件是否改变了许多状态变量,局部帧条件与全局Reiter风格帧条件中的一个将比另一个更短。
最后,如果你的模型中有非one
签名,通常可以在单个约束中表达对字段的效果和帧条件。参见这里的"指定全局效果"部分2。
编辑:修复了一个拼写错误。
英文:
You're right that predicates (encoding events) just constrain future states. And because constraints can be arbitrary formulas, it seems impossible to infer frame conditions out of effects. One solution, not currently implemented in Alloy and which would change the language a lot, would be to restrict the syntax of effects in such a way that the said inference would be possible.
Meanwhile, there are a few approaches to simplify your frame conditions. For instance, you can rely on a macro to define an unchanged
keyword (macros are a fragile, untyped, parametrized expressions or constraints). E.g.:
let unchanged[r] { ((r) = (r)') } // mind the parentheses
pred measuring_begin {
...
// Frame conditions
unchanged[Machine.login]
unchanged[Machine.tools]
unchanged[Machine.activeTool]
}
In your case, as there's only one Machine
, you may even get rid of the Machine.
part and write unchanged
.
Another approach is to rely on Reiter-style frame conditions (see e.g. these slides by Daniel Jackson (in Alloy 4)). In this approach, you write frame conditions, in a global fact, saying that if relation r
changes, it's only because of this or that event. E.g. for login
:
fact {
always {
(unchanged[Machine.login] or login)
(unchanged[state] or login or measuring_begin or measuring_end)
...
}
}
Depending on whether events change a lot of state variables or not, one out of local frame conditions vs. global Reiter-style frame conditions will be shorter than the other.
Finally, if you have non-one
sigs in your model, you can often express an effect and a frame condition on a field in a single constraint. See the box "Specifying global effects" here.
EDIT: fixed a typo.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论