fc2ブログ

マルチパラダイム時代におけるデータ構造 第18回 ー ネットワークみたいなグラフ。

 この記事は、「マルチパラダイム時代におけるデータ構造 第17回 ー 後入れ先出しのスタック」の続きです。前回は、スタックについて解説しました。今回は、新たにグラフオブジェクトについて解説します。
 今まで、タプル、コンセンスセル、配列、キュー、スタックについて解説してきました。これらのデータ構造を使いこなせば、かなりの数のアルゴリズムを実装できます。しかしながら、それらのデータ構造では対応できない複雑なデータもあります。例えば、ネットワークです。
 ここでいうところのネットワークとは、網状のものであり、インターネットはもちろんの事、登場人物の関係図におよぶまで含むものであり、複雑な現在社会において必須のデータの形状です。このネットワークは、今までのデータ構造を使用して実装します。
 データ構造を作成するために、違うデータ構造を包含するというのは、イメージが湧き難いかもしれません。しかしながら、本当はそれほど難しくありません。何故ならば、今まで紹介してきたデータ構造は、タプル→コンセンスセル→他のデータ構造というふうに、すでに他のデータ構造を含む形になっているからです。インタフェースプログラミングになれない人は、包含関係の実感が湧き難いと思いますが、そのうち慣れるので大丈夫です。
 さて、ここからが本題です。ネットワーク状のものを表すデータ構造としてグラフがあります。グラフを活用すれば、今までになく複雑なアルゴリズムが、簡潔に実装できるようになりますし、より高度に洗練することも可能となります。もちろん、グラフを使用しなくても、一応高度なアルゴリズムは実現可能なのですが、保守性や可読性から見ると問題があります。プログラムは簡潔な方が良いのです。
 グラフオブジェクトは基本的に、値と他の値からなります。またしても、コンセンスセルを連想する構造ですが、私がグラフオブジェクトは今まで紹介してきたデータ構造よりも複雑だと言及したのにはわけがあります。その理由をこれから解説していくのですが、せっかちな人のために一言言っておくと、グラフ理論というものがあるのがその証明です。グラフは奥が深いオブジェクトで、一大理論になるほどのものです。ただ、この連載では、プログラミングがメインテーマであり、数学を解説するものではないので、ちょっとだけ触れる程度にしておきますので安心してください。続く...
スポンサーサイト



テーマ : プログラミング
ジャンル : コンピュータ

ネタつつき208 - 情報技術とは何なのだろう

 ここ最近よく思うのですが、情報技術とはいったい何なのでしょうか?技術力を向上させればさせるほど、その疑問が強くなります。というのも、見聞きしたもの全てをプログラムで表現可能であるばかりではなく、プログラムの必要すらなくなってくるからです。
 例えば、数学のように、現実の現象を情報技術で解析すれば、ある程度の量だと、もはやPCすら要りません。頭の中だけで完結してしまいます。それゆえ、私の開発スタイルは、「お客様の話しを聞く」の一点につきます。聞けばもう答えは自明なので、聞くこと以上に注目するべきことはありませんし、些細な開発手法何てどうでもよくなります。
 その状態になってかなりの時間が過ぎ、面白みがないし、より高みを目指したいので数学に手をだし、数学もまた情報技術で解析可能であるという結論に達しました。このことから、他の分野でも適用可能だと推測できます。
 となれば、結局のところ、情報技術とは何なのかわからなくなりました。一言でいうと、「考える」それ以外の何の定義が必要なのか、それがわかりません。私にとって、考える事全てが情報技術なのですが、全ての学問にそれが該当すると思います。となると、全てが「考える」で終わるのではないかという疑問がわきます。
 では、何をもって情報技術と呼ぶのでしょうか?情報技術を学習すればするほどわかりません。私の人生目標は「情報技術を極める」ことだから、これは重要な問題です。辞書なんてうわべだけの言葉であり、本当の意味で情報技術というものを理解するというのは非常に難しいです。
 私たちは秒進日歩のIT業界に身を置き、忙しい毎日を送っています。だからこそ、時々、情報技術とは何なのかを、自問する必要があるのかもしれません。

テーマ : 情報処理技術
ジャンル : コンピュータ

中の人の徒然草487 環は円柱螺旋なのか?

 あれから少し、環論の専門書を読んで感じたのは、螺旋構造であるという事です。環の発想源である整数を分析すると、加法と乗法の関係性は、精密度を表していると思います。何故ならば、明らかに加法を表す関数fをy回数実行したが乗法だからです。ここで問題となってくるのは、どれぐらいの精度があるのかという事です。
 おそらく、環を考える際に重要なのは、対照性を判定しているので、逆演算子の存在です。情報技術者から見れば、「逆」なのは演算子そのものではなく、記号テーブルという気がしますが(操作的意味論の発想)、それは超宣言型である数学には関係がない事ですし、数学は基本的に表示的意味論の分野だと思います。ですから、その点については無視して考えると、問題となるのは、y回数加法&減法を行った際に、その微分がいかに精度が高いのかという点です。乗法演算を自由に微分できるのであれば、それは体になるという気がします。すなわち、微分可能性と記号の表現が関係してくると思います。
 それらの事は、加法⇔減法および、乗法⇔除算でセットで考えるので、分配法則で連結される加法→乗法の関係を幾何学的に脳内で表現すると、2つの輪があり、それが繋がっている姿です。従って、私の心の目には螺旋に見えます。このイメージがあれば、現実世界のオブジェクト分析に役立つと思います。
 ここで興味深いのは、結局のところ乗法は加法の延長線上に存在し、微分可能性および表現(対応する記号)の有無により性質が変わるという点です。これをさらに抽象化して考えると、対応Aから写像される要素から対応Bの線、対応Bから写像される要素から対応Aの線があり、2本線でつながっている螺旋円状であるから、対応Bは対応Aの定義域からはみ出さず、上へと生成される部分集合だと思います。という事は、環の実例は対応Aさえ決めてしまえば、何でもOKですね♪
 なんだかわかってきました。集合における対応Aを群で調べ、その発展版?対応Bを定義し環もしくは体で調べる。そうすることにより、集合そのものの対称性と、演算の対称性を調べることができるという構造のようです。なるほど、ガロアがしたかったことが見えてきました。ガロアが分析対象としたのは5次方程式の解らしいから、対称性を判定しようとしたことも頷けます。そりゃそうなるわ。ただ、もう一つの考えも浮かび上がってきます。
 あくまで記号における問題だから、任意の記号さえ拡大して付け加えれば、5次方程式であろうと、なんであろうと無理やり写像先を作れます。となれば、その解が実用に耐えられるか否かが問題となります。その問題に対応するためには、新しい数オブジェクトを作ればいい。どのようなオブジェクトが扱いやすいのか、それを考えるのは我々情報技術者の得意とする所です。情報技術者は、何でも抽象化して、オブジェクト化するのに慣れているから、数学者からシステム構築の依頼が来れば普通にします。あとは、仕事の依頼が来ていないのに、趣味でそこまでするのは、プロとしてどうなのかという精神的な問題になります。依頼がないという事は報酬が0で虚しいだけだし、納期がないと燃えない。それに、秒進日歩で進む情報技術の学習と、依頼主の業界研究に忙しいし、情報技術の研究(いくつもある)もしているのでそんなことをしている暇がありません。ただ、知的好奇心という観点から見れば、非常に面白い題材です。う~ん、非常に悩ましいです。優先順位としては、0:仕事、1:情報技術、2:業界研究、3:数学ぐらいだから、面白い題材ではあるものの、実際問題どうやってリソースをひねり出すのか...とにかく時間が欲しいです。1日240時間ほどあれば、私の知的好奇心も満足するかもしれません。時間が欲しい!
 あれ?今気づいた。それにしても、群・環・体という理論にはなじみがあるなーと思ったら、私が発明した情報集合論の一部に相当するぞ。細部を言えば違いますが、かなり昔の人が同じことを考えていたと思うと、やっぱり過去の天才はすごい。どんな発明だって、過去の偉人の考え事からはみ出さないという気がします。まぁ、考えてみれば当然の結果かな?人間という制約がある以上、どのような発明であれ、その人間集合の元にしかなりえないのだから。過去の偉人達の考えをかけらも当たらない発明をするには、人間を止めるしかありません。でも、そんなことをする意味がないから、結局のところ、ご先祖様たちに感謝するという結論に至ります。偉人って、本当に偉大だなー。

