集合を要素とする集合

VDM++ の set 型には、「集合を要素とする」集合を定義できます。これに準拠した事例を紹介します。

    s1 = VDM_Set([1,2,3])
s2 = VDM_Set([4])
s3 = VDM_Set([])
s4 = VDM_Set([5,6])
print "s1:",s1
print "s2:",s2
print "s3:",s3
print "s4:",s4

ss = VDM_Set([s1,s2,s3,s4])
print ">>> VDM_Set([s1,s2,s3,s4])"
print ss

まず、4つの集合 s1/s2/s3/s4 を作成します。次に、これらを要素とする集合 ss を作成します。このコードを実行すると、

s1: {1, 2, 3}
s2: {4}
s3: {}
s4: {5, 6}
>>> VDM_Set([s1,s2,s3,s4])
{{4}, {1, 2, 3}, {}, {5, 6}}

4つの集合を要素とする集合が得られます。このとき、要素の順序には、意味がありません。

要素の帰属関係

VDM++ の set 型には、集合に対する要素の帰属関係を定義できます。数学の世界では、ある要素 e が集合 S に含まれるか否かを、e∈S および e∉S と表現します。これを VDM++ では、次のように表現します。

    3 in {3,1,2}                = true

整数 3 は、集合の要素に含まれるので、true になります。

    3 not in {3,1,2}            = false

整数 3 は、集合の要素に「含まれる」ので、false になります。

    0 not in {3,1,2}            = true

整数 0 は、集合の要素に含まれないので、true になります。

    {1,2} in {{1,2},{},{3}}     = true

集合 {1,2} は、集合の要素に含まれるので、true になります。このように「集合を要素とする」集合に対しても、要素の帰属関係を判定できます。

事例:演算 in

VDM++ での演算 in に準拠した事例を紹介します。

    s1 = VDM_Set(range(1,4))

e = 3
print ">>> %s in %s"%(e,s1)
X = e in s1
print X; assert X is True

e = 0
print ">>> %s in %s"%(e,s1)
X = e in s1
print X; assert X is False

任意の要素が「含まれる」ことを判定するには、演算子 in を利用します。このコードを実行すると、

>>> 3 in {1, 2, 3}
1
>>> 0 in {1, 2, 3}
0

整数 3 は、集合 s の要素に含まれますが、整数 0 は、その要素に含まれません。
《Note》Python 2.5.x では、bool 型の値は、True/False と表示されます。ただし、Jython 1.x/2.2.x では、それぞれ 1/0 と表示されます。□

    s1 = VDM_Set(range(1,4))

e = 3
print ">>> %s not in %s"%(e,s1)
X = e not in s1
print X; assert X is False

e = 0
print ">>> %s not in %s"%(e,s1)
X = e not in s1
print X; assert X is True

任意の要素が「含まれない」ことを判定するには、演算子 not in を利用します。このコードを実行すると、

>>> 3 not in {1, 2, 3}
0
>>> 0 not in {1, 2, 3}
1

整数 3 は、集合 s の要素に含まれませんが、整数 0 は、その要素に含まれます。

集合を要素とする集合についても、要素の帰属関係を判定できます。

    s0 = VDM_Set()
s1 = VDM_Set(range(1,2))
s2 = VDM_Set(range(2,4))
ss = VDM_Set([s0,s1,s2])

e = VDM_Set([2,3])
print ">>> %s in %s"%(e,s1)
X = e in ss
print X; assert X is True

e = VDM_Set([3])
print ">>> %s in %s"%(e,s1)
X = e in ss
print X; assert X is False

集合 ss は、3つの集合を要素とする集合です。このコードを実行すると、

>>> {2, 3} in {{}, {1}, {2, 3}}
1
>>> {3} in {{}, {1}, {2, 3}}
0

整数 {2,3} は、集合 ss の要素に含まれますが、整数 {3} は、その要素に含まれません。
《付記》集合 ss は、3つの集合を要素として含み、これらの(要素としての)集合の中には整数 3 を要素として含む集合があります。しかし、集合 {3} のように、整数 3 を要素とする集合は、これら(要素としての)3つの集合には含まれません。なぜなら、整数 3 と「整数 3 を要素とする」集合とは、別のオブジェクトだからです。これは、1つの文字と「1つの文字からなる」文字列とが、別のオブジェクトである状況と似ています。□

演算 in を実現する

VDM++ での演算 in に準拠するように、メソッド VDM_Set.__contains__ を実現します。

class VDM_Set:
def __contains__(s1,e):
"""
e in set s1
; A * set of A -> bool
;
; Membership
; tests if e is a member of the set s1

e not in set s1
; A * set of A -> bool
;
; Not membership
; tests if e is not a member of the set s1
"""
return e in s1.list

メソッド __contains__ では、演算子 in の動作を規定します。指定された e が、リスト s1.list に含まれるかを判定して、その結果をリターン値とします。
《Tips》演算子 in を実現するのに、Set 型で規定された他の演算子 in を再利用していることに注意してください。なぜなら、s1.list が VDM_Set のインスタンスなら、再帰的に __contains__ が呼び出される可能性があるからです。□
《Note》以前は、__contains__ 役割を __getitem__ が兼ねていました。今後は、関係演算子 in は __contains__ で、添字演算子 [] は __getitem__ で、役割分担を明確するのがよいでしょう。□
《Tips》OCL では、in と似た演算 includes が規定されています。

includes: Collection(t) × t → Boolean		v∈C
includes(object: T): Boolean
post: result = (self->count(object) > 0)

《Tips》OCL では、not in と似た演算 excludes が規定されています。

excludes: Collection(t) × t → Boolean		v∉C
excludes(object: T): Boolean
post: result = (self->count(object) = 0)


《ひよ子のきもち♪2006/10/04》
Previous|3/20|Next