アプリケーションの構造
Rは,統計の計算とグラフィックスを扱うためのプログラミング言語およびソフトウェア環境である.RLinkはWolframシステムアプリケーションで,JLinkとRJava/JRI Javaライブラリを使ってR言語の機能にリンクする.RLinkを使うと,ユーザはWolfram言語とR言語の間でデータを交信し,R言語コードをWolfram言語内から実行することができる.
Rランタイムが共有ライブラリ(.dll/.so/.dylib)として使える.Rは,Rを外部プログラムから呼び出すのに使えるCレベルインターフェースを定義する.JRI Javaライブラリは,低レベルCインターフェースの一番上の層を形成し,似た(但し,クロスプラットフォームの)Javaインターフェースを提供し,JavaプログラムがRを呼び出してRと情報を交換できるようにする.またJRIは,より高レベルのインターフェースも最もよくある操作に対して提供し,このインターフェースがRLinkでは広く使われる.
RLinkは,JavaとWolfram言語を組み合せる形で書かれ,この2つを繋げるのにJLinkを使っているWolframシステムアプリケーションである.Javaを選択したのは実装の詳細のためである.Javaは,Rへの高レベルのクロスプラットフォームインターフェースと(Javaの)オブジェクトシステムへのアクセスを提供するという点で便利であるが,Javaはここで重要な役割を担っているわけではない.将来のRLinkでC++等の別の言語を代りに使うということさえあるかもしれない.
Javaの部分には,RへのデータとRからのデータの移動を行うのに使われる2つのクラス階層と,すべてをまとめるためのより高レベルのクラスのいくつかが含まれている.入出の階層はどちらも,Rの簡略化されたオブジェクトモデルに,RLinkで実装,使用される形でマップされる.
Wolfram言語の部分には,Javaの部分の上に構築されたより高レベルのコンストラクトが含まれる.これには,Javaオブジェクトとの交信,自動的な型の認識と関数派遣,データ変換(Rは,より長い式の内部形式をRとWolfram言語の間のデータの交信に使うが,エンドユーザにはより短くて便利な形式が提供される),およびRSet,REvaluate,RFunction等のより高レベルの論理とコマンドの実装が含まれる.
アプリケーションのレイアウト
RLinkは,Wolfram言語のコード,ドキュメント,共有ライブラリ,Javaライブラリ(.jarファイル)を含むWolframシステムアプリケーションとして構築される.ファイルPacletInfo.mは,アプリケーションの記述子である.以下はその概要である.
RLink
PacletInfo.m
RLink.m
Kernel
init.m
RDataTypes.m
DataTypes
Base.m
Common.m
Java
RLink.jar
jna.jar
JRI.jar
...
Documentation
English
ガイド,シンボル,チュートリアルのページ
アプリケーションレイアウトのより詳しい情報とその構築方法は,Wolfram Workbench についてのドキュメント(http://www.wolfram.com/products/workbench)の特にアプリケーション開発を説明するセクションを参照されたい.
完全なR配布がRLinkには含まれており,これはRLinkRuntimeと呼ばれる別個のパクレットとしてパッケージされている.このR配布には,共有ライブラリ(JRIライブラリと,プラットフォームによってはその他のライブラリも含まれることがある)も追加され,機能が強化されている.さらに,これらの共有ライブラリ(およびRの共有ライブラリ)の中には,修正されたものもある(LinuxおよびMac OSのRLinkがそうである.)修正はソースコードには影響を与えないので,ロードする際に自動的に見付けられる(修正はライブラリがロードされる方法にだけ影響するものである).このため,同梱のRを自分のものと置き換えても通常うまくいかない.RLinkにはその代りに,自分のR配布(RLinkプロジェクトの外に位置するものでなければならない)を使うために切り替えることができる明示的なオプションがある(このオプションは現在Windowsのみで使用できる).
以下は,RLinkRuntimeのパクレットレイアウトの大まかな概要を示すものである(Windowsのレイアウトがここでは示されている).
SystemFiles
Windows
R
bin
i386
jri.dll
R.dll
...
doc
...
PacletInfo.m
RLinkを最初に使ったときに,Wolframのパクレットサーバからパクレットが自動的にダウンロードされる.またRLinkでは,このパクレットを手動でダウンロードすることもできる.
RLinkには型の拡張システムが含まれ,ユーザがさまざまなRのデータ型(中核となるRの型ではないが,別の型となるような有意な機能を持つ型)に対してWolfram言語のラッパー(データ型)を定義することができる.この型の拡張システムは,このような新しい型を定義するツールを提供し,これらをRLinkで登録する.このため,これらの拡張の型を中核となる型と同じように使え(Rと交換でき),中核となる RLinkのソースコードに変更を加える必要がない.
Wolframシステムでは,アプリケーションのさまざまな部分が必要になる.例えば,Wolfram言語ドキュメントセンターが使われると,自動的に該当のドキュメントが検索される.アプリケーションがNeeds["RLink`"]でロードされると,init.m ファイルがロードされる.最後にInstallR関数が実行されると,RLinkのプロジェクト設定が立てられ,Rのランタイムがロードされる.RLinkは自動的に関連する.jarファイルをJavaのClassPathに加え,R_HOMEおよびWindowsではPATHといった対応する環境変数(実行のプロセスとサブプロセス用)を設定または更新する.
簡略化されたR言語オブジェクトモデル
次のスキームは,RLinkで使われるように,簡略化されたRのオブジェクトモデルの例である.
|RCode
RObject --> |RCoreObject + RAttributes
|REnvironment
|-- NULL
RCoreObject --> |-- RVEctor
|-- RList
|-- RFunction
RFunction --> |-- builtin
|-- closure
RVector --> [(RNativeType|NA)..]
NA --> Missing element, can be at any position in a vector
|-- integer
|-- double
RNativeType --> |-- complex
|-- logical: TRUE|FALSE
|-- character (string)
RList --> {RObject..}
RAttributes --> RList
この例で明らかのように,このモデル内では,どのようなR言語オブジェクトでもRベクトル,Rリスト,R関数,RのNULLオブジェクトとして表すことができ,どのようなR言語オブジェクトでも属性(Rリストに保存される)を持つことができる.型REnvironmentおよび型RCodeのオブジェクトもあり,これらはそれぞれ,R環境と一般的なR言語オブジェクトを表し,RLinkにおいて特別なサポートは持たない.これらの2つの型は,ほかの型とは違って,(Wolfram言語側での)表示を行うためだけに使われるもので,R言語オブジェクトをこれらの型のオブジェクトを使って正しく構築することは通常できない.
Rベクトルは同じネイティブ型の要素だけを含むことができ,このうち5つの型(integer,double,complex,logical,character )をRLinkはサポートする.どのようなRベクトルでも欠落要素を含むことができ,これはRではNAと書かれる.Rリストは,他のRリストを含む任意のR言語オブジェクトをその要素として含むことができる.リストは,再帰的データ構造であり,このことがこの簡単なオブジェクトを強力にするものであることに注意する.
Javaの実装
Javaの実装の中心となるのは,2つの階層またはクラス / インターフェース(Rにデータを送るクラス("In"クラス)とRからデータを受け取るクラス("Out"クラス))と,R言語コードを実行するクラスRExecutor.java,およびプロジェクト初期化を行うクラスRLinkInit.javaである.
"In"クラスと"Out"クラスの階層はどちらもJavaと簡略化されたR言語のオブジェクトモデル(先ほどのセクションを参照)の間のマッピングを実装する.クラスは不変である(セッターメソッドはなく,すべてのデータはコンストラクタ内で,あるいは"Out"の型のために,rGet()メソッドのアクションの結果として)ことを意図されたもので,そのインスタンスは単一のデータ転送について一度だけ使われてから処分される(このため,2度以上のデータ転送に使われるクラスインスタンスは存在しない).このことによって,データ転送は処理状態が把握できないものとなる.
public interface IRInType {
public boolean rPut(String rVar, RExecutor exec);
}
IRInType
RListInType
RNullInType
RVectorInType
RCharacterVectorInType
RComplexVectorInType
RDoubleVectorInType
RIntegerVectorInType
RLogicalVectorInType
public interface IROutType {
public boolean rGet(RExecutor exec);
public String getVariableNameOrCodeString();
public ROutTypes getType();
public IROutAttributes getAttributes();
}
"Out"クラスのクラス階層は,"In"クラスのものに似ている.
クラスRLinkInit.javaは,プロジェクトの初期化を行うメソッドを含む.いつでも最大で一つのインスタンスしかアクティブであることができず,これはシングルトンの設計パターンの使用を通して実現される.Rのランタイムは,RLinkInit.javaクラスのメソッドinstallRで起動される.
public static synchronized boolean installR(String[] args)
これは,関連する環境変数を設定し,共有ライブラリをロードして,Rのランタイムを開始する.共有ライブラリは,まずjriライブラリがJRI.jarJavaライブラリのコードによってロードされ,次にRとRblas(およびその他の共有ライブラリがこれに含まれることもある)がjriによってロードされる.
Wolfram言語の実装
Wolfram言語の実装は,いくつかのコンポーネントと層からなる.最初のコンポーネントは,自動の型の認識と関数派遣を実装する.このため,このモジュールが型の情報に基づいて,正しいJavaクラスをWolfram言語関数に結合する.
2つ目のモジュールは,自動派遣を使って,RとWolfram言語の間のデータ交換を実際に実装する.Rに送られるデータについては,データの各要素の型はWolfram言語側で行われる分析によって,RLinkが使うデータを表す式の特別の内部形式に基づいて判断される.Rから送られるデータについては,型は,R言語オブジェクトの型(R言語のコード文字列の場合),あるいはJavaの型(Javaクラスのインスタンスの場合)をクエリすることで判断される.この結果,データは自動的にRに送られ,Rから受け取る.Rリストについては,この過程は再帰的である.Wolfram言語側のデータ交換は,データの(長い)内部形式上で行われ,データは頭部RList,RVector,RNull,RAttributes,RCode,REnvironment,RFunctionを持つWolfram言語式で表され,そのような式には,Rにデータを送るのに便利な形式で対応するR言語オブジェクトを構築するのに必要な完全情報が含まれる.
データを表すためにRLinkによって使われる(より長い)内部形式は,使用にあまり便利ではないので,変換層もある.この層では,長い形式を通常のWolfram言語ワークフローによりよく対応できるより短く便利な形式に変換する. この層は,短い形式をより長い形式に変換し直すことも行う.これらの変換を行う2つの関数は,ToRFormとFromRFormである.この2つの関数は,厳密には内部利用を目的とする関数であるが,エンドユーザも利用することは可能であり,状況によっては便利である.このことは式の内部形式についても同様であり,必要であればユーザが短縮形の代りにこれを使うことも可能である.
一番上の層もあり,トップレベルの関数であるRSetとREvaluate,関数の参照(RFunction)を使った関数の呼出し,および RLinkのインストールに関連する関数(InstallRとUninstallR)を実装する.この層は,Wolfram言語側とR側の両方でエラーを処理することにも使われる.最後に, RDataTypeRegister,RDataTypeUnregister,RDataTypeDefinitionsReload等の関数からなる型の拡張システムがある.このシステムでは,ユーザがさまざまなRのデータ型に対して新しいWolfram言語表現を作成し,RLinkがこれらの型をRLinkが処理する既存の中核となるデータ型と対等の立場にあるものとして扱うことができるようにする.