■■ sf: scientific matrix formula calculator 速習マニュアル (1.001版) ■■

sf は 数式を使って計算できる、コンソール上で使う電卓です。下のように、文字変数を含む数式を計算できます。

>   sf "x=4.8, y=2.1, z = x^-2 + 2 + !exp(3x^2) y "
    < 2.19106e+030 >

x,y などの文字変数には、複素数・行列・ベクタを割り当てられます。x, y, z などの左辺値変数は、変数ファイルとしてカレント・ディレクトリに残ります。別の数式を記述するときに再利用できます。ベクタ変数の各要素に関数値を設定してやれば、ベクタ変数を関数値とみなせます。これを gnuplot などの画像化ソフトと組みわせることで sf で計算した関数のグラフ表示もできます。

sf は素早く結果を得られることを狙って作ってあります。コマンド引数自体に数式を記述します。コンソールをホワイト・ボードのように使って数式を書き、コンピュータに計算させます。sf 自体が CUI プログラムですから、プログラム素養のある方ならば、個自分のエディタに sf を組み込む事も可能です。sf 専用のインターフェース・ウィンドウを立ち上げることはありません。計算のたびに入力インターフェース・ウィンドウを立ち上げていたのでは、その手間と時間が思考の妨げとなるからです。

単純に16進数/10進数/2進数の加減乗除算を "sf 0x=0x324 + 15 - 0b1101_0010" などとキーボードからタイピングするだけで実行できることだけでも、sf が有用なことを理解してもらえるはずです。

>   sf 0x=0x324 + 15 - 0b1101_0010
0x261

sf は外部に開かれた計算ユーティリティです。C/C++ 言語でプログラムできる方ならば、sf 向けの実行ファイルを作成できます。 LAPACK などの行列ライブラリから sf 向けの実行ファイルを作ることで、望みのままに行列計算パッケージを sf に組み込むことが可能です。また、sf 式から python ルーチンを呼び出すこともできます。

残念なことですが sf を使いこなすには、コンソール操作が必要です。多くのユーザーが慣れている GUI マウス操作ではなく、CUI キーボード・コンソール操作です。でも、sf のコンソール操作に壁を感じたとしても、少し我慢をして挑戦して下さることを希望します。タッチ・タイプができればコンソール操作は難しいものではありません。慣れてしまえば、マウス操作が煩わしくなるほどに便利なものです。sf のような計算ソフトでは CUI 操作が適していることを納得できるはずです。。そこで得た CUI 操作は、sf 以外のソフトを使うときにも活用できます。コンピュータ操作を色々な面で効率化できます。

sf は 検証ソフト kVerifier ライブラリ、および正規表現ライブラリ kreg を実際に応用した例題でもあり、宣伝用ソフトとしてソースと共に公開しますが、登録料 5000 円の有償ソフトとします。(高級電卓代金だと思ってください。) sf だけでも、有償とする価値のある計算ツールにできたと自負しています。sf を無償ソフトの Maxima/Python/Gnuplot などと組み合わせて使えば、Mathematica や Matlab と同等以上のことも可能にできます。

■ sf の信頼性 ■

kVerifier を使って、リリース・コードについてのカバレッジ 100% テストを行っています。よくある一度は全部のチェック・マークをつけたとしても、それは出荷ソフトの全部のコードに対する最終チェックではありません。sf では修正が入るたびに coverage 100% テストを行えるようにしてあります。

■ sf インストール ■

インストーラーを設けていません。単純にこちらからダウンロードした sf12?zip ファイルを解凍してハード・ディスクのパスが通ったディレクトリに下のファイルを置くだけです。レジストリを修正することもありません。

sf.exe gnpltDt.exe, gdsp.bat, random.exe, Jacobi.exe, expM.exe shift.exe
zip ファイル
sf.ini

ただし VrfyMDdRt10C zip ファイルをカレント・ディレクトリに置く必要があります。このファイルがプログラム動作のキー・ファイルになっているからです。また単位系などのデフォルト定数を使うための sf.ini もカレント・ディレクトリに置く必要があります。

■ sf 速習 ■

○ 基本操作 ○

sf を関数電卓として扱ってみましょう。sf の後に計算式を書いて、コンソール上で実行させるだけです。

△ 四則演算(加減乗除演)とべき乗および基本関数とそれらの組み合わせ操作

sf での加減上除算は普通の数式と同様に +, -, *, / 記号を使います。べき乗は ^ 記号を使います。コマンドライン引数に計算式の文字列を与えて、sf.exe を実行させることで計算を行わせます。コンソール・ウィンドウで下のように実行させます
>   sf "3+4"
    < 7 >
    
>    sf "3-4"
    < -1 >
    
>    sf "3*4"
    < 12 >
    
>    sf "1+3/4"
    < 1.75 >

>    sf "(1+3)/4"
    < 1 >
    
>    sf "2*3^4"
    < 162 >
のような具合です。演算記号の優先順位も普通の数式と同じです。べき乗が最優先され、乗除算が次に優先されます。優先順位を変更するには括弧を使うことも普通の数式と同じです。

二重引用符の記号は省略できることも多いのですが、慣れないうちは、無条件に引数の最初と最後に二重引用符を付けることを勧めます。Windows のコマンドラインでは二重引用符がないと意味が変わってしまうことが多くあるからです。

例えば MS Windows では二重引用符がないとき、コマンドラインに記述された ^ べき乗記号は消されてしまいます。
# 下の計算コマンドは二重引用符がないので sf "2*34" の意味になってしまいます。
>    sf 2*3^4
    < 68 >

△ sf に組み込んである基本関数
sf には、下の基本関数が組み込んであります。
    sin  cos  tan  sinh  cosh  tanh  exp  log  asin acos atan log10 sqrt
    sqrt: square root の意味です。--- (..)^0.5 でもよい。でも sqrt のほうが見やすい
sf の組み込み関数は、文字列変数と区別するために ! で始めます。下の様に計算します。
>   sf "!exp(1)"
    < 2.71828 >
>   sf "!log(2)"
    < 0.693147 >
>   sf "!log10(100)"
    < 2 >
sin/cos などの三角関数は角度をラディアンの単位で表記します。度(degree) ではありません。`π=3.141592653589793 文字列変数を組み込んであるので、ラディアンで計算も簡単です。度(degree)の単位をつかうときは π/180 を掛けてください。下のように計算します。
>   sf "!sin(`π/2)"
< 1 >
>   sf "!cos(`π/4)"
< 0.707107 >
>   sf "!cos(60`π/180)"
< 0.5 >
>   sf "2*!atan(100000)"
< 3.14157 >
>   sf "!sqrt(2)"
    < 1.41421 >

これらの関数引数には複素数も与えられます。

△ 複素数
sf では数学での記述と同様に記号 'i' を使って複素数を記述できます。関数の引数にも複素数を使えます。
>    sf "(1+2i +  3+4i)"
    < 4+6i >

>    sf "(1+2i)(3+4i)"
    < -5+10i >

>    sf "(1+2i)/(3+4i)"
    < 0.44+0.08i >

>    sf "(-1+2i)^(3+4i)"        # 複素数による複素数のべき乗です
    < -0.00325069+0.000334598i >

    # sf の組み込み関数は ! で始まります
>    sf "!exp(3+4i)"
    < -13.1288-15.2008i >
基本関数は全て複素数の引数を使えます。下のような複素数計算が可能です
>    sf "!sin(-1+2i)"
    < -3.16578+1.9596i >
>    sf "!log(-1+2i)"
    < 0.804719+2.03444i >
>    sf "!exp( (-1+2i)^(3+4i) )"
    < 0.996755+0.000333512i >
複素数の計算結果に対して !image(), !real() を適用することで実数部分、複素数部分を取り出せます。
>    sf "!image( 3+4i )"
    < 4 >
>    sf "!real( !sin(-1+2i) )"
    < -3.16578 >
△ 変数への値の設定
sf では "変数 = 計算式" と記述することで、変数ファイルが作られます。できた変数ファイルは別の計算式に、変数名のまま使えます。下の様に使います
>   sf "tax = 1.05"
>   sf "total = 100 + 230+333"
    < 663 >
>   sf "total * tax"
    < 696.15 >
この変数ファイルは拡張子が val のテキスト・ファイルであり、カレント・ディレクトリに作られます。例として変数ファイル total.val の中身のテキストを下に示します。
>   type total.val
    % BaseDouble 1
    < 663 >
ベクタや行列などでは、この数値が、横または、横と縦に多く並びます。sf では計算結果をテキストとして変数ファイルに残すので、他のプログラムからの利用が容易です。フィルタ・プログラムによって、ベクタ変数ファイルなどのデータを特定のグラフ表示ソフト向けに変換したりすることが簡単にできます。
△ 計算精度と表示精度
sf の計算精度は 16 桁です。でも計算結果をコンソールに表示するときは 6 桁に四捨五入して表示します。不必要に長い桁数の数値を表示すると行列や、ベクトルの値を表示するとき、コンピュータの画面の一行にに納まりきらないからです。計算の中身は下のように 16 桁の精度を保っているので安心してください。
>   sf "test = 1/3"
    < 0.333333 >
>   type test.val
    < 0.3333333333333333 >
>   sf "test = 2* test"
    < 0.666667 >
>   type test.val
    < 0.6666666666666666 >

なお、デフォルトの表示桁数 6 は、後で説明する初期設定ファイル sf.ini を修正することでユーザーの使い方に合わせた桁数表示に修正できます。

△ 足し算の特別ルール
sf では、数式を記述するときと同様に演算子を省略したときは、積の * 演算子を自動的に挿入します。でも数値だけの足し算の計算のとき、スペースを + 演算子とみなす便法を適用します。合計数値を求めるなど、足し算だけを行う場合が多くあるからです。
     # 数値のみなので足し算、  "=" 演算子がないのでデフォルト _dt.val に計算結果を残す
>    sf 1200 451 311.23 43500 31000
    < 76462.2 >
のように数値を打ち込むだけで合計を計算できます。ブラインド・タッチができる方ならば、sf を使えばソロバンの有段者以上の計算力を得られます。読み上げ算程度は朝飯前です。人に読み上げてもらう必要がないぶん sf のほうがソロバンより優っています。数値入力だけならば右手だけで十分であり、左手で伝票を捲ることができますから。

sf の数値入力はコマンド・ラインから行います。数値入力データーの履歴はコンソール画面に残っています。入力数値に誤りがなかったかを後で再確認できます。

sf では、計算結果を代入する変数が指定されないとき _dt.val ファイル変数に入ります。この _dt が最初、または最後にあるときに限って、その他の入力が数字とスペースに限定されているときも、スペースを + 演算してみなします。これにより、前回の足し算の結果に追加の足し算していけます。複数回の計算のときでも、全体の合計を計算することができます。

     # 足し算
>    sf _dt 1345 212.43
    < 78019.7 >

     # 前回の計算結果を含む足し算
