« 2009年04月 | メイン | 2009年06月 »

2009年05月 アーカイブ

2009年05月08日

Windows 7のバージョン情報を調べた

C++Builder Tipsに「Windowsのバージョンを取得する」の記事を追加しました。

ついでに、Windows 7 RCが返す値を調べてみました。

Windows 7 RCが返した値は次の通りでした。

  • Win32Platform = VER_PLATFORM_WIN32_NT
  • Win32MajorVersion = 6
  • Win32MinorVersion = 1

Windows 「7」なのにメジャーバージョンは「6」でした。

2009年05月10日

Delphiのメソッドをメソッド名から実行する方法

Delphiのメソッドをメソッド名から実行する方法。

元ネタは「Execute a Delphi Method (Procedure/Function) by Name」より。
ヘルプの「TObject::MethodAddress」にも同じことが書かれていました。

次のような関数を用意します。

procedure ExecMethod(OnObject: TObject; MethodName: string);
type
  TExec = procedure of object;
var
  Routine: TMethod;
  Exec: TExec;
begin
  Routine.Data := Pointer(OnObject);
  Routine.Code := OnObject.MethodAddress(MethodName);
  if NOT Assigned(Routine.Code) then Exit;
  Exec := TExec(Routine);
  Exec;
end;

あとはこの関数を使って、目的のメソッドを実行します。

# Form1.Button1Clickを実行する
ExecMethod(Form1, 'Button1Click');

2009年05月12日

propertyを使うにはobjectクラスを継承した新スタイルクラス(new-style class)でなければならない

Pythonのpropertyについて。

objectクラスを継承しない旧スタイルクラス(classic class)でpropertyを使った。

class Foo:
    def __init__(self):
        self.__x = 1
    def getx(self):
        return self.__x
    def setx(self, val):
        self.__x = val
    x = property(getx, setx)

foo = Foo()
print foo.x #=> 1
foo.x = 2
print foo.x #=> 2

一見してうまく動作しているように見える。
ところが、

foo = Foo()
print foo.x #=> 1
print foo.getx() #=> 1
foo.x = 2
print foo.x #=> 2
print foo.getx() #=> 1

と、self.__xは変更されていなかった。

objectクラスを継承した新スタイルクラス(new-style class)にすると、期待通りの動作になる。

class Bar(object):
    def __init__(self):
        self.__x = 1
    def getx(self):
        return self.__x
    def setx(self, val):
        self.__x = val
    x = property(getx, setx)

bar = Bar()
print bar.x #=> 1
print bar.getx() #=> 1
bar.x = 2
print bar.x #=> 2
print bar.getx() #=> 2

propertyを使うには、objectクラスを継承した新スタイルクラス(new-style class)でなければならないようだ。

Python ライブラリリファレンスにも、そのように記載されていました。

property([fget[, fset[, fdel[, doc]]]])
新しい形式のクラス (object から導出されたクラス) におけるプロパティ属性を返します。

Python ライブラリリファレンス 2.1 組み込み関数

2009年05月14日

作家のつながりを視覚的に表現したビーケーワンの「作家マップ」

作家マップは、利用者の方がアクセスしたいくつかの書籍の著者同士をつなげて、地図のように一覧表示する機能です。多くのユーザーに共通してアクセスされている作家ほど近い関係としてマップに登場してきます。

オンライン書店ビーケーワン:新機能「作家マップ」

おもしろい試みです。
操作感もいいです。画面のスクロールが気持ちよく動きます。

ただ、ちょっとデータが少ないように思いました。
たとえば、例としてあげられている「チャンドラー」ですが、 『プードル・スプリングス物語』の共著者である「ロバート・B・パーカー」はつながりがあって当然だし、「原 りょう」とつながっていてもおかしくないはず。

データ量が増えると、おもしろいページになるかもしれません。
これからに期待。

疲れ目の原因「隠れ斜視」

本当は怖い家庭の医学」というテレビ番組で、疲れ目の原因の一つとして「隠れ斜視」が取り上げられました。

「隠れ斜視」という言葉はこの番組の造語のようで、 一般には「斜位」や「潜伏性斜視」というようです。
以下、「斜位」を使用することにします。

斜位について、次のページが参考になりました。

斜位は、大半の人はこの症状を少しは持っているそうです。
病気ではなく、日常生活では気づきにくいようです。
ただ、パソコン作業のように近くのものをずっと見続けると、目が疲れやすくなります。

専門の器具がなくてもカバーテストという方法で、斜位のチェックができます。
疲れ目が気になる人、斜位かどうか一度チェックしてみてはいかがでしょうか。

もし斜位だった場合(大半の人はそうなのですが)、対策としては「プリズム入り眼鏡」「トレーニング」「手術」があるようです。
プリズム入り眼鏡が簡単で、即効性がありますね。 パソコン用に一つプリズム入り眼鏡を用意するのもいいかもしれません。 ブログや掲示板を見ていると、軽度の斜位の人が疲れ目対策にプリズム入り眼鏡というケースもみつかりました。

ただ問題としては、眼科医も眼鏡店も問題意識は低く、ちゃんと対応できるところはわずかなようです。

自分も斜位だと疑い、眼科に行っても、それを判断出来る体制も人材も整っていないのが現状だろう。 それでは受け付けた眼科医さんもよく分からないのだから問題無しとお医者様が太鼓判を押してしまうケースも当然ある。

