Emacsに入ってる人工無脳ELIZAと対話する

AlphaGo | Google DeepMindと人類の戦いが最高潮なのにかこつけて、人工知能ネタを紹介します。

EmacsELIZA(イライザ)と呼ばれる、簡素な対話プログラムが入っているのはご存知でしょうか? ELIZAはJoseph Weizenbaumによって1964から1966年に書かれたプログラムで、人間の入力した言葉に対して、サイコセラピストであるかのような返答を返すというプログラムです。Emacs版の実装を試すには、M-x doctorとします。すると

I am the psychotherapist.  Please, describe your problems.  Each time
you are finished talking, type RET twice.

と、問診が始まります。「頭痛がする」と返してみましょう。

(私) I have a headache.

(ELIZA) Maybe you should consult a medical doctor; I am a psychotherapist. .

医者にかかれと怒られてしまいました。では、今度は「気持ちが落ち込んでいる」と返してみます。

(私) I am depressed.

(ELIZA) Are you depressed often?

会話を続けてみます。

(私) Yes.

(ELIZA) I see...  Well, why do you say this is so?

(私) I have a lot of work.

(ELIZA) What makes you believe you have a lot of work?

この辺で早くも限界を感じますが、続けてみます。

(私) I have to overwork every day.

(ELIZA) Earlier you said you felt depressed?

(私) Yes.

(ELIZA) Yes, hmmm... so, are you sure that this is so?

(私) Yes.

(ELIZA) I understand.  So do you really think this is so?

(私) Yes.

(ELIZA) Oh. ...And what makes you think this is so?

堂々巡りになり埒が明きません。目先を変えて、「死にたい」と伝えてみます。

(私) I want to die

(ELIZA) This is not a healthy way of thinking.

さらに直球で自殺をほのめかすと

(私) I wanna commit suicide.

(ELIZA) If you are really suicidal, you might want to contact the Samaritans
via E-mail: jo@samaritans.org or, at your option, anonymous E-mail:
samaritans@anon.twwells.com .  Or find a Befrienders crisis center at
http://www.befrienders.org/ .  I would appreciate it if you would
continue.

こころの相談室的なところを紹介されてしまいました。急にマジレスされて驚きました。

ソースコードらしきものがEmacs Doctorにあります。これを見るとELIZAが反応しそうな単語が分かります。

最後に、さよならの挨拶をしてみましょう。

(私) Bye!

(ELIZA) My secretary will send you a bill.

2016年センター試験英語(筆記)を解く

英語力の定点観測のために、今年のセンター試験英語(筆記)を解いてみました。結果からいうと183点で、期待よりも低い値でした。

以下、間違えた部分を中心としたメモです。ネタバレしてます。

第1問

B-3. charity, continent, demonstrate, opponentでアクセントの場所が異なる単語を選ぶ問題を間違えた。op-po-nentは2つ目の音節にアクセントがあり、他の単語は1つ目の音節にアクセントがあるので、opponentを選ぶのが正解。私はdemonstrateを誤選択。

第2問

A-9. "Wood (used to) be used as the main fuel, but nowadays fossil fuels (are used) widely."という文を完成させる問題。誤って(was used to), (are used)という選択肢を選んだ。正解すべき問題だった。

A-10. "(It) is so considerate (of) him to..."という、人の評価を述べるときに使う構文を完成させる問題。こんな構文の存在を完全に忘れていた。

C-3. PaulとYokoが結婚してる…? Johnではなく…?

第3問

  1. 不要な文を除く問題。英語力というより論理力が問われる。B-2とB-3はどの文もはっきりと不要といえる文はないように思えた。B-3で、罪悪感の話題が他と繋がらないため4を選んだが正解は1。納得できていない。

第4問

  1. 美術館のウェブサイトから情報を読み解く問題。TOEICみたいだ。

第6問

A-5. パッセージにタイトルを付ける問題。"The Difficulties Facing Opera"と"The Historical Context of Opera"とで迷って後者を選択。正解は前者。最近のオペラの問題以外の歴史的な話題もあったのでより広いタイトルを選んだのだが…。

Anacondaのcondaコマンドによる仮想環境の使い方のまとめ

Pythonパッケージ集として人気のあるAnacondaに付属するcondaコマンドを使って、クリーンなPython環境を作ったり破棄したりする方法についてまとめました。

環境を作る

myenvという名前のpython環境を作ってみましょう。

$ conda create --name myenv python

とすると、myenvという名前の環境が作成されます。以下、--nameの代わりに-nでもOKです。

Pythonのバージョンを指定したい場合はpython=x.xなどと書きます。

$ conda create --name myenv python=3.3

追加のパッケージを入れたい場合はパッケージ名を羅列します。