>    sf 1000 _dt 
    < 79019.7 >

     # 足し算
>    sf total = 2312 _dt 
    < 81331.7 >

     # tatal 値に消費税と手数料 100 円を足した請求額を計算します
>    sf total * 1.05 + 100
    < 85498.2 >
    
    # tata.val は諸費税計算の後も変わりないままです
>    sf total
    < 81331.7 >

     # tatal が在るので、スペースは掛け算と見なします。デフォルトの 6 桁四捨五入精度で表示します。
>    sf total 2
    < 162663 >

デフォルトの _dt 変数ではなく totol などの指定した変数ファイルに結果を残したいときは、" 変数名= " によって保存先を指定します。このように指定した変数は、sf の計算式で total などの変数名のまま再利用できます。でも tatal や = のように数字とスペース以外の文字が計算式に入ると、通常の数学でのように、スペースは * 演算の意味になります。

電卓のキーボードの大部分はラバー・キーの低品質なものです。電卓のキーボードより、コンピューターの安物のキーボードのほうがまだましです。sf を使って日常の業務を効率的に、気持ちよく済ませてください。

また多くのノート・パソコンには "NumLK Number Lock"キーがあります。これを使えば、キーボードの右側の一部ががテンキーになりスペースと数字の両方の入力を右手だけで簡単に行えます。足し算を簡単に入力できます。お試しください。

△ 基数変換
sf では 0x で始めることで 16 進数の整数値を、また 0b で始めることで 2 進数の整数を入力できます。下のように使います
>   sf "10 + 0x100 + 0b1__0000_0001"
    < 523 >

2 進数では桁位置を分かりやすくするために "_" を自由に挿入できます。

計算結果を 16 進数の整数で表示させるためには "0x = 数式" と記述します。16 進数の結果表示では、小数点以下は切り捨てます。下に計算例を示します。

>   sf "0x = 10 + 0x100 + 0b1_00000001"
    0x20b
>   sf "0x = 10.6 + 0x100 + 0b100_000_001"
    0x20b

なお "0x=" 16 進数表示を行ったときは、デフォルト _dt.val への代入は行われません。

△テンポラリ文字変数と複数の数式

一時的にしか使わない変数のためにテンポラリ変数を用意してあります。HDD のカレント・ディレクトリに設けられるファイル変数とは異なり、コンピュータのヒープ・メモリ上にダイナミックに設けられる変数です。テンポラリ変数を使えば、HDD 上に不必要なファイル変数を残しません。

下のようにテンポラリ変数を使うと、数式を使って計算させると同時に、計算パラメータの設定をを式の始めに集中させられます。 @= がテンポラリ変数を宣言・定義する構文です。

    # t @=2.5 はテンポラリ変数 t を宣言して、2.5 に初期化することを意味します
>    sf "t @=2.5, (1/2) g t^2"
    < 30.625 >

    #上の計算式で使っている "," は、コロン、複数の式を一行に記述するた
    #めの記号です。C 言語のコンマ演算子 "," と同じ意味です。

テンポラリ変数を使えば、大文字と小文字を区別できるようになるメリットもあります。Window OS では大文字と小文字の区別ができないため、ファイル変数は大文字・小文字による変数の区別はできません。

なお、テンポラリ変数はスコープ制御がなされたローカル変数です。同じ変数名を使っても、ブロックが異なれば変数名の衝突がありません。逆にファイル変数は HDD のカレントディレクトリに作られるグローバルな変数です。後に述べる sf サブルーチンを使うときには、テンポラリ変数を使うことが必須となります。

○ 行列・ベクタ操作 ○

sf ではベクタ・行列計算もできます。変数を使うことでベクタ・行列計算式を簡単に記述できます。ベクタや行列の定義も簡単に行えるように複数の設定方法を用意してあります。

sf ではベクタと行列は異なる種類の変数として扱っています。1 x n 行列をベクタとしているわけではありません。また 行列 * ベクタ 演算のみを考えています。ベクタ * 行列の演算をさせてもエラーになります。

△ ベクタ
sf でのベクタは "<数値,数値, ... 数値>" で記述します。下に例を示します。
>   sf "vTest = <1,3,5,0>"
    < 1, 3, 5, 0 >
>   sf "2 vTest"
    <  2,  6, 10,  0 >

sf では <<N>> で 0 要素のみからなるサイズ N のベクタを意味します。[index] でベクタ要素を意味します。0 要素の多いベクタのときは、下のように記述します。

>   sf "vTest = <<10>>, vTest[3] =4"
    < 0, 0, 0, 4, 0, 0, 0, 0, 0, 0 >

なお、sf でのベクタのインデックスは 0 から始まります。C 言語の配列と同じです。フォートランとは異なります。御注意下さい。

注意! コンソール上で入力するとき "<" や ">" はりダイレクトの意味になります。コンソール引数で " 引用符は省略できないことにも御注意ください。

△ 行列

sf では [[N]] で 0 要素からなるサイズ N x N の正方行列を意味します。[[N,M]] で 0 要素からなるサイズ N x M の長方行列を意味します。Matrix[j,k] で (j,k) 行列要素を意味します。Matrx[n,*] で行列の n 行を表します。Matrix[*,m] は行列の m 列を表します。Matrix[*,*] は正方行列の対角要素を表します。正方行列でないときは Matrix[*,*] はエラーになります。以下のように記述します。

    # サイズ 3 の 0 要素ベクタ変数 vector.val を生成します
>   sf "vector = <<3>>"
    < 0, 0, 0 >

    # ベクタ最後の要素を 1 にする
>   sf "vector[2] = 1"
    < 0, 0, 1 >

    # 3x3 の 0 要素のみの行列(変数ファイル Matrix.val)を生成する
>   sf "Matrix = [[3]]"
    < 0, 0, 0 >
    < 0, 0, 0 >
    < 0, 0, 0 >

    # Matrix 変数の最初の列を <1,2,3> にする
>   sf "Matrix[*,0] = <1,2,3>"
    < 1, 0, 0 >
    < 2, 0, 0 >
    < 3, 0, 0 >

    # 最初の行を <3,4,5> にする
>   sf "Matrix[2,*] = <3,4,5>"
    < 1, 0, 0 >
    < 2, 0, 0 >
    < 3, 4, 5 >

    # 行列の対角要素を <6,7,8> にする
>   sf "Matrix[*,*] = <6,7,8>"
    < 6, 0, 0 >
    < 2, 7, 0 >
    < 3, 4, 8 >

    # 行列をベクタに作用させる
>   sf "Matrix vector"
    < 0, 0, 5 >

    # ベクタに行列の 0 列目を足し合わせる
>   sf "vector+Matrix[*,0]"
    < 6, 2, 4 >


    # 3x4 の 0 要素行列(変数ファイル)を生成する
>   sf "Matrix = [[3,4]]"
    < 0, 0, 0, 0 >
    < 0, 0, 0, 0 >
    < 0, 0, 0, 0 >
△ 組み込み関数のベクタ・行列への適用
sin/cos などの組み込み関数をベクタ・行列に働かせたとき、ベクタや行列要素に関数が働きます。下に例を示します。
>   sf "vector = <<3>>, vector[1]=1"
    < 0, 1, 0 >
>   sf "!exp(vector)"
    <       1, 2.71828,       1 >

>   sf "matrix = [[3]], matrix[0,0] = `π, matrix[1,1] = `π/4"
    <  3.14159,        0,        0 >
    <        0, 0.785398,        0 >
    <        0,        0,        0 >

>   sf "!cos(matrix)"
    <       -1,        1,        1 >
    <        1, 0.707107,        1 >
    <        1,        1,        1 >
行列自体の exp や sin 関数は後に説明する「ブロック実行とサブルーチン」「ユーザー関数を使っての拡張 」で実現します。
△ベクタの内積
a,b ベクタの内積はディラックの記述法に似た下のような方法で表します。
>   sf "a@=<<3>>, b@=<<3>>,<a | b>"
    < 0 >
>   sf "<<3+4i, 5> | <2,3>>"
    < 21-8i >
ベクタ a が複素数のときは、sf は自動的に conjugate を取ってから、ベクタ要素同士を掛けて足し合わせます。
>   sf "a@=<1+2i,3+4i>,  "
    < 30 >
#   上と、下は同じ値になります
>   sf "< <1,2,3,4>|<1,2,3,4> >"
    < 30 >
行列 M が与えられたとき下のように書けるのもディラック流です。
>   sf "<a|M|b>"
>   sf "a@=<1,1>, b@=<1,-2>,  <a|`σx|b>"
    < -1 >

#  上の sf 式で `σx は sf に組み込んである 2x2 定数行列であり、下の行列要素を持ちます。
#  Pauli 行列と呼ばれている行列です。`σy,`σz も組み込んであります
>   sf `σx
< 0, 1 >
< 1, 0 >

ただし |a> や <b| 単独でのベクタ記述がない点でディラック流とは異ります。sf には共役ベクタ(縦ベクタ)の考え方はありません。明示的に N x 1 の縦行列を N x N の正方行列との積演算をさせても、N x 1 の行列となるだけです。sf ではベクタと N x 1 や 1 x N 行列は別物と見なしてください。

#    2x2 行列と 2x1 縦行列の積
>    sf "M@=[[2,1]], M[*,0]=<1,1>, `σx M"
    < 1 >
    < 1 >

>type _dt.val
% BaseDoubleMatrix 2,  1
< 1 >
< 1 >

#    行列とベクタの積
>    sf "a@=<1,1>, `σx a"
    < 1, 1 >

>type _dt.val
% BaseDouble 2
< 1, 1 >

>    sf "M@=[[2,1]], M[*,0]=<1,1>, "
< 2 >

>type _dt.val
% BaseDouble 1
< 2 >
各要素の conjugate をとる意味での共役ベクタを表現したいときはは、明示的に !dggr(.) 組み込み関数を使います。でも、内積の sf 式で記述すると逆に conjugate をとらない内積になってしまいます。
>   sf "!dggr(<3+4i, 5i>)"
    < 3-4i,  -5i >

>   sf "<!dggr(<3+4i, 5i>)|<3+4i, 5i> >"
    < -32+24i >
△ ベクタの操作

ベクタを操作する関数として !sum, !prdct ,~shift を用意しています。!sum() はベクタ引数の要素の全を足し合わせたスカラー値を返します。!prdct() はベクタ引数の要素の全を掛け合わせたスカラー値を返します。!norm() は自乗和のルートを返します。!size() はベクトルの次元数を返します。~shift(,) は後に述べるユーザー関数として実装してあり、最初が '~' 文字で始まります。ベクタ引数と、シフト整数スカラー引数の二つの引数をとります。シフト引数の正負に従い、M右/左 側へずらしたベクタを返します。ずらされた後の要素値は 0 になります。],

    # temp ベクタ変数に試験データの設定
