Mathlink on IronPython 1.0
先日公開されたIronPython 1.0は、予想以上に優れモノで、.Netランタイム用に作られたモジュール(マネージコード)と全くシームレスに連携できる(ようだ)。対するオリジナルPython(+ctypesパッケージ)による既存のネイティブコードとの連携では、相互のデータタイプを考慮する必要がある。(もっとも新規にオリジナルpython用のdllを作成する場合なら、boost/pythonを利用することで、連携自体は比較的容易。)
試みに、mathematica 5.1の標準添付アドオンのひとつで、マネージ用のWolfram.NETLink.dllをIronPython上で使い、簡単なmathematicaのfrontendを作ってみた。(以下のスクリプトを適当なファイル名で保存し、DOS窓から"ipy.exe <適当なファイル名>で実行する。)
#!cmd ipy.exe """ipMathlink.py ver0.3 : Mathematica Simple Frontend on IronPython1.0""" import time import clr clr.AddReferenceToFile("Wolfram.NETLink.dll") from Wolfram.NETLink import MathKernel class ipMathKernel: """ >>> mkl = ipMathKernel() """ def __init__(self, gWidth=640, gHeight=480): self.mkl = MathKernel() self.mkl.AutoCloseLink = "True" self.mkl.CaptureGraphics = "True" self.mkl.CaptureMessages = "True" self.mkl.GraphicsFormat = "JPEG" self.mkl.GraphicsWidth = gWidth self.mkl.GraphicsHeight = gHeight self.strOut = [] def console(self): """yet another mathmatica console (with saving graphics)""" print "Mathematica Simple Frontend 0.3 on IronPython1.0" print "usage: input mathematica-style sentence (use quit to exit)" print " ex) Plot3D[Sin[x y],{x,0,2 Pi},{y,0,2 Pi}] " count = 0 while 1: print "" func = raw_input("In[%s]:= " % str(count)) if func == "quit": return self.strOut self.mkl.Compute(func) self.strOut.append(self.mkl.Result) print "Out[" + str(count) + "]=", self.mkl.Result self._saveGraphics() count += 1 def _saveGraphics(self): if len(self.mkl.Messages) > 0: print "Messages:" for i in self.mkl.Messages: print i if len(self.mkl.PrintOutput) > 0: print "PrintOutput:" for i in self.mkl.PrintOutput: print i if self.mkl.Graphics.Length > 0: strtime = time.strftime("%y%m%d%H%M%S_", time.localtime()) for i in range(self.mkl.Graphics.Length): imageFileName = strtime + str(i) + ".jpg" self.mkl.Graphics[i].Save(imageFileName) def runFunc(self, func=""): """ >>> result = run("Prime[10^9}") """ self.mkl.Compute(func) self._saveGraphics() return self.mkl.Result def setVal(self,val_name,data): """ >>> setVal("valiable", data) """ strtmp = str(data) if strtmp[0] == "[": strtmp = "{" + strtmp[1:len(strtmp)-1] + "}" func = str("%s = " % val_name) + strtmp self.mkl.Compute(func) def getVal(self,val_name): """ >>> valiable = getVal("val") """ func = str("%s" % val_name) self.mkl.Compute(func) result = self.mkl.Result if result[0] == "{": result = result[1:len(result)-1] return result if __name__ == '__main__': mkl = ipMathKernel(640,480) results = mkl.console() print "results= ",results
IronPythonとWolfram.NETLink.dllの連携自体の機能として、Mathematica形式の関数式を文字列として入力でき、かつ、Python側に出力データを文字列として取り込むことができる。また、関数式に用いたMathematica側の変数を保持していて、以降の入力に再利用することもできた。
当初、グラフィックデータが生成される場合に、mspaint.exeなどを内部から起動して表示する予定だったが、IronPython1.0には、オリジナルPythonの関数os.systemが無く(チュートリアルの記述にある方法で、オリジナルのosライブラリを取り込むことは出来るが、os.systemはパージされている)、相当する機能も見当たらなかったため、自動保存に止めた。
ちなみに、オリジナルPythonでは、mathematicaのネイティブコードとの連携用アドオン(Mathlink)を用いるMLというパッケージがある。だが、MLは、mathematica形式の関数式を直接入力できず変形して入力する必要がある。
「追記」少し改良した。IronPythonについては、使い方が良く分かっていないこともあるが、スレッド周りに改善の余地ありとの印象を持った。