$ conda create --name myenv numpy scipy

パッケージ全部入りのpython環境を作るには最後をanacondaにします。

$ conda create --name myenv anaconda

すでに作成した環境をクローンして新たな環境を作成したい場合は--cloneを使います。ここではmyenvという環境をクローンしてclonedenvという環境を作成しています。

$ conda create --name clonedenv --clone myenv

作成した環境の一覧を見る

以下のコマンドを打ちます。

$ conda info --envs

自分が今いる環境にはアスタリスクが付与されています。

環境を切り替える

Linux, OS Xの場合は

$ source activate myenv

Windowsの場合は

$ activate myenv

とすると、作成した環境に入れます。

環境から出る

Linux, OS Xの場合は

$ source deactivate

Windowsの場合は

$ deactivate

とすると、作成した環境から出られます。

環境を消す

$ conda remove --name myenv --all

とします。

参考

Managing environments — Conda documentation

VirtualBOX + Ubuntuの環境構築メモ

Windows 10 + VirtualBOX + Ubuntuを動かすときのメモです。適宜更新します。

Ubuntuの仮想イメージを取得

Ubuntuの入手 | Ubuntu Japanese Teamから「日本語 Remix 仮想ハードディスクイメージのダウンロード 」をクリックして「Ubuntu 14.04 LTS」を入手します。

LTSはLong Term Supportの略。サポート期間が長いので、LTSのついたものを選ぶのがよさそうです。

もっさりの解消

Ubuntuを起動すると、Unityのあまりの遅さに驚きます。VirtualBox 上の Ubuntu がもっさりする件を解消するメモ - Qiitaに従って3D アクセラレーションを有効化すると、もっさりが解消しました。

よく使うソフトのインストール

まずパッケージを更新

$ sudo apt-get update
$ sudo apt-get upgrade

個人的によく使うソフトをインストール

$ sudo apt-get install emacs git lv nkf python-pip zsh

C言語でOpaqueポインタを使って構造体のメンバを隠蔽する

C言語で、自作の構造体のメンバをユーザに開示しないテクニックとして、Opaqueポインタというものが知られています。今回は、書籍「C++のためのAPIデザイン」の3.1.6節を参考に、Opaqueポインタを使う簡単なサンプルを紹介します。

Opaqueポインタを使わない場合

人に関するデータを集めた構造体Personと、その構造体を使ったライブラリを作成することを考えます。以下にPerson.hのコードを示します。

#pragma once

typedef struct _Person
{
    int age;
} Person;

// 以下、Person構造体に関するAPI

Person* createPerson(int age);    // Person構造体のオブジェクトを生成
void printPerson(Person* ptr);    // Person構造体を使った操作(メンバのプリント)
void destroyPerson(Person* ptr);  // Person構造体のオブジェクトを破棄

Person構造体のメンバがベタ書きされていることに注目してください。

Person.cppのコードを以下に示します。

#include "Person.h"
#include <stdio.h>

Person* createPerson(int age)
{
    Person* ptr = (Person*)malloc(sizeof(Person));
    if (ptr)
    {
        ptr->age = age;
    }
    return ptr;
}

void printPerson(Person* ptr)
{
    if (ptr) printf("age: %d\n", ptr->age);
}

void destroyPerson(Person* ptr)
{
    if (ptr) free(ptr);
}

と記述します。

このPerson構造体の呼び出し側のコードは以下のとおりです。

#include "Person.h"

int main(void)
{
    Person *p = createPerson(42); // オブジェクトを生成
    printPerson(p);
    destroyPerson(p); // オブジェクトを破棄

    return 0;
}

createPerson()を使ってPerson構造体のオブジェクトを新規作成し、Person構造体を利用する関数を呼び出した後、destroyPerson()を使ってオブジェクトを破棄しています。

この例ではPerson.hにPerson構造体のメンバをすべてベタ書きしているため、以下のような問題が生じます。

Personオブジェクトの中身を、呼び出し側が自由に変更できてしまう。 上記例では、呼び出し側がp->age = 100;などと内部の値を自由に変更できてしまいます。これはライブラリの作者が予期しない結果をもたらす可能性があります。

Person構造体の実装が外部に露出してしまう。 Person構造体の実装は呼び出し側が知る必要がない情報であっても、実装が露出してしまっています。

Person構造体に変化があるたびに、Person.hの呼び出し側で再コンパイル・再リンクが必要。 ビルドの時間が増加します。またライブラリ側と呼び出し側で異なる定義のPerson構造体を想定している場合、リンクすると危険なことが起こるはずです。

Opaqueポインタを使う場合

上述の問題を解決するためにOpaqueポインタが使われます。修正したPerson.hを以下に示します。

