2017-11-04 6 views
1

나는 LRU 캐시 시스템을 정의하려고 시도하고있는 스펙을 가지고 있는데, 그 중 하나는 구조 키/값 쌍 (기본적으로 사전 또는 해쉬 된 값)에서 값을 삭제하는 방법이다. 다른 언어로 된지도).TLA + : 구조 키/값 쌍을 삭제하는 방법?

EXTENDS Integers, Sequences 
VARIABLES capacity, currentSize, queue, dictionary 

Init == /\ (capacity = 3) /\ (currentSize = 0) 
     /\ (queue = <<>>) /\ (dictionary = []) 


AddItem(Item, Value) == IF currentSize < capacity 
      THEN /\ currentSize' = currentSize + 1 
       /\ queue' = Append(queue, Item) 
       /\ dictionary[item] = value 
      ELSE /\ queue' = Append(Tail(queue), Item) 
       /\ dictionary' = [x \in dictionary: x /= queue[3]] 

GetItem(Item) == dictionary[item] 

Next == \/ AddItem 
     \/ GetItem 

내가 this documentation on the Learn TLA Plus 웹 사이트를 참조하지만, 목록에서 키 값 쌍을 제거에 아무 것도 없을 것 같다되었다 : 여기

은 사양까지 (불완전) 자체입니다. 지금까지 내가 생각할 수있는 유일한 방법은 키와 일치하는 값을 걸러 내고 새 사전 객체를 만드는 것이 었습니다. 그러나 좀 더 직접적인 접근이 가능한 메소드를 선호했습니다.

+0

가이드는 여기에 문제를 제기,이 구조를 설명하는 방법에 오해의 소지가있다 : https://github.com/hwayne/ learntla/issues/41 – Hovercouch

답변

2

내가 대답 할 수 있기 전에 다른 질문을해야합니다. '값 삭제'란 무엇을 의미합니까? TLA +는 프로그래밍 언어가 아닙니다. 사양 언어입니다. 즉, 자신이하는 일에 대해 아주 명확하게 이해하고있는 것입니다. 그럼 삭제에 대해 이야기 해 봅시다.

TLA +의 두 가지 복잡한 컬렉션은 집합과 기능입니다. 함수는 값의 일부 요소 인 도메인을 매핑합니다. 구조와 시퀀스는 함수에 대한 문법적 당당한 것입니다 : 구조의 도메인은 고정 키이고 시퀀스의 도메인은 1..n, n \in Nat입니다. 함수에는 도메인이 있어야합니다. 구조체에서 키를 '삭제'하려면 구조체 도메인에서 키를 '삭제'해야합니다.

해당 작업이 시퀀스의 꼬리를 잡습니다. Lamport는 341 페이지의 Specifying Systems에 대해 TLA + Toolbox에 포함되어 있다고 정의합니다. 여기서 (--slightly 링크 된 버전에서 수정 Sequences.tla 표준 모듈에서) 정의이다 : 다른 말로

Tail(seq) == [i \in 1 .. (Len(seq) - 1) |-> seq[i + 1]] 

는 시퀀스의 꼬리를 제거 마지막 요소와 하나의 오프셋 시퀀스를 구성하여 정의 . 함수의 도메인에서 무언가를 제거하는 것은 동일한 기능을 구성함으로써 '완료'되며 도메인에있는 하나의 요소를 제거합니다. 생각해 보면 이해할 만합니다. 숫자 7을 변형 할 수있는 것 이상으로 수학 함수를 변형 할 수는 없습니다.

그런 다음 TLA +에서 몇 가지 편리한 구문을 추가 할 정도로 기존 함수의 새로운 함수를 구성해야합니다. . 함수에서 단일 매핑을 변경하려면 EXCEPT이 있어야합니다. 새로운 매핑을 추가하기 위해 TLC 모듈은 @@ 연산자를 추가합니다. 매핑을 삭제하는 것은 일반적으로 사람들이하는 일이 아니므로 직접 정의해야합니다. dictionary[item] = value는 평등을 확인하지 할당입니다 : 당신은 사전에 추가하는 당신의 방법이 잘못

dictionary' = [x \in DOMAIN dictionary \ {item} |-> dictionary[x]] 

주처럼 뭔가를해야 할 것입니다. dictionary'[item] = value은 모두 dictionary을 지정하지 않았기 때문에 작동하지 않습니다. 당신은

dictionary' = [x \in {item} |-> value] @@ dictionary 

같은 뭔가를해야 (또는 TLC 모듈 또한, :>를 사용) 우리가 잘못된 길을 가고있는 것처럼 맛이 있습니다이 시점에서