隠れ斜視パートⅢ~どこまで踏み込む!?~

眼鏡店でも斜位の検査をしているところはごく少数派で、大半の眼鏡店はそれをしていません。

しかし、快適なメガネの度数を決めるための検査において、斜位の測定は必須なのです。

「斜視」と「斜位」とは何か?

専門家のいるところを探すのが大変かもしれません。
大阪でおすすめの眼科医や眼鏡店をご存じでしたら教えてください。

最後に、心に残ったのがこの文章です。

確かに僕も斜位の検査を全ての方に実施すれば、多くの方の能力が増え、当然稼ぎも増え、学力が平均値に追いつかず脱落する方々が減る。

隠れ斜視!?

当人の能力や努力とは無関係に、斜位のために本来持っている自分の能力を発揮できないという問題。
気づかないだけで、もしかすると本当はたくさんあるのかもしれません。

幅優先探索

Javaによる知能プログラミング入門』の「2.探索とパターン照合」にある幅優先探索のソースコードをPythonで実装してみました。

有向グラフとして表現されている状態空間の、初期状態から目標状態までの探索を行います。

状態空間

元のJavaのコードはSearchクラスのbreadthFirstメソッドとして実装されていますが、 今回は関数として実装しました。

実際に探索を行うのはbreadth_first()関数です。
ポイントは隣接する状態を探索して、探索予定ノードリスト(変数open)に追加するところです。

for m in node.children:
    if m in open or m in closed:
        continue
    m.pointer = node
    if m == goal:
        open.insert(0, m)
    else:
        open.append(m)

探索予定ノードリスト(変数open)の末尾に隣接する状態を追加しているので、幅優先探索になります。
ここを変えると深さ優先探索になります。

#! /usr/bin/python
# -*- coding: Shift_JIS -*-

class Node:
    def __init__(self, name):
        """
        @param name: 都市名
        """
        self.name = name
        self.children = [] #遷移できるノードのリスト
        self.pointer = None #解表示のためのポインタ

    def __str__(self):
        return self.name

def nodes_str(nodes):
    """
    Nodeのリストの出力用文字列を作成する
    @param nodes: Nodeのリスト
    """
    return map(str, nodes)

def make_state_space():
    """
    状態空間の生成
    @return: ノードのリストを返す。
    """
    node = [Node("L.A.Airport"),
            Node("UCLA"),
            Node("Hoolywood"),
            Node("Anaheim"),
            Node("GrandCanyon"),
            Node("SanDiego"),
            Node("Downtown"),
            Node("Pasadena"),
            Node("DisneyLand"),
            Node("Las Vegas")]
    node[0].children = [node[1], node[2]]
    node[1].children = [node[2], node[6]]
    node[2].children = [node[3], node[6], node[7]]
    node[3].children = [node[4], node[7], node[8]]
    node[4].children = [node[8], node[9]]
    node[5].children = [node[1]]
    node[6].children = [node[5], node[7]]
    node[7].children = [node[8], node[9]]
    node[8].children = [node[9]]
    return node

def print_solution(node):
    """
    解の表示
    """
    if node.pointer == None:
        print node
    else:
        print node, "<-",
        print_solution(node.pointer)

def breadth_first(start, goal):
    """
    幅優先探索
    @param start: 探索開始ノード
    @param goal: 探索終了ノード
    """
    open = [start] #探索予定のノードのリスト
    closed = [] #探索を終了したノードのリスト
    success = False
    step = 0

    while 1:
        step += 1
        print "STEP:", step
        print "OPEN:", nodes_str(open)
        print "closed:", nodes_str(closed)

        if len(open) == 0:
            success = False
            break

        node = open.pop(0)
        if node == goal:
            success = True
            break

        closed.append(node)
        for m in node.children:
            if m in open or m in closed:
                continue
            m.pointer = node
            if m == goal:
                open.insert(0, m)
            else:
                open.append(m)
    if success:
        print "*** Solution ***"
        print_solution(goal)

if __name__ == "__main__":
    nodes = make_state_space()
    breadth_first(nodes[0], nodes[-1])

ちなみに、NetBeansのPythonプラグインを使ってみました。
よくできていて、なかなか快適です。

2009年05月15日

深さ優先探索

前回の「幅優先探索」の続きです。

Javaによる知能プログラミング入門』の「2.探索とパターン照合」にある深さ優先探索のソースコードをPythonで実装してみました。

有向グラフとして表現されている状態空間の、初期状態から目標状態までの探索を行います。

状態空間

元のJavaのコードはSearchクラスのbreadthFirstメソッドとして実装されていますが、 今回は関数として実装しました。

実際に探索を行うのはdepth_first()関数です。
ポイントは隣接する状態を探索して、探索予定ノードリスト(変数open)に追加するところです。

j = 0
for m in node.children:
    if m in open or m in closed:
        continue
    m.pointer = node
    if m == goal:
        open.insert(0, m)
    else:
        open.insert(j, m)
    j += 1

探索予定ノードリスト(変数open)の先頭から隣接する状態を追加しているので、深さ優先探索になります。
ここを変えると幅優先探索になります。

#! /usr/bin/python
# -*- coding: Shift_JIS -*-