テーマ : 日記
ジャンル : 日記

マルチパラダイム時代におけるデータ構造 第17回 ー 後入れ先出しのスタック

 この記事は、「マルチパラダイム時代におけるデータ構造 第16回 ー 不変オブジェクトと宣言型プログラミング」の続きです。前回は、不変オブジェクトと宣言型プログラミングに関して改めて解説しました。今回は新たに、データ構造のスタックについて解説します。
 以前、先入れ先出しのデータ構造であるキューを解説しました。その逆に、後から入れたデータを先に返すのがスタックです。概要はもうわかったと思いますので、実装例を掲載します。

using System;

namespace DataStructure
{
    //後入れ先出しでデータを管理するオブジェクト
    public class Stack<T> : IDataManager<T>
    {
        private IDataFreeManager<T> _elemets;

        public Stack( )
        {
            this._elemets = new ConsCell<T>();
        }

        //データを追加(プッシュ)する。
        public void Push( T element )
        {
            this.Insert( element );
        }

        //後入れ先出しでデータを取り出す。
        public T Pop( )
        {
            T result = this.Select();
            this.Delete();
            return result;
        }

        //要素の個数。
        public int Count
        {
            get { return this._elemets.Count; }
        }

        //最後のデータを選択する。
        public T Select( )
        {
            return this._elemets.Select( this.Count - 1 );
        }

        //最後尾にデータを追加する。
        public void Insert( T value )
        {
            this._elemets.Insert( value, this.Count - 1 );
        }

        //最初のデータを消す。
        public void Delete( )
        {
            this._elemets.Delete( this.Count - 1 );
        }
    }
}

using System;

namespace DataStructure
{
    //後入れ先出しでデータを管理する不変オブジェクト
    public class ImmutableStack<T> : IImmutablDataManager<T>
    {
        private IImmutablDataFreeManager<T> _elemets;

        //格納する要素を指定し、インスタンスを生成する。
        public ImmutableStack( T element )
        {
            this._elemets = new ImmutabConsCell<T>( element, null );
        }

        //要素を指定し、インスタンスを生成する。
        private ImmutableStack( IImmutablDataFreeManager<T> elements )
        {
            this._elemets = elements;
        }

        //データを追加(プッシュ)する。
        public IImmutablDataManager<T> Push( T element )
        {
            return this.Insert( element );
        }

        //後入れ先出しでデータを取り出す。
        public ImmutabTuple<IImmutablDataManager<T>, T> Pop( )
        {
            T result = this.Select();
            IImmutablDataManager<T> stack = this.Delete();
            return new ImmutabTuple<IImmutablDataManager<T>, T>( 
                stack, 
                result );
        }

        //要素の個数。
        public int Count
        {
            get 
            { 
                return this._elemets == null
                    ? 0
                    : this._elemets.Count; 
            }
        }

        //最後のデータを選択する。
        public T Select( )
        {
            return this._elemets.Select( this.Count - 1 );
        }

        //最後尾にデータを追加する。
        public IImmutablDataManager<T> Insert( T value )
        {
            return new ImmutableStack<T>( 
                this._elemets.Insert( 
                value, this.Count ) );
        }

        //最初のデータを消す。
        public IImmutablDataManager<T> Delete( )
        {
            return new ImmutableStack<T>(
                this._elemets.Delete( 
                this.Count - 1 ) );
        }
    }
}

実に簡単なプログラムですが、テストもちゃんとパスします。インタフェースプログラミングをしたら、大体こんな具合になります。もちろん、データ構造の個性に合したテストも必要となってくるのですが、今はまだ気にしないで行きましょう♪
 プログラムそのものは簡単なのですが、始めてこのデータ構造を知った人が気にするのが「どこで使うの?」です。実は、プログラミングではすごく使い道があります。例えば、コンパイラ、メソッド呼び出しの機械語レベルの部分、メモリヒット率を上げる工夫をしたアルゴリズム・・・。そういったものは、場数を踏むと自然と出会うので、今はあまり気にしなくてもいいと思います。「キューの反対の動きをするのがスタックだ」程度に覚えておきましょう。

テーマ : プログラミング
ジャンル : コンピュータ

