2016年1月30日土曜日

ラグランジュ補間でルンゲ現象を再現してみた[Python]

テスト期間中だけどラグランジュ補間のプログラムを作成した.で,試しにルンゲ現象を再現してみた.

ベッ……別に単位落とした時の言い訳なんかじゃないんだからねっ(。>﹏<。)

1.前知識

ラグランジュ補間は関数の近似を行うアルゴリズム手法の一つ.例えば値がわかっているデータが10個あったとする(例えばこんな感じ.x_data = { x0,x1,x2,...,x9}の時のy_data={y0,y1,y2,…,y9})

この時,f(x)を近似したい式として,近似式p(x)は次のように計算される.

この時,f(x)を近似したい式として,近似式p(x)は次のように計算される.
N(i,x)はxがi番目のデータに近い数字なら1を返す.もしxがi番目のサンプルデータに近ければ,i番目の時だけN(i,x)が1になるように出来てる.

こいつの利点としては雨の雨量みたいな離散的なデータを積分したいときに,そのサンプリングした奴の間のデータを出せたりする.

2.プログラム

とりあえずプログラムはこんな感じ.例としてsin関数の近似をやってみた.
で,結果はこんな感じ.

6個のデータしか与えてないのにだいぶいい感じに近似出来てる.すごい.まぁサンプルデータが偏ったりしているとうまくいかない.あとルンゲ現象なんてものもある.ちょっとやってみますか.

3.ルンゲ現象

Wikipediaに載ってる式を試しにやってみます.この式です.

プログラムはこいつ.
結果はこんな感じ.

荒ぶってますねぇ~.補間する点を多くすると過学習みたいになってまぁ変な風になってしまうというやつですね.まぁ気をつけましょうってことっすかね.

多変数関数の補間とかできるのか気になる.

2016年1月20日水曜日

MNISTの自己組織化マップ(SOM)を作った[Python]

さっき昔の記事の修正してたら操作を誤ってしまい,古い投稿がさっき投稿されたようになっててちょっとつらいです…….なのでもう少し温めてから出そうと思ってた内容をさっさと書いちゃいます.

自己組織化マップというのは,教師なしクラスタリングの一種で,似た者同士がまとまっていくものです.詳細はプログラムのコメントに書いたリンク先を参照してください.

とりあえずこういった感じの画像が得られます.(実際に使うときはこういった画像を探してくるのではなくて写像した2次元座標を使います.scikit-learnにもクラスが無く,ひょっとしたら可視化以外に使う人はもういないのかもしれません)

MNISTの手書き数字を似た者同士でまとめてる感じです.上のような画像を作るには結構演算が必要なので以下のプログラムのパラメータを幾つか変更してやる必要がありますが,基本的にはこのプログラムで出来ます(n_side=50,n_learn=5000ぐらい).これを見て,画像認識のプログラムを作る際に,どういった特徴量を作るかを考えるのに役立てることができます.

まぁ画像以外にも元素のデータ突っ込んで似た元素でまとめたりとか,動物の特徴から似た者同士をまとめたりとかという使い方もあります.よくネットに上がっている例だと色の自己組織化マップがあります.そんなに時間がかからないので出来る様子を動画にしてみました.

最初は結構変化しますが,時間が立つに連れて落ち着いてくるようすがわかります.

以下ソースコード

PythonでWebカメラの画像を保存する[Python]

 Pythonで画像処理の勉強をちょっとやってみたいと思い,とりあえずWebカメラから画像を取得してみた。

1.OpenCVのインストール


 OpenCVの公式サイトのダウンロードページからOSに合ったバージョンをダウンロードしてインストールする。opencvフォルダ内のbuild\python\2.7\x86\cv2.pydをPython27フォルダ内のLib\site-packagesにコピーすれば大丈夫なはず。

2.プログラム

 俺が書いたみたいに見せてるけれどOpenCVの公式ドキュメントをちょこっと変えただけでなんか申し訳ない。sを押すとphoto.jpgという名前で保存される。qを押すと終了する。

# -*- coding: utf-8 -*-
import numpy as np
import cv2

cap = cv2.VideoCapture(0)