class Node:
    def __init__(self, name):
        """
        @param name: 都市名
        """
        self.name = name
        self.children = [] #遷移できるノードのリスト
        self.pointer = None #解表示のためのポインタ

    def __str__(self):
        return self.name

def nodes_str(nodes):
    """
    Nodeのリストの出力用文字列を作成する
    @param nodes: Nodeのリスト
    """
    return map(str, nodes)

def make_state_space():
    """
    状態空間の生成
    @return: ノードのリストを返す。
    """
    node = [Node("L.A.Airport"),
            Node("UCLA"),
            Node("Hoolywood"),
            Node("Anaheim"),
            Node("GrandCanyon"),
            Node("SanDiego"),
            Node("Downtown"),
            Node("Pasadena"),
            Node("DisneyLand"),
            Node("Las Vegas")]
    node[0].children = [node[1], node[2]]
    node[1].children = [node[2], node[6]]
    node[2].children = [node[3], node[6], node[7]]
    node[3].children = [node[4], node[7], node[8]]
    node[4].children = [node[8], node[9]]
    node[5].children = [node[1]]
    node[6].children = [node[5], node[7]]
    node[7].children = [node[8], node[9]]
    node[8].children = [node[9]]
    return node

def print_solution(node):
    """
    解の表示
    """
    if node.pointer == None:
        print node
    else:
        print node, "<-",
        print_solution(node.pointer)

def depth_first(start, goal):
    """
    深さ優先探索
    @param start: 探索開始ノード
    @param goal: 探索終了ノード
    """
    open = [start] #探索予定のノードのリスト
    closed = [] #探索を終了したノードのリスト
    success = False
    step = 0

    while 1:
        step += 1
        print "STEP:", step
        print "OPEN:", nodes_str(open)
        print "closed:", nodes_str(closed)

        if len(open) == 0:
            success = False
            break

        node = open.pop(0)
        if node == goal:
            success = True
            break

        closed.append(node)
        j = 0
        for m in node.children:
            if m in open or m in closed:
                continue
            m.pointer = node
            if m == goal:
                open.insert(0, m)
            else:
                open.insert(j, m)
            j += 1
    if success:
        print "*** Solution ***"
        print_solution(goal)

if __name__ == "__main__":
    nodes = make_state_space()
    depth_first(nodes[0], nodes[-1])

Ruby on RailsでRSpecを使うときに使用するコマンドのまとめ

Ruby on RailsでRSpecを使うときに使用するコマンドのまとめ

RSpecとrspec-railsのインストール(Ruby on Rails 2.1.0以上の場合)

gem install rspec
gem install rspec-rails

#Ruby on Rails 2.1.0未満の場合はhttp://wiki.github.com/dchelimsky/rspec/railsを参考にしてください。

色づけして表示するならWindowsならwin32consoleが必要

gem install win32console

カバレッジテストに必要

gem install rcov

必要なファイルの作成

ruby script/generate rspec

RSpecのバージョンの確認

ruby script/spec -v

モデルの作成

ruby script/generate rspec_model モデル名 [フィールド名:データ型 …]

# 例
ruby script/generate rspec_model person name:string

コントローラの作成

ruby script/generate rspec_controller コントローラ名 [メソッド名 …]

#例
ruby script/generate rspec_controller person

ひな形の作成

ruby script/generate rspec_scaffold モデル名 [フィールド名:データ型 …]

#例
ruby script/generate rspec_scaffold purchase order_id:integer amount:decimal

任意のspecを実行

ruby script\spec ファイル名

# 例
ruby script\spec spec\models\blog_spec.rb

すべてのspecを実行

rake spec

モデルのspecを実行

rake spec:models

コントローラのspecを実行

rake spec:controllers

ヘルパーのspecを実行

rake spec:helpers

ビューのspecを実行

rake spec:views

データベースにfixtureファイルを読み込む

rake spec:db:fixtures:load

Specdocを出力

rake spec:doc

vendor/plugin 以下にあるspecを実行

rake spec:plugins

vendor/plugin以下にあるspecのSpecdocを出力

rake spec:plugin_doc

すべてのspecを実行し、rcovで測定
($RAILS_ROOT/coverage ディレクトリにファイルが作成される)

rake spec:rcov

RSpec関連のタスクをすべて表示

rake --tasks spec

spec_serverを使用する

ruby script/spec_server &
ruby script/spec --drb spec/models

または、spec/spec.optsを編集して- -drb を追加する

2009年05月16日

分岐限定法

前回の「深さ優先探索」の続きです。

Javaによる知能プログラミング入門』の「2.探索とパターン照合」にある分岐限定法のソースコードをPythonで実装してみました。

有向グラフとして表現されている状態空間の、初期状態から目標状態までの探索を行います。

ノード間の□の中の数字は、各ノード間のコストを表します。
分岐限定法では、コストが最も小さいノードからたどっていきます。

ポイントはソースコードの次の部分です。 ノードのg_valueは、初期状態からそのノードへの最小コストを表します。

# node を展開して子節点をすべて求める
for m in node.children:
    # 子節点mがopenにもclosedにも含まれていなければ
    if m not in open and m not in closed:
        # m から node へのポインタを付ける.
        m.pointer = node
        # nodeまでの評価値とnode->mのコストを足したものをmの評価値とする
        m.g_value = node.g_value + node.get_cost(m)
        open.append(m)
    # 子節点mがopenに含まれているならば,
    if m in open:
        gmn = node.g_value + node.get_cost(m)
        if gmn < m.g_value:
            m.g_value = gmn
            m.pointer = node