#pragma once

typedef struct Person *PersonPtr;

PersonPtr createPerson(int age);
void printPerson(PersonPtr ptr);
void destroyPerson(PersonPtr ptr);

上記では、Person構造体の定義はしていません。すなわち、Person構造体のメンバを具体的に書き下すことはしていません。そのかわりに、どこかに定義されているPerson構造体へのポインタを、PersonPtrという型名で呼ぶという約束だけをしています。こうすることでPerson.hの呼び出し側にPerson構造体の実装が漏れることがなくなりました。

修正したPerson.cppは以下です。

#include "Person.h"
#include <stdio.h>
#include <stdlib.h>

struct Person
{
    int age;
};

PersonPtr createPerson(int age)
{
    PersonPtr ptr = (PersonPtr) malloc(sizeof(struct Person));
    if (ptr)
    {
        ptr->age = age;
    }
    return ptr;
}

void printPerson(PersonPtr ptr)
{
    if (ptr) printf("age: %d\n", ptr->age);
}

void destroyPerson(PersonPtr ptr)
{
    if (ptr) free(ptr);
}

呼び出し側は以下です。

#include "Person.h"

int main(void)
{
    PersonPtr p = createPerson(42);
    printPerson(p);
    destroyPerson(p);

    return 0;
}

構造体の中身は呼び出し側からは知る由はないので、もし仮にここでp->age = 70;などと構造体の中身を書き換えようとしても、コンパイルが通りません。Opaqueポインタを使うことで実装の詳細を適切に隠蔽でき、安全性も向上していることがわかります。

メインPCをWindows 10にUpgradeした記録

自宅でメインPCとして5年以上使っているDell XPS 8100をWindows 7からWindows 10にアップグレードしました。大多数のアプリは問題なく動いており、おおむね満足です。

このエントリでは、アップグレードにまつわる記録を記します。

アップグレードできなかったソフト

Windows 7にインストールしていたDaemon ToolsはそのままWindows 10に移行できないようだったので、アンインストールしたあと手動で入れなおしました。

Windows 10にしてからの設定

グラボのドライバ

Windows 10へのアップグレード直後はグラボ(Radeon HD57XX)にドライバが当たっておらず、画面の解像度が低く、グラボのファンが高速回転してうなりを上げている状態でした。

AMDのサイトからCatalystの最新版を落として手動インストールするも、毎回ブルースクリーンになり失敗。結局、Windowsによる自動ドライバインストール?により、勝手にドライバが入るのを待たねばなりませんでした。

休止状態の復活

dynabook.com | サポート情報 | [電源](電源メニュー)に[休止状態]が表示されない<Windows 10> 【動画手順付き】

夜中にPCが休止状態から目覚める問題

従来、休止状態にしたPCは勝手に目覚めることはなかったはずですが、Windows 10にしてからは休止状態でも構わずお目覚めになるようになってしまいました。 Windowsでスリープ・休止状態・スタンバイなどの状態が勝手に解除されてしまう現象の回避方法 - 結果だけでなく過程も見てくださいに対策が網羅的に記されているので、順番に試して様子を見ているところです。

Google日本語入力をデフォルトにする

タスクバーの通知領域からGoogle日本語入力を選択しても、いつのまにか異なるIMEに切り替わってしまう現象が起きています。

Windows10で既定のIMEを変えられない? Google日本語入力やATOKに設定する方法 | アプリオの「既定の文字入力方式(IME)を変更する」を実行しましたが改善しません。

IMEが切り替わるたびWin + Spaceというショートカットを使ってGoogle日本語入力に戻していますが、正直面倒です。

(2016/01/26追記)Google日本語入力をアンインストール後にインストールし直すと、「押し間違えの多いホットキー (Ctrl + Shfit) による IME の切り替え機能を無効化する」というオプションの選択ダイアログが出てきました。これまでIMEが勝手に入れ替わると思っていたのは、知らずにこのホットキーを押していたことが原因だったかもしれません。このオプションをONにして様子を見ます。

ソフトのインストール

Travis CI にて、C++11のソースをgccとclangの両方でビルドする

githubレポジトリと簡単に連携できる継続的インテグレーションサービスであるTravis CIを使って、C++11で書かれたソースコードをテストできるようにしました。想像以上に大変だったのでメモしておきます。

ソースコードとテストコードの準備

Travis CIで提供される仮想マシンLinuxOS Xなので、Visual Studio向けのコードはビルドできません。MakefileやCMakeなどコンソールからビルドできる仕組みを用意する必要があります。

今回は以下のような簡単なMakefileを用意しました。

CXX = g++
CPPFLAGS = -I3rdparty/catch -IMyVector
CXXFLAGS = -std=c++11
TARGET = test