while(True):
    # フレームをキャプチャする
    ret, frame = cap.read()

    # 画面に表示する
    cv2.imshow('frame',frame)

    # キーボード入力待ち
    key = cv2.waitKey(1) & 0xFF

    # qが押された場合は終了する
    if key == ord('q'):
        break
    # sが押された場合は保存する
    if key == ord('s'):
        path = "photo.jpg"
        cv2.imwrite(path,frame)

# キャプチャの後始末と,ウィンドウをすべて消す
cap.release()
cv2.destroyAllWindows()


 左はArduinoの箱。特に意味は無いです。右は画面を撮影したらこうなった。写し鏡みたいな。こちらも特に意味は無いです。

 ちなみにcv2.Cannyという関数を使うとエッジ検出ができます。ラズパイでは難しいかもしれないですが,普通のパソコンならリアルタイムで処理できるはずです。

# -*- coding: utf-8 -*-
import numpy as np
import cv2

cap = cv2.VideoCapture(0)

while(True):
 # フレームをキャプチャする
 ret, frame = cap.read()

 # エッジ検出
 frame = cv2.Canny(frame,100,200)

 # 画面に表示する
 cv2.imshow('frame',frame)

 # キーボード入力待ち
 key = cv2.waitKey(1) & 0xFF

 # qが押された場合は終了する
 if key == ord('q'):
  break
 # sが押された場合は保存する
 if key == ord('s'):
  path = "photo.jpg"
  cv2.imwrite(path,frame)

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()


 こちらエッジがされた画像。緑茶の二文字が見て取れる。画像処理と言っても既存の関数を使うだけで中身を知らなくてもできるという現実が嬉しいような悲しいような……。

