トップ > 製品紹介 > psim言語

psim言語

シミュレーション記述に最適化された言語であるpsim言語は、離散イベントシミュレーションで発生する大量のプロセスを効率的にスケジューリングする事ができ、今までのシミュレーション言語では難しかった複雑な待ち受け表現や状態遷移を、柔軟かつ簡潔に記述する事ができるという特長があります。

S4 Simulation System には、GUI が用意されており、基本的な離散イベントシミュレーションであれば、部品を配置し、リンクを結ぶという簡単な操作でモデルを構築する事が出来ます。このようなグラフィカルなインターフェイスだけでも、かなり複雑なモデルも実現出来るように設計されていますが、現実世界に存在するシステムをモデル化しようとした場合、どうしても、もう一歩踏み込んだカスタマイズを行いたいような状況に遭遇する事があります。

psim言語を使う応用例としては、エージェントを主体としたエージェントベースシミュレーションが挙げられますが、ここでは、まず、ちょっと変わった視点として、並列計算言語としてのpsim言語を紹介します。

素数を列挙するアルゴリズムとしてはエラトステネスのふるいが有名です。古代ギリシャの科学者エラトステネスが考案したアルゴリズムで、合成数をふるい落としていって、残ったものが素数であるという非常に簡単なアルゴリズムです。

Pythonをご存じの方なら、そのコードを書くのは簡単だと思います。しかし、ここではpsim言語を使って、並列的なアプローチをとってみようと思います。実際に書いてみると以下のようになります。

  
from psim import *
buf = [True] * 100

def generate():
    i = 2
    yield pause(i - now())
    while now() < len(buf):
        if buf[i]: # i は素数
            print i
            yield subactivate(sieve)(i) # i * k (k > 1) は素数でない
        yield pause(1)
        i += 1

def sieve(b):
    i = b * 2 
    yield pause(i - now())
    while now() < len(buf):
        buf[i] = False
        yield pause(b)
        i += b

initialize()
activate(generate)()
start()
  

まず、buf に100までの、素数の判定結果を表わす配列を作っていますが、初期値は全て素数としています。プロセス generate は 2 以上の整数を順次素数かどうかの判定を行いつつ、もし素数であるなら、その倍数を素数でないと判定する(ふるい落とす)プロセス sieveを起動します。yield subactivate(sieve)(i) がプロセス起動を指示しています。sieve プロセスは、generate プロセスや、他の sieve プロセスとは独立に動き続けます。

結果として、素数のリスト

2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97

が表示されますが、内部的には、その素数の個数のsieveプロセスが並列に動作したことで、結果が得られた事になります。

エラトステネスのふるい自体は非常に単純なアルゴリズムなので、並列化しないでも、結果を得ることはできます。しかしながら、エージェントベースシミュレーションなどを考えると、各エージェントが自律的に動作すると考える方が自然であり、このような動的なプロセス起動が大量に発生します。例えばネットワークシミュレーションであれば、通信セッションの発生はプロセス起動に相当します。口コミによる評判の伝播シミュレーションであれば、口コミ伝播がプロセス起動に相当します。エージェントベースシミュレーションを考えた場合、このようなプログラミングにおけるパラダイムシフトが重要であり、それをサポートする言語機能の必要性がおわかりになるかと思います。

より複雑なエージェントベースモデリングを考えると、状態遷移を考えることが重要になってきます。psim言語では、状態遷移図を一対一にコード化する事ができます。例えば、以下のような状態遷移図を考えます。

状態遷移図

この状態遷移図を実現するコードは以下のようになります。

  
def S1():
yield (G1() >> go(S2)() |
               G2() >> go(S3)())
def S2():
     # 電話応答処理
def S3():
     # メール応答処理
  

「A|B」はOR待ち受けと呼ばれ、A と B を同時に観測する事を示します。「C>>D」は逐次待ち受けと呼ばれ、Cが成立したらDを実行する事を示します。「go(P)()」は状態Pに状態遷移する事を示します。つまり、上記コードはG1が成立すればS2状態遷移、G2が成立すれば状態S3に状態遷移する事を示しています。

基本的には、このような記法を組み合わせることで、世の中に存在する複雑なシステムをモデル化できるようにpsim言語は設計されています。例えば以下のような事も簡潔に記述可能です。