>   sf "temp =<<8>>, temp[0]=1, temp[3]=3"
    # temp ベクタをシフトさせる
    < 1, 0, 0, 3, 0, 0, 0, 0 >
    # temp ベクタ全要素を足し合わせる
>   sf "!sum(temp)"
    < 4 >
    # temp ベクタ全要素を掛け合わせる
>   sf "!prdct(temp)"
    < 0 >

>   sf "!norm(temp)"
    < 3.16228 >
>   sf "!size(temp)"
    < 8 >

    # temp ベクタ全要素を右側にシフトする
>   sf "~shift(temp,1)"
    < 0, 1, 0, 0, 3, 0, 0, 0 >

後で説明する繰り返し構文を使えば、関数を sf のベクタ数値列として表現できます。この数値ベクタに対して !sum 関数を使えば、階段関数近似による定積分が計算できます。

工学分野でよく使われる FFT、逆 FFT も sf の組み込み関数として実装してあります。これも一種のベクタの操作と言えるでしょう。

    #fft: Fast Fourier 変換
>   sf "temp =<<8>>, temp[0]=1"
    < 1, 0, 0, 0, 0, 0, 0, 0 >
>   sf "temp = !fft(temp)"
    < 0.353553, 0.353553, 0.353553, 0.353553, 0.353553, 0.353553, 0.353553, 0.353553 >
    #rft: Reverse faset Fourier 変換
>   sf "!rft(temp)"
    < 1, 0, 0, 0, 0, 0, 0, 0 >

    #fft: Fast Fourier 変換。2 のべき乗の長さデータに限らない。
>   sf "temp =<<10>>, temp[0]=1"
    < 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 >
    # FFT 計算。2^4 の長さのベクトルにアジャストされる
>   sf "temp = !fft(temp)"
    < 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25 >
    # fft の後も ノルムが 1 のまま保たれていることを確認する
>   sf "!norm(temp)"    
    < 1 >

    #rft: Reverse faset Fourier 変換
>   sf "!rft(temp)"
    < 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 >
2 のべき乗以外の長さのベクタに対しても FFT 計算を行います。でも計算結果は 2 のべき乗に長さのベクタにアジャストされてしまうので、御注意ください。

!sin(), !exp() などの基本関数にベクタ引数を与えると、ベクタ要素に !sin(), !exp() などの関数を適用したベクタを返します。

#   !sin(), !exp() 基本関数のベクタへの適用
>   sf "!sin(<`π/3, 0>)"
    < 0.866025,        0 >
    <  3, -4 >
>   sf "!exp(<`π/3, 0>)"
    < 2.84965,       1 >
#   ベクタの実数部分の取り出し
>   sf "!real(<-1+3i, 2-4i>)"
    < -1,  2 >


△テンポラリ文字変数への代入

テンポラリ変数への代入操作では、ファイル変数への出力を行いません。このことは変数がサイズの大きな行列変数になったときに、計算速度の差となってきます。サイズの大きな行列や、ベクタでは temporary 変数への代入によってコンソールへの出力を避けるテクニックを使うと sf 計算が速くなります。

>   sf "temp=<<10000>>, temp[0]=3,temp[100]=2,temp[1000]=3, test=temp"
    # 上の書き方より、下の書き方のほうが計算時間が短くなります
>   sf "temp@=<<10000>>, temp[0]=3,temp[100]=2,temp[1000]=3, test=temp"
とくに、後で述べるループ処理の中で、大きな行列要素への代入操作を行うとき、テンポラリ変数に代入するか、ファイル変数に代入するかは処理速度の何十倍もの差になって利いてきます。サイズの大きな変数を扱うときのテクニックとして覚えておいてください。

○ sf の動作指定と sf.ini デフォルト設定ファイル ○

sf コンソールへの出力を制御するオプション/p, /zsを備えています。動作を指定する以下の種類の設定が可能です
#    /p N    コンソールへの出力桁数を N にする(N は 16 以下の整数)
>   sf "/p 10, 1/3"
    < 0.3333333333 >

#   /zs db  zero suppress --- db より小さい値はコンソールに 0 を出力する。
            db は小さい浮動小数点値
#    zero supress を行わなくする
>    sf "/zs 0, 1/!sqrt(2) - !cos(`π/4)"
    < -1.11022e-016 >
# <== 数学では 0 ですが、コンピュータでは丸めによる計算誤差がでます。
.3
#    デフォルトで 1e-14 に設定してあります
>    sf "/zs 1e-14, 1/!sqrt(2) - !cos(`π/4)"
    < 0 >

/s, /ns は後で述べる繰り返し構文を使うとき、コンソールに出力される途中の計算結果を出力したり、しなくしたりの選択をおこないます。

/zs は浮動小数点演算に付きまとう微小な値を 0 に丸めるために使います。0 要素の多い行列が計算誤差によって 0 でなくなったときでも 0 に表示させることを目的としています。これにより 0 以外の本来欲しい行列要素の値が、見やすくします。

でも、プランク定数 1.05457e-034(単位 Joule sec) のように小さな数値を 0 に丸めてしまうのも不味いので、0 に丸めるのは指定したサイズ以上のベクトル、行列に限定しています。デフォルトでは長さが 4(複素数のときは 2) を超えるベクタのサイズまたは行列の列数のときに zero supress を行います。このサイズを変更するには、下のように zero suppress 浮動小数点の次に、サイズを 0 以上の整数値で指定します。

#   σz は対角要素が <1,-1> でサイズが 2x2 の実数行列です
>    sf "`σz"
    <  1,  0 >
    <  0, -1 >
#   `σy はサイズが 2x2 の複素行列です
>    sf "`σy"
    <  0, -i >
    <  i,  0 >

#   `σz は列数が 2 の実数行列であり、default 4 より小さいので zero supress を行わない
>    sf "/zs 1e-14, `σz 1e-18"
    <  1e-018,       0 >
    <       0, -1e-018 >
#   行列の列数が 2 であり、3 より小さいので zero supress を行わない
>    sf "/zs 1e-14 3, `σz 1e-18"
    <  1e-018,       0 >
    <       0, -1e-018 >

#   複素行列であり、列数が 1.5 == 3/2 を超えているとき 1e-14 以下の値を 0 にする
>    sf "/zs 1e-14 3, `σy 1e-18"
    < 0, 0 >
    < 0, 0 >

#   サイズが 0 以上の指定であり、無条件に 1e-14 より小さい時に 0 suppress を行う
>    sf "/zs 1e-14 0, `σz 1e-18"
    < 0, 0 >
    < 0, 0 >

なお、丸めるサイズ指定は実数を対象とするベクター・サイズであり、複素数のベクタに対しては、指定数値の半分のサイズから丸めが始まってしまいます。一つの複素数は二つの実数で表示されるからです。

/s はコンソールへの出力を抑制するオプションです。後で説明する繰り返し処理を大規模な行列変数などについて行うとき、コンソールを出力しないほうが動作が高速になります。/ns はコンソールへの出力をさせる動作に戻します。

#   /s     途中経過をコンソールに出力しなくする。
#   /ns    途中経過をコンソールに出力する。(デフォルト)
>   sf "/s, temp=!sin(`π/2+`π/3), /ns, !sin(`π/2+`π/3)"
 sf command argment: /s
 sf command argment: !sin(`π/2+`π/3)
 sf command argment: `π/2+`π/3
< 2.61799 >
< 0.5 >
△sf.ini ファイルとデフォルト・テンポラリ変数
`π などの何時も使う変数は、カレント・ディレクトリのテキスト・ファイル sf.ini に、あらかじめテンポラリ変数として宣言しておけます。sf が動作を開始するとき、最初に sf.ini を読み取り、テンポラリ変数を宣言・定義します。
    # light velosity m/s
    `c @= 2.99792458e+8
    
    # `π 円周率
    `π @= 3.141592653589793
    
    # プランク定数 h/2π 1.05457266(63)×10-34 J s 
    `h @= 1.05457266e-34
    
    `h` @= h` 2 π
    
    #ボルツマン定数   J K^-1 K は絶対温度の単位です。Kg ではありません
    `kB  @= 1.380662e-23 # Joule/ degree
    
    #万有引力定数 G  = 6.672 ×10-11  N m^2 kg^-2 
    `gU @= 6.672e-11
    #重力加速度 g  = 9.80665  m s-2 
    `gH @= 9.80665
    #素電荷 e  = 1.6021892 ×10-19  C 
    `eQ @= 1.6021892e-19
        ・
        ・
    # 真空の誘電率 ε0 クーロン**2 / (Newton * M ** 2)
    `ε0 @= 8.854187816e-12
  
    #Pauli 行列 x 
    `σx @= [[2]] 
    `σx[<0,4,1>] = <0,1\ 
                   ,1,0> 
     
    `σy @= [[2]] 
    `σy[<0,4,1>] = <0,-i\ 
                   ,i,0> 
     
    `σz @= [[2]] 
    `σz[<0,4,1>] = <1,0\ 
                   ,0,-1> 
上のような sf.ini ファイルが定義されているので下の微細構造定数が、数式どおりに計算できてしまいます。
>    sf "4 `π `ε0 `h` `c / `eQ^2"
    < 137.034 >
理系の数式には分野ごとに特有の、様々の定数が覚えきれないほどあります。御自分の分野に合わせて、sf.ini にデフォルト・テンポラリ変数を定義しておくと便利です。数式をそれらの文字列変数で表現できるからです。お試しください。
計算の勧め

理工系の教科書を読んでいくとき、往々にして計算確認を避けてしまいます。電卓が手元にあっても数値の入力が面倒なためです。でも自然科学では具体例を作って計算により確認することが、理論を理解していく過程で行われるべきです。それによって教科書では書ききれない全体との関係が見えてくるからです。

下の式はクーロンの法則の計算式です。

q@=1, r@=1, q q/(4 `π `ε0 r^2)
< 8.98755e+009 >
上では、1 クーロンの電荷が 1 m の距離だけ離れているときに働く力を計算しています。これを実際に計算してみると 89 億ニュートンという、とてつもなく大きな値になります。これは計算間違いではありません。自然はこのようになっているのです。自然は重力に対して電磁気力に、このように桁数の異なった力を持たせています。

この性質は身近な電気の使い方を様々に規定しています。プラスとマイナスの電荷があることは知っていても、プラスの電荷だけを取り出して電気を蓄えておくことは実際には行いません。上で計算したような巨大な力が働いてしまうからです。常にプラスの電荷とマイナスの電荷が殆ど打ち消しあった状態で電気は使われています。プラスの電荷をとマイナスの電荷を分離するとしても、コンデンサのように、物質の狭い中にペアの形で閉じ込めてやることで、巨大な力が表面に出てこないようにしています。それでまマイクロ・ファラッドのオーダーでしか電荷を溜められません。