것, 아마 간단한 방법이있다 변화하는 dict를 지정하십시오. 귀하의 사양은 귀하의 키의 구현 세부 사항에 의존하지 않는다고 생각합니다 : 키 대신 정수를 사용하는 경우 캐시의 동작이 바뀔 것으로 예상하지 않습니다.이 경우, 나는 우리가이 같은 변이를 정의 할 수 있습니다 키와 값의 임의의 집합을 지정하는 것 : dict[key] = NULL 해당 키 사전에없는을 나타냅니다

CONSTANTS Keys, Values, NULL 
VARIABLE dict \* [key \in Keys |-> NULL] 

Add(dict, key, val) == [dict EXCEPT ![key] = val] 
Del(dict, key, val) == [dict EXCEPT ![key] = NULL] 

.

이것은 일반적으로 초보자를위한 PlusCal을 권장하는 이유 중 하나입니다. 그 이유는 사양의 기본 사항을 배우는 동안 기능을 변경하는 방법을 염려 할 필요가 없기 때문입니다. 당신이 pluscal 알고리즘을 쓰고 있다면, dict[key] := val으로 dict을 돌연변이시킬 수 있습니다.

+0

이것은 매우 도움이되었는데, 아직도 배울 점이 많음을 보여줍니다. 고맙습니다. –

1

@ Hovercouch의 답변에 추가 : "삭제"는 프로그래밍 언어와 달리 TLA + 사양의 의미와 일치하지 않습니다. VARIABLE 같은 dictionary 선언

dictionary은 (nullary)를 인수가없는 운영자의 식별자이며, 동작 이상 값을 변경할 수 있다고 ("시간 경과"). 그것은 다른 말을하지 않습니다.

단계를 살펴보면 (a 동작의 연속적인 상태의 켤레) (제 1 상태)에서 dictionary 값 및 dictionary' (제 2 상태에서의 dictionary)의 [1, p.313] 무관하다. 규격에서 표현 된 제약 조건을 통해서만 우리는 그 값을 제한 할 수있다. 상태 dictionary = [x \in {"foo", "bar"} |-> x]의 경우

다음 dictionary' (즉 ZF 어떤 값, 임의의 집합) 것도 될 수있다. [1, 초. 6.5, p.72, Sec. "하지 마라."(p.80, pp.139-140). 실제로 dictionary이 값 "foo"에 값 "foo" 매핑하기 때문에

이러한 상태에서 상태 술어

dictionary["foo"] = "foo" 

의 값은 TRUE입니다. 반대로, 상태 술어 :

dictionary["foo"] = "bar" 

"foo" # "bar" 때문에 FALSE이다. 첫 번째로 그 상태와 단계에서, 우리는 쓰기 ([1, P.82]도 참조)

(dictionary["foo"] = "foo")' 

을 우리가 표현 dictionary["foo"]다음 상태에서 "foo"에 해당 것만 말하고있다. 우리는 dictionary이 그 상태에있는 함수라고 말하지 않았습니다. 단지 dictionary["foo"]"foo"과 같아지는 값입니다. 어쩌면 dictionary은 그곳의 기능이 아닙니다.

기능이란 무엇입니까?

언제 주어진 값 f을 "함수"라고 부릅니까? 그 f 운영자 IsAFunction가 [1, p.303]로 정의되는 화학식 IsAFunction(f) 만족 일어나는 경우 대답은 :

IsAFunction(g) == g = [x \in DOMAIN g |-> g[x]] 

튜플 ("배열")는 일부 n \in Nat위한 도메인 1..n과 기능은. TLA +에서 함수는 단순히 위 속성을 갖는 값입니다.ZF의 모든 값은 집합이므로, 함수는 집합이며, f이 [1, 위의 초] 함수 인 경우에도 y \in f을 쓸 수 있습니다. 4.5 절, p.33 절, 3.3 절 p30 절]. 우리가 모르기 때문에

---- MODULE test ---- 
EXTENDS TLAPS 

f == [x \in {} |-> x] 
g == [x \in {1, 2} |-> 3] 

THEOREM 
    LET 
     S == f \cup {g} 
    IN 
     (1 \in f) => (1 \in S) 
    PROOF BY Zenon 
    (* you can replace this with OBVIOUS *) 
===================== 

