多数の index 付変数とした扱っていたものをテンソル変数として一つの変数で扱えるようにします。テンソルの縮約操作を導入します。
index 付き変数は varName{1,3,5} などのように、{...} 内部にインデックス パラメータ数値を指定することで、ベクトルやテンソルの空間分布を sf でも表現するために設けました。varName{1,3,5}.val など、インデックス毎に sf ファイル変数を作っていました。このたも 100 x 100 x 100 の三次元ベクトル分布を扱うだけでも 100 万個のファイルが必要となりました。このように、多くのファイルをカレント ディレクトリに作ると OS の動作に問題が出てきます。explorer などのファイラーが表示をするのに膨大な時間がかかるようになり、あたかも hung up したかの様になります。
この嫌らしさ避けるため、複数のインデックス付変数を一つの sf ファイル変数(sf テンソル変数と名付けます。)とすることにしました。既存の sf ベクトル変数、sf マトリックス変数に sf テンソル変数を追加します。
sf テンソル変数の要素には実数だけではなく、ベクトルや行列要素も許します。数学や物理でのテンソルより少し拡張された意味ををもたせます。ベクトルポテンシャル分布、応力行列分布なども扱えるようにするためです。また 0 要素をテンソル変数から省略します。これにより sparcity のある行列をメモリ効率良く記述します。
テンソル変数の index には整数値の組のみを許します。整数値であり、マイナス値も許します。このことは ver1.2 と同じです。
# テンソル変数のインデックス例 brcVar{1,2,3} brcVar{1,2,5} brcVar{1,-2,5} テンソル要素が 0 のとき、変数内部からは、その値を抹消します。 brcVar{1,2,3,4} は許されません。。 一つのテンソル変数の vrcVar インデックスの長さは一つだけです。(ver1.2 までは可能でした。)
sf テンソル変数に加減乗算を実装します。除算は実装しません。ただし縮約 contraction を実装します。相対論や微分幾何で扱われるクリストッフェル記号を扱えるようにします。
「株式データなどの、より広い範囲のデータを扱えるようにせよ」などの意見もあると思います。でも、それらは別途 python アプリケーションなどで実装すべきと考えます。sf の対称を数学・物理・工学などで使う行列・ベクトル・テンソル計算に限定し、仕様を単純化する事を選択します。
要素が空のインデックスの長さを 3 とする Tensor variable は下のように、デュアル ブレースを使って宣言します。インデックスの長さは 3 以外でも一以上であれば任意の長さにできます。任意個数の足を持ったテンソルを記述できます。
# 3 index [0:16)x[0,16)x[0,16) テンソル TensorVar={{16,16,16}} # 2 index [0:32)x[0:16) テンソル TensorVar = {{32,16}} # 2 index [0:32)x[0:32) テンソル TensorVar = {{32,32}} # <== 行列の [[32]] 時のように {{32}} で代用できません。 # 1 index [0:16) テンソル TensorVar = {{16}}
インデックスの最小値を 0 以外の整数にもできるようにします。ベクトル ポテンシャル 分布などを表現するためです。下のように、end インデックスの次に begin インデックス設定する事で、begin 側のインデックスが 0 以外の値であることを示します。end インデックスと begin インデックスの長さは同じでなければなりません。begin インデックスは end インデックスより小さくなければなりません。
# 2 index [0:16)x[0,16)x{0,16 テンソル TensorVar={{16,16,16},{-16,-16,8}} # エラー インデックスの長さが異なる TensorVar={{16,16,16},{-16,,8}} # エラー !( end index > begin index) TensorVar={{16,16,16},{-16,16,8}} TensorVar={{16,16,16},{-16,-16,17}}
インデックス要素がスカラー ベクトル 行列の何れであるかは、テンソル変数に最初に代入する変数により定まります。
TensorVar={{16,16,16}} # 最初にスカラー要素を代入したので、TensorVar の要素はスカラーになる TensorVar{1,2,3} = 1 # スカラー要素となったテンソルにベクトル要素を設定しようとするとエラーになる。 TensorVar{1,2,3} = <1, 5>
sf ファイル変数として HDD のカレント ディレクトリに書き出されるときは、下のフォーマットで出力されます
#p string parameter % BaseTensor % BeginParameter <0,0,0,0> % EndParameter <10,10,10,10> % TermCount 10000 % ElementSize <2,3> # 2 x 3 行列を要素とするテンソル % <0,0,0,0> #indexes which size is parameterCounts < 2 , 2, 3> # 2 x 3 行列要素データ <10.5, 4, 0.3> % <i,.....> #indexes which size is parameterCounts <--- data --->
# 3 indexes テンソルから 3,5,2 パラメータで特定される要素を取り出します。 tensor{3,5,2}
テンソル要素がが行列/ベクタのときは、行列やベクタが返されます。返された行列要素の特定の成分を取り出したいときは [i,j] 指定を続けます。
# テンソルから 3,5,2 要素行列の[0,1]値を取り出します。 tensor{3,5,2}[0,1]
テンソル積は下のように、n 個と m 個の足をもったテンソルより、n+m 個の足を持ったテンソルを作ることです。テンソル積の要素の値は、元の二つのテンソル要素の積です。
tensor{{i1,i2,..,in}}* tensor{{j1,j2,..,jm}} ≡ tensor{{i1,i2,..,in,j1,j2,..,jm}} tensor{i1,i2,..,in,j1,j2,..,jm} ≡ tensor{i1,i2,..,in}* tensor{j1,j2,..,jm}
テンソル要素はベクトルや行列も可能でした。二つのテンソル要素が行列であるとき、上のテンソル積の意味で、互いの行列要素が掛け算を行えるとき、テンソル積が意味を持ちます。行列を要素とするテンソルとベクトルを要素とするテンソルの積も、行列とベクトルの積の意味で意味を持ちます。ベクトルを要素とするテンソルどおしの積はベクトルの内積すなわちスカラーを要素値とするテンソルになります。
テンソルどおしの積によって広がった足を、縮約操作で少なくします。普通の行列とベクトルの積は、上の意味のテンソル積と縮約操作を自動的に行うものと見なせます。でも足の数が増えてくると、縮約の対象となる足を明示的に指示する必要があります。行列とベクトルのときのように縮約パラメータとなる足の位置が自動的に定まらないためです。このために、足の数を増やすテンソル積と、足の数を減らす縮約操作の二段階にわけた操作が必要になります。
テンソルの縮約は下のような brace 括弧と wedge 括弧の組によるダブルプラケットを使って、表現します
# contraction described by brace wedge double bracket parameters tensor{<0,2>} #<== 0 th, 2nd の足の組で縮約を行います
数学でよく書かれる、テンソルの縮約を伴った積は sf 式では下のように記述されます。
n Σ leftTen[i,j] rightTen[j,k] # == multiplyTensor(leftTen, rightTen,[i,k]) j=0
(leftTen *rightTen){<1,2>} # == multiplyTensor(leftTen,rigtTen) の後、足 1,2 の組を縮約 #<== * の演算記号や (..) 括弧は省略とします。
(..) 括弧を省略可能にするため、積の演算子と {<..>} 括弧の優先順位は同じとします。左側から順番に計算されて行きます。
# スカラー値を要素とする 3 indexes からベクトルを取り出す tensor{2,3,*} # スカラー値を要素とする 3 indexes から行列を取り出す tensor{*,3,*}
ベクトルや行列を要素とするテンソルからベクトルや行列を * を使って取り出すします。下のように [..] と * 記号を使って要素を指定します。
#ver2.1 以降の実装とします。 # ベクトル値を要素とする 3 indexes からベクトルを取り出す tensor{2,3,*,[3]} # 行列をテンソル要素とするとき、 3,4 indexes から行列を取り出す tensor{*,3,4,[*,0]}
* 記号は最大二つまでしか許されません
テンソルからサブ テンソルを + 記号を使って取り出すときは、下のように [..] と + 記号を使ってサブ テンソル要素を指定します。
# + 部分をスキャンした一次元配列のテンソルを取り出す。 tensor{2,3,+} # + 部分をスキャンした二次元配列のテンソルを取り出す。 tensor{+,3,+}'+' 記号の個数はインデックス パラメータの長さ以内だったらいくつでも構いません。'*' のときのように二個までの制限はありません。テンソルの要素がスカラー/ベクタ/行列いずれであってもかまいません。
!tensor() 関数によって、ベクトル/行列変数からテンソル変数を作ります。
# ベクタ変数より 1 index テンソルを作り tensorVar に代入します。 # beginIndexes は 0 です。 tensorVar = !tensor(vctrVar) # 行列変数より 2 index テンソルを作り tensorVar に代入します。 # beginIndexes は 0 ベクトルです。 tensorVar = !tensor(mtrxVar)
下のように、二つまでの * 記号を、行列/ベクタを使ってテンソル要素への一括要素値指定を行います。
# スカラー値を要素とする 3 indexes へのベクトルによる値設定 tensor{2,3,*}= vectorValue # スカラー値を要素とする 3 indexes への行列による値設定 tensor{*,3,*} = matrixValue !! ブランク テンソルへの * と行列/ベクトルを使った一括アサインは、スカラー値を要素とするテンソルにする事を意味します。
行列/ベクタを要素とするテンソルへの * と行列/ベクタを使った一括アサインは ver2.1 以降とします。
私自身の内部でも部分テンソルによるアサインとの間で整合性のある仕様となっていません。sf テンソルを様々に使ってみてから決めます。
ver1.2 まではユーザー関数への引数渡しブレース変数 _arg{N}.val で行っていました。でも、今回のテンソル変数への改定で _arg{1}.val などの '{' や '}' 文字を使った変数ファイル名を使わないことにしました。
これに伴いユーザー関数引数ファイル名も _argN.val とすることに変更します。sf 変数ファイル名に不必要に '{', '}' 文字が入ることを避けるようにします。登録ユーザーの少ない今ならば許される変更だと考えます。
またついでに ~userFunction('sgring argment', 3, var) などのように '....' で囲んだ引数文字列をユーザー関数として渡せるようにします。そのときの _argN.val ファイルの中身は下のようになるものとします。
#ユーザー関数 ~userFunction('test string') 呼び出しをしたときにできる _arg1.val type _arg1.val #p test string % BaseDouble 0 <>
また、_arg0.val に sf の /s, /p, /z, /pvt 設定パラメータを引き渡すようにします。
ブロック実行ファイルやサブルーチン ファイルで、sf ファイル変数への書き込みを := 演算子で明示的に行うように変更します。ただし、一つの式のみの sfVar= !sin(x) などの実行の時は、従来と同様に HDD 上の sfVar.val 変数に値の書き出しを行います。
行列 sf ファイル変数が 300x300 のように大きいときでも、「matVar[1,2] = 5」の sf 式を実行させたびに、
でも、ファイル変数への書き込みを行うか否かが、temporay 変数の有無で決まることになりました。間接的にファイル変数への書き込を制御することになりました。sf 変数の規模が小さいときは、どちらでも大差ないのですが、規模が大きくなりやすい sf テンソル変数を使いだすと、ファイル変数への書き込みをユーザーが直接制御しないと使いにくくなってしまいます。
このため代入とファイルへの書き込みを同時に行う := 演算子を導入することにしました。@= による temporay 変数の宣言を止めることにしました。sfVar= !sin(x) のような一つの sf 式のときは、sfVar.val 変数への書き出しを行うので、大きな使い勝手の変更にはなりません。
一行で書ける sf 式でも a=3, sfVar= !sin(a x) のような複式のときに a=3, sfVar := !sin(a x) と明示的にファイル変数への書き出しの支持が必要となります。
vectorVar[3] := 5 のような書き方はできません。:= の左側はファイル名にも使える変数名でなければならないからです。
sf ver1.2 では 「varName1@, varName2@」や「varName @= expression」によって、temporay 変数を宣言していました。sf ver2.0 以降は @= による temporary 変数の指定を止めます。tempVar = 3 としても同じ意味となるからです。
「varName1@, varName2@」によるローカル変数の宣言は残します。元ルーチンとの変数の衝突を避けるオート変数の機能をもつテンポラリ変数の宣言は、サブルーチン記述で必須の機能だからです。それを @ マークで明示的に示すことは可読性を高めるからです。
下のように左値のないファイルへの書き込み ':=' があったときは右値の計算結果をコンソールに出力します。
:= sfExpression
python プログラム tensor.py tensorTest.pyを使って動作するテンソル演算モックを実装します。tensor.py に下のような関数を実装しています
機能 | python 関数 | 備考 |
テンソル宣言 | tensor.tn(endIndexAg, beginIndexAg=() ) | {{endIndexAg}} または{{endIndexAg},{beginIndexAg]}} に対応します |
テンソル和 | + | __add__ |
テンソル | - | __sub__ |
テンソル積 | *, | __mul__ |
テンソル要素の取り出し | [..int tuple..] | sf では {int index} |
縮約 | tn['c',1,3] | 'c' で始まる tuple。tensorVariable{<1,3>} に対応します |
テンソルからの行列ベクタの取り出し | tn[1,3,'*','*'] | '*' を含む tupl。'*' は 1 or 2 個だけ |
テンソルから部分テンソルの取り出し | tn['+',3,'+','+'] | '+' を含む tuple。 '+' は足の個数以内なら任意 |
行列 ベクトルのアサイン | ClTensor::def assginInBlock(self, tplAg, arrayAg): | tensor{j,k,l,m,*.*} = varMt, sf への実装は後のバージョンで行う |
新しい sf ファイル変数と pthon tensor 変数のコンバータ sfValNew.py も実装しました。
今回、python モックを初めて試みました。良い方法です。文章で書くより、ソフトウエア仕様の本質的部分を浮き上がられてくれます。問題点を C++ での実装の前に明らかにしてくれます。
擬似コードやフローチャート(いまどきフローチャートを書くくわけではないでしょうが、それに類する図形表示も含めてください)を書くぐらいなら、python コードに落としたほうがましです。
kenji□nasuinfo.or.jp 注意! □は @ に置き換えてください