# Nodeをg_valueの昇順(小さい順)に列べ換える
sort_upper_by_g_value(open)

探索するノードが見つかると、g_valueを計算します。
そして、g_valueでソートしてコストの小さいものから探索します。

#! /usr/bin/python
# -*- coding: Shift_JIS -*-

def printNodes(nodes):
    """
    Nodeのリストの出力用文字列を作成する
    nodes Nodeのリスト
    """
    return map(str, nodes)

class Node(object):
    def __init__(self, name):
        self.name = name
        self.children = [] #遷移できるノードのリスト
        self.children_costs = {} #<Node, Integer>
        self.pointer = None #解表示のためのポインタ
        self.__g_value = 0 # コスト
        self.has_g_value = False

    def get_g_value(self):
        return self.__g_value
    def set_g_value(self, value):
        self.has_g_value = True
        self.__g_value = value
    g_value = property(get_g_value, set_g_value)

    def add_child(self, child, cost):
        """
        @param child: この節点の子節点
        @param cost:  その子節点までのコスト
        """
        self.children.append(child)
        self.children_costs[child] = cost

    def get_cost(self, child):
        """
        子節点までのコストを取得する
        @param child: この節点の子節点
        @return: 子節点までのコスト
        """
        return self.children_costs[child]

    def __str__(self):
        result = self.name
        if self.has_g_value:
            result = "%s(g:%d)" % (result, self.__g_value)
        return result

def nodes_str(nodes):
    """
    Nodeのリストの出力用文字列を作成する
    @param nodes: Nodeのリスト
    """
    return map(str, nodes)

def make_state_space():
    """
    状態空間の生成
    @return: ノードのリストを返す。
    """
    node = [Node("L.A.Airport"),
            Node("UCLA"),
            Node("Hoolywood"),
            Node("Anaheim"),
            Node("GrandCanyon"),
            Node("SanDiego"),
            Node("Downtown"),
            Node("Pasadena"),
            Node("DisneyLand"),
            Node("Las Vegas")]
    node[0].add_child(node[1],1)
    node[0].add_child(node[2],3)
    node[1].add_child(node[2],1)
    node[1].add_child(node[6],6)
    node[2].add_child(node[3],6)
    node[2].add_child(node[6],6)
    node[2].add_child(node[7],3)
    node[3].add_child(node[4],5)
    node[3].add_child(node[7],2)
    node[3].add_child(node[8],4)
    node[4].add_child(node[8],2)
    node[4].add_child(node[9],1)
    node[5].add_child(node[1],1)
    node[6].add_child(node[5],7)
    node[6].add_child(node[7],2)
    node[7].add_child(node[8],3)
    node[7].add_child(node[9],7)
    node[8].add_child(node[9],5)
    return node

def print_solution(node):
    """
    解の表示
    """
    if node.pointer == None:
        print node
    else:
        print node, "<-",
        print_solution(node.pointer)

def sort_upper_by_g_value(open):
    """
    Nodeをg_valueの昇順(小さい順)に列べ換える
    @param open: Nodeのリスト
    """
    def g_value_compare(x, y):
        return x.g_value - y.g_value
    open.sort(g_value_compare)

def branch_and_bound(start, goal):
    """
    分岐限定法
    @param start: 探索開始ノード
    @param goal: 探索終了ノード
    """
    open = [start] #探索予定のノードのリスト
    start.g_value = 0
    closed = [] #探索を終了したノードのリスト
    success = False
    step = 0

    while 1:
        step += 1
        print "STEP:", step
        print "OPEN:", nodes_str(open)
        print "closed:", nodes_str(closed)

        if len(open) == 0:
            success = False
            break

        node = open.pop(0)
        if node == goal:
            success = True
            break

        closed.append(node)
        # node を展開して子節点をすべて求める.
        for m in node.children:
            # 子節点mがopenにもclosedにも含まれていなければ,
            if m not in open and m not in closed:
                # m から node へのポインタを付ける.
                m.pointer = node
                # nodeまでの評価値とnode->mのコストを足したものをmの評価値とする
                m.g_value = node.g_value + node.get_cost(m)
                open.append(m)
            # 子節点mがopenに含まれているならば,
            if m in open:
                gmn = node.g_value + node.get_cost(m)
                if gmn < m.g_value:
                    m.g_value = gmn
                    m.pointer = node
        # Nodeをg_valueの昇順(小さい順)に列べ換える
        sort_upper_by_g_value(open)
    if success:
        print "*** Solution ***"
        print_solution(goal)

if __name__ == "__main__":
    nodes = make_state_space()
    branch_and_bound(nodes[0], nodes[-1])

2009年05月17日

sprinfのC++版「boost::format」

C++Builder 2009からBoostが標準添付されて、とても使いやすくなりました。

そのBoostのライブラリの一つ「boost::format」は、sprinfのC++版とも言えるライブラリです。
(The Boost Format library)

printfの書式指定子と同じ書式文字列を使用することができます。
また拡張フォーマットにより%1%で1番目の引数、%2%で2番目の引数を出力できます。