(모델 검사기 TLC이 열거 상태를, 그리고 :

예를 들어, 정리의 증명 TLAPS으로 우리는 다음과 같은 정리를 증명할 수 tlapm -v -C test.tla을 실행하여 Isabelle를 사용하여 증거를 확인 어떤 요소가 한 세트의 함수로 포함되어있는 경우, TLC는 표현식 y \in f을 평가할 수 없으며 Error: Attempted to check if the value: ... is an element of the function ...을 발생시킬 수 있습니다. 구문 분석기 SANY은 위 모듈의 형식이 올바른지 확인합니다.

f이 함수가 아니거나 x \notin DOMAIN f 일 때 f[x]이라고 쓸 수도 있습니다. 문제는 그러한 경우에 f[x]의 값이 지정되지 않았으므로 사양은 값이 무엇인지에 따라 달라져서는 안됩니다. 사양

표현 dictionary = []

댓글은 TLA +의 일부가 아닙니다. 이 의도되어 있기 때문에,

dictionary = [x \in {} |-> TRUE] 

가 나는 CONSTANT으로 capacity를 선언합니다 : 빈 도메인과 기능을 쓰려면 (정확히 하나의 기능이있는 것은, 기능 extensionality [1, p.303]에 대한 공리 참조) (물론 변경되지 않는 한) 행동에 대해 변함없이 유지됩니다. 또한 currentSize은 사양에 따라 감소하지 않지만 아직 추가되지 않았다고 가정합니다.

또한 dictionary은 각 항목을 고유 한 값으로 매핑하지만 queue은 동일한 항목의 여러 복사본을 포함 할 수 있습니다. OP가이 사건을 위해 의도하는 것이 확실하지 않습니다.

EXTENDS Integers, Sequences 


CONSTANT capacity 
VARIABLES currentSize, queue, dictionary 


Init == /\ (capacity = 3) /\ (currentSize = 0) 
     /\ (queue = <<>>) /\ (dictionary = [x \in {} |-> TRUE]) 

AddItem(Item, Value) == 
    IF currentSize < capacity 

     (* Overwrite to what value the dictionary maps 
     the value. *) 
     THEN /\ currentSize' = currentSize + 1 
      /\ queue' = Append(queue, Item) 
      /\ dictionary' = 
        [x \in DOMAIN dictionary |-> 
         IF x = Item 
          THEN Value 
          ELSE dictionary[x]] 

     (* Remove the leading item from the dictionary's domain, 
     then add the given item (perhaps the same), and 
     map it to the given value. *) 
     ELSE /\ queue' = Append(Tail(queue), Item) 
      /\ LET 
        (* It can happen that OldDom = NewDom. *) 
        OldDom == DOMAIN queue 
        first == queue[1] 
        TailDom == OldDom \ { first } 
        NewDom == TailDom \cup {Item} 
       IN 
        dictionary' = 
         [x \in NewDom |-> 
          IF x = Item 
           THEN Value 
           ELSE dictionary[x]] 

GetItem(Item) == dictionary[item] 

Next == \/ AddItem 
     \/ GetItem 

dictionary' = [x \in DOMAIN dictionary |-> 
       IF x = Item THEN Value ELSE dictionary[x]] 

식 [1, P.49]

dictionary' = [dictionary EXCEPT ![Item] = Value] 

dictionary' = [x \in NewDom |-> 
       IF x = Item THEN Value ELSE dictionary[x]] 

EXCEPT로 대체 할 수없는 식으로 대체 될 수있다.

참조

[1] 레슬리 램 포트, "Specifying systems", 애디슨 - 웨슬리 2002

+0

"ZF의 모든 값은 집합이므로, 함수가 세트인데, f가 함수 일 때 f에서 y를 쓸 수 있습니다."내가 틀렸다면 수정하십시오. 그러나 TLC로 모델을 확인할 수 있습니까? 방금 시도했는데 오류가 발생했습니다. – Hovercouch

+1

어떤 값이라도'IsAFunction (f)'를 만족시키는'f' 값을 포함한 집합입니다. [회원 자격 설정] (https : //en.wikipedia.org/wiki/Element_ (mathematics)) 연산자'_ \ in _'는 두 개의 인자 (집합체 - 집합체 이외에는 아무것도 없습니다)에 적용됩니다. 그래서 우리는'y \ in f'라고 쓸 수 있습니다 (p.43과 p.30 참조). TLC는'f'의 원소를 모르기 때문에 이것을 열거 할 수 없습니다. 정리 해설자 TLAPS는 그러한 공식을 포함하는 정리를 증명할 수 있으며 (위의 예제를 추가했습니다), 구문 분석기 SANY는 예제가 구문 적으로 잘 형성되어 있음을 확인합니다. –

+0

나는 꽤 많은 독서를해야한다. LRU 캐시를 구현하는 것이 단순한 예제 일 것이라고 생각했지만, 이는 내가 아직도 무엇을하고 있는지 전혀 알 수 없음을 보여줍니다. –

관련 문제