11月になってから急激に寒くなりました。そんな時は、外に出ずにプログラミングが一番です。ということで昨日は、集合理論を検証したプログラムをリファクタリングしてみました。
using System;
using System.Collections.Generic;
//可能性
enum Possibility
{
Absolutely,
Possible,
Impossible,
}
//集合
class Set
{
#region フィールドとプロパティ
//集合の説明
private string m_explanation;
public string Explanation
{
get { return m_explanation; }
}
//対応
private Func<object, Possibility> m_contained;
internal Func<object, Possibility> ContainedFunction
{
get { return m_contained; }
}
//部分集合
List<Set> m_subSet;
//保持する元
List<object> m_elements;
//Not集合
Set notSet;
internal Set NotSet
{
get { return notSet; }
}
//普遍集合
Set universal_set;
internal Set UniversalSet
{
get { return universal_set; }
set { universal_set = value; }
}
#endregion
#region コンストラクタ
//説明文および集合と元(要素)の対応を指定する
public Set( string explanation, Func<object, Possibility> isFunc )
{
this.m_explanation = explanation;
this.m_contained = isFunc;
this.m_subSet = new List<Set>( );
this.m_elements = new List<object>( );
}
#endregion
#region 所属判定
//指定した元が集合に属するか判定する
public bool Contained( object element )
{
Func<object, Possibility>[ ] checkFuncs =
new Func<object, Possibility>[ ] {
SpecialSetCheck, //Not集合と普遍集合は属しない
ContainedCheck, //対応規則
SubSetCheck, //部分集合
SubSetElementCheck //部分集合の要素
};
foreach ( var f in checkFuncs ) {
Possibility pos = f( element );
switch ( pos ) {
case Possibility.Absolutely:
if ( element is Set &&
!this.m_elements.Contains( element ) ) {
this.m_elements.Add( element );
} else {
if ( !this.m_elements.Contains( element ) )
this.m_elements.Add( element );
}
return true;
case Possibility.Impossible:
return false;
case Possibility.Possible:
break;
}
}
return true;
}
//特別な集合かチェック
//特別な集合はこの集合に属しない
private Possibility SpecialSetCheck( object element )
{
if ( this.notSet == element ||
this.universal_set == element )
return Possibility.Impossible;
return Possibility.Possible;
}
//集合の対応規則をチェック
private Possibility ContainedCheck( object element )
{
Set parent = this.universal_set;
while ( parent != null ) {
Possibility result = parent.ContainedFunction( element );
if ( result == Possibility.Impossible )
return Possibility.Impossible;
parent = parent.UniversalSet;
}
return this.m_contained( element );
}
//指定した要素が部分集合の元なのかをチェック
private Possibility SubSetCheck( object element )
{
Set obj = element as Set;
if ( obj != null ) {
if ( this.m_subSet.Contains( obj ) ) {
return Possibility.Absolutely;
} else {
Possibility subFlag = this.IsSubSet( obj );
if ( subFlag == Possibility.Absolutely )
this.m_subSet.Add( obj );
if ( subFlag == Possibility.Impossible )
return Possibility.Impossible;
}
return Possibility.Possible;
}
return Possibility.Possible;
}
//指定された集合が部分集合かチェックする
private Possibility IsSubSet( Set target )
{
bool result = false;
if ( this.Equals( target ) )
return Possibility.Possible;
if ( target.m_subSet.Count == 0 ) {
result = this.IsElement( target );
if ( result == false ) return Possibility.Impossible;
else return Possibility.Possible;
}
if ( this.m_contained( target ) == Possibility.Impossible ) {
return Possibility.Impossible;
} else {
foreach ( Set sub in target.m_subSet ) {
if ( this.IsSubSet( sub ) == Possibility.Impossible )
return Possibility.Impossible;
}
return Possibility.Possible;
}
}
//自身の要素かチェックする
private bool IsElement( Set target )
{
if ( target.m_elements.Count != 0 ) {
foreach ( object element in target.m_elements ) {
if ( this.Contained( element ) == false )
return false;
}
return true;
}
return true;
}
//部分集合の要素かチェック
private Possibility SubSetElementCheck( object target )
{
foreach ( Set subSet in this.m_subSet ) {
if ( subSet.Contained( target ) == false )
return Possibility.Impossible;
}
return Possibility.Possible;
}
#endregion
#region 比較
public override bool Equals( object obj )
{
if ( obj == null ) return false;
Set s = obj as Set;
if ( s == null ) return false;
return base.Equals( s );
}
public bool Equals( Set obj )
{
return this.Explanation.Equals( obj.Explanation );
}
public override int GetHashCode()
{
return this.ToString().GetHashCode();
}
#endregion
#region 論演算
//Not演算
public Set Not()
{
Func<object, Possibility> f = ( x ) =>
this.m_contained( x ) == Possibility.Impossible ?
Possibility.Absolutely : Possibility.Impossible;
Set result = new Set( this.Explanation + "のNot集合", f );
this.notSet = result;
return result;
}
#endregion
#region その他
//集合の説明を返す
public override string ToString()
{
return this.m_explanation;
}
#endregion
}
class Program
{
//実験
static void Main()
{
//メタ集合(集合の集合の普遍集合)
Func<object, Possibility> metaF = ( x ) => {
if ( x == null ) return Possibility.Impossible;
bool hit = x.GetType( ) == typeof( Set );
if ( hit ) return Possibility.Absolutely;
return Possibility.Possible;
};
Set metaSet = new Set( "メタ集合", metaF );
//全ての集合を元として持つ集合
Func<object, Possibility> setF = ( x ) => {
Set y = x as Set;
if ( y == null ) return Possibility.Possible;
return Possibility.Possible;
};
Set setSet = new Set( "集合の集合", setF );
/*どの集合にも属しない元からなる集合
(集合の集合のNOT集合)
長いからNOT集合とする*/
Set notSet = setSet.Not( );
setSet.UniversalSet = metaSet;
//メタ集合に属するか?
Action<object, Set, bool> MessageShow = ( x, y, z ) => {
bool result = y.Contained( x );
Console.WriteLine( "{0}は{1}に属するか?:{2}",
x, y, result );
if ( result != z )
throw new ArgumentException( );
};
MessageShow( setSet, metaSet, true );
MessageShow( notSet, metaSet, true );
Console.WriteLine( );
//自然数の集合は集合の集合に属するか?
Func<object, Possibility> nf = ( x ) => {
if ( x is int == false ) {
if ( x is Set ) return Possibility.Possible;
else return Possibility.Impossible;
}
bool hit = ( ( int ) x ) > 0; //0も含まないとする
if ( hit ) return Possibility.Absolutely;
else return Possibility.Impossible;
};
Set N = new Set( "自然数の集合", nf );
int a = -1;
MessageShow( a, N, false );
int b = 0;
MessageShow( b, N, false );
int c = 1;
MessageShow( c, N, true );
Console.WriteLine( );
//自然数の集合はどこに属する?
MessageShow( N, setSet, true );
MessageShow( N, notSet, false );
MessageShow( N, metaSet, true );
Console.WriteLine( );
//自然数の奇数の集合
Func<object, Possibility> of = ( x ) => {
int value = ( int ) x;
bool result = ( value > -1 && value % 2 == 1 );
if ( result ) return Possibility.Absolutely;
else return Possibility.Impossible;
};
Set oddSet = new Set( "自然数の奇数の集合", of );
oddSet.UniversalSet = N;
int d = 0;
MessageShow( d, oddSet, false );
int e = 1;
MessageShow( e, oddSet, true );
int f = 2;
MessageShow( f, oddSet, false );
string g = "1"; //数値ではない
MessageShow( g, oddSet, false );
int h = -1;
MessageShow( h, oddSet, false );
Console.WriteLine( );
//奇数集合はどこに属する?
MessageShow( oddSet, N, true );
MessageShow( oddSet, setSet, true );
MessageShow( oddSet, notSet, false );
MessageShow( oddSet, metaSet, true );
Console.WriteLine( );
//集合の集合は2つの集合を含むか?
MessageShow( notSet, setSet, false );
MessageShow( metaSet, setSet, false );
Console.WriteLine( );
//終了
Console.WriteLine( );
Console.WriteLine( "終了しました。" );
Console.WriteLine( "Enterキーを押して下さい。" );
Console.ReadLine( );
}
}
今後機能拡張するためにちょっとコードが長くなっています。他の論理演算を追加して、演算しも定義して、より集合理論の検証をしやすくしようと思っています。
リファクタリングしていてちょっと思ったのですが、集合理論の部分集合の定義には、ちょっと曖昧さがあります。集合の集合ということは、すべての数字の集合も含まれるわけですが、数値は集合なのでしょうか?集合でないと集合の集合に属せないと仮定すれば変になりますから、このプログラムのようにそれでも良いとみなすのか、それとも、集合とみなすかによって集合論が変わってくると思います。
個々の数値を集合とみなす場合、数値1の扱いが気になります。他の数値ならば、容易に集合とみなせますが、この数値1は集合とするのは苦しいです。付番した集合1とみなすこともできますが、その集合1の元が集合でないならば同じことです。つまり、どこかで集合でない元が入り込みます。そう考えると、やっぱり元が何らかの集合に属するならば、集合の集合に属すると考えてもいいのかな?ということは、集合の集合の正体は、集合もしくは何らかの集合に属する元から成る集合なのでしょう。この集合オブジェクトは原子論を連想させます。
すべての物質は原子からなっているとするならば、ほとんどの要素は集合とみなせます。それを応用すれば、すべての事柄が集合で表現できます。現在原子よりも小さいものが見つかっていますが、それでも内容としては同じです。ようするに、小さいものの集合が物質なのですから、どれだけ小さなものが発見されても、集合論的には何も変わりません。原理的にはすべてが集合と対応で表現できることになります。
ただ気になることがあります。最小の要素/元をどのように扱うのか、その点について集合論は何も語ってくれません。その点を補充しないと、集合論は完璧だといえません。といっても、「集合」なのに集合でないものを定義するのは、集合論の守備範囲外という気もします。要は公理の問題なのでしょう。
テーマ : プログラミング
ジャンル : コンピュータ