マルチパラダイム時代におけるデータ構造 第16回 ー 不変オブジェクトと宣言型プログラミング

 この記事は、「マルチパラダイム時代におけるデータ構造 第15回 ー 続可変オブジェクトと命令型プログラミング」の続きです。前回は、可変オブジェクトと命令型プログラミングについて解説しました。今回は、不変オブジェクトと宣言型プログラミングについて解説します。
 この連載で何度も、不変オブジェクトと宣言型プログラミングに言及してきましたが、実際にプログラミングするときについて解説したいので書きます。不変オブジェクトと宣言型プログラミングでは、基本的に常に新しいインスタンスを使用する事が大事です。命令型プログラミングに慣れている人は、その点で間違いをしやすいので注意しましょう。
 実例として不変コンセンスセルのテストを実装します。これにより、不変オブジェクトと宣言型プログラミングを楽しむための準備は万全だと思います。

using System;
using DataStructure;

namespace Test
{
    //IImmutablDataManager<T>を実装するオブジェクトに対するテスト。
    abstract class IImmutablDataManagerTest<T>
    {
        //要素数が正しいかチェックする。
        protected virtual void CountCheck(
            string testName,
            IImmutablDataManager<T> target,
            string methodName,
            int before,
            int rightValue )
        {
            if ( target.Count != rightValue )
                throw new TestException(
                    testName,
                    methodName +
                    "メソッド実行後のCountプロパティの値が正しくありません。"
                    + Environment.NewLine +
                    "予想値:" + rightValue +
                    " 実際の値:" + target.Count
                    + Environment.NewLine +
                    methodName +
                    "メソッドとCountプロパティを確認してください。" );
        }

        //指定したデータが選択可能か否か判定する。
        protected abstract bool CanSelect(
            IImmutablDataManager<T> target,
            int count,
            T value );

        //発生したデータが選択できないときに行うエラー処理。
        protected void InsertSelectError(
            string testName,
            IImmutablDataManager<T> target,
            string methodName, //オーバーロードがあるから
            bool success,
            T value )
        {
            if ( !success ) {
                throw new TestException(
                    testName,
                    methodName +
                    "メソッド実行後に発生したデータを選択できませんでした。"
                    + Environment.NewLine +
                    "選択できない値:" + value
                    + Environment.NewLine +
                    methodName +
                    "メソッドとSelectメソッドを確認してください。" );
            }
        }

        //発生したデータが選択できないときに行うエラー処理。
        protected void DeleteSelectError(
            string testName,
            IImmutablDataManager<T> target,
            string methodName, //オーバーロードがあるから
            bool success,
            T value )
        {
            if ( success ) {
                throw new TestException(
                    testName,
                    methodName +
                    "メソッド実行後に消滅したデータを選択できてしまいました。" +
                    "選択値:" + value
                    + Environment.NewLine +
                    methodName +
                    "メソッドとSelectメソッドを確認してください。" );
            }
        }

        //1つのデータを生成・消滅できる事を確認するテスト。
        protected void OneDataLifeCycleTest(
            IImmutablDataManager<T> target,
            T value )
        {
            string testName = "OneDataLifeCycleTest";
            int count = target.Count;
            var oneTarget = OneDataInsertSubTest( target, value, testName, count );
            OneDataDeleteSubTest( oneTarget, value, testName, count );
        }

        //1つのデータを発生させるサブテスト。
        private IImmutablDataManager<T> OneDataInsertSubTest(
            IImmutablDataManager<T> target, T value,
            string testName, int count )
        {
            var newTarget = target.Insert( value );
            this.CountCheck(
                testName: testName,
                target: newTarget,
                methodName: "Insert",
                before: count,
                rightValue: ( count + 1 ) );
            bool success = this.CanSelect(
                target: newTarget,
                count: 1,
                value: value );
            if ( !success ) {
                this.InsertSelectError(
                    testName: testName,
                    target: target,
                    methodName: "Insert",
                    success: success,
                    value: value );
            }
            return newTarget;
        }

        //1つのデーターを消滅させるサブテスト。
        private void OneDataDeleteSubTest(
            IImmutablDataManager<T> target, T value,
            string testName, int count )
        {
            var newTarget = target.Delete();
            this.CountCheck(
                testName: testName,
                target: newTarget,
                methodName: "Delete",
                before: count,
                rightValue: count );
            bool error = this.CanSelect(
                target: newTarget,
                count: 1,
                value: value );
            if ( error ) {
                this.DeleteSelectError(
                    testName: testName,
                    target: newTarget,
                    methodName: "Delete",
                    success: error,
                    value: value );
            }
        }

        //2つのデータが生成・消滅できる事を確認するテスト。
        protected virtual void TwoDataLifeCycleTest(
            IImmutablDataManager<T> target,
            T one,
            T two )
        {
            string testName = "TwoDataLifeCycleTest";
            int count = target.Count;
            var twoTarget = TwoDataInsertSubTest( target, one, two, testName, count );
            TwoDataDeleteSubTest( twoTarget, testName, count );
        }

        //2つのデータを発生させるサブテスト。
        private IImmutablDataManager<T> TwoDataInsertSubTest(
            IImmutablDataManager<T> target, T one, T two,
            string testName, int count )
        {
            var oneTarget = target.Insert( one );
            var twoTarget = oneTarget.Insert( two );
            this.CountCheck(
                testName: testName,
                target: twoTarget,
                methodName: "Insert",
                before: count,
                rightValue: ( count + 2 ) );
            return twoTarget;
        }

        //2つのデーターを消滅させるサブテスト。
        private void TwoDataDeleteSubTest(
            IImmutablDataManager<T> target, string testName, int count )
        {
            var newTarget = target.Delete();
            this.CountCheck(
                testName: testName,
                target: newTarget,
                methodName: "Delete",
                before: count,
                rightValue: ( count + 1 ) );
            var zeroTarget = newTarget.Delete();
            this.CountCheck(
                testName: testName,
                target: zeroTarget,
                methodName: "Delete",
                before: count,
                rightValue: count );
        }
    }
}

using System;
using DataStructure;

namespace Test
{
    abstract class IImmutablDataFreeManagerTest<T> : IImmutablDataManagerTest<T>
    {
        //1つのデータを任意の場所で、生成・更新・消滅できる事を確認するテスト。
        protected void OneDataLifeCycleToIndexTest(
            IImmutablDataFreeManager<T> target,
            T value )
        {
            string testName = "OneDataLifeCycleTest";
            int count = target.Count;
            int index = 0;
            var oneTarget = this.OneDataInsertSubTest(
                target, value, testName, count, index );
            this.OneDataDeleteSubTest(
                oneTarget, value, testName, count, index );
        }

