alloy - 处理 Alloy 中的映射

标签 alloy mappings

我试图在 Alloy 中生成两组类,例如,重构应用程序之前的类和重构应用程序之后的类。假设在第一组中我们有以下类:

a -> br -> cr
           class1
           class2

这意味着 a 是 br 的父级,而 br 又是 cr、class1 和 class2 的父级。

另一方面,按照相同的推理,我们在第二组中有以下一组类:

a -> bl -> cl 
           class1
           class2

类 br、bl、cr 和 cl 是实际参与重构的类。另外,br和bl实际上是相同的类(并且具有相同的标识)但是时间顺序不同(不同的状态),还有cr和cl。所表示的重构是下推方法的简化,其中方法从 br 类下推到 cl 类。

支持此转换的模型的简化如下:

open util/relation

abstract sig Id {}

sig ClassId, MethodId, FieldId extends Id {}

abstract sig Accessibility {}

one sig public, private_, protected extends Accessibility {}

abstract sig Type {}

abstract sig PrimitiveType extends Type {}

one sig Long_ extends PrimitiveType {}

abstract sig Class {
    extend: lone ClassId,
    methods: MethodId -> one Method,
    fields: set Field
}

sig Field {
    id: one FieldId,
    type: one Type,
    acc : one Accessibility,
}

sig Method {
    return: lone Type,
    acc: one Accessibility,
    body: seq Statement
}

abstract sig Expression {}
abstract sig Statement{}

abstract sig PrimaryExpression extends Expression {
}

one sig this_, super extends PrimaryExpression {}

sig newCreator extends PrimaryExpression {
    id_cf : one ClassId
}

sig MethodInvocation extends Statement{
    pExp: one PrimaryExpression,
    id_methodInvoked: one MethodId
}

sig Program {
  classDeclarations: ClassId -> one Class
}

pred wellFormedProgram [p:Program] {

    all c:ClassId | c in (p.classDeclarations).univ => wellFormedClass[p, c]
}

pred wellFormedClass[p:Program, c:ClassId] {

   let class = c.(p.classDeclarations) {
          all m:Method, mId:MethodId | m = mId.(class.methods) => wellFormedMethod[p, class, m, mId]
    }
}

pred wellFormedMethod[p:Program, c:Class, m:Method, mId:MethodId]{

    let body = (m.body).elems
    {
         all stm : Statement | stm in body => wellFormedStatement[p, c, stm]
    }

}

pred wellFormedStatement[p:Program, c:Class, st:Statement]{
      st in MethodInvocation => wellFormedMethodInvocation[p,c,st/*,m.param*/]    
}

pred wellFormedMethodInvocation[p:Program, c:Class, stm: MethodInvocation] {
     stm.pExp in PrimaryExpression => wellFormedPrimaryExpression[p, c, stm.pExp]

    let target = stm.pExp {
         target in newCreator => stm.id_methodInvoked in ((target.id_cf).(p.classDeclarations).*(extend.(p.classDeclarations)).methods).univ
         target in this_ => stm.id_methodInvoked in (c.*(extend.(p.classDeclarations)).methods).univ
         target in super => stm.id_methodInvoked in (c.^(extend.(p.classDeclarations)).methods).univ
    }
}

pred wellFormedPrimaryExpression[p:Program, c:Class, stm: PrimaryExpression] {
     stm in newCreator => classIsDeclared[p, stm.id_cf]
}

pred classIsDeclared[p:Program, c:ClassId] {
      let cds = p.classDeclarations {
         c in cds.univ
     }
}

pred law14RL[b, c:ClassId, mId:MethodId, left, right: Program] {
    wellFormedProgram[right]

    let leftCds = left.classDeclarations, 
         rightCds= right.classDeclarations,
         bl = b.leftCds,
         br = b.rightCds, 
         cl = c.leftCds,
         cr = c.rightCds,
         mRight = mId.(br.methods),
         mLeft = mId.(cl.methods)
         {
             mRight = mLeft

             cr.extend = b
              cl.extend = b
              bl.extend = br.extend
              leftCds = rightCds ++ {b -> bl} ++ {c -> cl}

              all c:{Class - br - cl} | mId !in (c.methods).univ

             cl.fields = cr.fields
              bl.fields = br.fields         

              bl.methods = br.methods - {mId -> mRight}
              cl.methods - {mId -> mLeft} = cr.methods
    }
}

assert law14Prop {
 all b, c:ClassId, mId:MethodId, left, right: Program |
          law14RL[b, c, mId, left, right] implies wellFormedProgram[left]
}

check law14Prop for 15 but exactly 2 Program

看到谓词 law14RL 描述了转换本身以及 b 和 c 类的等价性(通过比较它们的方法和字段 - 在该谓词的末尾)。我们看到b类之间唯一的区别是br类中的方法mRight;同样,方法mLeft存在于cl类中,但不存在于cr类中。创建断言 law14Prop 是为了返回 Alloy 实例,该实例描述由于方法移动而出现编译错误问题(在转换的结果端)的程序表示。

例如,假设 br 类中有一个方法 m',其主体包含类似 this.mId() 的语句。如前所述,mId 表示 mRight 方法的标识。此语句会导致 bl 类中出现编译错误,因为方法 m' 也存在于该类中,但由 mId 标识表示的方法(方法 mLeft)位于 cl 类中相反。

重点(问题)是这个模型没有返回任何反例,我不明白为什么。我做错了什么?

奇怪的是,当我用set Method(而不是MethodId -> Method)替换sig Class中的关系methods时em>) - 当然,在模型中进行所需的修改 - 返回计数器示例。

最佳答案

这个问题存在于非常详细(且涉及)的上下文中,因此最好尝试分解它并缩小问题的潜在来源范围。

Curiously, when i replace the relation methods in sig Class by set Method (instead of MethodId -> Method) - and of course do the required modifications in the model - counter examples are returned.

这对我来说确实很好奇,因为事实证明,这两个公式(加上一些附加约束)确实应该表现相同,以您对模型所做的其他更改为模。 我试图强制执行额外的约束,这些约束确实应该使这两个公式等效(或者可能前者更强),但我没有设法获得反例:

// all method Ids must map to same actual methods
fact methodsIdUnique {
    all a,b: Class, mId: MethodId |
        all m1: mId.(a.methods) |
        all m2: mId.(b.methods) |
        m1 = m2
}

// there cannot be two different Ids that map to the same method
fact methodsIdUnique {
    all a: Class, mId1: MethodId, mId2: MethodId, m: Method |
        m = mId1.(a.methods) && m = mId2.(a.methods) implies
            mId1 = mId2
}

// this is too strong, wrt to your description
fact methodsExist {
    all a,b: Class, mId: MethodId |
        some mId.(a.methods) &&
        some mId.(b.methods)
}

因此,您所做的更改可能会更改模型的语义(并使其返回计数器示例)。 请注意,一种可能性是搜索域完全适合模型的一种表述,但不适合另一种表述(因此,例如宇宙不够大,无法在后一种情况下发现反例),但我怀疑这里的情况是否如此。

无论如何,我建议尽可能缩小约束范围,直到求解器开始给出反例(再次,正如您提到的)。

关于alloy - 处理 Alloy 中的映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39584681/

相关文章:

alloy - 4.2 中的语义变化?

java - Alloy API 导致 java.lang.UnsatisfiedLinkError

alloy - util/Natural 合金中的意外行为

Java Spring Hibernate,运行时是否可选地执行映射?

合金分子式翻译

alloy - 了解合金基数

templates - 如何定义ElasticSearch动态模板?

VIM:视觉线模式的映射

未创建/复制 TypeScript 键入文件