TLA +序列未通过Append或Tail调用进行更新

时间:2019-01-07 00:26:51

标签: tla+

问题

我正在玩TLA+,并认为我会在PlusCal中编写以下明显错误的规范:

telephone

在将---- MODULE transfer ---- EXTENDS Naturals, TLC, Sequences (* --algorithm transfer \* Simple algorithm: \* 1. Start with a shared-memory list with one element. \* 2. A process adds arbitrary numbers of elements to the list. \* 3. Another process removes arbitrary numbers of elements from the list, \* but only if the list has more than one item in it. This check is \* applied just before trying to removing an element. \* Is it true that the list will always have a length of 1? \* You would expect this to be false, since the adder process can add more elements \* than the remover process can consume. variables stack = <<0>> process Adder = 0 begin AddElement: stack := Append(stack, Len(stack)); either goto AddElement or skip end either; end process; process Remover = 1 begin RemoveElement: \* Pop from the front of the stack if Len(stack) > 1 then stack := Tail(stack); end if; either goto RemoveElement or skip end either; end process; end algorithm *) IsStackAlwaysUnitLength == Len(stack) = 1 ==== 作为要报告的时间属性之一后,我希望TLA +将此属性标记为失败。

但是,所有状态都通过了!为什么它不会失败?

调试尝试

在使用IsStackAlwaysUnitLength语句进行调试时,我注意到以下奇怪行为:

print

在调试面板中显示产量

process Adder = 0
  begin
      AddElement:
        print stack;
        print "Adder applied!";
        stack := Append(stack, Len(stack));
        print stack;
        print "Adder task complete!";
        \* Force 
        either goto AddElement
        or skip
        end either;
end process;

process Remover = 1
  begin
      RemoveElement:
        \* Pop from the front of the stack
        print stack;
        print "Remover applied!";
        if Len(stack) > 1 then
            stack := Tail(stack);
            print stack;
            print "Remover task complete!";
        else
            print "Remover task complete!";
        end if;
        either goto RemoveElement
        or skip
        end either;
end process;

我不确定为什么<<0>> "Adder applied!" <<0>> "Adder task complete!" <<0>> <<0>> "Remover applied!" "Remover applied!" "Remover task complete!" "Remover task complete!" <<0>> "Adder applied!" <<0>> "Adder task complete!" stack := Append(stack, Len(stack));没有更新全局stack := Tail(stack);变量。

已生成完整的TLA规范

stack

1 个答案:

答案 0 :(得分:2)

恭喜,您遇到了PlusCal错误!而且这不是一个漏洞,但仍然不直观。让我们从错误开始。

有时使用PlusCal时,我们希望多个进程共享标签。我们通过过程来实现。为了使其全部正常工作,PlusCal转换器添加了一个额外的簿记变量,称为stack通常,如果用户定义的变量foo与生成的变量foo冲突,则转换会将其重命名为foo_。在这种情况下,由于没有冲突,因此没有任何重命名。*错误在于,翻译人员感到困惑,并翻译了变量,好像被认为是簿记{{1} }。您可以看到它将附加变成

stack

什么时候应该出现

stack' = [stack EXCEPT ![0] = Append(stack, Len(stack))]

您可以通过将stack' = Append(stack, Len(stack)) 重命名为stack来解决此问题。这样可以正确显示规范。但是它仍然会通过:那是因为您将mystack当作属性而不是不变。作为时间属性,IsStackAlwaysUnitLength如果在初始状态下为true,则为true。作为不变式,IsStackAlwaysUnitLength all 状态下都是正确的。**通过将IsStackAlwaysUnitLength从时态属性更改为IsStackAlwaysUnitLength,可以使规范正确失效。 “什么是模型”页面中的。

*实际上,在这种情况下,如果添加过程,翻译器将不会重命名stack,而只会引发错误。但这仍然是安全的。

**这是因为TLC(模型检查器)将不变的P视为时间属性[]P。基本上是语法糖。