画像を油絵風に変換する[C#]

 機能はメインのPCのOS(Windows10)が起動しなくなった。まぁ調べたところOSが悪いというよりもう寿命だったみたい。CPUが熱で落ちて運悪く重要なファイルが破損したようです。

 今は再インストールをしている最中です(´Д`)ハァ…。

 愚痴はこのへんにして,今日は画像を油絵風に変換するプログラムを作成しました。

1.アルゴリズム


 比較的簡単な方法です。

 まず元の画像からランダムに一個点を選びます。


 次にその点の色を取り出します。ここでは赤とします。次にその点の周辺にその色の円を書きます。この時ちょっと透明度を入れるといいです。


 まぁこんな感じ。今手作業で適当にやったから辺だけど,本当はもう少しいい感じになる。これを繰り返すとこんな感じになる。

 半透明の円が組み合わさって元の色を作る。他の色との境界部分は混ざり合うという算段です。これが本当に油絵風と言っていいのかは読者様の感性にお任せします。

2.ソースコード

ソースコードにするとこんな感じ。
/**
 *  2015/10/19
 *  画像を油絵風に変換するプログラム
 */

using System;
using System.Drawing;

class Program
{
 // 一辺をどのぐらい分割するか
 // この値を大きくすると精細な画像になる
 const int N = 128;
 
 static void Main()
 {
  Console.WriteLine("a.jpgという画像をを読み込みます");
  
  var img = new Bitmap("a.jpg");
  
  Console.WriteLine("画像を変換し,b.jpgという名前で保存します");
  
  OilPainting(img).Save("b.jpg");
  
  Console.WriteLine("保存が完了しました");
 }
 
 // 油絵っぽい画像に変換するプログラム
 static Bitmap OilPainting(Bitmap src)
 {
  // 描画用のBitmapクラス
  var img = new Bitmap(src);
  // 長辺の長さを出す
  var min = Math.Min(img.Width,img.Height);
  // 円の半径を計算する
  var r = min / N;
  // 乱数生成用クラス
  var rand = new Random();
  // 打点回数(絵全体を覆える回数にしなければならない)
  var count = 6*img.Width * img.Height / (r*r);
  // 描画するのに必要なGraphicsクラス
  var g = Graphics.FromImage(img);
  
  for(int i = 0 ; i < count ; i++ ) 
  {
   // ランダムに点を決める
   var x = rand.Next(src.Width);
   var y = rand.Next(src.Height);
   // 色を取り出す。この時透明度を入れておくといい感じになる
   var color = Color.FromArgb(128,src.GetPixel(x,y));
   // 描画に必要なSolidBrushクラスを先ほど作成した色からつくる
   var brush = new SolidBrush(color);
   
   // 円の描画
   // 円の中心が(x,y)に来るように調整してある
   g.FillEllipse(brush,x-r,y-r,2*r,2*r);
  }
  
  // 変換後の画像を返す
  return img;
 }
}

 「ぱくたそ」さんから借りてきた画像を変換してみた。


 もう一度言いますがこれが本当に油絵風と言っていいのかは読者様の感性にお任せします。

BigIntegerを使って累乗和の公式を計算[C#]

 累乗和の公式シリーズ完全版です。べき乗和の公式の計算結果はこちらです。見づらいし利用価値もないけれど,とりあえずネットにあげとくと頭のいい人は面白い使い道思いついたりするからね。

1.BigInteger構造体とは

たぶんべき乗和の公式よりもこっちのほうが需要ありそうなので説明します。べき乗和の方はアルゴリズムを以前説明したのでそちらを参照してください。

 BigInteger構造体はでっかい数字を扱うためのint型。int型だから整数しか扱えない。でもメモリが使えるだけ桁数を増やせる。オーバーフローしない。すごい。そんなクラスです。

 ただいくつか設定をしないと使えません。コマンドプロンプトでコンパイルをしているという方は「csc -r:System.Numerics.dll *.cs」というように参照を追加します。

 VisualStudioでは以下の様な参照の追加を行います。ソリューションエクスプローラーの参照から,参照の追加をクリック。
アセンブリ→フレームワーク→System.Numerics.dllにチェックを入れる。
これで準備が完了。次のプログラムを打ち込んでみる。
// コンパイル時にはSystem.Numerics.dllを参照追加すること

using System;
// BigIntegerを使うために必要
using System.Numerics;

class Program
{
 static void Main()
 {
  // お行儀のよい宣言
  BigInteger a = new BigInteger(3);
  // int型からは暗黙の型変換が可能
  BigInteger b = 5;
  
  // 掛け算,割り算も普通のint型のように使える
  b = 1024 * b;
  
  // いくつかの数学関数はBigInteger構造体に用意されてる
  a = BigInteger.Pow( a , 20 );
  
  // 出力も簡単
  Console.WriteLine("{0}",a);
  Console.WriteLine("{0}",b);
 }
}

 まぁ何も気にせずに使えるということがよくわかりましたね。詳しい情報はやっぱり公式のMSDNさんが一番だと思います。

2.プログラム

べき乗和の公式を求めるプログラムです。一応任意のべき乗数を求めることができるようになりました。100乗和の公式を求めてやるぜ!と冗談半分で言っていたのですが,何とかうまくいきました。

 例えば20乗和の公式は
となることがわかります。ただ残念ながら出力結果はこんな画像にはなりません(´・ω・`)。

 ちなみに今回255乗和の公式までは求めました(→計算結果)。結構時間がかかりましたが数十分程度なのでまだまだ上は目指せそうですよ。

 たいていMathematicaみたいなお高いソフト使って,誰かがこういうのは求めているものですが,1000乗和の公式とか計算したら,この世で最初に自分が計算した式かもしれない……と思うとワクワクしますね。

using System;
using System.Numerics;

class Program
{
    static void Main()
    {
        Console.WriteLine("何乗和の公式を求めますか?");
        var N = int.Parse(Console.ReadLine()) + 1;

        // 係数を求める連立方程式の拡大係数行列を作る
        var formula = MakeFormula(N);
        // 連立方程式をガウス消去法で計算
        Solve(formula, N);
        // 結果を表示
        Show(formula, N);

        Console.WriteLine("値を代入します");
        while (true)
        {
            Console.Write(" n = ");
            var n = int.Parse(Console.ReadLine());
            var f = new Fraction(0);

            for (int i = 0; i < N; i++ )
                f += BigInteger.Pow(n, i+1) * formula[i, N];
            Console.WriteLine(f.ToString());
        }
    }

    // 連立方程式を解くメソッド
    static void Solve(Fraction[, ] formula, int N)
    {
        Fraction temp;

        // ガウス消去法

        // 前進消去
        for (int i = 0; i < N; i++)
        {
            // まれに対角成分が0の時がある
            if (formula[i, i] == 0)
            {
                // そういった場合は下の行から探してくる
                for (int j = i + 1; j < N; j++)
                {
                    // i行目が0でない行が見つかった場合
                    if (formula[j, i].ToDouble() != 0.0)
                    {
                        for (int k = i; k < N + 1; k++)
                        {
                            // 下の行から0でない値を持ってくる
                            formula[i, k] += formula[j, k];
                        }
                        break;
                    }
                }
            }

            // 対角対角成分をを1にする
            temp = formula[i, i];

            for (int j = 0; j < N + 1; j++)
                formula[i, j] /= temp;

            // i+1行以降のi列目を0にする
            for (int j = i + 1; j < N; j++)
            {
                temp = formula[j, i];
                for (int k = 0; k < N + 1; k++)
                    formula[j, k] -= temp * formula[i, k];
            }
        }

        // 後進消去
        for (int i = N - 1; i >= 0; i--)
        {
            // 対角成分以外を0にする
            for (int j = i - 1; j >= 0; j--)
            {
                formula[j, N] -= formula[j, i] * formula[i, N];
                formula[j, i] = 0;
            }
        }
    }

    // 累乗和の公式を表示するメソッド
    static void Show(Fraction[, ] d, int N)
    {
        Console.WriteLine("{0}乗和の公式は……", N - 1);
        for (int i = 0; i < N; i++)
        {
            if ( d[i, N] != 0 )
            {
                if ( i != 0 )
                    Console.Write("+");

                Console.Write("({0})*n^{1}", d[i, N], i + 1);
            }
        }
        Console.WriteLine();
    }

    // 累乗和の公式を求める連立方程式の拡大係数行列を作るメソッド
    static Fraction[, ] MakeFormula(int N)
    {
        var ret = new Fraction[N, N + 1];
        var sum = new BigInteger(0);

        for (int i = 0; i < N; i++)
        {
            // 係数部分を作る
            for (int j = 0; j < N; j++)
                ret[i, j] = BigInteger.Pow(i + 1, j + 1);

            // 答えの部分を作る
            sum = sum + BigInteger.Pow( i + 1, N - 1);
            ret[i, N] = sum;
        }

        return ret;
    }
}
class Fraction
{
    /// <summary>
    /// 分子
    /// </summary>
    public BigInteger Upper
    {
        get { 
            return _Upper;
        }
        set { 
            this._Upper = value; 
            CheckFraction();
        }
    }
    /// <summary>
    /// 分母
    /// </summary>
    public BigInteger Lower
    {
        get { 
            return _Lower;
        }
        set { 
            this._Lower = value; 
            CheckFraction();
        }
    }
    /// <summary>
    /// 分子の値を格納する変数
    /// </summary>
    private BigInteger _Upper;
    /// <summary>
    /// 分母の値を格納する変数
    /// </summary>
    private BigInteger _Lower;

    public Fraction(BigInteger Upper, BigInteger Lower)
    {
        Assignment(Upper, Lower);
    }
    public Fraction(BigInteger n)
    {
        Assignment(n, 1);
    }
    public Fraction(int n)
    {
        Assignment(n, 1);
    }
    public Fraction(Fraction f)
    {
        Assignment(f.Upper, f.Lower);
    }

    /// <summary>
    /// double型に変換するメソッド
    /// </summary>
    /// <returns>double型に変換した値</returns>
    public double ToDouble()
    {
        return (double)Upper / (double)Lower;
    }

    /// <summary>
    /// float型に変換するメソッド
    /// </summary>
    /// <returns>float型に変換した値</returns>
    public float ToFloat()
    {
        return (float)Upper / (float)Lower;
    }

    /// <summary>
    /// 約分や分母が0などのミスが無いか確認するメソッド
    /// </summary>
    private void CheckFraction()
    {
        BigInteger u = _Upper;
        BigInteger l = _Lower;
        BigInteger temp;
        bool sign;


        if (l == 0)
        {
            // 分母が0なのでゼロ除算の例外をぶん投げる
            throw new DivideByZeroException();
        } else if (u == 0)
        {
            // 分母が0ならばこうする
            _Upper = 0;
            _Lower = 1;
        } else
        {
            // 分数の値が負ならsign = true となる
            sign = l * u < 0;
            // とりあえずl,uを正にする(余りの計算をするため)
            l = BigInteger.Abs(l);
            u = BigInteger.Abs(u);

            // 常にu <= lとなるようにする
            if (u > l)
            {
                temp = u;
                u = l;
                l = temp;
            }

            // ユークリッドの互除法
            while (l % u != 0)
            {
                temp = l % u;
                l = u;
                u = temp;
            }

            // 約分
            _Upper = BigInteger.Abs(_Upper) / u;
            _Lower = BigInteger.Abs(_Lower) / u;

            // 正負を直す
            if (sign)
                _Upper = -_Upper;
        }
    }

    /// <summary>
    /// クラス内で代入を行うメソッド(ただしCheckFractonから呼んではならない)
    /// </summary>
    /// <param name="Upper">分母</param>
    /// <param name="Lower">分子</param>
    private void Assignment(BigInteger Upper, BigInteger Lower)
    {
        this._Upper = Upper;
        this._Lower = Lower;
        CheckFraction();
    }

    public static Fraction operator +(Fraction left, Fraction right)
    {
        BigInteger l = left.Lower * right.Lower;
        BigInteger u = left.Upper * right.Lower + right.Upper * left.Lower;

        return new Fraction(u, l);
    }

    public static Fraction operator -(Fraction left, Fraction right)
    {
        BigInteger l = left.Lower * right.Lower;
        BigInteger u = left.Upper * right.Lower - right.Upper * left.Lower;

        return new Fraction(u, l);
    }

    public static Fraction operator *(Fraction left, Fraction right)
    {
        BigInteger l = left.Lower * right.Lower;
        BigInteger u = left.Upper * right.Upper;

        return new Fraction(u, l);
    }

    public static Fraction operator /(Fraction left, Fraction right)
    {
        // 逆数にする(0除算ならここで例外が発生する)
        right = new Fraction(right.Lower, right.Upper);
        return right * left;
    }

    public static Fraction operator /(Fraction f, int n)
    {
        return new Fraction(f.Upper, f.Lower * n);
    }

    public static Fraction operator *(Fraction f, int n)
    {
        return new Fraction(f.Upper * n, f.Lower);
    }

    public static implicit operator Fraction(BigInteger n)
    {
        return new Fraction(n);
    }

    public static implicit operator Fraction(int n)
    {
        return new Fraction(n);
    }

    public static bool operator <(Fraction left, Fraction right)
    {
        return left.ToDouble() < right.ToDouble();
    }

    public static bool operator >(Fraction left, Fraction right)
    {
        return left.ToDouble() > right.ToDouble();
    }

    public static bool operator <=(Fraction left, Fraction right)
    {
        return left.ToDouble() <= right.ToDouble();
    }

    public static bool operator >=(Fraction left, Fraction right)
    {
        return left.ToDouble() >= right.ToDouble();
    }

    public static implicit operator double (Fraction f)
    {
        return f.ToDouble();
    }

    public static implicit operator float (Fraction f)
    {
        return f.ToFloat();
    }

    public static bool operator ==(Fraction left, Fraction right)
    {
        // nullかどうかは分子があるかどうかで判断する
        if (left.Upper == null || right.Upper == null)
            return false;
        return left.Upper == right.Upper && left.Lower == right.Lower;
    }

    public static bool operator ==(Fraction left, int n)
    {
        Fraction right = new Fraction(n);

        // nullかどうかは分子があるかどうかで判断する
        if (left.Upper == null || right.Upper == null)
            return false;

        return left.Upper == right.Upper && left.Lower == right.Lower ;
    }

    public static bool operator !=(Fraction left, int n)
    {
        Fraction right = new Fraction(n);

        return !(left == right);
    }

    public static bool operator !=(Fraction left, Fraction right)
    {
        return !(left == right);
    }

    public override bool Equals(object obj)
    {
        if (obj == null || this.GetType() != obj.GetType())
            return false;

        return (this == (Fraction)obj);
    }

    public override int GetHashCode()
    {
        return (int)((this.Upper * this.Lower) % int.MaxValue);
    }

    public override string ToString()
    {
        if ( this.Upper == 0 )
            return String.Format("0");
        else if ( this.Lower == 1 )
            return String.Format("{0}", this.Upper);

        return String.Format("{0}/{1}", this.Upper, this.Lower);
    }
}

2016年1月8日金曜日

ラングトンのアリを実装してみた[Python]

『心はプログラムできるか』の話の続き。
ライフゲームの話とともに,ラングトンのアリも紹介されていたので実装してみた。この先生蟻コロニー最適化も本の中で紹介してるしアリ好きだな(笑)。というか本の中でアリを飼っている話が出てきていた。

1.ラングトンのアリ

詳細はWikipediaがあるので引用。
平面が格子状に構成され、各マスが白または黒で塗られる。ここで、1つのマスを「アリ」とする。アリは各ステップで上下左右のいずれかのマスに移動することができる。アリは以下の規則に従って移動する。
  • 黒いマスにアリがいた場合、90°右に方向転換し、そのマスの色を反転させ、1マス前進する。
  • 白いマスにアリがいた場合、90°左に方向転換し、そのマスの色を反転させ、1マス前進する。
この単純な規則で驚くほど複雑な動作をする。
ルールが非常に単純(プログラム書くのも簡単)。なのに結構複雑な動きをする。まさに複雑系(よく理解していないケド)。

実際の動画はこんな感じ。
ツイートにも書いたけど,これで自由に絵がかけたら面白いんだけれどなぁ。Wikipediaには二次元チューリングマシンって書いてあるけれど,チューリング完全ってことで良いのだろうか。もし仮にそうならば,ある程度絵がかけるとは思うけど……まぁ良いや。
追記
巻き戻す方向にルールを決めてやればいいだけの話でした。

2.プログラム


こちらのサイトを参考にしました。
ライフゲーム - 人工知能に関する断創録

Processingでライフゲームを実装[Processing]

 プログラマーなら誰しも一度はハマるライフゲーム。知ってる人も知らない人も見てってくださいな。

1.ライフゲームとは


 ライフゲームはよく「最も単純な人工生命」とか言われる。まぁ見方によっては間違っていないけれど,どちらかと言うとパズルみたいなもの。

 基本的には細胞(セル・Cell)の生き死にを,ルールに従って決める。ルールは大まかにいうと,

・寂しいと死んじゃう(周囲に生きているセルが無いと死ぬ)
・暑苦しいと死んじゃう(周囲にセルが多すぎると死ぬ)
・環境が良ければ子供が生まれる(周囲に生きているセルがそこそこあれば生まれる)

 という感じ。もう少し詳しく言うと。

・自分が生きていて,周り8マスに生きているセルが2か3なら生きられる。
・自分が死んでいてい,周り8マスに生きているセルが3つなら生まれる。
・上記以外の場合は死ぬ。

 というもの。実際の例で示す。


 緑色の部分が生きているセル。上の図の赤く囲った部分のセルは,周囲に4つ生きているセルがあるので「暑苦しく」て死ぬ(黒くなる)。

 逆に,生まれるケースはこんな感じ。


 この図では自分が死んでいていて(黒くて),周りに生きているセルが3つなので生まれます(緑になる)。
 とこんな感じになるが,実際に見てみればわかると思います。

追記
ライフゲームに関する動画で非常に面白い動画があったので貼っておきます。


2.ソースコード


 上の文章を読まずにソースコードコピペするのが割りと賢い判断かもね。

boolean[][] board;      /* 現在の状態を保存する変数 */
boolean[][] temp_board; /* 次の状態を保存する変数 */
int N = 64;            /* 一辺の数 */


void setup() {
  size(512, 512);

  /* ボードの作成 */
  board = new boolean[N][N];
  temp_board = new boolean[N][N];
  for (int i = 0; i < N * N; i++ )
    board[i/N][i%N] = int(random(2)) == 0 ;

  frameRate(10);
}

void draw() {
  background(0);

  /* 四角形の幅を決める */
  int w = width/N;

  /* 生き死にを決める */
  step();
  /* マウスで状態を変える */
  edit_board();

  /* 色を指定 */
  fill(0, 255, 0);
  stroke(0, 255, 0);
  
  for (int i = 0; i < N; i++ ) {
    for (int j = 0; j < N; j++ ) {
      /* board[i][j]がtrueすなわち生きている場合描画 */
      if ( board[i][j] )
        rect(i*w, j*w, w, w);
    }
  }
}

/* 生き死にを決める関数 */
void step() {
  /* temp_boardにとりあえずその後の状態を保存 */
  for (int i = 0; i < N; i++ ) 
    for (int j = 0; j < N; j++ ) 
      temp_board[i][j] = is_alive(i, j);
      
  /* ボードをコピー */
  for (int i = 0; i < N; i++ ) 
    for (int j = 0; j < N; j++ ) 
      board[i][j] = temp_board[i][j];
}

boolean is_alive(int x, int y) {
  int count = 0;
  
  /* 周囲8マスを見る */
  for (int i = -1; i <= 1; i++ ) 
    for (int j = -1; j <= 1; j++ ) 
      if ( in_range(x+i, y+j) )
        if ( i != 0 || j != 0 )
          if ( board[x+i][y+j] )
            count++;

  
  if ( board[x][y] && ( count == 2 || count == 3 ) )
    return true;/* 生きていて周りに友達がいるから生き残れる */
  else if ( board[x][y] == false && count == 3 )
    return true;/* それなりに人がいるから新しい子供が生まれる */
  else 
    return false;/* それ以外は生き残れない */
}

boolean in_range(int x, int y) {
  if ( x < 0 || x >= N || y < 0 || y >= N )
    return false;
  return true;
}

void edit_board() {
  int x = mouseX * N / width;
  int y = mouseY * N / height;

  if ( in_range(x, y) )
    board[x][y] = !board[x][y];
}

2016年1月6日水曜日

バイオモルフみたいに選ぶだけで音楽を作れるプログラム[Python]

1.バイオモルフ

昨日の続き。『心はプログラムできるか』にバイオモルフというプログラムが紹介されていた。
次のリンクはBiomorphで検索したら出てきたサイト。
バイオモルフというものを実際に実行できる。
・Biomorphs | Emergent Mind

表示されている9つの個体の中で,一番おもしろいと思うものをクリックしていく。
すると今度はクリックしたものと微妙に異なった新たな個体ができる。
それを繰り返していけば,とてもおもしろい形を作れるというハナシ。

本の中では「進化の力を借りてアートを創る試み」として紹介されていた。
評価関数をコンピュータの中ではなく,人間を用いるというのが非常に面白い着想で,「美しさ」みたいな抽象的なものでも作れる可能性があるということが面白いと思った。

2.ミュージックモルフ

作者の有田先生の研究室では顔モルフというものを作っていたらしい。
似顔絵をクリックするだけで作れるというもの。

この辺りから着想を得て良い音楽を選んでいくことで,だんだんと良い音楽に進化していくというプログラムを作ってみた。


残念ながらあまりいい出来とはいえないです……。音楽は5段階中3だったかな……。

2016/01/07 追記
この動画を見るとコードというものを使ってる……コードってなんぞ?プログラムのソースコードのことかの?どうやら音符の塊みたいなもののようだけれど……こういうのは音楽のトーシローができるもんじゃなさそうだ。


とりあえずソースコードを貼っておく。練習でGitHubでレポジトリを作ってみたのでそちらのリンクも貼っとく。
・TonyMooori/Music_Morph

ソースコード

『心はプログラムできるか』を読んだ話

1.感想

実家に帰省した際,有田隆也先生の『心はプログラムできるか 人工生命で探る人類最後の謎』という本を読んだ。

今まで人工生命の研究が役に立つのか?と今まで疑問に思ったことがあったが,この本を読んで役に立つ場所をいくつか知ることができた。

例えば蟻の力を借りることで巡回セールスマン問題をある程度解くことができる蟻コロニー最適化
こういった突拍子もないアルゴリズムは,なかなか理解されにくい研究分野からポロッと出るのかもしれないと思った。

他にも似顔絵を作成することができる「顔モルフ」なるプログラムや遺伝的アルゴリズムによるロボットの形状・行動の学習などはとても面白いと感じた。

顔モルフに関しては,サポートサイトで実行することができるそうなのだが,30億のデバイスで走るJavaさんが奇跡的に動かなかった。

他のプログラムも実際に動く姿を見たいので,自分で実装できるぶんは実装したいと思う。
なのでこのページは関連リンク集にしたいと思う。

2.リンク

自分でやったこと
・バイオモルフみたいに選ぶだけで音楽を作れるプログラム[Python]
バイオモルフから着想を得て音楽でも似たようなことができないかやってみた。結果は……私の音楽の成績が低かったようで……。

・Processingでライフゲームを実装[Processing]
セル・オートマトンの一種。チューリング完全でライフゲームでライフゲームをやってる人をニコニコ動画で見たことがある。すごく面白い。

・ラングトンのアリを実装してみた[Python]
ラングトンのアリ。セル・オートマトンの一種。

・蟻コロニー最適化と遺伝的アルゴリズムで巡回セールスマン問題(TSP)を解いてみる
蟻コロニー最適化を実装した.

外部サイト
・Biomorphs | Emergent Mind
本で紹介されていたバイオモルフと呼ばれるプログラム。表示された9つの個体から,好きなモノをクリックしていくと,面白い個体が得られる。

・「心はプログラムできるか」のすべて! 公式サポートサイト(サイエンス・アイ新書)
サポートサイト。リンクをたどればバイオモルフの考え方を応用した顔モルフのプログラムが(運が良ければ)実行できる。

・人工生命ティエラ - 哲学的な何か、あと科学とか
ティエラの概要が書いてある。ティエラの話は同じく有田隆也先生の書かれた『人工生命』という専門書にものすごく詳しく書いてある。

2016年1月5日火曜日

2016年最初の投稿

あけましておめでとうございます。

ブログを初めておおよそ3ヶ月がたちました。
昨年の10月には毎日のように投稿していたブログですが,早くもだらけ始めています。

・昨年を振り返って

誰も私の昨年の状況を見たって面白くもなんともないと思うのですが,ブログですから,多少なりとも自分の事も書こうと思います。

さて昨年ブログ上で私が作った主なプログラムは

  • 累乗和の公式の計算プログラム
  • 遺伝的アルゴリズムによるオセロのAI最適化

ぐらいですかね。ろくなプログラムが無いですね。
一応サークルや趣味の方では

  • ドローンのPID制御プログラム
  • パノラマ動画の傾き・回転補正プログラム
  • 水玉コラ作成支援ソフト
  • MNISTの手書き文字認識

といったところでしょうか。ドローンの制御プログラムはサークルで共有してるプログラムなのでブログで紹介できませんが,他のやつは時期が来たらGitHubに上げたりフリーソフトとして公開しようかと思っています。

こうまとめてみると,線形代数の授業が思いの外プログラミングに役立っている気がします。累乗和やパノラマ動画,MNISTなどのプログラムに結構使ってます。ちゃんと勉強しようと思います。ハイ。

・今年の目標

せっかくアウトプットの場を得たので3つの目標を掲げておこうと思います。

  • ニューラルネットワークの実装(DNNを含む)
  • 数学の能力を上げる
  • 大会・コンテストなどに沢山出る

1つめのニューラルネットワークですが,ライブラリを使ったことがあっても実装したことがないので実装します。ディープラーニングはライブラリを扱えるぐらいにはなりたいですね。画像認識の勉強してるという話をすると「知ってる知ってるディープラーニングだよね」みたいな返事が来るぐらい知名度がありますしおすし。
2つめの数学力を上げるはまんまですね。線形代数役に立ったし。フーリエ変換とかパノラマ動画の時にちょっと使ったけど完全に理解できてないし。
3つめの大会・コンテストなどに沢山出るというのはKaggleとかTopCoderですかね。競プロもずっとやってないので。就職するときに言えるような実績がほしいところです。

まぁ他にもブログの更新を増やすだとか,本をたくさん読むだとか,GitHub使えるようにするとかは大事だけれども,とりあえずこの3つの目標を達成したいです。

私のブログを見てくださる人もいらっしゃるようなので,今年もどうぞよろしくお願いします。