        //1つのデータを生成するサブテスト。
        protected IImmutablDataFreeManager<T> OneDataInsertSubTest(
            IImmutablDataFreeManager<T> target,
            T value,
            string testName,
            int before,
            int index )
        {
            var newTarget = target.Insert( value, index );
            this.CountCheck(
                testName: testName,
                target: newTarget,
                methodName: "Insert(int)",
                before: before,
                rightValue: ( before + 1 ) );
            if ( !newTarget.Select( index ).Equals( value ) )
                throw new TestException(
                    testName,
                     "挿入した位置に正しいデータがありません。"
                     + Environment.NewLine +
                    "予想値:" + value +
                    ", 実際の値:" + newTarget.Select( index ) +
                    "Insert(index)メソッドと" +
                    "Select(index)メソッドを確認してください。" );
            return newTarget;
        }

        //1つのデータを消滅するサブテスト。
        protected IImmutablDataFreeManager<T> OneDataDeleteSubTest(
            IImmutablDataFreeManager<T> target,
            T value,
            string testName,
            int before,
            int index )
        {
            var newTarget = target.Delete( index );
            this.CountCheck(
                testName: testName,
                target: newTarget,
                methodName: "Delete(int)",
                before: before,
                rightValue: before );
            if ( newTarget.Select( index ).Equals( value ) )
                throw new TestException(
                    testName,
                   "任意の位置にあるデータを正常に消滅できていません。"
                   + Environment.NewLine +
                   "Select(int)メソッドと" +
                   "Delete(int)メソッドを確認してください。" );
            return newTarget;
        }

        //2つのデータが生成・更新・消滅できる事を確認するテスト。
        protected void TwoDataLifeCycleToIndexTest(
            IImmutablDataFreeManager<T> target,
            T one,
            T two )
        {
            string testName = "TwoDataLifeCycleTest";
            int initCount = target.Count;
            var result = this.TwoDataInsertSubTest(
                target, one, two, testName, initCount );
            this.TwoDataDeleteSubTest(
                result.First, 
                one, 
                two, 
                testName, 
                initCount, 
                result.Second );
        }

        //2つのデータを生成するサブテスト。
        protected DataStructure.ImmutabTuple<IImmutablDataFreeManager<T>, int> 
            TwoDataInsertSubTest(
            IImmutablDataFreeManager<T> target,
            T one,
            T two,
            string testName,
            int before )
        {
            int oneindex = 0;
            int twoIndex = oneindex + 1;
            var oneTarget = target.Insert( one, oneindex );
            var twoTarget = oneTarget.Insert( two, twoIndex );
            this.CountCheck(
               testName: testName,
               target: twoTarget,
               methodName: "Insert(int)",
               before: before,
               rightValue: ( before + 2 ) );
            if ( !twoTarget.Select( oneindex ).Equals( one ) )
                throw new TestException(
                    testName,
                   "挿入した位置に正しいデータがありません。"
                   + Environment.NewLine +
                    "予想値:" + one +
                    ", 実際の値:" + twoTarget.Select( oneindex ) +
                    "Insert(index)メソッドと" +
                    "Select(index)メソッドを確認してください。" );
            if ( !twoTarget.Select( twoIndex ).Equals( two ) )
                throw new TestException(
                    testName,
                   "挿入した位置に正しいデータがありません。"
                   + Environment.NewLine +
                    "予想値:" + two +
                    ", 実際の値:" + twoTarget.Select( twoIndex ) +
                    "Insert(index)メソッドと" +
                    "Select(index)メソッドを確認してください。" );
            return new DataStructure.ImmutabTuple<IImmutablDataFreeManager<T>, int>( 
                twoTarget, 
                oneindex );
        }

        //2つのデータを消滅するサブテスト。
        protected virtual void TwoDataDeleteSubTest(
            IImmutablDataFreeManager<T> target,
            T one,
            T two,
            string testName,
            int before,
            int oneindex )
        {
            var oneTarget = target.Delete( oneindex );
            this.CountCheck(
               testName: testName,
               target: oneTarget,
               methodName: "Delete(int)",
               before: before,
               rightValue: ( before + 1 ) );
            if ( oneTarget.Select( oneindex ).Equals( one ) )
                throw new TestException(
                    testName,
                   "任意の位置にあるデータを正常に消滅できていません。"
                   + Environment.NewLine +
                   "Delete(int)メソッドを確認してください。" );
            var zeroTarget = oneTarget.Delete( oneindex );
            this.CountCheck(
               testName: testName,
               target: zeroTarget,
               methodName: "Delete(int)",
               before: before,
               rightValue: before );
            if ( zeroTarget.Select( oneindex ).Equals( two ) )
                throw new TestException(
                    testName,
                   "任意の位置にあるデータを正常に消滅できていません。"
                   + Environment.NewLine +
                   "Delete(int)メソッドを確認してください。" );
        }
    }
}

using System;
using DataStructure;

namespace Test
{
    //不変コンセンスセルのテスト
    class ImmutabConsCellTest<T> : IImmutablDataFreeManagerTest<T>
    {
        //指定したデータが選択可能か否か判定する。
        protected override bool CanSelect(
            IImmutablDataManager<T> target,
            int count,
            T value )
        {
            bool result = false;
            var temp = ( ImmutabConsCell<T> ) target;
            try {
                T returnValue = temp.Select( count );
                result = returnValue.Equals( value );
            } catch ( IndexOutOfRangeException ) {
            }
            return result;
        }

        //全てのテストを実行する。
        public void AllTestExecute(
            Func<ImmutabConsCell<T>> initFunc,
            T one,
            T two,
            T selectRightValue )
        {
            this.OneDataLifeCycleTest( initFunc(), one );
            this.TwoDataLifeCycleTest( initFunc(), one, two );
            this.OneDataLifeCycleToIndexTest( initFunc(), one );
            this.TwoDataLifeCycleToIndexTest( initFunc(), one, two );
        }
    }
}