$(TARGET): MyVectorTest/main.cpp MyVectorTest/test_constructor.cpp
        $(CXX) $(CXXFLAGS) $(CPPFLAGS) $^ -o $@

clean:
        rm -r $(TARGET)

単に

$ make

とすればg++でビルドできますし、

$ make CXX=clang++

などと変数を引数で指定すればclangでもビルドできます。

今回は、このMakefileを使い、gccとclangの両方でC++11のコードをビルドすることを目標にします。

参考までに、テストフレームワークには、最近人気があるphilsquared/Catchを使っています。ただし本編には関係ありません。

.travis.ymlの作成

Travis CIで提供されるUbuntuマシンで使えるg++とclang++のバージョンは現時点でそれぞれg++ 4.6.3とclang++ 3.4と古く、C++11には対応してません。そこで、Travis CIの設定ファイル.travis.ymlに、新しいバージョンのg++とclang++が使えるよう設定を加える必要があります。

Web検索をしまくった結果できあがったのが以下の設定ファイルです。g++ 5とclang++ 3.7を使ってC++11のコードがビルドできるようになりました。

sudo: false
language: cpp
compiler:
  - clang++
  - g++

install:
  - if [ "$CXX" = "g++" ]; then export CXXFLAGS="-std=c++11"; fi
  - if [ "$CXX" = "g++" ]; then export CXX="g++-5" CC="gcc-5"; fi
  - if [ "$CXX" = "clang++" ]; then export CXXFLAGS="-std=c++11"; fi
  - if [ "$CXX" = "clang++" ]; then export CXX="clang++-3.7" CC="clang-3.7"; fi

  - make CXXFLAGS="${CXXFLAGS}" CXX="${CXX}"

addons:
  apt:
    sources:
      - ubuntu-toolchain-r-test
      - llvm-toolchain-precise-3.7
      - llvm-toolchain-precise
    packages:
      - clang-3.7
      - g++-5
      - gcc-5

script:
  - ./test

addonsの項で何が起こっているのか正確に理解していませんが、とにかくこれがミソのようです。後は変数CXX, CXXFLAGSに適当な変数を代入して、makeの引数として渡せばOKです。

蛇足ですが、このコードにたどり着く前は、以下のようにapt-getや自力ビルドを駆使してg++とclang++を用意していました。複雑な上に時間もかかり不経済なので、このコードを使う必要はまったくありません。

language: cpp
compiler:
    - clang++
    - g++
before_install:
  # g++4.8.1
  - if [ "$CXX" == "g++" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi

  # clang 3.4
  - if [ "$CXX" == "clang++" ]; then sudo add-apt-repository -y ppa:h-rayflood/llvm; fi

  - sudo apt-get update -qq

install:
  # g++4.8.1
  - if [ "$CXX" = "g++" ]; then sudo apt-get install -qq g++-4.8; fi
  - if [ "$CXX" = "g++" ]; then export CXXFLAGS="-std=c++11"; fi
  - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8"; fi

  # clang 3.4
  - if [ "$CXX" == "clang++" ]; then sudo apt-get install --allow-unauthenticated -qq clang-3.4; fi
  - if [ "$CXX" == "clang++" ]; then export CXXFLAGS="-std=c++0x -stdlib=libc++"; fi
  - if [ "$CXX" == "clang++" ]; then svn co --quiet http://llvm.org/svn/llvm-project/libcxx/trunk libcxx; fi

  - if [ "$CXX" == "clang++" ]; then cd libcxx/lib && bash buildit; fi
  - if [ "$CXX" == "clang++" ]; then sudo cp ./libc++.so.1.0 /usr/lib/; fi
  - if [ "$CXX" == "clang++" ]; then sudo mkdir /usr/include/c++/v1; fi
  - if [ "$CXX" == "clang++" ]; then cd .. && sudo cp -r include/* /usr/include/c++/v1/; fi
  - if [ "$CXX" == "clang++" ]; then cd /usr/lib && sudo ln -sf libc++.so.1.0 libc++.so; fi
  - if [ "$CXX" == "clang++" ]; then sudo ln -sf libc++.so.1.0 libc++.so.1 && cd $cwd; fi
  - if [ "$CXX" == "clang++" ]; then export CXX="clang++-3.4"; fi

  - cd ${TRAVIS_BUILD_DIR}
  - ls
  - make CXXFLAGS="${CXXFLAGS}" CXX="${CXX}"
  - ls

script:
  - chmod ugo+x test
  - ./test

ビルド例

githubminus9d/MyVectorTravis CIでテストできるようにしています。この記事執筆時点でのテスト成功例は Build #34 - minus9d/MyVector - Travis CI です。

参考リンク