//formatの生成
format fmter("%1% %2% \n"); //引数は書式文字列
cout << fmter % "abc" % "efg"; //=> abc efg

//何度でも取り出せる
string s1 = fmter.str(); //メンバ関数str()
cout << s1; //=> abc efg

//何度でも取り出せる
string s2 = str(fmter); //関数boost::str()
cout << s2; //=> abc efg

//並べ替え
cout << format("%1% %2% %3% %2% %1% \n") % "11" % "22" % "33";
//=> 11 22 33 22 11

//printf互換
cout << format("%05d %x %f %%") % 200 % 255 % 3.33;
//=> 00200 ff 3.330000 %

2009年05月18日

RSpecのコントローラのテストで利用できる機能

アクセス

Getでアクセスする

get(action, params={})

#例
get(:index, :username => 'foo', :password => 'bar')

Postでアクセスする

post(action, params={})
#例
post(:index, :username => 'foo', :password => 'bar')

取得

レスポンスを取得する

reponse()

コントローラのインスタンス変数を取得する

assigns[変数名]

#例
user = assigns[:user]

セッションオブジェクトを取得する

session()

#例
session[:user].id.should == 1

flashの内容を取得する

flash()

#例
flash[:error_message].should be_blank

コントローラのテストで使うmatcher

レスポンスのステータスコード

response.should be_success

リダイレクト先

response.should redirect_to(:controller => 'login', :action => 'index')

テンプレート

response.should render_template('login')

A*アルゴリズム

前回の「分岐限定法」の続きです。

Javaによる知能プログラミング入門』の「2.探索とパターン照合」にあるA*アルゴリズムのソースコードをPythonで実装してみました。
本では分岐限定法の後に山登り法と最良優先探索を説明して問題点を明らかにし、その後でA*アルゴリズムが説明されています。

有向グラフとして表現されている状態空間の、初期状態から目標状態までの探索を行います。

ノード間の□の中の数字は、各ノード間のコストを表します。
各ノートに添付された○の中の数字は、そのノードのヒューリスティックな値を表します。

#! /usr/bin/python
# -*- coding: Shift_JIS -*-

def printNodes(nodes):
    """
    Nodeのリストの出力用文字列を作成する
    nodes Nodeのリスト
    """
    return map(str, nodes)

class Node(object):
    def __init__(self, name, value):
        self.name = name
        self.children = [] #遷移できるノードのリスト
        self.children_costs = {} #<Node, Integer>
        self.pointer = None #解表示のためのポインタ
        self.__g_value = 0 # コスト
        self.__f_value = 0 # 評価値
        self.has_g_value = False
        self.has_f_value = False
        self.h_value = value # ヒューリスティック値

    def get_f_value(self):
        return self.__f_value
    def set_f_value(self, value):
        self.has_f_value = True
        self.__f_value = value
    f_value = property(get_f_value, set_f_value)

    def get_g_value(self):
        return self.__g_value
    def set_g_value(self, value):
        self.has_g_value = True
        self.__g_value = value
    g_value = property(get_g_value, set_g_value)

    def add_child(self, child, cost):
        """
        @param child: この節点の子節点
        @param cost:  その子節点までのコスト
        """
        self.children.append(child)
        self.children_costs[child] = cost

    def get_cost(self, child):
        """
        子節点までのコストを取得する
        @param child: この節点の子節点
        @return: 子節点までのコスト
        """
        return self.children_costs[child]

    def __str__(self):
        result = "%s(h:%d)" % (self.name, self.h_value)
        if self.has_g_value:
            result = "%s(g:%d)" % (result, self.g_value)
        if self.has_f_value:
            result = "%s(f:%d)" % (result, self.f_value)
        return result

def nodes_str(nodes):
    """
    Nodeのリストの出力用文字列を作成する
    @param nodes: Nodeのリスト
    """
    return map(str, nodes)

def make_state_space():
    """
    状態空間の生成
    @return: ノードのリストを返す。
    """
    node = [Node("L.A.Airport",0),
            Node("UCLA",7),
            Node("Hoolywood",4),
            Node("Anaheim",6),
            Node("GrandCanyon",1),
            Node("SanDiego",2),
            Node("Downtown",3),
            Node("Pasadena",4),
            Node("DisneyLand",2),
            Node("Las Vegas",0)]
    node[0].add_child(node[1],1)
    node[0].add_child(node[2],3)
    node[1].add_child(node[2],1)
    node[1].add_child(node[6],6)
    node[2].add_child(node[3],6)
    node[2].add_child(node[6],6)
    node[2].add_child(node[7],3)
    node[3].add_child(node[4],5)
    node[3].add_child(node[7],2)
    node[3].add_child(node[8],4)
    node[4].add_child(node[8],2)
    node[4].add_child(node[9],1)
    node[5].add_child(node[1],1)
    node[6].add_child(node[5],7)
    node[6].add_child(node[7],2)
    node[7].add_child(node[8],3)
    node[7].add_child(node[9],7)
    node[8].add_child(node[9],5)
    return node

def print_solution(node):
    """
    解の表示
    """
    if node.pointer == None:
        print node
    else:
        print node, "<-",
        print_solution(node.pointer)