一目でわかると思いますが、基本的にインスタンスを処理→新しいインスタンスを使って処理...というふうに、連鎖的にインスタンスを使用しています。利点は、処理前の状態がわかることです。以前テストがやり易くなると述べましたが、その言葉には、この利点があるから処理結果を追いやすく、デバッグ作業がやり易いという意味も含まれています。
 今回はこれで終わりです。次回は新しいデータ構造を解説しますが、読者の方は不変配列と、不変キューを作ってみてください。そうすれば、不変オブジェクトと宣言型プログラミングの基本を押さえられるでしょう。続く...

テーマ : プログラミング
ジャンル : コンピュータ

ニュースを分析15回 - 世論調査はあてにならない

 今回はよくあるニュースである世論調査について取り上げたいと思います。私は以前から世論調査および世間の意見に疑問を持っていました。といのも、全然真実を言い当てていないからです。
 世論調査の結果そのものは本当の事なのでしょうが、この手の統計法には、雑音が混じりやすく、本当の意見を反映しにくいという側面があります。何故ならば、質問の仕方により、人間の反応は変わるからです。同じ内容でも質問の表現により、人間の答えは変わります。その性質から世論調査は参考程度にしかすぎないといえます。
 今回の問題は、ニュースを報道している組織よりも、受け手に問題が多いです。なぜそう思うのかというと、「世間の声」として真に受けやすいからです。しかしながら、こういったものはあくまで参考程度のものであり、真実を表すものではないので、鵜呑みにして自分の意見を合わす日本人体質は問題が大きいです。
 再信の例を挙げると、大阪都構想に関する世論調査結果が該当します。大阪都構想について理解しているという人が50%ぐらいいるのも関わらず、大半の人が雇用・景気対策・保障などの方が重要だと答えています。さらに半数の人が税金の無駄だと答えているそうです。これが実に可笑しいです。というのも、雇用景気対策などを効果的行うには、正しい組織体制が必要であり、今まで通りの組織体制でよくなるはずがないからです。実際大阪都構想の目的は、これらの要求に対処するためのものです。という事は、結局のところ、組織体制を変える案が大阪都構想という一案しかない状態では、大阪都構想を支持するしかないのです。それにもかかわらず、15%ほどしかないとは、本当に大阪都構想を理解しているのか疑わしいです。
 さらに言えば、一番比率が高い「税金の無駄」は報道を鵜呑みにした結果に見えます。本当の税金の無駄は、今まで有効な対策もとれず、既得権益の保持に努めていた今までの大阪市の構造にあるのですが、それを理解していません。税金の無駄を言うのであれば、一案に絞る程度の事も出来ない市議会に費やした税金ほど無駄なものはありません。それだけのことに、時間とお金を費やしている会社があるのでしょうか?税金の浪費を行う体質を変える費用が無駄というのであれば、今まで通り税金の浪費を許してもいいという事なり、明らかに矛盾しています。つまり、世間とやらは大阪都構想を理解しているとは思えません。
 日本人は「世間様」を盲信する風潮がありますが、あてにならない世間を盲信した結果が現在の惨状です。誰かの言葉を鵜呑みにせず、自分の頭で考えていれば、今のような世の中にはなっていなかったでしょう。あてにならないものを盲信するよりも、まずは自分の頭で考えるべきだと私は思います。

テーマ : ニュース
ジャンル : ニュース

中の人の徒然草486 分配法則は意外と奥が深い

 昨日、環の定義できになったので、分配法則について考えていました。環には分配法則があるため、2つの2項演算子の間には関係性があります。その関係性がどの程度強いのかと思い、分配法則を考察したところ、結束が結構強いと思いました。分配法則は他方の演算子(対応)を使用するので、自ずと他方の対応が受け入れられる要素でなければならなくなります。それを考えると結構結びつきが強いです。しかしながら、なまじ関係性があるために、色々な疑問がわきます。
 例えば、名前だけが違う内容が同一の対応を指定した場合、それは環として妥当なのでしょうか?環の定義を見ると、同一対応だと駄目だと明記していませんし、片方が余計に条件を満たす場合を禁止していません。これについては、暗黙の了解なのかもしれませんが、暗黙だと仮定すると公理主義的に考えて不十分だと思います。また、加法に相当する対応が、要素(部分集合)の一部だけを使って演算する場合も、処理内容と関係なく、分配法則を満たすこともあり得ます。
 ただし、環の定義を厳密にしすぎると、抽象化のレベルが下がって、余計に適用範囲が狭くなる気がするし、かといって、加法と乗法に関する関係性をどこまで想定しているのか気になるし・・・うーん、どこまで抽象化するべきなのか難しい問題です。
 群は数学以外の実例を見出しやすいですが、環は難しいです。環はおそらく、対応同士の対称性も表しているだろうけど、群・環・体の学習を始めて間もないから、今のところわかりません。非常に興味深い題材です。もっと、学習する時間が取れたらいいのにな・・・

テーマ : 日記
ジャンル : 日記

マルチパラダイム時代におけるデータ構造 第15回 ー 続可変オブジェクトと命令型プログラミング

 この記事は、「マルチパラダイム時代におけるデータ構造 第14回 ー 可変オブジェクトと命令型プログラミング」の続きです。前回は、 可変オブジェクトと命令型プログラミングについて解説しました。今回は引き続き、 可変オブジェクトと命令型プログラミングについて解説します。
 今度は更新と消滅を考えてみましょう。こんな具合に、イメージすると面白いですよ・・・

武田「食堂のおばん!準備が遅すぎるぞ!
 こっちは貴重な昼休みの時間を使っているんだ!」
?「うるさい!貴方は必要最低限度のマナーを守れないの?」
一同(よく言ってくれた!)
武田「誰に向かって口をきいている。こっちへ来い!
 俺が一言声を書ければ、何時でも業者を変えられるんだぞ。」
?「うるさいね・・・私が出て後悔するのはそっちだよ。」
武田「ふん。食堂のおばん風情が何を言っている。」
?「私の顔を忘れたの?」
武田「?...まさか!」
会長「久しぶりね。」
武田「か、会長...」
会長「誰が誰のクビを飛ばすって?」
武田「い、いや、その、なんでこんなところに・・・」
会長「わが社は大衆食堂から始まった事忘れたのかい?
 初心を忘れないために、そして何よりも、
 うちで頑張ってくれている社員をねぎらうためにいるのよ。」