プランク定数など多くの物理定数が、我々の日常に至るところに影響を与えています。理工系の方ならば sf を使って具体的に様々の計算を行ってみてください。意外な発見と理解があるはずです。


○ 繰り返し ○

数値計算では、似たような計算を繰り返すことが多くあります。繰り返し計算を簡単するため、 sf ではも繰り返しパラメータを設定できます。

sf での繰り返しは、ベクタを生成するパラメーター start, size, stride と呼ばれる三つで指定します。C++ 言語の slice array パラメータに似た意味と働きをします。sf での繰り返し操作はベクタを生成する副作用として実現されます。以下、この三つの繰り返しパラメータの働きを見ていきましょう。

△ 繰り返しパラメータによるベクタの生成

sf では、ベクタ要素が規則的に生成されているとき、ベクタを簡便に記述できます。長いベクタ要素が等差級数のときは << start, size, stride >> のように級数のベクタを簡便に記述できます。start は初期値、size はベクトルの長さ、stride は隣り合う要素の差分値です。(ベクタ要素の値が全て 0 のときは << size >> と、より単純に記述できることは既に説明しました)

>    sf "<<0,15,3>>"
    <  0,  3,  6,  9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42 >
>    sf "<<15>>"
    < 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 >
のように、等差級数数列である、また最初の要素が 0である、長さ 15、差分が 3 のベクタを記述できます。

△ 関数のベクタ化
sf では、より複雑な数列を、下のようにテンポラリ変数(tempVar)と数式(expression with tempVar)によって表現できます。
>   sf <<start, size, stride @tempVar| expression with tempVar>>
    注: start, size, stride 数値の記述には直接の数値指定に限りません。
        sf のファイル変数、テンポラリ変数や数式値を使って表現できます。
        ただし、stride 以外は、書数点以下を切り捨てて整数値にします。
#  例題:[0,2π] の範囲を 256 等分した位置それぞれでの sin(t) 関数の値を要素とする
#  長さ 256 のベクタを作る。
>   sf "N@=256, SIN=<< 0,N, 2`π/N @t|!sin(t)>>
    <          0,  0.0245412,  0.0490677,  0.0735646,  ... -0.0245412 >
>   type sin.val
    % BaseDouble 256
    < 0, 0.02454122852291229, 0.04906767432741802, ..... -0.02454122852292932 >

上のように 数式 sin(t) 関数の値を要素とするベクタ変数ファイル SIN.val を生成できます。SIN.val には sin(t) 関数値が並べられています。これを gnuplot が扱えるように並べ変えるフィルタを作れば、sin 関数を表示できます。SIN 以外でも、フィルタを介して sf の計算結果を gnuplot による表示させることが可能です。

関数をベクタ化することで、関数のベクトル的な操作が可能になります。例えば下のように sin/cos 関数が [0, 2 π] の領域で直交していることを簡単に確認できます。

>   sf "N@=256, < <<0,N,2`π/N@t|!sin(t)>> |<<0,N,2`π/N@t|!cos(t)>> >
    < -7.70183e-014 >
でも、[0, 0.6 π] の領域では、同じ関数でも直交していなことも、同様に確認できます
>   sf "N@=256, < <<0,N,0.6`π/N@t|!sin(t)>> |<<0,N,0.6`π/N@t|!cos(t)>> >
    < 61.5675 >
△ 積分・微分
関数をベクタ化した後に、ベクタの !sum(.) 関数を使えば、関数の定積分が求められます。
#    π/2
#   ∫  sin(x) dx 定積分の数値計算
#    0
>   sf "N@=256, !sum(<<0,N,0.5`π/N @t|!sin(t)>>) 0.5`π/N"
    < 0.996929 >

<<0,N,0.5`π/N @t|!sin(t)>>の式は `π/N の等差級数により定まる sin(t) の値を要素とするベクトルを意味します。。N の値を 100 とか 256 とかの値にしてプロット数を多くしてやると、コンピュータでグラフ表示したとき sin 関数の形になります。

ベクタの !shift(.) 関数を使えば、微分関数のベクタも求められます。

#   sin(x) の数値微分
>   sf "N@=256, sin@=<<0,`N,π/N @t|!sin(t)>>, (sin - ~shift(sin,1) )/(`π/N)"
    <           0,    0.999975,    0.999824, .... 1,   -0.999523,   -0.999824 >
数値微分ですから精度を期待することはできませんが、傾向性を掴むのに有効です。


△ 数列のベクタ化
前の節では、ベクタを関数と見なしましたが、ベクタを数列と見なすこともできます。例えば、下のように、(1+1/n)^n n=1,2,... の数列をベクタ記述できます。(ここで、N を大きくしていくと、この数列は常用対数の低に近づいていきます。)
>    sf "N@=6,<<1,N,1@t|(1+1/t)^t>>"
    <       2,    2.25, 2.37037, 2.44141, 2.48832, 2.52163 >

下のように、(1+1/n)^n n=1,2,.. の収束が良くないことまで分かります

>    sf "N@=100,<<1,N,1@t|(1+1/t)^t>>"
    loop count:_n  0 mtrxCommand argment: (1+1/t)^t
                ・
                ・
    loop count:_n  99 mtrxCommand argment: (1+1/t)^t
    <       2,    2.25, 2.37037, 2.44141, 2.48832, 2.52163,  2.5465, 2.56578, ・・
                ・
                ・
     ・・・・ 2.70396, 2.70411, 2.70426,  2.7044, 2.70454, 2.70468, 2.70481 >
△アルゴリズムにより定まる数列ベクタ
sf の繰り返しを使えば、アルゴリズムにより定まる数列ベクタも記述できます。F[n+2] = F[n+1] + F[n] のような漸化式アルゴリズムで表現されるフィボナッチ数列も、下のようにベクタを使って記述できます。C 言語などを持ち出すまでもありません。
>    sf "N@=16, F=<<N>>, F[0]=1,F[1]=1, <<0,N-2,1 @t| F[t+2] = F[t+1] + F[t]>>,F"
    loop count:_n  0 sf command argment: F[t+2]= F[t+1]+ F[t]
                ・
                ・
    loop count:_n  13 sf command argment: F[t+2]= F[t+1]+ F[t]
    <   1,   1,   2,   3,   5,   8,  13,  21,  34,  55,  89, 144, 233, 377, 610, 987 >


>    sf "N@=100, F=<<N>>, F[0]=1,F[1]=1, <<0,N-2,1 @t| F[_n+2] = F[_n+1] + F[_n]>>,F"
    loop count:_n  0 mtrxCommand argment: F[_n+2]= F[_n+1]+ F[_n]
                ・
                ・
    loop count:_n  97 mtrxCommand argment: F[_n+2]= F[_n+1]+ F[_n]
    <            1,            1,            2,            3,            5,・・
                ・
                ・
    ・・, 5.16807e+019, 8.36211e+019, 1.35302e+020, 2.18923e+020, 3.54225e+020 >

上の sf の繰り返し構文はフィボナッチ変数 F.val を作るための sf 式です。、ユーザーは、ベクタを生成するための sf 式のつもりではなく。このようなアルゴリズムのための繰り返しのつもりかもしれません。でも <<0,N-2,1 @t| F[t+2] = F[t+1] + F[t]>> 式は F[t+2] の要素値を持つ _dt 変数を作ってしまいます。次の S 式によって、また 直ぐに _dt の値も変更されてしまうので、問題にはならないと思います。

今度は、長さ 1 で複素数平面上を一回転する、exp(2 π i n/N) を足し合わせていくときの軌跡を計算してみましょう。

N@=6,Sum=<<N>>, Sum[0]=1, <<2`π/N, N-1, 2`π/N @θ| Sum[_n+1]=Sum[_n]+!exp(iθ) >>, Sum
<              1,  1.5+0.866025i,     1+1.73205i,       1.73205i, -0.5+0.866025i,              0 >
N@=20,Sum=<<N>>, Sum[0]=1, <<2`π/N, N-1, 2`π/N @θ| Sum[_n+1]=Sum[_n]+!exp(iθ) >>, Sum