def sort_upper_byf_value(open):
    """
    Nodeをf_valueの昇順(小さい順)に列べ換える
    @param open: Nodeのリスト
    """
    def f_value_compare(x, y):
        return x.f_value - y.f_value
    open.sort(f_value_compare)

def a_star(start, goal):
    """
    最良優先探索
    @param start: 探索開始ノード
    @param goal: 探索終了ノード
    """
    open = [start] #探索予定のノードのリスト
    start.g_value = 0
    start.f_value = 0
    closed = [] #探索を終了したノードのリスト
    success = False
    step = 0

    while 1:
        step += 1
        print "STEP:", step
        print "OPEN:", nodes_str(open)
        print "closed:", nodes_str(closed)

        if len(open) == 0:
            success = False
            break

        node = open.pop(0)
        if node == goal:
            success = True
            break

        closed.append(node)
        for m in node.children:
            gmn = node.g_value + node.get_cost(m)

            if m not in open and m not in closed:
                m.g_value = gmn

            if m in open:
                if gmn < m.g_value:
                    m.g_value = gmn
                    m.pointer = node

            fmn = gmn + m.h_value
            if m not in open and m not in closed:
                m.pointer = node
                m.f_value = fmn
                open.append(m)

            if m in open and fmn < m.f_value:
                m.f_value = fmn
                open.append(m)
                m.pointer = node

            if m in closed and fmn < m.f_value:
                m.pointer = node
                m.f_value = fmn
                closed.remove(m)
                open.append(m)

        sort_upper_byf_value(open)

    if success:
        print "*** Solution ***"
        print_solution(goal)

if __name__ == "__main__":
    nodes = make_state_space()
    a_star(nodes[0], nodes[-1])

2009年05月19日

パターン照合(1)

Javaによる知能プログラミング入門』の「2.探索とパターン照合」にあるパターン照合プログラムのソースコードをPythonで実装してみました。

このプログラムはパターンが文字列に一致するかどうかをテストします。
パターンでは、「?」を先頭に付加した文字列を変数とします。
たとえば「?x」は変数です。

次のような動作を期待します。

文字の比較

matching("Hanako", "Hanako") #=> True
matching("Taro", "Hanako") #=> False

変数を含むパターンとの比較

matching("I am ?x", "I am Hanako") #=> True(?x : Hanako)

同じ変数を複数回使用できる。

matching("?x is ?x", "a is a") #=> True(?x : a)
matching("?x is ?x", "a is b") #=> False

複数の変数を使用できる

matching("?x is ?y", "a is b") #=> True(?x : a, ?y : b)

ソースコードの全体です。

#! /usr/bin/python
# -*- coding: Shift_JIS -*-

import re

def matching(string1, string2):
    """
    実際にマッチングを行う関数
    @param string1: マッチングをする文字列
    @param string2: マッチングをする文字列
    @return: 成功ならTrue,失敗なら False
    """
    vars = {} #変数と値の辞書

    print string1
    print string2

    # 同じなら成功
    if string1 == string2: return True

    # 各々トークンに分ける
    r = re.compile('\s')
    sl1 = r.split(string1)
    sl2 = r.split(string2)

    # 数が異なったら失敗
    if len(sl1) != len(sl2): return False

    # 定数同士
    for s1, s2 in zip(sl1, sl2):
        if not token_matching(s1, s2, vars):
            return False

    # 最後まで O.K. なら成功
    print vars
    return True

def token_matching(token1, token2, vars):
    if token1 == token2: return True
    if var(token1) and not var(token2): return var_matching(token1, token2, vars)
    if not var(token1) and var(token2): return var_matching(token2, token1, vars)
    return False

def var(str):
    """ strは変数か。先頭が ? なら変数。 """
    return str.startswith("?")

def var_matching(vartoken, token, vars):
    if vars.has_key(vartoken):
        if vars[vartoken] == token:
            return True
        else:
            return False
    vars[vartoken] = token
    return True

if __name__ == "__main__":
    print matching("Hanako", "Hanako")
    print matching("Taro", "Hanako")
    print matching("I am ?x", "I am Hanako")
    print matching("?x is ?x", "a is a")
    print matching("?x is ?x", "a is b")
    print matching("?x is ?y", "a is b")

2009年05月20日

ユニフィケーション照合アルゴリズム

前回(パターン照合(1))の続き。

Javaによる知能プログラミング入門』の「2.探索とパターン照合」にあるパターン照合プログラムのソースコードをPythonで実装してみました。

前回のパターン照合プログラムは文字列とパターンが一致するかをテストしました。
今回のプログラムでは、2つのパターンが矛盾のない変数代入によって同一と判断できるかをテストします。

次のパターンをテストします。

print Unify().unify("Takayuki", "Takayuki")
print Unify().unify("Takayuki", "Takoyuki")
print Unify().unify("?x am Takayuki", "I am Takayuki")
print Unify().unify("?x is ?x", "a is b")
print Unify().unify("?x is ?x", "a is a")
print Unify().unify("?x is a", "b is ?y")
print Unify().unify("?x is a", "?y is ?x")

ユニフィケーション照合アルゴリズムというらしい。

関数をまたかってやりとりする変数(vars,buffer1,buffer2)があるので、クラスにしました。
読みやすくなったかどうかは、微妙なところです。

#! /usr/bin/python
# -*- coding: Shift_JIS -*-
import re