武田「申し訳ございません。何卒、お赦し下さい。」
会長「そんなことより、順番がおかしいから並び替えなさい。」
武田「そ、その。いつから・・・」
会長「一部始終見ていたわ。これからいう順番通りに変更して。」
一同「はい」

ケース1:最初の位置のデータ更新
会長「始めは、山田さんだったわ。」
佐藤「はい。」
武田「あの、俺は・・・」
会長「一度、列の外に出て。」
行列:山田 前田 (山田) 田中 斎藤 佐藤
※()内は重複データ

ケース2:任意の位置のデータを更新
会長「次は田中さんね。」
田中「はい。」
行列:山田 田中 (山田) (田中) 斎藤 佐藤

会長「次は武田。3番目に並びなさい。」
武田「はい。」
行列:山田 田中 武田 (田中) 斎藤 佐藤

会長「4番目は...斎藤さん。」
斎藤「はい。」
行列:山田 田中 武田 斎藤 (斎藤) 佐藤

会長「5番目は前田さん。」
前田(甘え声)「そんなぁ。」
会長「甘えても駄目!」
行列:山田 田中 武田 斎藤 前田 佐藤

ケース3:任意のデータを消滅
会長「これでよし!次はマナーを守れない人に退場してもらうよ。」
武田「!!!」
会長「武田。マナーが悪すぎるからおひるごはん抜きよ。」
武田「そ、それは、あんまりです。」
会長「前から悪いうわさを聞いていたわ。
 次の人事楽しみにしていなさい。」
武田「........」
行列:山田 田中 斎藤 前田 佐藤

会長「これにて一件落着!」
斎藤「流石会長!名判事です。」
山田「いやぁ、それにしてもおなかすいたな。」
会長「はは。腕によりをかけて作るよ。」
田中「楽しみにしています。」
前田「ダイエットしているから、カロリー低いめでお願いします♪」
会長「あいよ。任しな。ダイエット用もあるよ。」
前田「わーい♪」
佐藤(あれ?みんな、俺の事を忘れているぞ。)


この例を見てわかるのは、一時的に重複データがあることです。データの更新は、書き換えるまで重複するデータが存在します。これを意識しておかないと、データの整合性に関するトラブルが発生します。また、更新と消滅はともにデータを検索していることに注目してください。carとcdrがある構造上、データ更新時はcarを持つインスタンスを、データの消滅時はcdrを持つインスタンスを検索しています。これらの事を把握すれば、容易に実装できます。
 命令型プログラミングで単刀直入に実装すると、こんな感じになります・・・


//指定位置の要素を検索する。
private ConsCell<T> Search( int index )
{
    var before = this.SearchBefore( index );
    return before.Cdr;
}

//指定位置のデータを更新する。
public void Update( T newValue, int index )
{
    var target = this.Search( index );
    target.Car = newValue;
}

//最後尾のデータを消滅する。
public void Delete( )
{
    this.Delete( this.Count - 1 );
}

//指定位置のデータを消滅する。
public void Delete( int index )
{
    if ( this.Count == 0 )
        throw new ArgumentException( 
            "データは1件も存在しません。" );
    var before = SearchBefore( index );
    if ( before.Cdr == null )
        throw new ArgumentException( 
            index + "にデータは存在しません。" );
    if ( before.Cdr.Cdr != null ) {
        before.Cdr = before.Cdr.Cdr;
    }
}

これでテストができるようになったので、テストにかけると・・・失敗します。何故ならば、nullに関する処理が甘いからです。命令型プログラミングでは、nullに対するチェックを厳重にしないとなりません。そこで、nullチェックを強化すると、次のようになります・・・

using System;

namespace DataStructure
{
    //1つの要素とそれ以外の要素への参照を持つデータ構造。
    public class ConsCell<T> : IDataFreeManager<T>
    {
        //要素
        private Tuple<T, ConsCell<T>> _cons;

        //要素を持っているか否か
        private bool _hasElement;

        // 最初の要素。
        //※プロパティ名はカーと読む。
        public T Car
        {
            get { return this._cons.First; }
            private set 
            {
                this._cons.First = value;
                this._hasElement = true;
            }

        }

        //他の要素。
        //※プロパティ名はクダーと読む。
        public ConsCell<T> Cdr
        {
            get 
            {
                return this._cons.Second; 
            }
            private set 
            {
                this._cons.Second = value;
                this._hasElement = true;
            }
        }
        
        //インスタンスを生成する。
        public ConsCell()
        {
            //始めはデータを持っていない
            this._cons = new Tuple<T, ConsCell<T>>();
            this._hasElement = false; 
        }

        //インスタンスの文字列表現を取得する。
        public override string ToString( )
        {
            System.Text.StringBuilder result = 
                new System.Text.StringBuilder();
            ConsCell<T> cons = this;
            result.Append( "{ " );
            do {
                result.Append( cons.Car + " " );
                cons = cons.Cdr;
            } while( cons != null );
            result.Append( "}" );
            return result.ToString();
        }

        //cdrの数を数える。
        private int GetCdrCount( ConsCell<T> target, int index )
        {
            if ( !this._hasElement ) return 0;
            if ( target.Cdr == null ) return index;
            else return GetCdrCount( target.Cdr, ++index );
        }

        //要素の数を返す。
        public int Count
        {
            get 
            {
                return this.GetCdrCount( this, 1 );
            }
        }

        //最初のデータを選択する。
        public T Select( )
        {
            return this.Car;
        }

        //指定位置のデータを選択する。
        private ConsCell<T> Select( 
            ConsCell<T> target, int index, int count )
        {
            if ( index > this.Count )
                throw new IndexOutOfRangeException( 
                    "指定された位置" + index + 
                    "にデータは存在しません。" );
            return index == count
                ? target
                : this.Select(
                    target.Cdr, 
                    index, 
                    ++count );
        }

        //指定位置のデータを選択する。
        public T Select( int index )
        {
            return this.Select( this, index, 0 ).Car;
        }

        //指定した位置の前の要素を返す。
        private ConsCell<T> SearchBefore( int index )
        {
            ConsCell<T> before = null;
            ConsCell<T> current = this;
            int count = 0;
            while( current.Cdr != null && index != count) {
                before = current;
                current = current.Cdr;
                ++count;
            }
            if ( index != count ){
                new ArgumentOutOfRangeException(
                    "指定された位置にデータは存在しません。" );
            }
            return before;
        }