下の gnuplot のためのグラフ表示処理については後で説明します

    Sum = !print(plot \"-\" using 2:3 with line)
    gnpltDt.exe Sum.val > gnuplot.ini
    wgnuplot

上では、sf が繰り返しのときにデフォルトで用意しているテンポラリ・インデックス・変数 _n を使っています。_n は 0,1,...size-1 と変化するインデックス変数です。行列やベクタなどの要素を簡単にアクセスするために設けています。Start,Size,Stride による sf の繰り返し分を使うとき、自動的に sf 内部で宣言されています。

    loop count:_n  0 sf command argment: Sum[_n+1]=Sum[_n]+!exp(iθ)
コンソールにループごとに打ち出される上の行に出てきている _n と同じ変数です。0 から始まり、1 つづつ増えていきます。

デフォルト・インデックスを使うことで、この例のように繰り返しパラメータが実数であって 0 から始まる整数でないときでも、行列/ベクタ要素へのアクセス・パラメータとして _n を使用できます。新たにテンポラリ変数を設ける必要はありません。

△ start, size, stride によるベクタ・行列の部分要素

sf では、ベクタや行列の部分要素を、C++ 言語の slice array の形式を使って、ベクタ・行列要素の部分要素をまとめて扱えるようにしています。(slice array を理解していないと判りにくいとも思います。でも C++ 言語で数値計算をするときには使う考え方であり、ここで苦労しても損にはならないはずです。sf 速習で一番解り難い個所ですが、この節にもお付き合いください)

sf ではベクタの部分要素を 行列やベクタ直後の各カッコの中 [...] に start, size, stride の三要素からなるベクタを指定することで、ベクタの部分要素を指定します。ここで start, size, stride は全て正の整数です。

 vector[<start, size, stride>]
ベクタのインデックスを start から初めて、stride ずつ size 回だけ増やしていき、そのインデックス値群により定まる部分ベクタを指定します。例えば、長さ 10 のベクタの 1,3,5,7 要素に、1,2,3,4 の数値を代入する操作は下の様に行えます。さらに続けて 0,4,8 要素に 5,6,7 の数値を代入します。
>   sf "vector = <<10>>"
    < 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 >

>   sf "vector[<1,4,2>] = <1,2,3,4>"
    < 0, 1, 0, 2, 0, 3, 0, 4, 0, 0 >

>   sf "vector[<0,3,4>] = <5,6,7>"
    < 5, 1, 0, 2, 6, 3, 0, 4, 7, 0 >
このベクタの三番目から七番目まで 5 個の要素をを連続して読み出したければ、stride を 1 にして、下のように記述します。
>   sf "vector[<2,5,1>]"
    < 0, 2, 6, 3, 0 >
ベクトル演算した結果から部分ベクタを取り出して、別のベクタを作り出すこともできます
>   sf "temp@=<<1,!size(vector),1>>+vector,temp[<2,4,1>]"
    <  3,  6, 11,  9 >
>   sf "(<<1,!size(vector),1>>+vector)[<2,4,1>]"
    <  3,  6, 11,  9 >

インデックスは 0 から始まるので三番目の要素はインデックス 2 で指定されます。慣れるまでは判りにくいと思います。でも自分で上の数値を変えがら、配列の部分操作を色々と行ってみることで直ぐに判るはずです。

このような一見わかりにくい slice array を使うのは、行列要素の部分要素群を手短に一括してアクセスするためです。行列を一列に並べなおしたベクタとみなして、その部分ベクタにアクセスするためです。

行列から部分ベクタ成分を取り出すとき、行列を column*row size ベクトルと start, size, stride の考えを適用します。5x5 行列を例に slice array による行列要素の一括指定の例を幾つか下に示します。

    # 0 要素のみから構成される 5 x 5 正方行列 Matirx を作る。
    sf Matrix = [[5]]
    < 0, 0, 0, 0, 0 >
    < 0, 0, 0, 0, 0 >
    < 0, 0, 0, 0, 0 >
    < 0, 0, 0, 0, 0 >
    < 0, 0, 0, 0, 0 >

    # 対角要素の最初の四つを 1,2,3,4 にする
    sf "Matrix[<0,4,5+1>] = <1,2,3,4>"
    < 1, 0, 0, 0, 0 >
    < 0, 2, 0, 0, 0 >
    < 0, 0, 3, 0, 0 >
    < 0, 0, 0, 4, 0 >
    < 0, 0, 0, 0, 0 >

    # 対角要素から一つ右上の四つ斜め要素を 5,6,7,8 にする
    sf "Matrix[<1,4,5+1>] = <5,6,7,8>"
    < 1, 5, 0, 0, 0 >
    < 0, 2, 6, 0, 0 >
    < 0, 0, 3, 7, 0 >
    < 0, 0, 0, 4, 8 >
    < 0, 0, 0, 0, 0 >

    # 右上から左下への対角要素を 11,12,13,14,15 にする
    sf "Matrix[<4,5,5-1>] = <11,12,13,14,15>"
    <  1,  5,  0,  0, 11 >
    <  0,  2,  6, 12,  0 >
    <  0,  0, 13,  7,  0 >
    <  0, 14,  0,  4,  8 >
    < 15,  0,  0,  0,  0 >

    # 5 行目の 2 列目以降の連続する三つの要素を 21,22,23 にする
    sf "Matrix[<5*(5-1)+3-1,3,1>] = <21,22,23>"
    <  1,  5,  0,  0, 11 >
    <  0,  2,  6, 12,  0 >
    <  0,  0, 13,  7,  0 >
    <  0, 14,  0,  4,  8 >
    < 15,  0, 21, 22, 23 >

    # 行列の 2 列目と 3 列目の二つより長さ 10 のベクトルを取り出す
    sf "Matrix[<(2-1)*5,10,1>]"
    <  0,  2,  6, 12,  0,  0,  0, 13,  7,  0 >

    sf "(Matrix[<4,5,4>])[<1,3,1>]"
    < 12, 13, 14 >

    # 100x100 のシフト行列を作ります。すなわち対角要素の一つ斜め上の要素を 1 にします。
    sf "N@=100,Matrix=[[N]], Matrix[<1,N-1,N+1>]=<<1,N-1,0>>"
    < 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,....
    < 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,....
    < 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,....
    < 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,....
    < 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,....
    < 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,....
    < 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,....
            ・
            ・
            ・
行列部分要素を slice array を使ってアクセスすることは、ベクタのときより、判りにくいとも思います。上の例で様々の数値を入れて納得するまで操作してみてください。slice array に慣れれば、規則性のある部分行列要素へのアクセスを短く記述できます。



○ 括弧付きの sf 複式 ○

下のような "," で区切った複数の sf 式を既に使ってきました。これを sf の複式と言います。

N@=10,<<0,N,1>>

sf の複式を丸括弧で囲む事により、sf の複式に一つの値を持たせることができます。括弧付きの sf 複式を sf 演算の対称にできます。下のような具合です。

(N@=10,<<0,N,1>>) 3
<  0,  3,  6,  9, 12, 15, 18, 21, 24, 27 >

~shift( (N@=10,<<0,N,1>>) 3, 2)
<  0,  0,  0,  3,  6,  9, 12, 15, 18, 21 >

~shift( (N@=10,temp@=<<0,N,1>>, temp[5]=100), 2)
<   0,   0,   0,   1,   2,   3,   4, 100,   6,   7 >

上の最後の式での括弧付きの sf 複式の値は 100 では有りません。temp[5] に 100 を代入した後の temp ベクタが括弧付き sf 複式の値です。これは下のようにして確認できます。

(N@=10,temp@=<<0,N,1>>, temp[5]=100)
<   0,   1,   2,   3,   4, 100,   6,   7,   8,   9 >

なお、下のような sf 式はエラーになります。

~shift( (N@=10,<<0,N,1>>[5]=100), 2)

Regular Pattern match by krgstr::% is not detected 
    for "=100"

a.cpp:2411:kAssert Error: We can't find variable term in rStrResidualAg:=100 at detectVariableTerm(.):
Assertion failed: 0, file a.cpp, line 2411

下の式も上と同じエラーになります。= 100 を代入するための変数がないからです。

<<0,N,1>>[5]=100

なお、右辺値のときは部分要素を戻り値とする括弧付き sf 複式を使えます

(N@=10,<<0,N,1>>[5]) 3
< 15 >

○ ブロック実行とサブルーチン ○

△ ブロック実行ファイル

sf は、計算式の数が多い、コメントを書いておきたいなどのために、テキスト・ファイルに計算式を複数行書いておき、連続して実行する機能を持っています。

先の sin(.) 関数の定積分を台形公式を使うことで精度を上げてみます。改行とコメントを入れることができるため、式の意味が分かり易くなります。

//@@
    # sin(.) 関数を [0, π) の区間で、台形公式を使って定積分する
    N @= 100
    vect @= <<0,N,0.5`π/N @t| !sin(t)>>
    vect2 @= vect
    
    #下の二行は、最初に私が犯した誤り
    #vect2 @= !shift(vect)
    #vect[N-1]=0

    #左端の位置に、右端の値を追加する
    vect2[0] = !sin(0.5`π)
    0.5`π/N !sum(vect + vect2) /2
//@@@
< 0.999979 >
sf のブロック実行

//@@, //@@@ の記号は 「//@@ から //@@@ までの間の文字列を内容とする temp.se の名前のファイル作成する そしてsf.exe @@temp を実行する」 との意味です。左上に "sf block}" のマークを付けることでも sf のブロック実行であることを示します。

temp.se ファイルにコピーしたり sf @temp コマンドを実行させたりする操作を手作業で実際に行ってもかまいませんが、お使いのエディタに、このようなマクロを組み込んでしまうことを強く勧めます。私自身は WZ エディタのマクロでこれを実現しています。//@@ から //@@@ の間の何れかの行にカーソルを置いて ctrl + O and P の操作をすることで sf 計算をできるようにしています。詳細はコンソール操作の勧めを参照願います。

ブロック実行ファイルのデフォルトの拡張子は se です。sf @@temp のように拡張子が無いファイルを指定されたときは、自動的に se 拡張子を補って temp.se ファイルを探し実行します。se 以外の拡張子を使うときは、ユーザーが明示的に記述します

なお sf @@\#####.### と直接 #####.### ファイルを指定して実行させることはできません。sf では "#" 文字以降をコメント文字列とみなしてしまうので、# を含んだファイル名を指定できないからです。

具体例を作って実際に計算させてみると、教科書を読んでいるだけでは見逃してしまう、本質的な点に気づかされます。だからといって、この台形公式による定積分の計算を C 言語、python などでやろうとすると、プログラムのデバッグ作業という、余分な作業が入りこんでしまいます。本来の数学を理解することから離れた作業を強いられます。sf を使えば、実例による確認計算作業を簡単に実行できます。多くの場合、プログラムを持ち出すまでもなく、sf のブロック実行で済ませられます。

この台形公式を使った積分の具体例を計算することで、新規に右端の値を追加することが精度を上げるために必要であることに気づかされました。最初は単純に vect をシフトしただけのものを vect2 としたため、単純な区分求積方より精度の悪い結果となりました。台形公式による積分を誤って理解していた気づかされました。


ブロック実行での改行位置
なおブロック実行ファイルでの改行位置は sf 複式を書いたときに "," を書く場所にするのが便利です。sf が自動的に "," を追加するからです。逆に、"," を書かずに改行する必要があります。

sf ブロック実行ファイルの中で "," 以外の場所で改行したいときは行末を \ にします。下のような具合です。

//@@
N@=5
<<0,N,1 @j|\
        < j, 100
        j+1>
>>
//@@@
<   4, 100,   5 >
<   0, 100,   1 >
<   1, 100,   2 >
<   2, 100,   3 >
<   3, 100,   4 >
<   4, 100,   5 >

なお、上のように sf ベクトルを繰り返し実行すると、行列になります。下のように sf 行列を繰り返し実行したときは、繰り返し行列を横ベクトルとした行列になります。

//@@
N@=5
<<0,N,1 @j|\
    <<0,N,1 @k|\
        < j,k, 100>
    >>
>>
//@@@
<   0,   0, 100,   0,   1, 100,   0,   2, 100,   0,   3, 100,   0,   4, 100 >
<   1,   0, 100,   1,   1, 100,   1,   2, 100,   1,   3, 100,   1,   4, 100 >
<   2,   0, 100,   2,   1, 100,   2,   2, 100,   2,   3, 100,   2,   4, 100 >
<   3,   0, 100,   3,   1, 100,   3,   2, 100,   3,   3, 100,   3,   4, 100 >
<   4,   0, 100,   4,   1, 100,   4,   2, 100,   4,   3, 100,   4,   4, 100 >

△サブルーチン・ファイル

sf では何度も繰り返して行われる関数計算を数式中から呼び出せるようにする、サブルーチン・ファイルの機能を設けています。ブロック実行ファイルに似ていますが、下の点で異なります。

  1. @subFile(,,) の形式で呼び出される
  2. 呼び出すとき、引数 _prm1, _prm2, ,... の名前のテンポラリ変数に引数値を渡す
  3. _rt テンポラリ変数に戻り値を記述する
  4. 戻り値 _rt が @subFile の値となるので、数式中に式要素として記述できる
  5. デフォルトの拡張子が sf である

下のような行列のポアソン・ブラケット演算を行わせる Poisson.sf を作っておけば、それを sf の計算式の中から呼び出し、実行させられます。サブルーチンのなかの _prm{n} に n 個目の引数値が入ります。(_prm{0} には引数の個数が入っているのですが、_rpm{0} を使う機会は限られると思います)

    type Poisson.sf
    _rt = _prm{1} _prm{2} - _prm{2} _prm{1}

    sf `σz @Poisson(``σx, `σy)
    < 2i,  0 >
    <  0, 2i >

    sf `σz + @Poisson(`σx `σz, `σy)
    <  1,  0 >
    <  0, -1 >

    # 上で使った Pauli 行列 `σx,`σy,`σz は sf.ini に定義してあります。下の値を持ちます
    sf `σx
    < 0, 1 >
    < 1, 0 >

    sf `σx
    < 0, 1 >
    < 1, 0 >

    sf `σz
    <  1,  0 >
    <  0, -1 >

sf のサブルーチン・ファイルをユーザーが自分で記述するとき _rt に戻り値を設定することを忘れないで下さい。戻り値がなくなってしまいます。エラーになります

上の Poisson.sf はエディタで作成してもよいのですが、sf ブロック・ファイルの中で記述することもできます。そのときは @@subFile と @@endSubFile の間にサブルーチンファイルを記述します、サブルーチン・ファイル名を宣言します。下のように記述します

//@@
    @@subFile Poisson.sf
        _rt = _prm{1} _prm{2} - _prm{2} _prm{1}
    @@endSubFile

    `σz + @Poisson(`σx `σz, `σy)
//@@@

@@subFile ... @@endSubFile によって sf ブロック実行ファイルで作った sf サブルーチン・ファイルは HDD のカレント ディレクトリに残ります。他の計算でも再利用できます。

最後に実用的に使える、sf ベクタ・データの標準偏差を計算させる sf サブルーチンを示します。任意のサイズの sf ベクタで動作するように作ってあります。

//@@@
    @@subFile
    #    標準偏差 `σ^2 = (Σ(x[i]-x_bar)^2) / N を計算させる sf サブルーチン
        N@=!size(_prm1)
        x_bar@=!sum(_prm1)/N
        x'@=_prm1-x_bar<< 1,N,0>>
        _rt = !sqrt( (< x'|x'>/N) )
    @@endSubFile

    @standardDv(<1,2,3>)
//@@@
< 0.816497 >
ブロック実行とサブルーチン実行の違い

プロック実効とサブルーチン実行はよく似ています。違いを持たせたのは、戻り値を持たないブロック・ファイルと、戻り値を持つサブ・ルーチン・ファイルを区別するためです。
  \ サブ・ブロック・ファイル  サブルーチン・ファイル
呼び出し  @@subBlock@suFile(...)
戻り値
戻り値なし戻り値 _rt がある
var = @subFile
_rt に値を設定しないとエラー
拡張子 sesf

○ サブ・バリアブル・ファイル ○

行列やベクトルの要素を sf 式で記述した変数を使いたい事がよくあります。下のように二次元の回転行列を表す行列変数を作っておき、ベクトルを様々の角度で回転させたいことが良く有ります。

Rotate2.var 二次元座標軸の回転の定義
    < !cos(θ), -!sin(θ)>
    < !sin(θ),  !cos(θ)>

ベクトルの回転操作
    θ@=π/4, Rotate.var <0,1>

これは下のように @@subVar と @@endSubvar の間に行列要素やベクトル要素を直接記述する事で実現できます。 に記述することで実現できます。

//@@
    @@subVar Rotate2 2,2  # 二次元座標軸の回転の定義
        < !cos(θ), -!sin(θ)>
        < !sin(θ),  !cos(θ)>
    @@endSubVar

#   ベクトルの回転操作
    θ@=`π/4, Rotate2.var <0,1>
//@@@
< -0.707107,  0.707107 >


//@@
    @@subVar Vector2 2 # 二次元ベクトル サブ バリアブル
    < !sin(θ),  !cos(θ)>
    @@endSubVar

#   ベクトルどうしの積の操作
    θ@=`π/4, Vector2.var <0,1>
//@@@
<        0, 0.707107 >

ここで、行列やベクトルのサイズはユーザーが明示的に 2,2 のように指定する必要があります。

subFile のときと同様に Rotate2.var ファイルがカレントディレクトリに作られ、他の計算でも再利用できます。 "% BaseVarDoubleMatrix 2, 2" や "% BaseVarDouble 2" を自分で記述することで Rotate2.var や Vector2.var をエディタを使って自分で記述してもかまいません。

type Rotate2.var
% BaseVarDoubleMatrix 2, 2
< !cos(θ), -!sin(θ)>
< !sin(θ),  !cos(θ)>

type Vector2.var
% BaseVarDouble 2
< !sin(θ),  !cos(θ)>

サブ・バリアブル変数は内部変数をグローバル変数として渡します。サブルーチン・ファイルのときのように引数で渡すことはできません。サブ・バリアブル変数を sf 式の中に記述するとき拡張子 "var" を付けねばなりません。省略できません。

△変数のスコープ

sf にはファイル変数、テンポラリ変数の二種類がありますが、どちらもグローバル変数です。別のルーチンから参照できます。書き換えることさえもできます。

ただし、テンポラリ変数はサブルーチン ファイル変数などの、より階層の高い側で再度宣言できます。階層が異なればテンポラリ変数名の衝突は発生しません。

//@@
    @@subFile
    #    標準偏差 `σ^2 = (Σ(x[i]-x_bar)^2) / N を計算させる sf サブルーチン
        N@=!size(_prm1)
        x_bar@=!sum(_prm1)/N
        x'@=_prm1-x_bar<< 1,N,0>>
        _rt = !sqrt( (< x'|x'>/N) )
    @@endSubFile

    N @=4
    @standardDv(<1,2,3>)
    N +1
//@@@
< 5 >
テンポラリ変数 N を使っている @standardDv(.) を呼び出しても N @=4 の N は壊されません。

一般にプログラムを記述するときグローバル変数を避けるべきです。昔の Basic のようなグローバル変数しか書けない言語仕様避けるべきです。でも sf のように高々数十行のコードのときはグローバル変数のほうが分かり易くなることも多く有ります。テンポラリ変数の階層的なスコープにより、ローカル変数のみの記述にすることも可能です。どちらにするかはユーザーに負かされています。

△リカーシブ呼び出しの禁止
sf では、ブロック実行/サブルーチン呼び出し/サブ・バリアブルのネスティングが可能です。ブロック実行ファイル、サブルーチンファイルの中から別のブロック実行ファイル、サブルーチン・ファイルやサブ・バリアブルを呼び出せます。

でも、でもネスティングの先に自分自身を含んではいけません。リカーシブ呼び出しは避けてください。下の様に、サブルーチン・ファイルの中で下のような

>   type testAdd.sf
    _rt = _prm1 + _prm2

>   type testSub.sf
    _rt = _prm1 - _prm2

>   type test.sf
    _rt = 3*testAdd(_prm1,_prm2)
"
    #サブルーチン呼び出しのネスティングは可能です
>   sf "@testAdd( @testSub(1,2), @testSub(2,4) )"
    < -3 >

    #サブルーチンのリカーシブ呼び出しはできません。例外が発生します。
>   sf "@test( 2,4 )"

リカーシブな呼び出しが発生すると、if then else 構文のない sf では呼び出し側に戻ることが全くありません。スタックが消費されながらの繰り返し sf コマンドの実行つづきます。最後に例外が発生します。下のメッセージが出ます。

"We catched unexpected execption."


○ sf のコンソール実行環境 ○

sf はコンソールで実行させます。 エディタ上でメモを書きながら、メモに埋め込まれた数式をコンソールで実行する使い方を主な使い方として想定しています。たぶんメモ テキストに書かれている数式行をクリップ・ボードにコピーし、次にコンソールにペーストして実行させることが多いはずです。このコピー・ペーストをマウスで行っていては効率的ではありません

単純な効率化の方法としてマウス・キーボード・エミュレータの使用があります。ウィンドウズのコンソールではマウスの右クリップで、クリップ・ボードの文字列をコンソールに貼り付けられることを利用します。

以上の操作によって、コンソールに数式を実行させられます。マウス・キーボード・エミュレータを使うことで、キーボードからマウスに持ち代える手間を省けますが、それでも面倒です。

sf を効率よく使うためには、お使いのエディタに書いてある sf の数式行を実行させる、下のようなマクロを組み込んでしまうことを勧めます。

計算が複雑になると、一行の数式には収まらなってきます。そのときは、ブロック実行ファイルを作成して、sf に一括実行させます。このとき、エディタに次のようなマクロがあると便利です。

//@@
  ↑
  │<== この範囲をカレント ディレクトリの temp.se に書き出し sf @@temp を実行する
  ↓
//@@@

私自身は WZ エディタをを使っており WZ の shell マクロと、それに行、ブロック実行マクロを組み合わせています。これについてもソースも一緒に公開してあります。参照ください。

○ グラフ表示 ○

sf でのグラフ表示は、gnuplot や Excel などの既存の表示ソフトで行わせます。sf 自体にはグラフ表示機能を持たせません。ユーザーにとっても、既に慣れ親しんだグラフ表示ソフトを使うほうが便利だと考えます。

sf では gnuplot による表示のためのフィルタを用意しています。少ない操作で手軽に表示させることを狙っています。

もし、今までグラフ表示ソフトを使ったことがなければ、この機会に gnuplot グラフ表示ソフトを使ってみてください。gnuplot は無料で使えます。また多くのソフトからグラフ表示端末として使われています。gnuplot は sf に限ることなく、多くの場面で使えます。

こちらに要領よくまとまった gnplot の解説があります。gnuplot home page の download を辿って gnuplot の Source FORGEに行けます。ここで gp400win32.zip をダウンロードすれば Windows 向けのバイナリが入手できます。なお、sf でのグラフ表示のためだけならば、ダウンロードした zip ファイルのなかから wgnuplot.exe を path の通ったディレクトリに置くだけで済みます。インストールの必要もありません。

△ 関数のグラフ表示

sf での計算結果は、拡張子が val のテキスト・ファイル変数に、数値文字列の集まりとして出力されます。その数値文字例の集まりを、フィルター・プログラムを使って gnuplot や Excel などのグラフ表示ソフトが扱えるデータに変形してやってグラフ表示させます。

グラフ表示ソフトへの表示方法を指示するための文字列を渡せるように、sf には !print(.) 関数を用意しました。sf のブロック実行ファイルなどからグラフ表示のためのパラメータなどを渡します。

表示可能なデータへの変形は Perl, Ruby など、お好きなフィルタ言語が使えます。私自身は、自作の kreg C++ 正規表現ライブラリを使っています。kreg を使った、sf のベクタ変数テキスト・ファイルを gnuplot で扱えるデータの形式に変換する gnpltMDt.exe/gdsp.bat, gnSplt.exe//gspl.bat ファイルも sf の配布 zip ファイル中にあります。

関数の二次元グラフ表示

ベクトル変数を元に gnpltMDt.exe/gdsp.bat フィルタを介して gnuplot 二次元表示を行わせます。

gdsp.bat は下の内容のものです。gnuplot を実行するとき、gnuplot.ini があると、そこにある表示コマンドを実行することを使います。plot "-" ... により、 gnuplot.ini ファイル内のデータを表示する事を利用します。

type gdsp.bat
gnpltMDt.exe %1 > gnuplot.ini
start wgnuplot.exe

gnpltMDt.exe が sf ベクタ変数を gnuplot 向けに変換するフィルタ プログラムです。自動的に plot "-" using 1:2 with lineコマンドを追加します。また、横に並んでいたデータを縦に並べます。そのとき、0 から始まるインデックス番号を左端に追加します。

    temp = <1,2,3,4>
< 1, 2, 3, 4 >
    gnpltMDt temp

plot "-" using 1:2 with line
      0              1
      1              2
      2              3
      3              4

なお、gnpltMDt.exe は引数が与えられないとき _dt.val が引数にあるものとして処理します。

下のように関数のグラフ表示をさせられます。

    N@=128, <<0,N,2`π/N @t| !sin(t) + 3 !cos(t + `π/7)>>
    gdsp

表示データが複素数のときは、real 値と image 値を横に並べます。 plot "-" using 1:2 with lineコマンドを使っているため、デフォルトでは実数側を表示します。

    expDt = (N@=6, <<0,N,1/N @t| !exp(2`π i t)>>)
<              1,  0.5+0.866025i, -0.5+0.866025i,             -1, -0.5-0.866025i,  0.5-0.866025i >
    gdsp expDt

type gnuplot.ini
plot "-" using 1:2 with line
      0              1                  0
      1            0.5            0.86603
      2           -0.5            0.86603
      3             -1         1.2246e-016
      4           -0.5           -0.86603
      5            0.5           -0.86603

!print(...)命令
sf にはグラフィック表示でのコマンド文字列を指定するために !print(...) 命令を持たせています。ユーザー側で明示的に plot コマンドをコメント文字列として sf ファイル変数に追加できます
    expDt = !print(plot \"-\" using 1:3 with line)
# <== コンソールで実行するコマンドのため \ 記号を追加しました。
 sf command argment: expDt = !print(plot "-" using 1:3 with line)
gnpltMDt.exe は #g で始まる行があると、表示コマンド行があると見なし、#g で始まった行を標準出力に打ち出します。ただし最初の #g の文字列は取り除きます。また plot "-" using 1:2 with lineコマンドの補完を止めます。↑の !print(..) によって、image 側の二次元グラフを表示させられます。
    gdsp expDt

    type gnuplot.ini
 plot "-" using 1:3 with line
      0              1                  0
      1            0.5            0.86603
      2           -0.5            0.86603
      3             -1         1.2246e-016
      4           -0.5           -0.86603
      5            0.5           -0.86603
二次元グラフ パラメーター表示
N x 2 の縦長行列にデータを入れた sf 変数を作って gnpltMDt.exe/gdsp 処理をすると二次元グラフの gnuplot parameter 表示になります。
    prm2Dt = (N@=6, <<0,N,1/N @t| < !cos(2`π t),!sin(2`π t)> >>)
<            1,            0 >
<          0.5,     0.866025 >
<         -0.5,     0.866025 >
<           -1, 1.22461e-016 >
<         -0.5,    -0.866025 >
<          0.5,    -0.866025 >
    gdsp prm2Dt

plot &quto;-&quto; using 2:3 with line を自動補完しています。
    type gnuplot.ini
plot "-" using 2:3 with line
      0              1             0
      1            0.5       0.86603
      2           -0.5       0.86603
      3             -1   1.2246e-016
      4           -0.5      -0.86603
      5            0.5      -0.86603
三次元グラフ パラメーター表示
N x 3 の縦長行列にデータを入れた sf 変数を作って gnpltMDt.exe/gdsp 処理をすると三次元グラフの gnuplot parameter 表示になります。
    prm3Dt = (N@=6, <<0,N,1/N @t|  >>)
<            0,            1,            0 >
<     0.166667,          0.5,     0.866025 >
<     0.333333,         -0.5,     0.866025 >
<          0.5,           -1, 1.22461e-016 >
<     0.666667,         -0.5,    -0.866025 >
<     0.833333,          0.5,    -0.866025 >

    gdsp prm3Dt

splot "-" using 2:3:4 with line を自動補完しています。
    type gnuplot.ini
splot "-" using 2:3:4 with line
      0              0             1             0
      1        0.16667           0.5       0.86603
      2        0.33333          -0.5       0.86603
      3            0.5            -1   1.2246e-016
      4        0.66667          -0.5      -0.86603
      5        0.83333           0.5      -0.86603
関数の三次元グラフ表示
N x M 行列変数を元に gnSplt.exe/gspl.bat フィルタを介して gnuplot 二次元表示を行わせます。行列の i, j インデックスが x,y 位置に対応します。行列要素の値が z 値に対応します。
//@@
N@=16
gnplt3Dt =<<0,N,1/N @t|\
    <<0,N+4,1/N @ u|\
        !sin( 2 `π u t)
    >>
>>
//@@@
    gspl gnplt3Dt

splot "-" using 1:2:3 with line を自動補完しています。
    type gnuplot.ini
splot "-" using 1:2:3 with line
      0       0       0
      1       0       0
      2       0       0
      .       .       .
      .       .       .
     17      15 -0.024541
     18      15 0.33689
     19      15 0.65317

○ ユーザー関数を使っての拡張 ○

sf の計算機能の拡張はユーザー関数を使って行います。ユーザーが C/C++ 言語を使って自由に拡張できます。

ユーザー関数を sf 式から呼び出すときは " ~ "tilda で始めます。sf は数式中で ~ で始まる文字列を見つけると、それをユーザー関数であるとみなし、子プロセスを起動して、~ より後、"(" 前までの文字列の名前のプログラムを実行させます。デフォルト拡張子 exe は省略できます。( bat ファイルをユーザー実行関数として指定するときは、拡張子 "bat" を明示的に書いてください)

ユーザー関数への引数は _arg{1}.val,_arg{2}.val, ... arg{N}.val ファイル変数です。_arg{0} には引数の個数が入ります。それら引数値への値の設定は、子プロセスを起動する直前に sf が行います。戻り値は _rs.val ファイル変数に書かれていなければなりません。

引数が文字列引数のときは '....' の single quote で表します。その文字列を子プロセスを呼び出すときの引数にします。文字列引数は一つだけとします。_arg{N} との混在はできません。(double quot にすると、コマンドラインでの記述するとき \ 記号が必要になった面倒なので single quot を使う仕様としました。)

簡単なユーザー関数ならば bat ファイルでも作れます。でも本格的に自前の関数を作るときは C/C++ 言語を使うことを勧めます。既存の任意の C/C++ 数値計算ライブラリを sf に組み込むことが可能です。詳細については "■ C/C++ exe プログラムによる sf 機能の拡張 ■" を参照ください

ここでは、ユーザー関数として既に実装してある random, expM, Jacobi の使い方について説明します。

random.exe は、size, seed, range の三つの文字列を引数として受け取り

を _rs ファイル変数に設定して返す、sf のユーザー関数 exe プログラムです。下のように使います。
    N @= 10
    # [0, 2 π) の範囲の長さ 5 の実数ベクタを作る
    !sin( ~random('5 1 999') 2 π /1000)
    < -0.385584,   0.93655,  -0.93655, -0.503623,  0.131564 >
random.exe の引数は文字列であり、sf の引数も single quot で囲ってあります。

random.exe は文字列引数に指定したバラメータ文字列によって動くコンソール exe プログラムでもあります。sf を介さずに単独でも使用できます。このときでも、_rs.val ファイルへの戻り値の設定はなされます。

>   random /?
    Please input random(int size, int seed=0, int range=0x7fff)
>   random 10 2
< 29216, 24198, 17795, 29484, 19650, 14590, 26431, 10705, 18316,  5557 >
>   sf _rs
< 29216, 24198, 17795, 29484, 19650, 14590, 26431, 10705, 18316,  5557 >

expM.exe は正方行列の exp 関数を計算させる sf ユーザー関数 exe プログラムです。実数行列、複素行列どちらでも計算します。下の様に使います

>   sf "t@=10,~expM( i t (`σx + `σy + `σz) )"
    sf command argment: _arg1=i t (`σx + `σy + `σz)
    <     10i,  10+10i >
    < -10+10i,    -10i >
    
    < 0.0417364-0.576847i, -0.576847-0.576847i >
    <  0.576847-0.576847i, 0.0417364+0.576847i >
expM も sf を介すことなく、コンソールから直接計算させられます。expM では文字列ではなく、sf ファイル変数のファイル名を指定します。val 拡張子は省略できます。
#   直前の計算結果のデフォルト変数ファイルに対して expM を実行させる
#   expM.exe にも default 拡張子 val を補う機能がある
>   expM _dt
<  0.564094-0.506245i, -0.506245-0.506245i >
<  0.506245-0.506245i,  0.564094+0.506245i >

ランダム数値ベクタを生成して sf で読める "_rt.val" sf ファイル変数を作って値を設定し、その値をファイルに出力する作業を行います。random.cpp の主要部分を下に示します。

なお、行列の exp 関数は誤差が入り込みやすいものです。行列要素の間で収束性に差があるためです。~expM(Matrix) ~expM(-Matrix) が単位行列になることを検算するなど、ユーザーによる精度の確認が必要です。

エルミート行列のときは、次に述べる Jacobi 法で対角化してから expM を実行すると、収束性の違いによる計算誤差蓄積は無くせます。

Jacob.exe はエルミート行列の固有値と、対角化行列を求める sf ユーザー関数 exe プログラムです。Jacobi 法を使って計算しています。実数/複素数どちらも計算します。引数行列がエルミート行列でないときの計算結果は保証されません。下の様に使います。

>   sf Jacobi(`σx + `σy)
<  0.707107+0.707107i,  0.707107-0.707107i >
<  0.707107+0.707107i, -0.707107+0.707107i >

#   対角化行列は Jacobi.val に残っています。
type Jacobi.val
% BaseComplexDoubleMatrix 2,  2
< 0.3250575836718681 -0.3250575836718681i, 0.8880738339771153 +0i >
< -0.8880738339771153 +0i, 0.3250575836718681 +0.3250575836718681i >

#   sf を経由せずに、直接エルミート行列変数ファイルを指定して実行させる
#   Uacobi.exe にも default 拡張子 val を補う機能がある
>Jacobi _dt
< 0.325058-0.325058i,           0.888074 >
<          -0.888074, 0.325058+0.325058i >

<       0, 1.22474 >

○ python インターフェース ○

"~" で初まる拡張子 ".py" の名前のユーザー関数呼び出しを行うことで sf は python を呼び出します。
`test.py(4}
上のようにな sf 式を実行すると sf は _arg[1}.val に引数値 4 を設定し
python test.py _argv{1}
を子プロセスで実行します。~test.py(.) の戻り値は _rt.val の名前の sf 変数ファイルに書き込みます。_rt.val に python ルーチンが戻り値を設定しないとエラーになります。

_arg{N} から python の array 変数にに変換する sfGet(.) また逆に python の array から _rt.val に変換する sfPut(.) を備えた python interface ルーチン sfVal.py を用意しています。

現在 sfVal.py はまだ実験的な運用です。sfVal.py もモジュールにしていません。python ルーチンの起動と戻り値設定は動作しますが、sfVal.py についてのテストは、まだアプリケーション例が少ないと判断しています。

○ その他 ○

△ インデックス付き変数

sf 変数に整数値インデックスを追加できます。行列の数列などを表現できます。 インデックスに sf 変数や数式を使えるので、sf の繰り返し構文でも使えます

インデックスの追加は変数名の後に "{ num1,num2, ... ,num }" を追加することで行います。インデックスの個数に制限はありません。下にインデックス変数の使用例を氏示します。

>   sf "<<0,4,1 @j| Test{j+1} = ~expM( j `σx)>>"

#   上のコマンドは 7/28 日に実行しました
#   下の様に 四つの Test{j} j=0,..3 sf 変数ファイルが作られました。
>dir Test{*.val  
2004/07/27  14:27                   46 Test{1}.val
2004/07/27  14:27                  110 Test{2}.val
2004/07/27  14:27                  110 Test{3}.val
2004/07/27  14:27                  108 Test{4}.val

#   Test{3} は 2x2 行列です
>sf "Test{3}"
 sf command argment: Test{3}
 sf command argment: 3
<  3.7622, 3.62686 >
< 3.62686,  3.7622 >

# test{3,4,5} インデックス付き sf ファイル変数にベクトル <5,6> を代入します
>sf "test{3,4,5} = <5,6>"
type "test{3,4,5}.val"
% BaseDouble 2
< 5, 6 >

インデックスが整数値であることはユーザーが保証せねばなりません。整数になっていないとき、小数点以下を切り捨てられた整数値をインデックスとして使います。

なお、10000 を超えるような多数のインデックス変数をシミュレーションなどど設けると、OS 自体の動作が遅くなります。将来のバージョンでは test{}.val のような一つのファイルに複数のインデックス付きファイル変数をまとめる予定です。

△ sf 変数名
sf の数式で扱える変数名はアルファ ニューメリックで表した変数名にいくつかの拡張を与えたものです。
アルファ ニューメリック文字列とは

「A から Z」「a から z」のアルファベットと "_" と「0 から 9」の数字を組み合わせた変数名です。 ただし 最初の文字には数字を使えません。"ab3" は アルファ ニューメリック文字列です。でも "3ab" はアルファ ニューメリック文字列ではありません。数字で始まるからです。

与えられた拡張とは
  1. [Α から Ω」「α から ω」のギリシャ文字が使えます
  2. 変数名の最後に "'" "`" のモデテファイ記号を複数使えます。
  3. 変数名の最初に "'" "`" のモデテファイ記号を一つだけ使えます。

厳密には sf 変数名は正規表現で定義されています。

# program source の定義です。kreg 正規表現です。拡張子まで含んでいます。
krgstr("^(['\\`Α-Ωα-ωA-Za-z_][Α-Ωα-ωA-Za-z_0-9]*[_'``]*)({[^{}]+})?(`.[A-Za-z]*)?(`[)?");

# 上をperl 正規表現で表します
"^(['\`Α-Ωα-ωA-Za-z_][Α-Ωα-ωA-Za-z_0-9]*[_'``]*)({[^{}]+})?(`.[A-Za-z]*)?(`[)?");
下のように sf 変数を使えます。
ギリシャ文字    ;;Δt  = 0.25
'modifier       ;;Δt1' = 0.25
`modifier       ;;Δt2` = 0.25
` _ modifier    ;;Tensor`_=[[4]], Tensor`_[0,1] = 0.25
下の sf 変数も使えます。
_variableName
`variableName
でも "`" で始まる変数は sf.ini に記述する定数変数に限定してください。"_" 一文字で始まる変数は sf 側で使うものとします。すでに、 _rt, _rs, _prm{N}, _arg{N} を使っています

下のような sf 変数名は使えません。

# 数字で始まる変数名
23x
#<== 23 * x の意味になります

#文字列の途中に "'""`" モディファイアが入っています
a`bc
#<== a` * bc の意味になります

なお "i" 単独の変数名を使えません。i は虚数だからです。vector[i] などと index に "i" を使えないのは苦痛に感ずるかもしれませんが、複素数値を数学での記述と同様に記述するほうを優先しました。ご理解ください。

# OK 複素数 3+23i と複素数 4+5i の積の意味です
(3+23i)(4+5i)

# OK 複素数 23i と 変数 a の積の意味です
23i a

# OK 実数 23 と 変数 ia  の積の意味です
23ia

# i` * c * t の意味になります
i`c t

# Error 純虚数 i のインデックスに意味がありません
vector[i]

# Error 純虚数 i のインデックス変数を使えません。
<<0,5,1 @i| i*2>>

# Error 純虚数 i のインデックスに意味がありません
indexFile{i}

また、sf ファイル変数めいは大文字/小文字を区別できません。Windows OS のせいです。テンポラリ変数では大文字/小文字を区別します。

関数名
sf ユーザー関数や sf サブルーチンでは"';""`" モディファイアを使えませんが、ギリシャ文字は使えます。下のようなサブルーチンやユーザー関数名をつかえます。
微分形式サブルーチン ファイル;;@dω(x,y)
微分形式ユーザー関数         ;;~dω2(x,y)
厳密には sf 関数名は下の正規表現で定義されています。
# program source の定義です。kreg 正規表現です。
krgstr "^([Α-Ωα-ωA-Za-z][Α-Ωα-ωA-Za-z_0-9`.]*)`(");

# 上をperl 正規表現で表します
    "^[Α-Ωα-ωA-Za-z][Α-Ωα-ωA-Za-z_0-9\.]*";
△ 単位系と sf.ini ファイル
sf は動作を開始するとき sf.ini ファイルを読み込みます。ですから、 sf ini ファイルに sf の動作をしていするオプションを書いておけば、sf のデフォルト動作を指定できます。
# デフォルトでの浮動小数点のコンソール表示桁数の設定
/p 10   # コンソール表示桁数を 10 桁に指定します

# デフォルトでの 0 サプレス設定
/z 1e-12 6  # サイズが 6 以上のベクタ 行列で 1e-12 以下の数値要素は 0 でコンソールに表示します。

# デフォルトで逆行列処理許容値
/pvt 0.000001
#<== 逆行列のために L/U 分解しているとき、この列の値全てが個の値より小さいときにエラーにします。

また、"`" で始まるテンポラリ変数を宣言しておくことで、単位系や物理定数を sf 式で使えるようになります。下のような sf 式の記述が可能です。

ω = 110`K `Hz/(2`π), N@=3, <<0,N,1/N@t|!exp(i ω t)>>
<                  1, 0.172033-0.985091i, -0.94081-0.338936i >
添付してある sf.ini には下の MKSA 単位系と、物理定数が宣言してあります。
type sf.ini
# user 拡張短池印 光メーター 光が 1meter を通過する時間
`lMeter @= 1

## ========== MKSA 単位系 記号 ==============================
# 長さ
`nm @= 1e-9, `um @= 1e-6, `mm @= 1e-3,`cm @= 1e-2, `meter @=1, `Km @= 1e+3
# 時間
`pS @= 1e-12, `nS @= 1e-9, `uS @= 1e-6, `mS @= 1e-3,  `minute@=60, `hour@=3600
# 質量
`Kg @= 1, gram @=1e-3
# 回路1
`pF @= 1e-12, `uF @= 1e-6, `uH @= 1e-6, `uA @= 1e-6, `mA @= 1e-3, `mV @= 1e-3, `KΩ@=1e+3
# 回路2
`Hz @=1, `Ω@=1,`sec @=1,`ampere@=1, `volt @=1, `weber@=1, `coulomb@=1
# 力学
`newton@=1, `dyne @=1e-5, `joule @=1
# 桁
`p @=1e-12, `n @=1e-9, `u @=1e-6, `m @=1e-3, `K @=1e+3, `M @=1e+6, `G @=1e+9, `T @=1e+12

## ========== 物理定数 MKSA 単位 ==============================
# light velosity m/s
`c @= 2.99792458e+8

# π 円周率
`π @= 3.141592653589793
`pi @= 3.141592653589793

# プランク定数 h/2π 1.05457266(63)×10-34 J s 
`h` @= 1.05457266e-34

`h @= `h`2`π

#ボルツマン定数   J K^-1 K は絶対温度の単位です。Kg ではありません
`kB  @= 1.380662e-23    # Joule/ degree

#万有引力定数 G  = 6.672 ×10-11  N m^2 kg^-2 
`gU @= 6.672e-11
#重力加速度 g  = 9.80665  m s-2 
`gH @= 9.80665
#素電荷 e  = 1.6021892 ×10-19  C 
`eQ @= 1.6021892e-19
#電子質量 me  = 9.10938188 ×10^-31  kg 
`eM @= 9.10938188e-31
#陽子質量 u  = 1.67262157 ×10^-27  kg 
`pM @= 1.67262157-27
#水素原子質量 mH  = 1.6735 ×10^-27  kg 
`HM @= 1.6735e-27
#モル数,Avogadro 数  NA  = 6.02214199 ×10^23  mol-1
`NA @= 6.02214199e+23
#モル体積 Vm  = 2.241383 ×10-2  m3mol-1 
`Vm @= 2.241383e-2

#真空の透磁率 1.2566370614E-06 == 4`π 1e-7, 物理単位 Newton A^-1 == henry/meter
`μ0 @= 1.2566370614e-6
`u0 @=`μ0
# 真空の誘電率 ε0 == 1/(`c^2 4`π 1e-7)==クーロン**2 / (newton * M ** 2) == farad/meter
`ε0 @= 8.854187816e-12
`e0 @=`ε0

## ========== その他の単位 ==============================
# 貨幣で使われる単位
`oku @= 1e+8, `cho @= 1e+12, `man @= 1e+4, `billion @= 1e+9

# 米国単位
`inch @= 0.0254, `feet @= 0.3048, `mile @= 1609.3

## ========== Pauli 行列 ==============================
`σx @= [[2]]
`σx[<0,4,1>] = <0,1\
               ,1,0>

`σy @= [[2]]
`σy[<0,4,1>] = <0,-i\
               ,i,0>

`σz @= [[2]]
`σz[<0,4,1>] = <1,0\
               ,0,-1>
この sf.ini ファイルはユーザー追加/修正できます。sf.ini の read only 属性を解除してからエディタで編集してください。

なお不必要な名前の衝突を避けるため sf.ini で宣言するテンポラリ変数は ` で始める変数名とすることを推奨します。



ホーム ページに戻る