class Unify(object):
    def __init__(self):
        self.vars = {} #変数と値の辞書

    def unify(self, str1, str2):
        print str1
        print str2

        # 同じなら成功
        if str1 == str2: return True

        # 各々トークンに分ける
        r = re.compile('\s')
        self.buffer1 = r.split(str1)
        self.buffer2 = r.split(str2)

        # 数が異なったら失敗
        if len(self.buffer1) != len(self.buffer2): return False

        for i in range(len(self.buffer1)):
            if not self.token_matching(self.buffer1[i], self.buffer2[i]):
                return False

        print self.vars
        return True

    def token_matching(self, token1, token2):
        if token1 == token2: return True
        if var(token1) and not var(token2): return self.var_matching(token1, token2)
        if not var(token1) and var(token2): return self.var_matching(token2, token1)
        if var(token1) and var(token2): return self.var_matching(token1, token2)
        return False

    def var_matching(self, vartoken, token):
        if self.vars.has_key(vartoken):
            if token == self.vars[vartoken]:
                return True
            else:
                return False
        else:
            self.replace_buffer(vartoken, token);
            if self.vars.has_key(vartoken):
                self.replace_bindings(vartoken,token)
            self.vars[vartoken] = token
        return True

    def replace_buffer(self, pre_string, post_string):
        def replace_pre(x):
            if pre_string == x:
                return post_string
            else:
                return x
        self.buffer1 = map(replace_pre, self.buffer1)
        self.buffer2 = map(replace_pre, self.buffer2)

    def replace_bindings(self, pre_string, post_string):
        for key in self.vars.keys():
            if pre_string == self.vars[key]:
                self.vars[key] = post_string

def var(str):
    """ strは変数か。先頭が ? なら変数。 """
    return str.startswith("?")

if __name__ == "__main__":
    print Unify().unify("Takayuki", "Takayuki")
    print Unify().unify("Takayuki", "Takoyuki")
    print Unify().unify("?x am Takayuki", "I am Takayuki")
    print Unify().unify("?x is ?x", "a is b")
    print Unify().unify("?x is ?x", "a is a")
    print Unify().unify("?x is a", "b is ?y")
    print Unify().unify("?x is a", "?y is ?x")

2009年05月22日

専門家による新型インフルエンザへの対応策の提言

日本感染症学会が『日本感染症学会緊急提言「一般医療機関における新型インフルエンザへの対応について」』を公開しました。

専門家による信頼できる情報です。

一般人は何ができるかというと「一般予防策ではうがい、手洗い、マスクが効果的です」とあります。
マスクの有効性については賛否両論あるそうですが、WHOは今回の新型インフルエンザ対策としての市中でのマスク着用を勧めています。
予防策はうがい・手洗い・マスクです。

知らないことがたくさんあり、とても勉強になります。

「20世紀の新型インフルエンザは、国内では、すべて2回の流行を起こしている事実」から、「今年の秋か、冬に大きな流行になると専門家が警戒している」とのこと。

「数年以内にはほぼ全ての国民が感染し、以後は通常の季節性インフルエンザになっていきます。」

などなど。

2009年05月24日

Django TIPSのページを作成しました。

Django TIPSのページを作成しました。

勉強したことを少しずつ記事として掲載していきたいと思います。

2009年05月27日

ファイル名に使用できない文字を判別する

PathGetCharTypeを使用すると、ファイル名に使用できない文字を判別することができます。

こんな便利な関数が用意されているとは知りませんでした。
ファイル名に使用できない文字の一覧表を作成して、チェックする必要はありませんでした。

サンプルコードです。
C++Builder2009で動作を検証しました。

#pragma hdrstop
#include <tchar.h>
#include <shlwapi.h>
#include <iostream>

#pragma argsused
#pragma link "shlwapi.lib"

using namespace std;
using namespace boost;
void CheckChar(wchar_t  C)
{
  const unsigned int result = PathGetCharType(C);
  if (result & GCT_INVALID)
    wcout << C << L" は不正な文字です。" << endl;
  if (result & GCT_LFNCHAR)
    wcout << C << L" は長いファイル名に使用できます。" << endl;
  if (result & GCT_SEPARATOR)
    wcout << C << L" は区切り文字です。" << endl;
  if (result & GCT_SHORTCHAR)
    wcout << C << L" は短いファイル名に使用できます。" << endl;
  if (result & GCT_WILD)
    wcout << C << L" はワイルドカード文字です。" << endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
  wcout.imbue(locale("japanese"));
  const wchar_t chars[] = L"\\/:,;*?\"<>|aあ";

  for (unsigned int i = 0; i < sizeof(chars) / sizeof(wchar_t); ++i)
  {
    CheckChar(chars[i]);
  }
    return 0;
}

実行結果

\ は区切り文字です。
: は区切り文字です。
, は長いファイル名に使用できます。
; は長いファイル名に使用できます。
* はワイルドカード文字です。
? はワイルドカード文字です。
a は長いファイル名に使用できます。
a は短いファイル名に使用できます。
あ は長いファイル名に使用できます。
あ は短いファイル名に使用できます。

追記
C++Builder Tipsに「ファイル名として正しいかどうかを調べる」を掲載しました。
ウィキペディアの「ファイル名の項」を参考にして、予約されているファイル名の検証も追加しています。