        //指定位置の要素を検索する。
        private ConsCell<T> Search( int index )
        {
            var before = this.SearchBefore( index );
            var result = before != null ? before.Cdr : null;
            return result;
        }

        //最後尾へデータを追加する。
        public void Insert( T value )
        {
            this.Insert( value, this.Count );
        }

        //指定位置へデータを発生させる。
        public void Insert( T value, int index )
        {
            if ( !this._hasElement || index == 0 ) {
                InsertFirst( value );
            } else if ( index == this.Count ) {
                InsertLast( value ); 
            } else {
                if ( index > this.Count )
                    throw new ArgumentOutOfRangeException(
                        "範囲外の値が指定されています。" );
                InsertMiddle( index, value );
            }
        }

        //最初の位置でデータを発生させる。
        private void InsertFirst( T value )
        {
            if ( !this._hasElement ) {
                //始めての要素
                this.Car = value;
            } else {
                var next = 
                    new ConsCell<T> { 
                        Car = this._cons.First,
                        Cdr = this._cons.Second
                };
                this.Car = value;
                this.Cdr = next;
            }
            return;
        }

        //中間位置でデータを発生させる。
        private void InsertMiddle( int index, T value )
        {
            ConsCell<T> before = this.SearchBefore( index );
            if ( before == null ) {
                ConsCell<T> newValue =
                new ConsCell<T> {
                    Car = value,
                    Cdr = null
                };
                this.Cdr = newValue;
            } else {
                ConsCell<T> newValue =
                new ConsCell<T> {
                    Car = value,
                    Cdr = before.Cdr
                };
                before.Cdr = newValue;
            }
            
        }

        //最後の要素を取得する。
        private ConsCell<T> GetLast( )
        {
            ConsCell<T> result = this;
            while ( result.Cdr != null )
                result = result.Cdr;
            return result;
        }

        //最後の位置でデータを発生させる。
        private void InsertLast( T value )
        {
            ConsCell<T> last = this.GetLast();
            ConsCell<T> newValue = new ConsCell<T> {
                Car = value 
            };
            last.Cdr = newValue;
        }

        //指定位置のデータを更新する。
        public void Update( T newValue, int index )
        {
            var target = this.Search( index );
            if ( target == null ) {
                this.Car = newValue;
            } else {
                target.Car = newValue;
            }
        }

        //最後尾のデータを消滅する。
        public void Delete( )
        {
            this.Delete( this.Count - 1 );
        }

        //指定位置のデータを消滅する。
        public void Delete( int index )
        {
            if ( this.Count == 0 )
                throw new ArgumentException( 
                    "データは1件も存在しません。" );
            if ( index == 0 ) {
                DeleteFirst();
                return;
            }
            var before = SearchBefore( index );
            if ( before.Cdr == null )
                throw new ArgumentException( 
                    index + "にデータは存在しません。" );
            if ( before.Cdr.Cdr != null ) {
                before.Cdr = before.Cdr.Cdr;
            } else {
                before.Cdr = null;
            }
        }

        //最初のデータを消滅する。
        private void DeleteFirst( )
        {
            if ( this.Cdr != null ) {
                this.Car = this.Cdr.Car;
                this.Cdr = this.Cdr.Cdr;
            } else {
                this.Car = default(T);
                this._hasElement = false;
            }
            return;
        }

        //暗黙的にコンスセルをタプルに変換する。
        public static implicit operator Tuple<T, ConsCell<T>>( ConsCell<T> obj )
        {
            if ( obj == null ) return null;
            return new Tuple<T, ConsCell<T>> { 
                First = obj.Car, 
                Second = obj.Cdr };
        }
    }
}

このように、命令型プログラミングは、nullチェック関連のコードにより、余計な処理が増える傾向があります。リファクタリングをすれば、もっと簡潔になります。ですが、命令型プログラミングの性質上、宣言型プログラミングと比べると、どうしても長くなりがちです。コードを磨くことを忘れないようにしましょう。
 前回と併せて読むと、可変オブジェクトと命令型プログラミングの特徴がよくわかると思います。オブジェクトの性質と、選択したプログラミングパラダイムの性質をよく考えプログラミングしましょう。続く...

テーマ : プログラミング
ジャンル : コンピュータ

中の人の徒然草485 些細な疑問だが気になる

 今日、代数学を楽しんでいて、ふと気になったことがあります。それは、環の定義において、2項演算子の関連性が分配法則だけでいいのかという事です。分配法則を満たすのですから、確かに2つの2項演算子には関連性があります。しかしながら、加法と乗法が生成できる元には集合によっては差があります。演算の関連性を定義しなくてよいのでしょうか?関連性の定義が不十分な気がします。加法に相当する対応Aと、乗法に相当する対応Bに、両対応ABについての定義が必要だと思えてなりません。
 一般的にいうと加法の方が、表現できるものが多いです。具体的には、割り切れない数は乗法だけで自然に表せません。加法に相当する対応は可換群だから当然差があります。もちろん、数だけを言えば有理数を使えば問題なしなのですが、それは「有理数」という集合の性質が影響しています。そういったことも含めて、どのような関連性があるのかについての厳密な定義が必要だという気がします。
 何故ならば、数だけを環として考える分には不自由しないのですが、群のように数学の範囲を超えたオブジェクトを分析したい場合、必ずしも加法と乗法のように自明な関係を持っているとは限りません。いえ、それどころか、加法と乗法すら、自明とすらいえないかもしれません。考察対象となる集合を限定しない場合、何でもありです。従って、考察対象の集合が持つ対応ABの関係性の分析も必要となります。つまり、環をもっと活用したい時困るのです。
 もしかしたら、もっと環を学習すればわかるのかもしれませんが、ちょっと気になったので日記に書いてみました。近い将来、そんな簡単なことで悩んでいたのかと思いたいです。
 ところで、加法と乗法の定義も十分ではないような気がします。何をもって加法と呼べばいいのか、何をもって乗法と呼べばいいのかと考えたとき、こんな具合になるかな?

 加法対応の公理
・任意の集合Gに属する全ての元を生成可能である。
・単位元がある。
・単位元をもとに要素を生成可能な対応が包含されている。
※インクリメント演算子のようなもの

 乗法対応の公理
・加法を包含し加法の繰り返しで構成されていなければならない。
※要するに、乗法(x, y)で指定される値yは、加法演算の回数である。

今思いついたことを書いたから抜けがあると思うけど、こんな感じになるかな?環というものは、どれだけの対応関係をカバーするのか、気になります・・・

テーマ : 日記
ジャンル : 日記

ニュースを分析14回 - 質が良いマスメディアを育てよう

 今までの記事で、残念ながら日本のマスメディアの質が極めて低いことが感じられると思います。今回はそのことについて、話題に取り上げます。日本のマスメディアの悪い点を一言でいうと、「論理も倫理もなく拝金主義一色である」といえると思います。この体質は戦前から変わっていません。反省や自浄作用という言葉がないようです。私はマスメディアの質の向上を願っているので、これからマスメディアの悪い点を3つに纏めます。
 第一に気になる点は、何でも茶化すところです。近頃では、ノーベル賞ものの技術が発明されたことに関して、記者が個人情報に注目したり、矮小な邪推をしたりしています。肝心な技術の内容はさっぱり報道しません。これは情報の質が悪いといってもよいかと思います。
 次に気になる点は、目立つ個人の攻撃に終始している点です。出る杭は叩くとはこのことで、何でも茶化しつつ、一度対象と定めた個人に対して、ありとあらゆる誹謗中傷の内容の報道を執拗にします。これが原因で、日本では何もしないのが得策ということになってしまっています。これだけが原因ではないのですが、それ故に政治問題や社会的問題は一向に解決しません。社会に対して実害を及ぼしているのは頂けません。
 最後の悪い点は、論理も倫理も何もなく、「儲ければ何をしてもいい」という拝金主義で染まっている点です。ほぼ毎日誰かの誹謗中傷を報道し、真実や本質に目を向けようともしません。スクラムを組んで、みんなで一緒に同じ話題でお金を稼ごうという姿勢が目に付きます。そのせいで犯罪被害者に対する二次被害が酷すぎます。こういった誹謗中傷に過ぎない情報に対してお金を出す消費者の問題でもありますが、儲ければ何をしてもよいというのであれば、考え方が犯罪者と変わりません。
 戦前からこれらの悪癖は変わらず、提供される情報の質も悪化する一方ですが、その中でも個々の記者を見ると、頑張っている人はいます。業界全体としては質が悪いのですが、少しだけ希望はあるので、「質が悪い情報は買わない」と「質が良い情報にはお金を出す」という姿勢を持てば、日本のマスメディアの質は向上すると思います。
 質が悪い日本のマスメディアは自分を映す鏡でもあります。質が悪い商品にお金を出し、悪貨を増やしているのは我々消費者です。質を見極め、良貨を増やすことを意識するべきだと私は思います。

テーマ : ニュース
ジャンル : ニュース

プロフィール

インドリ

Author:インドリ
みなさん、はじめまして、
コンニチハ。

ボクは、無限の夢(infinity dream)を持つネタ好きな虹色の鳥インドリ(in dre)です。
色々な情報処理技術を啄ばむから楽しみにしてね。

http://twitter.com/indori
は別人による嫌がらせ行為です。
私とは関係ないので注意して下さい。
次はなりすましブログなどをするかもしれませんが、ここ以外でブログをするつもりがないので、ここ以外にインドリのブログがあったとしても無視してください。


何度言っても分からない人がいるので、ここにコメント欄へ書き込むときの注意事項を書きます。


一、社会人としてのマナーをわきまえましょう。
一、妄想に基づく書き込みを止めてください。
一、暴言の類は書かないで下さい。
一、某誹謗中傷サイトの書き込みは彼らの妄想に基づく書き込みですから無視して、ここへ書き込まないで下さい。
一、コメント書く前に他のコメントよく読んでから行って下さい。
一、言いがかかり等の行為を禁止します。
一、その他常識的に考えて迷惑なコメントはしないで下さい。


以上のルールを守れない人のコメントは削除します。



利用上の注意
ここに紹介してある文章およびプログラムコードは正確であるように心がけておりますが、内容を保証するものではありません。当サイトの内容によって生じた損害については、一切の責任を負いませんので御了承ください。


執筆したCodeZineの記事


【VB.NETで仮想CPUを作ろう】

  1. VB.NETで仮想CPUを作ろう
  2. レジスタの実装
  3. 仮想CPUのGUI化
  4. テストドライバの改良
  5. CPUの基礎動作の実装
  6. MOV命令の実装
  7. ADD命令実装
  8. SUB命令実装
  9. INC命令&DEC命令の実装と命令長
  10. MLU命令の実装とModR/Mについて
  11. DIV命令の実装とイベント設計について
  12. 機械語駆動式 関数電卓を作ろう!
  13. 機械語駆動式 関数電卓を作ろう! 解答編(前半)
  14. 機械語駆動式 関数電卓を作ろう! 解答編(後半)


【仮想ネットワーク実装でTCP/IPを学ぼう】
  1. TCP/IPの基礎と勘所
  2. ネットワークアクセス層の勘所
  3. インターネット層の勘所
  4. トランスポート層の勘所
  5. アプリケーション層の勘所
  6. セキュリティの基礎と仮想ネットワークの仕様
  7. GDI+と独自プロトコルの定義



【並列化】
インテル Parallel Studioを使って並列化プログラミングを試してみた
並列プログラミングの効率的なデバッグを実現する「Parallel Inspector」


【TBBシリーズ】
  1. インテル スレッディング・ビルディング・ブロックの概要
  2. インテルTBBから学ぶループの並列化
  3. スレッドセーフとインテルTBBのコンテナ
  4. インテルTBBのスレッドクラス


【OpenMPシリーズ】
  1. OpenMPの基礎構文
  2. OpenMPの実行時ライブラリと並列ループ
  3. OpenMPのメモリモデルとfork- joinモデル

最近の記事
最近のコメント
月別アーカイブ
カテゴリ
Ada (9)
COBOL (5)
C (9)
C++ (11)
C# (370)
D (25)
Java (8)
Perl (1)
Ruby (14)
PHP (2)
Boo (2)
Cobra (2)
LISP (6)
F# (33)
HTML (0)
XHTML (0)
CSS (0)
XML (0)
XSLT (0)
Scala (4)
WPF (0)
WF (2)
WCF (0)
LINQ (4)
MONO (5)
Linux (0)
MySQL (0)
ブログ内検索
リンク
最近のトラックバック
RSSフィード
ブロとも申請フォーム

この人とブロともになる

QRコード
FC2カウンター