InitializeCriticalSectionEx

InitializeCriticalSectionExについて

Team Japan » InitializeCriticalSectionEx」によると、Windows Vista以降でクリティカルセクションのメモリ管理に関して仕様変更があり、InitializeCriticalSectionによる初期化ではリソースリークが発生するとのこと。
実行時にOSのバージョンをチェックして、動的に「InitializeCriticalSectionEx」を呼び出すようコードが紹介されています。

近いうちにC++Builderで書き直してみたいと思います。

Owl's perspective: InitializeCriticalSectionEx」も勉強になります。
Windowsデバッグの極意』という本が紹介されていて、良さそうな本に見えますが、値段を見ると気軽に手が出せません。
高橋智宏さんが紹介されている『Concurrent Programming on Windows』は洋書です。
なおさら手が出ません。

皆さん、よく勉強されているんですね。

2009年05月28日

ESET Smart Securityを安く購入する方法

イーセットスマートセキュリティ(ESET Smart Security)を購入しました。

ESET Smart Securityの性能の良さは、検索エンジンで調べてもらえばすぐにわかると思います。

無料で30日間使える体験版もありますので、お試し下さい。

さて、本題です。

イーセットスマートセキュリティ(ESET Smart Security)を安く購入する方法ですが、まずバリューコマースに登録します。

登録したら、ログインして、画面右にある「オファーリスト」からECサイト情報で「株式会社EC studio」を検索します。
見つかったら、「詳細」から「オファーに申し込む」ボタンを押します。

広告を作れるようになったら、株式会社EC studioの広告を作成します。

作成した広告を自分でクリックして、イーセットスマートセキュリティ(ESET Smart Security)を購入すればOKです。

購入1件(注文者からの入金確認)につき1000円(11月末まで1200円キャンペーン中!)。本人申込OK。

とありますので、本人申し込みも認められています。

ちょっと手間ですけど、1000円は大きいと思います。

C++Builder 2009 Update 3、Update 4、Boost Updateで、どこが修正されたのか

C++Builder 2009 Update 3、Update 4、Boost Updateがリリースされました。

「アップデートの確認」からインストールできます。
「[RAD Studio 2009 Update 3, Update 4 & Boost Update]」からもダウンロードできます。
想像通り、アップデートには時間がかかりますので、ご注意を。

Update 3 で修正された問題を見ると、たくさんの修正が行われています。

  • AnsiPos method of AnsiString class returns Unicode based index
  • LastDelimiter method of AnsiString class returns Unicode based index

    AnsiString::AnsiPosとAnsiString::LastDelimiterの挙動が、C++Builder2007以前と同じになりました。
    以前にこのブログに書いた件ですね。(C++Builder 2009への移植作業 その1)(C++Builder 2009への移植作業 その2)
    古いバージョンからの移植が楽になりました。

  • Implementation missing for UnicodeString::LastChar

    以前にこのブログに書いた件です。(UnicodeString#LastChar()がILINK32エラー)
    UnicodeString::LastCharが使えるようになりました。

  • Unresolved externals when linking pngimage.obj

    C++Builder Tipsに書いた「C++Builder2009でPNGを扱うとコンパイルエラーになる問題の解決方法」です。
    「[ILINK32 エラー] Error: 未解決の外部参照 'Pnglang::_EPngInvalidCRCText' が …」が発生しなくなりました。

  • DynamicArray template class does not use VCL memory management

    次のコードでCodeGuardがエラーを報告しないようになりました。

    UnicodeString a = "abc";
    a.BytesOf();
    

そのほかにもいろいろと気になる修正があります。

  • Lost focus after TOpenDialog when MainFormOnTaskBar is set
  • W8114: __DATE__ macro returns invalid string under Japanese locale
  • The UnicodeString( char *, int ) constructor is broken
  • C++ typedefs generated from Delphi class aliases are not correct
  • C++ Unit Test TTestCase constructors are incorrect
  • Length calculation of the UTF32ToUTF16 function is incorrect

Update 4 ではデータベース関連の問題が修正されたようです。
データベース関連の機能はあまり使っていないので、詳細は見ていません。

Boostライブラリアップデートですが、どこが変わったのでしょうか?

#include <boost/version.hpp>
std::cout << BOOST_LIB_VERSION << std::endl; //=>1_35

なので、バージョンは変わっていないようです。
使えるライブラリが増えたのでしょうか?

2009年5月29日 追記

Update2 時点のものと更新後の boost ヘッダの diff を取ってみましたが、残念ながら新たなライブラリは追加されてないようです。

C++Builder2009 Boost Update の更新内容

うーん、残念です。

英語サイト(Release Notes for RAD Studio 2009 Update Pack (Updates 3, 4, and Boost)の方にも、

What are the changes for the Boost library update?

というコメントがありました。
みんな、不思議に思っているのかも。

2009年05月31日

IDE Fix Pack 2009 2.6リリース

RAD Studio 2009 Update 3に対応した「IDE Fix Pack 2009 2.6」がリリースされています。

対応が早いですね。

About 2009年05月

2009年05月にブログ「山本隆の開発日誌」に投稿されたすべてのエントリーです。過去のものから新しいものへ順番に並んでいます。

前のアーカイブは2009年04月です。

次のアーカイブは2009年06月です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

Powered by
Movable Type 3.35