Introduction
************

マニュアルの構成
========

このマニュアルの構成は次の通りである.

 1. Introduction

     マニュアルの構成および notation

 2. Risa/Asir

     Asir の概要, インストレーション

 3. 型

     Asir における型

 4. ユーザ言語 Asir

     Asir のユーザ言語の解説

 5. デバッガ

     ユーザ言語のデバッガの解説

 6. 組み込み函数

     さまざまな組み込み函数の詳細

 7. グレブナ基底の計算

     グレブナ基底に関する函数, 演算の解説

 8. 代数的数に関する演算

     代数的数に関する函数, 演算の解説

 9. 付録

     文法の詳細, パソコン版 Risa/Asir, サンプルファイルの紹介, 文献

Notation
========

このマニュアルでは, いくつかの記法上の慣習がある. それらについて説明する.

  * 函数名は, タイプライタ体で表される.

     gcd(), gr()

  * 函数の説明における函数の引数は, 斜字体で表される.

     INT, POLY

  * ファイル名は, シングルクォートつきのタイプライタ体で表される.

     dbxinit, asir_plot

  * 例は字下げされ, タイプライタ体で表される.

          [0] 1;
          1
          [1] quit;

  * 文献の参照は, [] つきのタイプライタ体で表される.

     [Boehm,Weiser]

  * 函数の引数で, 省略可能なものは, [] で囲って示される. また, 0 個以上の繰り返しは, []* で示される.

     setprec([N]), diff(RAT[,VARN]*)

  * shell (csh) のプロンプトは % で表される. ただし, インストール時など, root として作業している場合のプロンプトは # で表される.

          % cat afo
          afo
          bfo
          % su
          Password:XXXX
          # cp asir /usr/local/bin
          # exit
          %

  * 有理整数環は Z, 有理数体は Q, 実数体は R, 複素数体は C で表す.

Risa/Asir
*********

Risa および Asir
=============

Risa は, 富士通情報研で開発中の数式処理システム/ライブラリの総称である. Risa の構成は次の通りである.

  * 基本演算部

     これは, Risa の内部形式に変換されたオブジェクト (数, 多項式など) の間の演算を実行する部分であり, UNIX の libc.a などと同様の, ライブラリとして存在する. エンジンは, C および アセンブラで記述され, 後述する言語インタフェース Asir の基本演算部として用いられている一方, 数式計算を必要とするさまざまなプログラム中にリンクして用いることができる.

  * メモリ管理部

     Risa では, メモリ管理部として, [Boehm,Weiser] によるフリーソフトウェアを用いている. これはガーベジコレクション (以下 GC と呼ぶ) を自動的に行うメモリ割り当て機構を持ち, Risa の各部分はすべてこれにより必要なメモリを得ている.

  * Asir

     Asir は, Risa の計算エンジンの言語インタフェースの一つである. Risa では, 比較的容易にユーザ用の言語インタフェースを作ることができる. Asir はその一つの例として作ったもので, C 言語に近い文法をもつ. また, C のデバッガとして広く用いられている dbx 風のデバッガも備えている.

Asir の特徴
========

Asir は, 前述の通り, 計算エンジンの言語インタフェースの一つである. 通常 asir という名前の実行可能ファイルとして提供される. 現在サポートされている機能は概ね次の通りである.

  * C 言語風のユーザ言語

  * 数, 多項式, 有理式の加減乗(除)

  * ベクトル, 行列の演算

  * 最小限のリスト処理

  * 組み込み函数 (因数分解, GCD など)

  * ユーザ定義函数によるツール (グレブナ基底など)

  * dbx 風のデバッガ

  * 陰函数の描画

  * PARI (see pari) による初等超越函数を含む式の評価

インストレーション
=========

ソースファイルからのインストレーションは, Installation Manual を参照. ここではバイナリ形式のファイルをインストールする場合の手続きについて述べる.

以下の手続きで不明な点, 不都合な点があった場合の問い合わせは

     noro@iias.flab.fujitsu.co.jp

宛に e-mail でお願いします.

UNIX 版
------

提供されているファイルとしては,

asir.gz
     Asir 本体

asir_ping.gz
     通信テスト用プログラム

asir_plot.gz
     陰函数描画用プログラム

asir.o.gz
     バイナリ函数追加用ファイル

asirlib.tar.gz
     ユーザ定義函数ファイル, help 用ファイル

の 5 つがある. このうち asir_ping.gz は必須ではない. また, asir.o.gz は, C で記述した函数を追加した Asir を作るためのもので, やはり必須ではない. これらは全て gzip で圧縮してあるので, 入手後 gzip で展開する.

     # gzip -dc asir > /usr/local/bin/asir
     # gzip -dc asir_plot > /usr/local/bin/asir_plot
     # chmod 755 /usr/local/bin/asir /usr/local/bin/asir_plot

asir, asir_plot, asir_ping は, /usr/local/bin などのコマンドディレクトリあるいは個人的に使用する場合には, $HOME/bin などに置く.

asirlib.tar.gz の中のファイルは, デフォルトでは /usr/local/lib/asir というディレクトリに置かれる.

     # mkdir /usr/local/lib/asir
     # gzip -dc asirlib.tar.gz | ( cd /usr/local/lib/asir; tar xf - )

もし, 異なるディレクトリに置く場合には, そのディレクトリの名前を環境変数 ASIR_LIBDIR に設定する必要がある.

     % mkdir $HOME/lib/asir
     % gzip -dc asirlib.tar.gz | ( cd $HOME/lib/asir; tar xf - )
     % setenv ASIR_LIBDIR $HOME/lib/asir

ライブラリをインストールしたら, ライブラリディレクトリから asir に asir_symtab という名前でシンボリックリンクを作る.

     # cd /usr/local/lib/asir
     # ln -s /usr/local/bin/asir asir_symtab

この状態で asir を起動してみる.

     % /usr/local/bin/asir
     asir_key not found.
     ID for this machine is XXXXXXXX.
     See the file ASIR_INSTALL to get the correct key.

すると, このようなメッセージが出て asir は終了する. UNIX 版では, マシンごとに key と呼ばれる文字列が必要である. key を入手するためには,

     risa@iias.flab.fujitsu.co.jp

宛に,

     ASIR XXXXXXXX

という 1 行のみからなる e-mail を送ればよい. XXXXXXXX は表示された ID である. 折り返し

     YYYYYYYY YYYYYYYY YYYYYYYY

という形の 1 行のみからなる e-mail が届くので, この 1 行を含む asir_key なるファイルをカレントディレクトリに作って asir を起動してみる.

     % /usr/local/bin/asir
     This is Asir, Version 940420.
     Copyright (C) FUJITSU LABORATORIES LIMITED.
     3 March 1994. All rights reserved.
     [0]

このようなプロンプトが出れば, 入手した key はそのマシンに対して有効である. key を書いておくファイルに関しては, 環境変数 ASIR_KEY の説明の項 (環境変数) で詳しく述べるが, ライブラリディレクトリにここで作成したファイル asir_key を置けば, そのマシン上で全てのユーザが asir を使用できるようになる. asir_key には複数のマシンに対する key を書けるので, ライブラリディレクトリを共有している場合でも asir_key に行を追加していけばよい.

     # cp asir_key /usr/local/lib/asir

Macintosh 版
-----------

提供されているファイルは次の 3 つである.

asir.sea
     CPU が 68020 以上で, 浮動小数演算機能をもつ Mac 用.

asir-sc.sea
     CPU が 68020 以上で, 浮動小数演算機能をもたない Mac 用.

asir-00.sea
     CPU が 68000 の Mac 用.

いずれもダブルクリックすると, フォルダが 1 つできる. このフォルダには Asir の実行可能ファイルと, ユーザ定義函数ファイルの入ったサブフォルダが入っている. Mac 版はkey は必要ないので, このまま起動できる. 詳しくは, see Macintosh 版 Risa/Asir.

DOS 版
-----

提供されているファイルは,

asir.lzh
     Asir 本体

asirlib.lzh
     ユーザ定義函数ファイル

go32.lzh
     IBM-PC, PC98, FM 用 go32.exe V1.10

の 3 つである. これらは lha.exe により圧縮してあるので lha.exe により解凍する.

     C> lha x asir
     C> lha x asirlib

DOS 版も key は必要ない. またデフォルトのライブラリディレクトリも設定されていないが, ASIR_LIBDIR および ASIRLOADPATH の設定は必須となる. DOS の場合, 環境変数の設定の仕方が UNIX と異なる. ASIRLOADPATH に対しては, パスのデリミタは ; を用いる.

     C> set ASIR_LIBDIR=C:¥usr¥lib¥asir
     C> set ASIRLOADPATH=.;C:¥usr¥noro¥lib¥asir

go32.exe がインストールされていない場合, go32.exe のインストールおよび環境設定は必須である. また, go32.exe のバージョンが古い場合, 既に組み込まれているデバイスドライバによっては go32 がメモリを確保できずに Asir の動作速度が極めて遅くなる (スワップし続ける) 場合がある. これは, Windows の DOS Window での動作でも同様である. V1.10 ではこのようなことはないようなので, 少なくとも V1.10 のものを使用することをお勧めする.

go32.lzh には,

go32-pc.exe
     IBM-PC clone 用

go32-98.exe
     PC98 用

go32-fm.exe
     FMR, FMTOWNS 用

emu387
     387 エミュレーションモジュール

readme
     go32 の readme

が入っている. go32-xx.exe のバージョンはいずれも 1.10 である. これらのいずれかを適当なコマンドディレクトリに go32.exe として置く. さらに, 環境変数 GO32TMP および GO32 を正しく設定する. これらについては go32 の readme 参照.

     C> set GO32TMP=C:¥tmp
     C> set GO32=ansi

特に, 80387 がない, あるいは浮動小数点演算機能のない 486 マシンでは, emu387 を用いることが必須となる. これは

     C> set GO32=emu C:¥usr¥djgpp¥lib¥emu387

などと指定する. これについても readme 参照. これ以降の操作および DOS 版 Asir の制限事項などについては see MS-DOS/DOS-Extender 版 Risa/Asir.

コマンドラインオプション
============

コマンドラインオプションは次の通り.

-heap NUMBER
     Risa/Asir では, 4KB のブロックをメモリ割り当ての単位として用いている. デフォルトでは, 初期 heap として, 16 ブロック (64KB) 割り当てるが, それを変更する場合, -heap を用いる. 単位はブロックである. heap の大きさは, heap() 函数で調べることができる (単位はバイト).

-adj NUMBER
     GC で回収されたメモリの量が, 1/NUMBER 以下の場合に, メモリ管理部は heap を伸ばす. デフォルトでは 4 である. メモリ量の制限のため, heap をなるべく伸ばさずに, GC を主体にしてメモリ管理したい場合には, この値を大きく (例えば 16) 設定する.

-norc
     初期化ファイル $HOME/.asirrc を読まない.

-paristack NUMBER
     PARI (see pari) 専用の領域の大きさを指定する. 単位はバイト. デフォルトでは 1 MB ( MSDOS マシンおよび Macintosh では 64 KB ).

環境変数
====

Asir の実行に関するいくつかの環境変数が存在する.

  * ASIR_KEY

     UNIX 版では, Asir が起動されたマシンに対する key がなければそのマシン上で Asir は動作しない. key は 16 進 8 桁 3 ワードからなり,

          % cat asir_key
          cf6f236c 61a35091 dddc4529 geisha
          82281685 d1929945 a8bd24ca yorktown
          34b75d30 63f8df93 3e881113 nyanchu

     という形で複数台のマシンに対する key を一つのファイルにまとめて書くことができる. key の後ろは無視されるので, コメントを書くことができる. key を含むファイルは, 以下の順でサーチされる.

      1. 環境変数 ASIR_KEY に指定されたファイル

      2. カレントディレクトリの asir_key

      3. 環境変数 ASIR_LIBDIR で指定されたディレクトリ (指定がなければ /usr/local/lib/asir) の asir_key

  * ASIR_LIBDIR

     Asir のライブラリディレクトリ, すなわちユーザ言語で書かれたファイルなどがおかれるディレクトリ. 指定がない場合 /usr/local/lib/asir が用いられる. バイナリを個人のディレクトリにインストールする場合など, この環境変数を適当に設定することになる.

  * ASIRLOADPATH

     ロードされるファイルがあるディレクトリを : (DOS 上では ;) で区切って並べる. ディレクトリは左から順にサーチされる. この指定がない場合, および指定されたファイルが ASIRLOADPATH になかった場合, ライブラリディレクトリもサーチされる.

起動から終了まで
========

Asir を起動すると, 著作権などの表示のあと

     [0]

なるプロンプトが表示され, セッションが開始する. $HOME/.asirrc が存在している場合, このファイルを Asir ユーザ言語でかかれたファイルと見なし, 解釈実行する.

プロンプトは入力の番号を表す. セッションは, end; または quit; を入力することにより終了する. 入力は, ; または $ までを一区切りとして評価される. ; のとき結果は表示され, $ のとき表示されない.

     % asir
     [0] A;
     0
     [1] A=(x+y)^5;
     x^5+5*y*x^4+10*y^2*x^3+10*y^3*x^2+5*y^4*x+y^5
     [2] A;
     x^5+5*y*x^4+10*y^2*x^3+10*y^3*x^2+5*y^4*x+y^5
     [3] a=(x+y)^5;
     evalpv : invalid assignment
     return to toplevel
     [3] a;
     a
     [4] fctr(A);
     [[1,1],[x+y,5]]
     [5] quit;
     %

この例では, A, a, x, y なる文字が使用されている. A はプログラムにおける変数で, a, x, y は数学的な意味での不定元である. 一般にプログラム変数は大文字で始まり, 不定元は小文字で始まる. この例でわかるように, プログラム変数は, 数, 式などを格納しておくためのものであり, C 言語などにおける変数に対応する. 一方, 不定元はそれ自身で値を持つことはできず, 従って, 不定元に対する代入は許されない. 後に示すが, 不定元に対する代入は, 組み込み函数 subst() により明示的に行われる.

割り込み
====

計算を実行中に割り込みをかけたい場合, 割り込みキャラクタ(通常は C, DOS 版では X, Mac 版では command+. ) を入力する.

     @ (x+y)^1000;
     Cinterrupt ?(q/t/c/d/w/?)

各選択肢の意味は次の通り.

q
     Asir を終了する. (確認あり)

t
     トップレベルに戻る. (確認あり)

c
     実行を継続する.

d
     次の Asir プログラムの文の先頭でデバッグモードに入る. ユーザ定義函数の中の文に対してのみ有効である. 基本演算部内の函数 (加減乗除, 因数分解など)を実行中の場合には, デバッグモードに入るまで, 長時間を要する場合も有り得る. デバッガに関しては see デバッガ.

w
     中断点までの函数の呼び出し列を表示する.

?
     各選択肢の意味を説明する.

エラー処理
=====

組み込み函数に不正な型の引数を渡した場合などには実行が中断されるが, ユーザ函数の中でエラーが起きた場合にはトップレベルに戻る前に自動的にデバッグモードに入る. この状態でエラーの場所, 直前の引数の値などを調べることができる. 表示されるエラーメッセージはさまざまであり, 内部の函数名に引き続いてメッセージが表示される. これは, 呼び出された組み込み函数と必ずしも対応はしない.

その他, さまざまな原因により内部演算函数においてエラーが生ずることがある. UNIX 版の場合, これは次のいずれかの internal error として報告され, 通常のエラーと同様に扱って, デバッグモードに入る.

SEGV
BUS ERROR

     組み込み函数によっては, 引数の型を厳密にチェックせずに演算ルーチンに引き渡してしまうものも存在している. このような状況において, 不正なポインタ, あるいは NULL ポインタによるアクセス違反があった場合, これらのエラーとなる.

BROKEN PIPE

     プロセス間通信において, 相手先のプロセスとの間のストリームが既に存在していない場合 (例えば既に相手先のプロセスが終了している場合など) に, そのストリームに入出力しようとした場合にこのエラーとなる.

UNIX 版では, signal() によるこれらのエラーの捕捉が可能のためプロセスは終了しないが, DOS/go32 版, Macintosh 版などは, プログラム自体が終了してしまう. これは現在のパソコン版における欠点であるが, この欠点を除くためには, 組み込み函数の入口において, 引数を完全にチェックすることが必要であり, 相当な手直しが必要である.

計算結果, 特殊な数
==========

@ はエスケープ文字として使用される. 現在次のような規定がある.

@N
     N 番目の計算結果.

@@
     直前の計算結果.

@i
     虚数単位.

@pi
     円周率.

@e
     自然対数の底.

     [0] fctr(x^10-1);
     [[1,1],[x-1,1],[x+1,1],[x^4+x^3+x^2+x+1,1],[x^4-x^3+x^2-x+1,1]]
     [1] @@[3];
     [x^4+x^3+x^2+x+1,1]
     [2] eval(sin(@pi/2));
     1.000000000000000000000000000000000000000000000000000000000
     [3] eval(log(@e),20);
     0.99999999999999999999999999998
     [4] @0[4][0];
     x^4-x^3+x^2-x+1
     [5] (1+@i)^5;
     (-4-4*@i)
     [6] eval(exp(@pi*@i));
     -1.0000000000000000000000000000

トップレベルで計算された値はこのようにヒストリとして取り出し可能であるが, このことは, ガベージコレクタにとっては負担をもたらす可能性がある. 特に, 大きな式をトップレベルで計算した場合, その後の GC 時間が急速に増大する可能性がある.

型
*

Asir で使用可能な型
============

Asir においては, 可読な形式で入力されたさまざまな対象は, パーザにより中間言語に変換され, インタプリタにより Risa の計算エンジンを呼び出しながら内部形式に変換される. 変換された対象は, 次のいずれかの型を持つ. 各番号は, 組み込み函数 type() により返される値に対応している. 各例は, Asir のプロンプトに対する入力が可能な形式のいくつかを示す.

0
     0

     実際には 0 を識別子にもつ対象は存在しない. 0 は, C における 0 ポインタにより表現されている. しかし, 便宜上 Asir の type(0) は値 0 を返す.

1
     数

          1 2/3  14.5  3+2*@i

     数は, さらにいくつかの型に分けられる. これについては下で述べる.

2
     多項式 (数でない)

          x  afo  (2.3*x+y)^10

     多項式は, 全て展開され, その時点における変数順序に従って, 再帰的に 1 変数多項式として降冪の順に整理される (see 分散表現多項式). この時, その多項式に現れる順序最大の変数を 主変数 と呼ぶ. また, 多項式の, 主変数に関する最大次数の項の係数を 主係数 と呼ぶ.

3
     有理式 (多項式でない)

          (x+1)/(y^2-y-x)  x/x

     有理式は, 分母分子が約分可能でも, 明示的に red() が呼ばれない限り約分は行われない. これは, 多項式の GCD 演算が極めて重い演算であるためで, 有理式の演算は注意が必要である.

4
     リスト

          []  [1,2,[3,4],[x,y]]

     リストは読み出し専用である. [] は空リストを意味する. リストに対する操作としては, car(), cdr(), cons() などによる操作の他に, 読み出し専用の配列とみなして, [INDEX] を必要なだけつけることにより要素の取り出しを行うことができる. 例えば

          [0] L = [[1,2,3],[4,[5,6]],7]$
          [1] L[1][1];
          [5,6]

     注意すべきことは, リスト, 配列 (行列, ベクトル) 共に, インデックスは 0 から始まることと, リストの要素の取り出しをインデックスで行うことは, 結局は先頭からポインタをたどることに相当するため, 配列に対する操作に比較して大きなリストでは時間がかかる場合があるということである.

5
     ベクトル

          newvect(3)  newvect(2,[a,1])

     ベクトルは, newvect() で明示的に生成する必要がある. 前者の例では2 成分の 0 ベクトルが生成され, 後者では, 第 0 成分が a, 第 1 成分が 1 のベクトルが生成される. 初期化のための 第 2 引数は, 第 1 引数以下の長さのリストを受け付ける. リストの要素は左から用いられ, 足りない分は 0 が補われる. 成分は [INDEX] により取り出せる. 実際には, 各成分に, ベクトル, 行列, リストを含む任意の型の対象を代入できるので, 多次元配列をベクトルで表現することができる.

          [0] A3 = newvect(3);
          [ 0 0 0 ]
          [1] for (I=0;I<3;I++)A3[I] = newvect(3);
          [2] for (I=0;I<3;I++)for(J=0;J<3;J++)A3[I][J]=newvect(3);
          [3] A3;
          [ [ [ 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 0 0 ] ] ]
          [4] A3[0];
          [ [ 0 0 0 ] [ 0 0 0 ] [ 0 0 0 ] ]
          [5] A3[0][0];
          [ 0 0 0 ]

6
     行列

          newmat(2,2)  newmat(2,3,[[x,y],[z]])

     行列の生成も newmat() により明示的に行われる. 初期化も, 引数がリストのリストとなることを除いてはベクトルと同様で, リストの各要素 (これはまたリストである) は, 各行の初期化に使われ, 足りない部分には 0 が埋められる. 行列も, 各要素には任意の対象を代入できる. 行列の各行は, ベクトルとして取り出すことができる.

          [0] M=newmat(2,3);
          [ 0 0 0 ]
          [ 0 0 0 ]
          [1] M[1];
          [ 0 0 0 ]
          [2] type(@@);
          5

7
     文字列

          ""  "afo"

     文字列は, 主にファイル名などに用いられる. 文字列に対しては加算のみが定義されていて, 結果は 2 つの文字列の結合である.

          [0] "afo"+"take";
          afotake

8
     構造体

          newstruct(afo)

     構造体に関しては, 章を改めて解説する予定である.

9
     分散表現多項式

          2*<<0,1,2,3>>-3*<<1,2,3,4>>

     これは, ほとんどグレブナ基底専用の型で, 通常の計算でこの型が必要となることはまずないが, グレブナ基底計算パッケージ自体がユーザ言語で書かれているため, ユーザが操作できるよう独立した型として  Asir で使用できるようにしてある. これについては see グレブナ基底の計算.

数の型
===

0
     有理数

     有理数は, 任意多倍長整数 (bignum) により実現されている. 有理数は常に既約分数で表現される.

1
     倍精度浮動小数

     マシンの提供する倍精度浮動小数である. Asir の起動時には, 通常の形式で入力された浮動小数はこの型に変換される. ただし, ctrl() により bigfloat が選択されている場合には bigfloat に変換される.

          [0] 1.2;
          1.2
          [1] 1.2e-1000;
          0
          [2] ctrl("bigfloat",1);
          1
          [3] 1.2e-1000;
          1.20000000000000000513 E-1000

     倍精度浮動小数と有理数の演算は, 有理数が浮動小数に変換されて, 浮動小数として演算される.

2
     代数的数

     See 代数的数に関する演算.

3
     bigfloat

     bigfloat は, Asir では PARI ライブラリにより実現されている. PARI においては, bigfloat は, 仮数部のみ任意多倍長で, 指数部は 1 ワード以内の整数に限られている. ctrl() で bigfloat を選択することにより, 以後の浮動小数の入力は bigfloat として扱われる. 精度はデフォルトでは 10 進 9 桁程度であるが, setprec() により指定可能である.

          [0] ctrl("bigfloat",1);
          1
          [1] eval(2^(1/2));
          1.414213562373095048763788073031
          [2] setprec(100);
          9
          [3] eval(2^(1/2));
          1.41421356237309504880168872420969807856967187537694807317654396116148

     eval() は, 引数に含まれる函数値を可能な限り数値化する函数である. setprec() で指定された桁数は, 結果の精度を保証するものではなく, PARI 内部で用いられる表現のサイズを示すことに注意すべきである. (eval, see pari)

4
     複素数

     複素数は, 有理数, 倍精度浮動小数, bigfloat を実部, 虚部として a+b*@i (@i は虚数単位) として与えられる数である. 実部, 虚部はそれぞれ real(), imag() で取り出せる.

不定元の型
=====

多項式の変数となり得る対象を不定元とよぶ. Asir では, 英小文字で始まり, 任意個のアルファベット, 数字, _ からなる文字列を不定元として扱うが, その他にもシステムにより不定元として扱われるものがいくつかある. Asir の内部形式としては, これらは全て多項式としての型を持つが, 数と同様, 不定元の型により区別される.

0
     一般不定元

     英小文字で始まる文字列. 多項式の変数として最も普通に用いられる.

          [0] [vtype(a),vtype(aA_12)];
          [0,0]

1
     未定係数

     uc() は, _ で始まる文字列を名前とする不定元を生成する. これらは, ユーザが入力できないというだけで, 一般不定元と変わらないが, ユーザが入力した不定元と衝突しないという性質を利用して未定係数の自動生成などに用いることができる.

          [1] U=uc();
          _0
          [2] vtype(U);
          1

2
     函数形式

     組み込み函数, ユーザ函数の呼び出しは, 評価されて何らかの Asir の内部形式に変換されるが, sin(x), cos(x+1) などは, 評価後もそのままの形で存在する. これは函数形式と呼ばれ, それ自身が 1 つの不定元として扱われる. またやや特殊な例として, 円周率 @pi や自然対数の底 @e も函数形式として扱われる.

          [3] V=sin(x);
          sin(x)
          [4] vtype(V);
          2
          [5] vars(V^2+V+1);
          [sin(x)]

3
     函数子

     函数呼び出しは, FNAME(ARGS) という形で行なわれるが, FNAME の部分を函数子と呼ぶ. 函数子には, 函数の種類により組み込み函数子, ユーザ定義函数子, 初等函数子などがあるが, 函数子は単独で不定元として機能する.

          [6] vtype(sin);
          3

ユーザ言語 Asir
**********

Asir の組み込み函数は, 因数分解, GCD などの計算を行うもの, ファイル入出力を行うもの, あるいは数式の一部を取り出すものなどさまざまなものが用意されているが, ユーザが実際に行いたいことを実行させるためには一般にはユーザ言語によるプログラムを書く必要がある. ユーザ言語も Asir と呼ばれる. 以下では, ユーザ言語の文法規則および実際のユーザ言語プログラムを例としたプログラムの書き方について述べる.

文法 --- C 言語との違い
===============

Asir の文法は C 言語に準拠している. 文法の詳細は, see 文法の詳細. おもな相違点は次の通りである. 以下で, 変数とは Asir におけるプログラム用の変数, すなわち大文字で始まる文字列を意味することとする.

  * 変数の型がない.

     既に説明したとおり, Asir で扱われる対象自身は全て何らかの型を持っている. しかし, プログラム変数自体は, どのような対象でも代入できるという意味で型がないのである.

          [0] A = 1;
          1
          [1] type(A);
          1
          [2] A = [1,2,3];
          [1,2,3]
          [3] type(A);
          4

  * 函数内の変数は, デフォルトでは仮引数をこめてすべて局所変数. ただし, extern 宣言された変数は, トップレベルにおける大域変数となる.

     すなわち, 変数のスコープは大域変数と局所変数の 2 種類に単純化されている. トップレベル, すなわちプロンプトに対して入力された変数は全て大域変数として登録される. また函数内では次のいずれかとなる.

      1. 函数が定義されるファイルにおいて, その函数定義以前に, ある変数が extern 宣言されている場合, 函数内のその変数も大域変数として扱われる.

      2. extern 宣言されていない変数はその函数に局所的となる.

          % cat afo
          def afo() { return A;}
          extern A$
          def bfo() { return A;}
          end$
          % asir
          [0] load("afo")$
          [5] A = 1;
          1
          [6] afo();
          0
          [7] bfo();
          1

  * プログラム変数は大文字で始まり, 不定元, 函数は小文字で始まる.

     この点は, 既存の数式処理システムのほとんどと異なる点である. Asir がこの仕様を採用したのは, ユーザが不定元のつもりで使用した変数になんらかの値が代入されていた場合に混乱を招く, という, 既存のシステムにありがちな状況を避けるためである.

  * switch 文, goto がない.

     goto がないため, 多重ループを一度に抜けるのがやや複雑になる場合がある.

  * コンマ式は, for (A;B;C) または, while(A) の A, B, C にのみ使うことができる.

     これは, リストを正式なオブジェクトとして加えたことによる.

以上は制限であるが, 拡張としては次の点が挙げられる.

  * 有理式に対する計算を, 通常の C における計算と同様にできる.

  * リストが扱える.

     構造体を用いるまでもない要素の集合体を, リストで表すことができ, C で直接書く場合に比較してプログラムが短く, 読みやすく書ける.

ユーザ定義函数の書き方
===========

ユーザ定義函数
-------

ユーザによる函数の定義は def 文で行う. 文法エラーは読み込み時にチェックされ, おおよその場所が表示される. 既に(引数の個数に関係なく)同名の函数が定義されている場合には, 再定義され,

     afo() redefined.

というメッセージが表示される. ある函数の定義において, まだ未定義の函数を呼び出していても, 定義時にはエラーにならない. 実行時に未定義の函数を呼び出そうとした場合にエラーとなる.

     def f(X) {
         if ( !X )
             return 1;
         else
             return X * f(X-1);
     }

     def c(N)
     {
         A = newvect(N+1); A[0] = B = newvect(1); B[0] = 1;
         for ( K = 1; K <= N; K++ ) {
             A[K] = B = newvect(K+1); B[0] = B[K] = 1;
             for ( P = A[K-1], J = 1; J < K; J++ )
                 B[J] = P[J-1]+P[J];
             }
         return A;
     }

2 つ目の例では, 長さ N+1 のベクトル (Aとする) が返される. A[I] は長さ I+1 の配列であり, そのそれぞれの要素が ICJ を要素とする配列である.

以下では, C によるプログラミングの経験がない人のために, Asir 言語によるプログラムの書き方を解説する.

変数および不定元
--------

既に述べた通り, Asir においてはプログラム変数と不定元を明確に区別している.

変数
     大文字で始まり, アルファベット, 数字, _ からなる文字列

     変数あるいはプログラム変数とは, Asir のさまざまな型の内部形式を格納するための箱であり, 格納された内部形式が, この変数の値である.  変数が式の要素として評価される時は, そこに収められた値に置き換えられる. すなわち, 内部形式の中にはプログラム変数は現れない. 変数は全て 0 で初期化されている.

          [0] X^2+X+1;
          1
          [1] X=2;
          2
          [2] X^2+X+1;
          7

不定元
     小文字で始まり, アルファベット, 数字, _ からなる文字列

     不定元とは, 多項式環を構成する際に添加される変数をいう. Asir においては, 不定元は値をもたない超越的な元であり, 不定元への値の代入は許されない.

          [3] X=x;
          x
          [4] X^2+X+1;
          x^2+x+1

引数
--

     def sum(N) {
         for ( I = 1, S = 0; I <= N; I++ )
             S += I;
         return S;
     }

これは, 1 から N までの自然数の和を求める函数 sum() の定義である. この例における sum(N) の N が引数である. この例は, 1 引数函数の例であるが, 一般に引数の個数は任意であり, 必要なだけの個数を , で区切って指定することができる. 引数は値が渡される. すなわち, 引数を受けとった側が, その引数の値を変更しても, 渡した側の変数は変化しない. ただし, 例外がある. それは, ベクトル, 行列を引数に渡した場合である. この場合も, 渡された変数そのものを書き替えることは, その函数に局所的な操作であるが, 要素を書き換えた場合, それは, 呼び出し側のベクトル, 行列の要素を書き換えることになる.

     def clear_vector(M) {
         /* M is expected to be a vector */
         L = size(M)[0];
         for ( I = 0; I < L; I++ )
             M[I] = 0;
     }

この函数は, 引数のベクトルを 0 ベクトルに初期化するための函数である. また, ベクトルを引数に渡すことにより, 複数の結果を引数のベクトルに収納して返すことができる. 実際には, このような場合には, 結果をリストにして返すこともできる. 状況に応じて使いわけすることが望ましい.

コメント
----

C と同様 /* と */ で囲まれた部分はコメントとして扱われる.

     /*
      * This is a comment.
      */

     def afo(X) {

コメントは複数行に渡っても構わないが, 入れ子にすることはできない. /* がいくつあっても最初のもののみが有効となり, 最初に現れた */ でコメントは終了したと見なされる. プログラムなどで, コメントを含む可能性がある部分をコメントアウトした場合には, #if 0, #endifを使えばよい. (see プリプロセッサ)

     #if 0
     def bfo(X) {
     /* empty */
     }
     #endif

文
-

Asir のユーザ函数は,

     def 名前(引数,引数,...,引数) {
         文
         文
         ...
         文
     }

という形で定義される. このように, 文は函数の基本的構成要素であり, プログラムを書くためには, 文がどのようなものであるか知らなければならない. 最も単純な文として, 単文がある. これは,

     S = sum(N);

のように, 式に終端記号 (; または $) をつけたものである. この単文及び類似の return 文, break 文などが文の最小構成単位となる. if 文や for 文の定義 (see 文法の詳細) を見ればわかる通り, それらの本体は, 単なる一つの文として定義されている. 通常は, 本体には複数の文が書けることが必要となる.  このような場合, { と } で文の並びを括って, 一つの文として扱うことができる. これを複文と呼ぶ.

     if ( I == 0 ) {
         J = 1;
         K = 2;
         L = 3;
     }

} の後ろには終端記号は必要ない. なぜなら, { 文並び }が既に文となっていて, if 文の要請を満たしているからである.

return 文
--------

return 文は,

     return 式;

     return;

の 2 つの形式がある. いずれも函数から抜けるための文である. 前者は函数の値として 式 を返す. 後者では, 函数の値として何が返されるかはわからない.

if 文
----

if 文には

     if ( 式 )             if ( 式 )
         文       及び         文
     else
         文

の 2 種類がある. これらの動作は明らかであるが, 文の位置に if 文が来た場合に注意を要する. 次の例を考えてみよう.

     if ( 式 )
         if ( 式 ) 文
     else
         文

この場合, 字下げからは, else 以下は, 最初の if に対応するように見えるが, パーザは, 自動的に 2 番目の if に対応すると判断する. すなわち, 2 種類の if 文を許したために, 文法に曖昧性が現れ, それを解消するために, else 以下は, 最も近い if に対応するという規則が適用されるのである. 従って, この例は,

     if ( 式 ) {
         if ( 式 ) 文 else 文
     }

という意味となる. 字下げに対応させるためには,

     if ( 式 ) {
         if ( 式 ) 文
     } else
         文

としなければならない.

ループ, break, return, continue
----------------------------

ループを構成する文は, while 文, for 文, do 文の 3 種類がある.

  * while 文

     形式は,

          while ( 式 ) 文

     で, これは, 式 を評価して, その値が 0 でない限り 文 を実行するという意味となる. たとえば 式 が 1 ならば, 単純な無限ループとなる.

  * for 文

     形式は,

          for ( 式並び-1; 式; 式並び-2 ) 文

     で, これは

          式並び-1 (を単文並びにしたもの)
          while ( 式 ) {
              文
              式並び-2 (を単文並びにしたもの)
          }

     と等価である.

  * do 文

          do {
              文
          } while ( 式 )

     は, 先に 文を実行してから条件式による判定を行う所が while 文と異なっている.

ループを抜け出す手段として, break 文及び return 文がある. また, ループの制御をある位置に移す手段として continue 文がある.

  * break

     break 文は, それを囲むループを一つだけ抜ける.

  * return

     return 文は, 一般に函数から抜けるための文であり, ループの中からでも有効である.

  * continue

     continue 文は, ループの本体の文の末端に制御を移す. 例えば for 文では, 最後の式並びの実行を行い, while 文では条件式の判定に移る.

さまざまな式
------

主な式の構成要素としては, 次のようなものがある.

  * 加減乗除, 冪

     冪は, ^ により表す. 除算 / は, 体としての演算に用いる. 例えば, 2/3 は有理数の 2/3 を表す. 整数除算, 多項式除算 (剰余を含む演算) には別途組み込み函数が用意されている.

          x+1  A^2*B*afo X/3

  * インデックスつきの変数

     ベクトル, 行列, リストの要素はインデックスを用いることにより取り出せる. インデックスは 0 から始まることに注意する. 取り出した要素がベクトル, 行列, リストなら, さらにインデックスをつけることも有効である.

          V[0] M[1][2]

  * 比較演算

     等しい (==), 等しくない (!=), 大小 (>, <, >=, <=) の 2 項演算がある. 真ならば有理数の 1, 偽ならば 0 を値に持つ.

  * 論理式

     論理積 (&&), 論理和 (||) の 2 項演算と, 否定 (!) が用意されている. 値はやはり 1, 0 である.

  * 代入

     通常の代入は = で行う. このほか, 算術演算子と組み合わせて特殊な代入を行うこともできる. (+=, -=, *=, /=, ^=)

          A = 2  A *= 3 (これは A = A*3 と同じ; その他の演算子も同様)

  * 函数呼び出し

     函数呼び出しも式の一種である.

  * ++, --

     これらは, 変数の前後について, それぞれ次のような操作, 値を表す.

          A++  値は元の A の値, A = A+1
          A--  値は元の A の値, A = A-1
          ++A  A = A+1, 値は変化後の値
          --A  A = A-1, 値は変化後の値

プリプロセッサ
-------

Asir のユーザ言語は C 言語を模したものである. C の特徴として, プリプロセッサ cpp によるマクロ展開, ファイルのインクルードがあるが, Asir においてもユーザ言語ファイルの読み込みの際 cpp を通してから読み込むこととした. これによりユーザ言語ファイル中で #include, #define, #if などが使える.

  * #include

     cpp に特に引数を渡さないため, インクルードファイルは, #include が書かれているファイルと同じディレクトリでサーチされる.

  * #define

     これは, C におけるのと全く同様に用いることができる.

  * #if

     /*, */ によるコメントは入れ子にできないので, プログラムの大きな部分をコメントアウトする際に, #if 0, #endif を使うと便利である.

次の例は, gr の先頭部分にあるマクロ定義である.

     #define FIRST(L) (L[0])
     #define SECOND(L) (L[1])
     #define THIRD(L) (L[2])
     #define FOURTH(L) (L[3])
     #define FIFTH(L) (L[4])

     #define HM(p) dp_hm(p)
     #define RP(p) dp_rest(p)
     #define HT(p) dp_ht(p)
     #define CO(p) dp_hc(p)
     #define TD(p) dp_td(p)
     #define ZERO(p) (!(p))
     #define LCM(l) THIRD(l)
     #define CPSUGAR(l) FOURTH(l)
     #define MAX(a,b) ((a)>(b)?(a):(b))
     #define CPUTIME (time()[0])

構造体を用いずにリストで代用する場合, マクロによりリストの各要素に名前をつけることは, プログラムの可読性を高めることになる.

デバッガ
****

デバッガとは
======

C 言語で書かれたプログラムのためのデバッガ dbx は, ソースレベルでのブレークポイントの設定, ステップ実行, 変数の参照などが可能な強力なデバッガである. Asir では, dbx 風のデバッガを用意している. デバッグモードに入るには, トップレベルで debug; と入力する.

     [10] debug;
     (debug)

その他, 次の方法, あるいは状況でデバッグモードに入る.

  * 実行中ブレークポイントに達した場合

  * 割り込みで d を選択した場合

  * 実行中エラーを起こした場合

     この場合, 実行の継続は不可能であるが, 直接のエラーの原因となったユーザ定義函数の文を表示してデバッグモードに入るため, エラー時における変数の値を参照でき, デバッグに役立たせることができる.

  * error() が呼び出された場合

コマンドの解説
=======

コマンドは dbx のコマンドの内必要最小限のものを採用した. 実際の機能は dbx とほぼ同様であるが, step, next は, 次の行ではなく次の文を実行する. 従って, 1行に複数の文がある場合は, その文の数だけ next を実行しなければ次の行に進めない. また, dbx と同様 .dbxinit を読み込むので, dbx と同じ alias を使うことができる.

step
     次の文を実行する. 次の文が函数を含むとき, その函数に入る.

next
     次の文を実行する.

cont
     デバッグモードから抜け, 実行を継続する.

list [STARTLINE]
list FUNCTION
     現在行, または STARTLINE, または FUNCTIONの先頭から 10 行ソースファイルを表示する.

print EXPR
     EXPR を表示する.

func FUNCTION
     対象函数を FUNCTION に設定する.

stop at SOURCELINE [if COND]
stop in FUNCTION
     SOURCELINE行目, または FUNCTION の先頭にブレークポイントを設定する. ブレークポイントは, 函数が再定義された場合自動的に取り消される. if が続く場合, COND が評価され, それが 0 でない場合に実行が中断し, デバッグモードに入る.

delete N
     ブレークポイント N を取り消す.

status
     ブレークポイントの一覧を表示する.

where
     現在の停止点までの呼び出し列を表示する.

quit
     デバッグモードを抜ける. 実行中は, cont と同様の効果を持つ.

print の引数として, トップレベルにおけるほとんどすべての式がとれる. 通常は, 変数の内容の表示が主であるが, 必要に応じて次のような使い方ができる.

  * 変数の書き換え

     実行中のブレークポイントにおいて, 変数の値を変更して実行を継続させたい場合, 次のような操作を行えばよい.

          (debug) print A
          A = 2
          (debug) print A=1
          A=1 = 1
          (debug) print A
          A = 1

  * 函数の呼び出し

     函数呼び出しも式であるから, print の引数としてとれる.

          (debug) print length(List)
          length(List) = 14

     この例では, 変数 List に格納されているリストの長さを length() により調べている.

          (debug) print ctrl("cputime",1)
          ctrl("cputime",1) = 1

     この例は, 計算開始時に CPU 時間の表示の指定をし忘れた場合などに, 計算途中でデバッグモードから指定を行えることを示している.

     また, 止むを得ず計算を中断しなければならない場合, デバッグモードから bsave() などのコマンドにより途中結果をファイルに保存することもできる.

          (debug) print bsave(A,"savefile")
          bsave(A,"savefile") = 1

     デバッグモードからの函数呼び出しで注意すべきことは, その函数呼び出しでエラーが起こった場合, 元の函数の実行継続は不可能になるということである.

  * トレース情報の表示

     trace コマンドはまだインプリメントしていないが, stop if を用いることにより, ある時点における変数の値などを自動的に表示させることができる.

          [51] debug$
          (debug) list gb
          194     def gb(F,M,SUBST)
          195     {
          196             NFMOD = 0;
          197             if ( M ) {
          198                     PSM = newvect(PSLen);
          199                     for ( I = 0; I < PSLen; I++ )
          200                             if ( PSH[I] && !validhc(PS[I],M,SUBST) )
          201                                     return 0;
          202                             else
          203                                     PSM[I] = dp_mod(PS[I],M,SUBST);
          (debug) stop at 203 if (print(PSH[I]))
          (0) stop at "/usr/local/lib/asir/gr":203 if  (print(PSH[I]))
          (debug) quit
          [52] grm(cyclic(5),[c0,c1,c2,c3,c4]);
          (1)*<<1,1,1,1,1>>
          (1)*<<1,1,1,1,0>>
          (1)*<<1,1,1,0,0>>

     print() は常に 0 を返すため, if の条件式が真になることはないが, print() は実行されるため, プレークポイントを通過するたびに値が表示されることになる.

デバッガの使用例
========

ここでは, 階乗を再帰的に計算させるユーザ定義函数を例として, デバッガの実際の使用法を示す.

     % asir
     [0] load("fac")$
     [3] debug$
     (debug) list factorial
     1   def factorial(X) {
     2       if ( !X )
     3           return 1;
     4       else
     5           return X * factorial(X - 1);
     6   }
     7   end$
     (debug) stop at 5                     <-- ブレークポイントの設定
     (0) stop at "./fac":5
     (debug) quit                          <-- デバッグモードを抜ける
     [4] factorial(6);                     <-- factorial(6) の呼び出し
     stopped in factorial at line 5 in file "./fac"
     5           return X * factorial(X - 1);
     (debug) where                         <-- ブレークポイントまでの呼び出し列の表示
     factorial(), line 5 in "./fac"
     (debug) print X                       <-- X の値の表示
     X = 6
     (debug) step                          <-- ステップ実行 (函数に入る)
     stopped in factorial at line 2 in file "./fac"
     2		if ( !X )
     (debug) where
     factorial(), line 2 in "./fac"
     factorial(), line 5 in "./fac"
     (debug) print X
     X = 5
     (debug) delete 0                      <-- ブレークポイント 0 の消去
     (debug) cont                          <-- 実行継続
     720                                   <-- 結果 = 6!
     [5] quit;

デバッガの初期化ファイルの例
==============

前に述べた通り, Asir は, 起動時に $HOME/.dbxinit を読み込む. このファイルは, dbx のさまざまな初期設定用のコマンドを記述しておくファイルであるが, Asir は, alias 行のみを認識する. 例えば,

     % cat ‾/.dbxinit
     alias n next
     alias c cont
     alias p print
     alias s step
     alias d delete
     alias r run
     alias l list
     alias q quit

なる設定により, print, cont など, デバッグモードにおいて頻繁に用いられるコマンドが, それぞれ p, c など, 短い文字列で代用できる.

     [100] grm(La,[a,b,c]);
     [M,99999989,EVAL,[]]
     stopped in gb at line 196 in file "/usr/local/lib/asir/gr"
     196             NFMOD = 0;
     (debug) p F
     F = [0,1,2]
     (debug) c
     [1,2,NFT,0.01,NB,2,NAB,4,RP,2,(1)*<<1,3,1>>]

組み込み函数
******

数の演算
====

idiv, irem
----------

idiv(I1,I2)
     :: 整数除算による商.

irem(I1,I2)
     :: 整数除算による剰余.

return
     整数

i1,i2
     整数

  * I1 の I2 による整数除算による商, 剰余を求める.

  * I2 は 0 であってはならない.

  * 被除数が負の場合, 絶対値に対する値にマイナスをつけた値を返す.

  * I1 % I2 は, 結果が正に正規化されることを除けば irem() の代わりに用いることができる.

  * 多項式の場合は sdiv, srem を用いる.

     [0] idiv(100,7);
     14
     [0] idiv(-100,7);
     -14
     [1] irem(100,7);
     2
     [1] irem(-100,7);
     -2

参照
     sdiv, srem, %

fac
---

fac(I)
     :: I の階乗.

return
     整数

i
     整数

  * I の階乗を計算する.

  * I が負の場合は 0 を返す.

     [0] fac(50);
     30414093201713378043612608166064768844377641568960512000000000000

igcd
----

igcd(I1,I2)
     :: 整数の GCD (最大公約数)

return
     整数

i1,i2
     整数

  * I1 と I2 の GCD を求める.

  * 引数が整数でない場合は, エラーまたは無意味な結果を返す.

  * 多項式の場合は, gcd, gcdz を用いる.

     [0] igcd(12,8);
     4

参照
     gcd, gcdz

inv
---

inv(I,M)
     :: M を法とする I の逆数

return
     整数

i,m
     整数

  * IA == 1 mod (M) なる整数 A を求める.

  * I と M は互いに素でなければならないが, inv() はそのチェックは行わない.

     [71] igcd(1234,4321);
     1
     [72] inv(1234,4321);
     3239
     [73] irem(3239*1234,4321);
     1

参照
     igcd

prime, lprime
-------------

prime(INDEX)

lprime(INDEX)
     :: 素数を返す

return
     整数

index
     整数

  * prime(), lprime() いずれもシステムが内部に持つ素数表の要素を返す. index は 0 以上の整数で, 素数表のインデックスに用いられる. prime() は高々 10 進 4 桁の素数を小さい順に 1229 個, lprime() は, 10 進 8 桁で最大の素数から大きい順に 999 個返す. それ以外のインデックスに対しては 0 を返す.

  * より一般的な素数生成函数としては, pari(nextprime,NUMBER) がある.

     [95] prime(0);
     2
     [96] prime(1228);
     9973
     [97] lprime(0);
     99999989
     [98] lprime(999);
     0

参照
     pari

random
------

radom()
     :: 乱数を生成する.

return
     自然数

  * 最大 2^27-1 の乱数を生成する.

  * UNIX 版でのみ使用可能.

nm, dn
------

nm(RAT)
     :: RAT の分子.

dn(RAT)
     :: RAT の分母.

return
     整数または多項式

rat
     有理数または有理式

  * 与えられた有理数また有理式の分子及び分母を返す.

  * 有理数の場合, 分母は常に正で, 符号は分子が持つ.

  * 有理式の場合, 単に分母, 分子を取り出すだけである. 有理式に対しては, 約分は自動的には行われない. red() を明示的に呼び出す必要がある.

     [2] [nm(-43/8),dn(-43/8)];
     [-43,8]
     [3] dn((x*z)/(x*y));
     y*x
     [3] dn(red((x*z)/(x*y)));
     y

参照
     red

conj, real, imag
----------------

real(COMP)
     :: COMP の実数部分.

imag(COMP)
     :: COMP の虚数部分.

conj(COMP)
     :: COMP の共役複素数.

return comp
     複素数

  * 複素数に対し, 実部, 虚部, 共役を求める.

  * これらは, 多項式に対しても働く.

     [111] A=(2+@i)^3;
     (2+11*@i)
     [112] [real(A),imag(A),conj(A)];
     [2,11,(2-11*@i)]

eval
----

eval(OBJ[,PREC])
     :: OBJ の値の評価.

return
     数あるいは式

obj
     一般の式

prec
     整数

  * OBJ に含まれる函数の値を可能な限り評価する.

  * 計算は PARI (see pari) が行う.

  * PREC を指定した場合, 計算は, 10 進 PREC 桁程度で行われる. PREC の指定がない場合, 現在設定されている精度で行われる. (see setprec)

  * 扱える函数は, 次の通り.

          sin, cos, tan,

          asin, acos, atan,

          sinh, cosh, tanh,

          asinh, acosh, atanh,

          exp, log, pow(a,b) (a^b)

  * 以下の記号を数として評価できる.

     @i
          虚数単位

     @pi
          円周率

     @e
          自然対数の底

     [118] eval(exp(@pi*@i));
     -1.0000000000000000000000000000
     [119] eval(2^(1/2));
     1.414213562373095048763788073031
     [120] eval(sin(@pi/3));
     0.86602540378443864674620506632
     [121] eval(sin(@pi/3)-3^(1/2)/2,50);
     -2.78791084448179148471 E-58

参照
     ctrl, setprec, pari

pari
----

pari(FUNC,ARG,PREC)
     :: PARI の函数 FUNC を呼び出す.

return
     FUNC 毎に異なる.

func
     PARI の函数名

arg
     FUNC の引数

prec
     整数

  * PARI の函数を呼び出す.

  * PARI [Batut et al.] は Bordeaux 大学で開発されフリーソフトウェアとして公開されている. PARI は数式処理的な機能を有してはいるが, 主なターゲットは整数論に関連した数 (bignum, bigfloat) の演算で, 四則演算に限らずbigfloat によるさまざまな函数値の評価を高速に行うことができる. PARI は他のプログラムからサブルーチンライブラリとして用いることができ, また, gp という PARIライブラリのインタフェースにより UNIX のアプリケーションとして利用することもできる. 現在のバージョンは 1.38 でいくつかの ftp site (たとえば math.ucla.edu:/pub/pari) から anonymous ftp できる.

  * 最後の引数 PREC で計算精度を指定できる. PREC を省略した場合 setprec() で指定した精度となる.

  * 現時点で実行できる PARI の函数は次の通りである. いずれも 1 引数で Asir が対応できる型の引数をとる函数である. なお各々の機能については PARI のマニュアルを参照のこと.

     abs, adj, arg, bigomega, binary, ceil, centerlift, cf, classno, classno2, conj, content, denom, det, det2, detr, dilog, disc, discf, divisors, eigen, eintg1, erfc, eta, floor, frac, galois, galoisconj, gamh, gamma, hclassno, hermite, hess, imag, image, image2, indexrank, indsort, initalg, isfund, isprime, ispsp, isqrt, issqfree, issquare, jacobi, jell, ker, keri, kerint, kerintg1, kerint2, kerr, length, lexsort, lift, lindep, lll, lllg1, lllgen, lllgram, lllgramg1, lllgramgen, lllgramint, lllgramkerim, lllgramkerimgen, lllint, lllkerim, lllkerimgen, lllrat, lngamma, logagm, mat, matinvr, matrixqz2, matrixqz3, matsize, modreverse, mu, nextprime, norm, norml2, numdiv, numer, omega, order, ordred, phi, pnqn, polred, polred2, primroot, psi, quadgen, quadpoly, real, recip, redcomp, redreal, regula, reorder, reverse, rhoreal, roots, rootslong, round, sigma, signat, simplify, smalldiscf, smallfact, smallpolred, smallpolred2, smith, smith2, sort, sqr, sqred, sqrt, supplement, trace, trans, trunc, type, unit, vec, wf, wf2, zeta

  * Asir で用いているのは PARI のほんの一部の機能であるが, 今後より多くの機能が利用できるよう改良する予定である.

     /* 行列の固有ベクトルを求める. */
     [0] pari(eigen,newmat(2,2,[[1,1],[1,2]]));
     [ -1.61803398874989484819771921990 0.61803398874989484826 ]
     [ 1 1 ]
     /* 1 変数多項式の根を求める. */
     [1] pari(roots,t^2-2);
     [ -1.41421356237309504876 1.41421356237309504876 ]

参照
     setprec

setprec
-------

setprec([N])
     :: bigfloat の桁数を N 桁に設定する.

return
     整数

n
     整数

  * 引数がある場合, bigfloat の桁数を N 桁に設定する. 引数のあるなしにかかわらず, 以前に設定されていた値を返す.

  * bigfloat の計算は PARI (see pari) によって行われる.

  * bigfloat での計算に対し有効である. bigfloat の flag を on にする方法は, ctrl を参照.

  * 設定できる桁数に上限はないが, 指定した桁数に設定されるとは限らない. 大きめの値を設定するのが安全である.

     [1] setprec();
     9
     [2] setprec(100);
     9
     [3] setprec(100);
     96

参照
     ctrl, eval, pari

多項式, 有理式の演算
===========

var
---

var(RAT)
     :: RAT の主変数.

return
     不定元

rat
     有理式

  * 主変数に関しては, see Asir で使用可能な型.

  * デフォルトの変数順序は次のようになっている.

     x, y, z, u, v, w, p, q, r, s, t, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o,以後は変数の現れた順.

     [0] var(x^2+y^2+a^2);
     x
     [1] var(a*b*c*d*e);
     a
     [2] var(3/abc+2*xy/efg);
     abc

参照
     ord, vars

vars
----

vars(OBJ)
     :: OBJ に含まれる変数のリスト.

return
     リスト

obj
     任意

  * 与えられた式に含まれる変数のリストを返す.

  * 変数順序の高いものから順に並べる.

     [0] vars(x^2+y^2+a^2);
     [x,y,a]
     [1] vars(3/abc+2*xy/efg);
     [abc,xy,efg]
     [2] vars([x,y,z]);
     [x,y,z]

参照
     var, uc, ord

uc
--

uc()
     :: 新たな不定元を生成する.

return
     vtype が 1 の不定元

  * uc() を実行するたびに, _0, _1, _2,... という不定元を生成する.

  * uc() で生成された不定元は, 直接キーボードから入力することができない. これは, プログラム中で未定係数を自動生成する場合, 入力などに含まれる不定元と同一のものが生成されることを防ぐためである.

  * 通常の不定元 (vtype が 0) の自動生成には rtostr(), strtov() を用いる.

  * uc() で生成された不定元の不定元としての型 (vtype) は 1 である. (see 不定元の型)

     [0] A=uc();
     _0
     [1] B=uc();
     _1
     [2] (uc()+uc())^2;
     _2^2+2*_3*_2+_3^2
     [3] (A+B)^2;
     _0^2+2*_1*_0+_1^2

参照
     vtype, rtostr, strtov

coef
----

coef(POLY,DEG[,VAR])
     :: POLY の VAR (省略時は主変数) に関する DEG 次の係数.

return
     多項式

poly
     多項式

var
     不定元

deg
     自然数

  * POLY の VAR に関する DEG 次の係数を出力する.

  * VAR は, 省略すると主変数 var(POLY) だとみなされる.

  * VAR が主変数でない時, VAR が主変数の場合に比較して効率が落ちる.

     [0] A = (x+y+z)^3;
     x^3+(3*y+3*z)*x^2+(3*y^2+6*z*y+3*z^2)*x+y^3+3*z*y^2+3*z^2*y+z^3
     [1] coef(A,1,y);
     3*x^2+6*z*x+3*z^2
     [2] coef(A,0);
     y^3+3*z*y^2+3*z^2*y+z^3

参照
     var, deg

deg, mindeg
-----------

deg(POLY,VAR)
     :: POLY の, 変数 VAR に関する最高次数.

mindeg(POLY,VAR)
     :: POLY の, 変数 VAR に関する最低次数.

return
     自然数

poly
     多項式

var
     不定元

  * 与えられた多項式の変数 VAR に関する最高次数, 最低次数を出力する.

  * 変数 VAR を省略することは出来ない.

  * VAR が主変数でない時, VAR が主変数の場合に比較して効率が落ちる.

     [0] deg((x+y+z)^10,x);
     10
     [1] deg((x+y+z)^10,w);
     0
     [75] mindeg(x^2+3*x*y,x);
     1

nmono
-----

nmono(RAT)
     :: RAT の単項式の項数.

return
     自然数

rat
     有理式

  * 多項式を展開した状態での 0 でない係数を持つ単項式の項数を求める.

  * 有理式の場合は, 分子と分母の項数の和が返される.

  * 函数形式 (see 不定元の型) は, 引数が何であっても単項とみなされる. (1 個の不定元と同じ. )

     [0] nmono((x+y)^10);
     11
     [1] nmono((x+y)^10/(x+z)^10);
     22
     [2] nmono(sin((x+y)^10));
     1

参照
     vtype

ord
---

ord([VARLIST])
     :: 変数順序の設定

return
     変数のリスト

varlist
     変数のリスト

  * 引数があるとき, 引数の変数リストを先頭に出し, 残りの変数がその後に続くように変数順序を設定する. 引数のあるなしに関わらず, ord() の終了時における変数順序リストを返す.

  * この函数による変数順序の変更を行っても, 既にプログラム変数などに代入されている式の内部形式は新しい順序に従っては変更されない. 従って, この函数による順序の変更は, Asir の起動直後, あるいは, 新たな変数が現れた時点に行われるべきである. 異なる変数順序のもとで生成された式どうしの演算が行われた場合, 予期せぬ結果が生ずることもあり得る.

     [0] ord();
     [x,y,z,u,v,w,p,q,r,s,t,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,_x,_y,_z,_u,_v,_w,_p,
     _q,_r,_s,_t,_a,_b,_c,_d,_e,_f,_g,_h,_i,_j,_k,_l,_m,_n,_o,exp(_x),(_x)^(_y),
     log(_x),(_x)^(_y-1),cos(_x),sin(_x),tan(_x),(-_x^2+1)^(-1/2),cosh(_x),sinh(_x),
     tanh(_x),(_x^2+1)^(-1/2),(_x^2-1)^(-1/2)]
     [1] ord([dx,dy,dz,a,b,c]);
     [dx,dy,dz,a,b,c,x,y,z,u,v,w,p,q,r,s,t,d,e,f,g,h,i,j,k,l,m,n,o,_x,_y,_z,_u,_v,
     _w,_p,_q,_r,_s,_t,_a,_b,_c,_d,_e,_f,_g,_h,_i,_j,_k,_l,_m,_n,_o,exp(_x),
     (_x)^(_y),log(_x),(_x)^(_y-1),cos(_x),sin(_x),tan(_x),(-_x^2+1)^(-1/2),
     cosh(_x),sinh(_x),tanh(_x),(_x^2+1)^(-1/2),(_x^2-1)^(-1/2)]

sdiv, srem, sqr
---------------

sdiv(POLY1,POLY2)
     :: POLY1 を POLY2 で割る除算が最後まで実行できる場合に商を求める.

srem(POLY1,POLY2)
     :: POLY1 を POLY2 で割る除算が最後まで実行できる場合に剰余を求める.

sqr(POLY1,POLY2)
     :: POLY1 を POLY2 で割る除算が最後まで実行できる場合に商, 剰余を求める.

return
     sdiv(), srem() : 多項式, sqr() : [商,剰余] なるリスト

poly1 poly2
     多項式

  * POLY1 を POLY2 の主変数 var(POLY2) に関する多項式と見て, POLY2 で, 割り算を行う.

  * 多項式の除算は, 主係数どうしの割算により得られた商と, 主変数の適当な冪の積を POLY2 に掛けて, POLY1 から引くという操作を POLY1 の次数が POLY2 の次数より小さくなるまで繰り返して行う. この操作が, 多項式の範囲内で行われるためには, 各ステップにおいて主係数どうしの除算が, 多項式としての整除である必要がある. これが, 「除算が最後まで実行できる」ことの意味である.

  * 典型的な場合として, POLY2 の主係数が, 有理数である場合, あるいは, POLY2 が POLY1 の因子であることがわかっている場合などがある.

  * sqr() は商と剰余を同時に求めたい時に用いる.

  * 整数除算の商, 剰余は idiv, irem を用いる.

  * 係数に対する剰余演算は % を用いる.

  * 主変数が指定できるよう改良の予定.

     [0] sdiv((x+y+z)^3,x^2+y+a);
     x+3*y+3*z
     [1] srem((x+y+z)^2,x^2+y+a);
     (2*y+2*z)*x+y^2+(2*z-1)*y+z^2-a
     [2] X=(x+y+z)*(x-y-z)^2;
     x^3+(-y-z)*x^2+(-y^2-2*z*y-z^2)*x+y^3+3*z*y^2+3*z^2*y+z^3
     [3] Y=(x+y+z)^2*(x-y-z);
     x^3+(y+z)*x^2+(-y^2-2*z*y-z^2)*x-y^3-3*z*y^2-3*z^2*y-z^3
     [4] G=gcd(X,Y);
     x^2-y^2-2*z*y-z^2
     [5] sqr(X,G);
     [x-y-z,0]
     [6] sqr(Y,G);
     [x+y+z,0]
     [7] sdiv(y*x^3+x+1,y*x+1);
     divsp: cannot happen
     return to toplevel

参照
     idiv, irem, %

tdiv
----

tdiv(POLY1,POLY2)
     :: POLY1 が POLY2 で割り切れるかどうか調べる.

return
     割り切れるならば商, 割り切れなければ 0

poly1 poly2
     多項式

  * POLY2 が POLY1 を多項式として割り切るかどうか調べる.

  * ある多項式が既約因子であることはわかっているが, その重複度がわからない場合に, tdiv() を繰り返し呼ぶことにより重複度がわかる.

     [11] Y=(x+y+z)^5*(x-y-z)^3;
     x^8+(2*y+2*z)*x^7+(-2*y^2-4*z*y-2*z^2)*x^6+(-6*y^3-18*z*y^2-18*z^2*y-6*z^3)*x^5
     +(6*y^5+30*z*y^4+60*z^2*y^3+60*z^3*y^2+30*z^4*y+6*z^5)*x^3+(2*y^6+12*z*y^5
     +30*z^2*y^4+40*z^3*y^3+30*z^4*y^2+12*z^5*y+2*z^6)*x^2+(-2*y^7-14*z*y^6
     -42*z^2*y^5-70*z^3*y^4-70*z^4*y^3-42*z^5*y^2-14*z^6*y-2*z^7)*x-y^8-8*z*y^7
     -28*z^2*y^6-56*z^3*y^5-70*z^4*y^4-56*z^5*y^3-28*z^6*y^2-8*z^7*y-z^8
     [12] for(I=0,F=x+y+z,T=Y; T=tdiv(T,F); I++);
     [13] I;
     5

参照
     sdiv, srem

%
-

POLY % M
     :: 整数による剰余

return
     整数または多項式

poly
     整数または整数係数多項式

m
     整数

  * POLY の各係数を M で割った剰余で置き換えた多項式を返す.

  * 結果の係数は全て正の整数となる.

  * POLY は整数でもよい. この場合, 結果が正に正規化されることを除けば irem() と同様に用いることができる.

  * POLY の係数, M とも整数である必要があるが, チェックは行なわれない.

     [0] (x+2)^5 % 3;
     x^5+x^4+x^3+2*x^2+2*x+2
     [1] (x-2)^5 % 3;
     x^5+2*x^4+x^3+x^2+2*x+1
     [2] (-5) % 4;
     3
     [3] irem(-5,4);
     -1

参照
     irem

subst, psubst
-------------

subst(RAT[,VARN,RATN]*)

psubst(RAT[,VAR,RAT]*)
     :: RAT の VARN に RATN を代入 (N=1,2,... で左から右に順次代入する).

return
     有理式

rat,ratn
     有理式

varn
     不定元

  * 有理式の特定の不定元に, 定数あるいは多項式, 有理式などを代入するのに用いる.

  * subst(RAT,VAR1,RAT1,VAR2,RAT2,...) は, subst(subst(RAT,VAR1,RAT1),VAR2,RAT2,...) と同じ意味である.

  * 入力の左側から順に代入を繰り返すために, 入力の順によって結果が変わることがある.

  * subst() は, sin() などの函数の引数に対しても代入を行う. psubst() は, このような函数を一つの独立した不定元と見なして, その引数には代入は行わない. (partial substitution のつもり)

  * Asir では, 有理式の約分は自動的には行わないため, 有理式の代入は, 思わぬ計算時間の増大を引き起こす場合がある. 有理式を代入する場合には, 問題に応じた独自の函数を書いて, なるべく分母, 分子が大きくならないように配慮することもしばしば必要となる.

  * 分数を代入する場合も同様である.

     [0] subst(x^3-3*y*x^2+3*y^2*x-y^3,y,2);
     x^3-6*x^2+12*x-8
     [1] subst(@@,x,-1);
     -27
     [2] subst(x^3-3*y*x^2+3*y^2*x-y^3,y,2,x,-1);
     -27
     [3] subst(x*y^3,x,y,y,x);
     x^4
     [4] subst(x*y^3,y,x,x,y);
     y^4
     [5] subst(x*y^3,x,t,y,x,t,y);
     y*x^3
     [6] subst(x*sin(x),x,t);
     sint(t)*t
     [7] psubst(x*sin(x),x,t);
     sin(x)*t

diff
----

diff(RAT[,VARN]*)

diff(RAT,VARLIST)
     :: RAT を VARN あるいは VARLIST の中の変数で順次微分する.

return
     式

rat
     有理式 (初等函数を含んでもよい)

varn
     不定元

varlist
     不定元のリスト

  * 与えられた初等函数を VARN あるいは VARLIST の中の変数で順次微分する.

  * 左側の不定元より, 順に微分していく. つまり, diff(RAT,x,y) は, diff(diff(RAT,x),y) と同じである.

     [0] diff((x+2*y)^2,x);
     2*x+4*y
     [1] diff((x+2*y)^2,x,y);
     4
     [2] diff(x/sin(log(x)+1),x);
     (sin(log(x)+1)-cos(log(x)+1))/(sin(log(x)+1)^2)
     [3] diff(sin(x),[x,x,x,x]);
     sin(x)

res
---

res(VAR,POLY1,POLY2)
     :: VAR に関する POLY1 と POLY2 の終結式.

return
     多項式

var
     不定元

poly1,poly2
     多項式

  * 二つの多項式 POLY1 と POLY2 の, 変数 VAR に関する終結式を求める.

  * 部分終結式アルゴリズムによる.

     [0] res(t,(t^3+1)*x+1,(t^3+1)*y+t);
     -x^3-x^2-y^3

fctr, sqfr
----------

fctr(POLY)
     :: POLY を既約因子に分解する.

sqfr(POLY)
     :: POLY を無平方分解する.

return
     リスト

poly
     有理数係数の多項式

  * 有理数係数の多項式 POLY を因数分解する. fctr() は既約因子分解, sqfr() は無平方因子分解.

  * 結果は [[数係数,1],[因子,重複度],...] なるリスト.

  * 数係数 と 全ての 因子^重複度 の積が POLY と等しい.

  * 数係数 は, (POLY/数係数) が, 整数係数で, 係数の GCD が 1 となるような多項式になるように選ばれている. (ptozp() 参照)

     [0] fctr(x^10-1);
     [[1,1],[x-1,1],[x+1,1],[x^4+x^3+x^2+x+1,1],[x^4-x^3+x^2-x+1,1]]
     [1] fctr(x^3+y^3+(z/3)^3-x*y*z);
     [[1/27,1],[9*x^2+(-9*y-3*z)*x+9*y^2-3*z*y+z^2,1],[3*x+3*y+z,1]]
     [2] A=(a+b+c+d)^2;
     a^2+(2*b+2*c+2*d)*a+b^2+(2*c+2*d)*b+c^2+2*d*c+d^2
     [3] fctr(A);
     [[1,1],[a+b+c+d,2]]
     [4] A=(x+1)*(x^2-y^2)^2;
     x^5+x^4-2*y^2*x^3-2*y^2*x^2+y^4*x+y^4
     [5] sqfr(A);
     [[1,1],[x+1,1],[-x^2+y^2,2]]
     [6] fctr(A);
     [[1,1],[x+1,1],[-x-y,2],[x-y,2]]

参照
     ufctrhint

ufctrhint
---------

ufctrhint(POLY,HINT)
     :: 次数情報を用いた 1 変数多項式の因数分解

return
     リスト

poly
     有理数係数の 1 変数多項式

hint
     自然数

  * 各既約因子の次数が HINT の倍数であることがわかっている場合に POLY の既約因子分解を fctr() より効率良く行う. POLY が, D 次の拡大体上におけるある多項式のノルム (see 代数的数に関する演算) で無平方である場合, 各既約因子の次数は D の倍数となる. このような場合に用いられる.

     [10] A=t^9-15*t^6-87*t^3-125;
     t^9-15*t^6-87*t^3-125
     0msec
     [11] N=res(t,subst(A,t,x-2*t),A);
     -x^81+1215*x^78-567405*x^75+139519665*x^72-19360343142*x^69+1720634125410*x^66
     -88249977024390*x^63-4856095669551930*x^60+1999385245240571421*x^57
     -15579689952590251515*x^54+15956967531741971462865*x^51
     ...
     +140395588720353973535526123612661444550659875*x^6
     +10122324287343155430042768923500799484375*x^3
     +139262743444407310133459021182733314453125
     980msec + gc : 250msec
     [12] sqfr(N);
     [[-1,1],[x^81-1215*x^78+567405*x^75-139519665*x^72+19360343142*x^69
     -1720634125410*x^66+88249977024390*x^63+4856095669551930*x^60
     -1999385245240571421*x^57+15579689952590251515*x^54
     ...
     -10122324287343155430042768923500799484375*x^3
     -139262743444407310133459021182733314453125,1]]
     20msec
     [13] fctr(N);
     [[-1,1],[x^9-405*x^6-63423*x^3-2460375,1],
     [x^18-486*x^15+98739*x^12-9316620*x^9+945468531*x^6-12368049246*x^3
     +296607516309,1],[x^18-8667*x^12+19842651*x^6+19683,1],
     [x^18-324*x^15+44469*x^12-1180980*x^9+427455711*x^6+2793253896*x^3+31524548679,1],
     [x^18+10773*x^12+2784051*x^6+307546875,1]]
     167.050sec + gc : 1.890sec
     [14] ufctrhint(N,9);
     [[-1,1],[x^9-405*x^6-63423*x^3-2460375,1],
     [x^18-486*x^15+98739*x^12-9316620*x^9+945468531*x^6-12368049246*x^3
     +296607516309,1],[x^18-8667*x^12+19842651*x^6+19683,1],
     [x^18-324*x^15+44469*x^12-1180980*x^9+427455711*x^6+2793253896*x^3+31524548679,1],
     [x^18+10773*x^12+2784051*x^6+307546875,1]]
     119.340sec + gc : 1.300sec

参照
     fctr

ptozp
-----

ptozp(POLY)
     :: POLY を有理数倍して整数係数多項式にする.

return
     多項式

poly
     多項式

  * 与えられた多項式 POLY に適当な有理数を掛けて, 整数係数かつ係数の GCD が 1 になるようにする.

  * 分数の四則演算は, 整数の演算に比較して遅いため, 種々の多項式演算の前に, 多項式を整数係数にしておくことが望ましい.

  * 有理式を約分する red() で分数係数有理式を約分しても, 分子多項式の係数は有理数のままであり, 有理式の分子を求める nm() では, 分数係数多項式は, 分数係数のままの形で出力されるため, 直ちに整数係数多項式を得る事は出来ない.

     [0] ptozp(2*x+5/3);
     6*x+5
     [1] nm(2*x+5/3);
     2*x+5/3

参照
     nm, dn

prim, cont
----------

prim(POLY)
     :: POLY の原始的部分 (primitive part).

cont(POLY)
     :: POLY の容量 (content).

return poly
     有理数係数多項式

  * POLY の主変数に関する原始的部分, 容量を求める.

  * 主変数の指定ができないので, 主変数でない変数について計算したい場合には, ord() で変数順序を調べて, その変数が主変数になるように変数を入れ替えて計算して, もとに戻すことになる.

  * 主変数指定ができるよう改良の予定.

     [0] E=(y-z)*(x+y)*(x-z)*(2*x-y);
     (2*y-2*z)*x^3+(y^2-3*z*y+2*z^2)*x^2+(-y^3+z^2*y)*x+z*y^3-z^2*y^2
     [1] prim(E);
     2*x^3+(y-2*z)*x^2+(-y^2-z*y)*x+z*y^2
     [2] cont(E);
     y-z
     [3] subst(prim(subst(E,x,w,z,x),x,z,w,x);
     (y-z)*x-z*y+z^2

参照
     var, ord

gcd, gcdz
---------

gcd(POLY1,POLY2)

gcdz(POLY1,POLY2)
     :: POLY1 と POLY2 の gcd.

return
     多項式

poly1,poly2
     多項式

  * 二つの多項式の最大公約式 (GCD) を求める. gcd() は, 有理数体上の多項式としての GCD を返す. すなわち, 結果は整数係数で, かつ係数の GCD が 1 になるような多項式, または, 互いに素の場合は 1 を返す. gcdz() は, POLY1, POLY2 ともに整数係数の場合に, 整数環上の多項式としての GCD を返す. すなわち, gcd() の値に, 係数全体の整数 GCD の値を掛けたものを返す.

  * Extended Zassenhaus アルゴリズム (EZGCD) による.

     [0] gcd(12*(x^2+2*x+1)^2,18*(x^2+(y+1)*x+y)^3);
     x^3+3*x^2+3*x+1
     [0] gcdz(12*(x^2+2*x+1)^2,18*(x^2+(y+1)*x+y)^3);
     6*x^3+18*x^2+18*x+6

参照
     igcd

red
---

red(RAT)
     :: RAT を約分したもの.

return
     有理式

rat
     有理式

  * Asir は有理数の約分を常に自動的に行う. しかし, 有理式については通分は行うが, 約分はユーザーが指定しない限り行わない. この約分を行うコマンドが red である.

  * EZGCD により RAT の分子, 分母を約分する.

  * 出力される有理式の分母の多項式は, 各係数の GCD が 1 の整数係数多項式である. 分子については整数係数多項式となるとは限らない.

  * GCD は大変重い演算なので, 他の方法で除ける共通因子は可能な限り除くのが望ましい. また, 分母, 分子が大きくなってからのこの函数の呼び出しは, 非常に時間が掛かる場合が多い. 有理式演算を行う場合は, ある程度頻繁に, 約分を行う必要がある.

     [0] (x^3-1)/(x-1);
     (x^3-1)/(x-1)
     [1] red((x^3-1)/(x-1));
     x^2+x+1
     [2] red((x^3+y^3+z^3-3*x*y*z)/(x+y+z));
     x^2+(-y-z)*x+y^2-z*y+z^2
     [3] red((3*x*y)/(12*x^2+21*y^3*x));
     (y)/(4*x+7*y^3)
     [4] red((3/4*x^2+5/6*x)/(2*y*x+4/3*x));
     (9/8*x+5/4)/(3*y+2)

参照
     nm, dn, gcd, ptozp

リストの演算
======

car, cdr, cons, append, reverse, length
---------------------------------------

car(LIST)
     :: 空でない LIST の先頭要素.

cdr(LIST)
     :: 空でない LIST から先頭要素を取り除いたリスト.

cons(OBJ,LIST)
     :: LIST の先頭に OBJ を付け加えたリスト.

append(LIST1,LIST2)
     :: LIST1 と LIST2 をこの順に 1 つにしたリスト.

reverse(LIST)
     :: LIST を逆順にしたリスト.

length(LIST)
     :: LIST の長さ.

return
     car() : 任意, cdr(), cons(), append(), reverse() : リスト,  length() : 自然数

list,list1,list2
     リスト

obj
     任意

  * リストは [OBJ1,OBJ2,...] と表される. OBJ1 が先頭要素である.

  * car() は, 空でない LIST の先頭要素を出力する. 空リストが入力された場合は, 空リストが出力される.

  * cdr() は, 空でない LIST から先頭要素を取り除いたリストを出力する. 空リストが入力された場合は, 空リストが出力される.

  * cons() は,  LIST の先頭に OBJ を付け加えたリストを出力する.

  * append() は, LIST1 の要素と LIST2 のすべての要素を結合させたリスト [LIST1 の要素の並び,LIST2 の要素の並び] を出力する.

  * reverse() は, LIST を逆順にしたリストを出力する.

  * length() は, LIST の長さを出力する. ベクトル及び行列の要素の個数は, size() を用いる.

  * リストは読み出し専用で, 要素の入れ替えはできない.

  * リストの N 番目の要素の取り出しは, cdr() を N 回適用した後 car() を適用することにより可能であるが, 便法として, ベクトル, 行列などの配列と同様, インデックス [N] を後ろに付けることにより取り出すことができる. ただし, システム内部では, 実際にポインタを N 回たどるので, 後ろの要素ほど取り出しに時間がかかる.

  * cdr() は新しいセルを生成しないが, append() は, 実際には第 1 引数のリストの長さだけの cons() の繰り返しとなるため, 第 1 引数のリストが長い場合には多くのメモリを消費することになる. reverse() に関しても同様である.

     [0] L = [[1,2,3],4,[5,6]];
     [[1,2,3],4,[5,6]]
     [1] car(L);
     [1,2,3]
     [2] cdr(L);
     [4,[5,6]]
     [3] cons(x*y,L);
     [y*x,[1,2,3],4,[5,6]]
     [4] append([a,b,c],[d]);
     [a,b,c,d]
     [5] reverse([a,b,c,d]);
     [d,c,b,a]
     [6] length(L);
     3
     [7] L[2][0];
     5

配列
==

newvect
-------

newvect(LEN[,LIST])
     :: 長さ LEN のベクトルを生成する.

return
     ベクトル

len
     自然数

list
     リスト

  * 長さ LEN のベクトルを生成する. 第 2 引数がない場合, 各成分は 0 に初期化される. 第 2 引数がある場合, インデックスの小さい成分から, リストの各要素により初期化される. 各要素は, 先頭から順に使われ, 足りない分は 0 が埋められる.

  * ベクトルの成分は, 第 0 成分から第 LEN-1 成分となる. (第 1 成分からではない事に注意. )

  * リストは各成分が, ポインタを辿る事によってシーケンシャルに呼び出されるのに対し, ベクトルは各成分が第一成分からのメモリ上の displacement (変位)によってランダムアクセスで呼び出され, その結果, 成分のアクセス時間に大きな差が出てくる. 成分アクセスは, リストでは, 成分の量が増えるに従って時間がかかるようになるが, ベクトルでは, 成分の量に依存せずほぼ一定である.

  * Asir では, 縦ベクトル, 横ベクトルの区別はない. 行列を左から掛ければ縦ベクトルとみなされるし, 右から掛ければ横ベクトルとみなされる.

  * ベクトルの長さは size() によって得られる.

  * 函数の引数としてベクトルを渡した場合, 渡された函数は, そのベクトルの成分を書き換えることができる.

     [0] A=newvect(5);
     [ 0 0 0 0 0 ]
     [1] A=newvect(5,[1,2,3,4,[5,6]]);
     [ 1 2 3 4 [5,6] ]
     [2] A[0];
     1
     [3] A[4];
     [5,6]
     [4] size(A);
     [5]
     [5] def afo(V) { V[0] = x; }
     [6] afo(A)$
     [7] A;
     [ x 2 3 4 [5,6] ]

参照
     newmat, size

newmat
------

newmat(ROW,COL [,[[A,B,...],[C,D,...],...]])
     :: ROW 行 COL 列の行列を生成する.

return
     行列

row,col
     自然数

a,b,c,d
     任意

  * ROW 行 COL 列の行列を生成する. 第 3 引数がない場合, 各成分は 0 に初期化される. 第 3 引数がある場合, インデックスの小さい成分から, 各行が, リストの各要素 (これはまたリストである) により初期化される. 各要素は, 先頭から順に使われ, 足りない分は 0 が埋められる.

  * 行列のサイズは size() で得られる.

  * M が行列のとき, M[I] により第 I 行をベクトルとして取り出すことができる. このベクトルは, もとの行列と成分を共有しており, いずれかの成分を書き換えれば, 他の対応する成分も書き換わることになる.

  * 函数の引数として行列を渡した場合, 渡された函数は, その行列の成分を書き換えることができる.

     [0] A = newmat(3,3,[[1,1,1],[x,y],[x^2]]);
     [ 1 1 1 ]
     [ x y 0 ]
     [ x^2 0 0 ]
     [1] det(A);
     -y*x^2
     [2] size(A);
     [3,3]
     [3] A[1];
     [ x y 0 ]
     [4] A[1][3];
     getarray : Out of range
     return to toplevel

参照
     newvect, size, det

size
----

size(VECT|MAT)
     :: [VECT の長さ] または [MAT の行数,MAT の列数].

return
     リスト

vect
     ベクトル

mat
     行列

  * VECT 又は, MAT のサイズをリストで出力する.

  * LIST のサイズは length()を, 有理式に現れる単項式の数は nmono() を用いる.

     [0] A = newvect(4);
     [ 0 0 0 0 ]
     [1] size(A);
     [4]
     [2] B = newmat(2,3,[[1,2,3],[4,5,6]]);
     [ 1 2 3 ]
     [ 4 5 6 ]
     [3] size(B);
     [2,3]

参照
     length, nmono

det
---

det(MAT)
     :: MAT の行列式を求める.

return
     式

mat
     行列

  * 行列 MAT の行列式を求める.

  * 分数なしのガウス消去法によっているため, 多変数多項式を成分とする行列に対しては小行列式展開による方法のほうが効率がよい場合もある.

     [91] A=newmat(5,5)$
     [92] V=[x,y,z,u,v];
     [x,y,z,u,v]
     [93] for(I=0;I<5;I++)for(J=0,B=A[I],W=V[I];J<5;J++)B[J]=W^J;
     [94] A;
     [ 1 x x^2 x^3 x^4 ]
     [ 1 y y^2 y^3 y^4 ]
     [ 1 z z^2 z^3 z^4 ]
     [ 1 u u^2 u^3 u^4 ]
     [ 1 v v^2 v^3 v^4 ]
     [95] fctr(det(A));
     [[1,1],[u-v,1],[-z+v,1],[-z+u,1],[-y+u,1],[y-v,1],[-y+z,1],[-x+u,1],[-x+z,1],
     [-x+v,1],[-x+y,1]]

参照
     newmat

型を求める函数
=======

type
----

type(OBJ)
     :: OBJ の 型 (整数) を返す.

return
     自然数

obj
     任意

  * OBJ の 型の値は次の通り.

     0
          0

     1
          数

     2
          多項式 (数でない)

     3
          有理式 (多項式でない)

     4
          リスト

     5
          ベクトル

     6
          行列

     7
          文字列

     8
          構造体

     9
          分散表現多項式

  * 数の型を求めるには, ntype を用いる. 不定元の型を求めるには, vtype を用いる.

参照
     ntype, vtype

ntype
-----

ntype(NUM)
     :: NUM (数) の 型 (整数) を返す.

return
     自然数

obj
     数

  * 数の型の値は次の通り.

     0
          有理数

     1
          倍精度浮動小数

     2
          代数的数

     3
          任意精度浮動小数 (bigfloat)

     4
          複素数

  * newalg(x^2+1) で生成した数と, 虚数単位 @i は, 異なるものとして扱われる.

  * 代数的数に関しては, see 代数的数に関する演算.

     [0] [10/37,ntype(10/37)];
     [10/37,0]
     [1] [10.0/37.0,ntype(10.0/37.0)];
     [0.27027,1]
     [2] [newalg(x^2+1)+1,ntype(newalg(x^2+1)+1)];
     [(#0+1),2]
     [3] [eval(sin(@pi/6)),ntype(eval(sin(@pi/6)))];
     [0.49999999999999999991,3]
     [4] [@i+1,ntype(@i+1)];
     [(1+1*@i),4]

参照
     type

vtype
-----

vtype(VAR)
     :: VAR (不定元) の 型 (整数) を返す.

return
     自然数

var
     不定元

  * VAR (不定元) の型の値は次の通り. 詳細は see 不定元の型.

     0
          一般不定元  (a,b,x,afo,bfo,...,etc.)

     1
          uc() で生成された不定元 (_0, _1, _2, ... etc.)

     2
          函数形式 (sin(x), log(a+1), acosh(1), @pi, @e, ... etc.)

     3
          函数子 (組み込み函数子, ユーザ定義函数子, 初等函数子 : sin, log, ... etc.)

  * a(); を実行(通常ではエラー)しただけでも ntype(a) は 3 となる. すなわち a はユーザ定義函数子とみなされる.

  * @pi, @e は不定元として扱われるが, eval(), pari() においては数として扱われる.

参照
     type, ntype, uc

函数に対する操作
========

functor, args, funargs
----------------------

functor(FUNC)
     :: FUNC の函数子を取り出す.

args(FUNC)
     :: FUNC の引数リストを取り出す.

funargs(FUNC)
     :: cons(functor(FUNC),args(FUNC)) を返す.

return
     functor() : 不定元, args(), funargs() : リスト

func
     函数形式を表す不定元

  * 函数形式に関しては, vtype() を参照.

  * 函数形式 FUNC の函数子, 引数リストを取り出す.

  * 逆に, 取り出した函数子を値に持つプログラム変数を F とすれば (*F)(x) で x を引数とする函数呼び出しまたは函数形式が入力できる.

     [0] functor(sin(x));
     sin
     [0] args(sin(x));
     [x]
     [0] funargs(sin(3*cos(y)));
     [sin,3*cos(y)]
     [1] for (L=[sin,cos,tan];L!=[];L=cdr(L)) {A=car(L); print(eval((*A)(@pi/3)));}
     0.86602540349122136831
     0.5000000002
     1.7320508058

参照
     vtype

文字列に関する演算
=========

rtostr
------

rtostr(OBJ)
     :: OBJ を文字列に変える.

return
     文字列

obj
     任意

  * 任意のオブジェクト OBJ を文字列に変える.

  * 整数などを文字列に変換して変数名と結合することにより, 添字付きの不定元を生成する場合に多く用いられる.

  * 逆に, 文字列を不定元に変換する時には, strtov を用いる.

     [0] A=afo;
     afo
     [1] type(A);
     2
     [2] B=rtostr(A);
     afo
     [3] type(B);
     7
     [4] B+"1";
     afo1

参照
     strtov, type

strtov
------

strtov(STR)
     :: STR (文字列) を不定元に変える.

return
     不定元

str
     不定元として変換可能な文字列

  * 不定元として変換可能な文字列を不定元に変える.

  * 不定元として変換可能な文字列とは, 英小文字で始まり, 英字, 数字および記号 _ で作られる文字列である.

  * rtostr() と組合せて, プログラム中で自動的に不定元を生成したい時に用いられる.

     [0] A="afo";
     afo
     [1] for (I=0;I<3;I++) {B=strtov(A+rtostr(I)); print([B,type(B)]);}
     [afo0,2]
     [afo1,2]
     [afo2,2]

参照
     rtostr, type, uc

入出力
===

end, quit
---------

end, quit
     :: 現在読み込み中のファイルを閉じる. トップレベルにおいてはセッションを終了することになる.

  * end, quit ともに無引数の函数であるが, () なしで呼び出すことができる. いずれも現在読み込み中のファイルを閉じる. これは, トップレベルにおいてはセッションを終了させることになる.

  * ファイルの場合, ファイルの終端まで読めば, 自動的にファイルは閉じられるが, トップレベルの場合プロンプトが出ないまま, 入力待ちになるので, ファイルの終端には end$ を書くのが望ましい.

     [6] quit;
     %

参照
     load

load
----

load("FILENAME")
     :: FILENAME を読み込む.

return
     (1|0)

filename
     ファイル名 (パス名)

  * 実際のプログラムの書き方は, see ユーザ言語 Asir. テキストファイルを読み込む場合, cpp を通すので, C のプログラム同様 #include, #define を使うことができる.

  * 指定したファイルが存在した時には 1 を返し, 存在しなかった時は 0 を返す.

  * ファイル名が / で始まる場合は絶対パス, . で始まる場合はカレントディレクトリからの相対パスと見なされる. それ以外の場合, 環境変数 ASIRLOADPATH に設定されているディレクトリを左から順にサーチする. それらに該当するファイルが存在しない場合, 標準ライブラリディレクトリ (あるいは環境変数 ASIR_LIBDIR に設定されているディレクトリ) もサーチする.

  * 読み込むファイルの最後に, end$ がないと load() 終了後にプロンプトがでないが, 実際には入力を受け付ける. しかし, 混乱を招くおそれがあるのでファイルの最後に end$ を書いておくことが望ましい. (end; でもよいが, end が返す値 0 が表示されるため, end$ をお勧めする. )

参照
     end, which

which
-----

which("FILENAME")
     :: 引数 FILENAME に対し, load() が読み込むパス名を返す.

return
     パス名

filename
     ファイル名 (パス名) または 0

  * load() がファイルをサーチする手順に従ってサーチし, ファイルが存在する場合にはパス名を文字列として, 存在しない場合には 0 を返す.

  * サーチの手順については load() を参照.

     [0] which("gr");
     ./gb/gr
     [1] which("/usr/local/lib/gr");
     0
     [2] which("/usr/local/lib/asir/gr");
     /usr/local/lib/asir/gr

参照
     load

output
------

output(["FILENAME"])
     :: 以降の出力先を FILENAMEまたは標準出力に切替える.

return
     1

filename
     ファイル名

  * Asir の出力を標準出力から, ファイルへの出力に切替える. なお, ファイル出力の間は, 標準出力にはキーボードからの入力以外, 出力されない.

  * 別のファイル出力に切替える時には, 再び output("FILENAME") を実行する. 又, ファイル出力を終了し標準出力に戻りたい時には, 引数なしで output() を実行する.

  * 指定したファイル FILENAME が存在した時は, そのファイルの末尾に追書きされ, 存在しなかった時には, 新たにファイルを作成し, そこに書き込まれる.

  * ファイルネームを "" ダブルクォートなしで指定をしたり, ユーザが, 書き込めないファイルを指定したりすると, エラーによりトップレベルに戻る.

  * 入力したものも込めてファイルに出力したい場合には, ctrl("echo",1) を実行した後でファイル出力に切替えれば良い.

  * 計算時間など, 標準エラー出力に書き出されるものはファイルには書き出されない.

  * 函数形式, 未定係数 (vtype() 参照) を含まない数式のファイルへの読み書きは, bload(), bsave() を使うのが, 時間, 空間ともに効率がよい.

     [83] output("afo");
     fctr(x^2-y^2);
     print("afo");
     output();
     1
     [87] quit;
     % cat afo
     1
     [84] [[1,1],[x+y,1],[x-y,1]]
     [85] afo
     0
     [86]

参照
     ctrl, bload, bsave

bsave, bload
------------

bsave(OBJ,"FILENAME")
     :: FILENAME に OBJ をバイナリ形式で書き込む.

bsave("FILENAME")
     :: FILENAME から数式をバイナリ形式で読み込む.

return
     bsave() : 1, bload() : 読み込んだ数式

obj
     函数形式, 未定係数を含まない任意の数式

filename
     ファイル名

  * bsave() は内部形式をほぼそのままバイナリ形式でファイルに書き込む. bload() は, bsave() で書き込んだ数式を読み込んで内部形式に変換する. 現在のインプリメンテーションの制限により, 函数形式, 未定係数 (vtype() 参照) を含まないリスト, 配列などを含む任意の数式をファイルに保存することができる.

  * output() などで保存した場合, 読み込み時にパーザが起動されるが, bsave() で保存したものを bload() で読む場合, 直接内部形式が構成できるため, 時間的, 空間的に効率がよい.

  * 多項式の場合, 書き込み時と読み込み時で変数順序が異なる場合があるが, その場合には, 自動的に現在の変数順序における内部形式に変換される.

     [0] A=(x+y+z+u+v+w)^20$
     [1] bsave(A,"afo");
     1
     [2] B = bload("afo")$
     [3] A == B;
     1
     [4] X=(x+y)^2;
     x^2+2*y*x+y^2
     [5] bsave(X,"afo")$
     [6] quit;
     % asir
     [0] ord([y,x])$
     [1] bload("afo");
     y^2+2*x*y+x^2

参照
     output

print
-----

print(OBJ [,NL])
     :: OBJ を表示する.

return
     0

obj
     任意

nl
     フラグ (任意)

  * OBJ を評価して表示する.

  * 第 2 引数が 0 の場合改行せず, それ以外は改行する.

  * この函数の戻り値は 0 であるから, print(); で実行すると, 出力の後に 0 が返される. print()$ とすれば, 最後の 0 は出力されない.

  * 複数の OBJ を同時に出力したい時は OBJ をリストにするとよい.

     [8] def cat(L) { while ( L != [] ) { print(car(L),0); L = cdr(L);} print(""); }
     [9] cat([xyz,123,"gahaha"])$
     xyz123gahaha

プロセス間通信
=======

tcpinit, tcpdebug, tcpclose
---------------------------

tcpinit(HOST,COMMAND [,DISPLAY])
     :: 遠隔プロセスの起動および通信を開始する.

tcpdebug(HOST,COMMAND [,DISPLAY])
     :: 遠隔プロセスの起動のための shell コマンドを返す.

tcpclose(ID)
     :: 遠隔プロセスを終了させ, 通信を終了する.

ping(OBJ)
     :: 数式を遠隔プロセスに送り, 返された数式を返す.

return
     tcpinit() : 整数, tcpdebug() : 文字列, ping() : 任意

host, command, display
     文字列

id
     整数

obj
     函数形式, 未定係数を含まない任意の数式

  * tcpinit() は, ホスト HOST 上でコマンド COMMAND を起動し, このプロセスと通信を開始する.

  * 返される整数は, 実際にはオープンされた TCP/IP ストリームのソケット番号である.

  * UNIX 版においては, グラフィックスは別プロセスで処理される. これらの函数は, グラフィックスに限らず一般に分散計算を行うためのツールとして用いることができる.

  * Asir と通信するプロセスは同一のマシン上で動作している必要はない. また, 通信におけるバイトオーダは big-endian に統一してあるため, 相手先のマシンとバイトオーダが異なっていても構わない.

  * 以下の準備が必要である. ここで, Asir の動いているホストを A, 通信相手のプロセスが起動されるホストを B とする.

      1. ホスト B の csh のサーチパスに起動されるプログラムのあるディレクトリをいれる. プログラムは rsh で起動される. したがって, ホスト B のサーチパスに そのプログラムが入っていない場合には起動できない. この場合絶対パスを与えるか, ‾/.cshrc のサーチパスにそのプログラムのあるディレクトリを追加する必要がある. その際, 相手先ホストにおけるディレクトリであることを忘れないようにすること.

      2. ホスト B の ‾/.rhosts に, ホスト A のホスト名を登録する.

      3. asir_plot など, X とのコネクションも用いられる場合, Xserver に対し, 必要なホストを authorize させる. xhost で必要なホスト名を追加すればよい.

      4. COMMAND によっては, スタックを大量に使用するものもあるため, .cshrc でスタックサイズを大きめ (16MB 程度) に指定しておくのが安全である. スタックサイズは limit stacksize 16m などと指定する.

  * COMMAND が, X 上にウインドウを開ける場合, DISPLAYが指定されればその文字列を, 省略時には環境変数 DISPLAY の値を用いる.

  * tcpdebug() は, tcpinit() と全く同じ引数をとり, tcpinit() が rsh により遠隔プロセスを起動する際のコマンドラインを返す. 更に, Asir は, tcpinit() と同様遠隔プロセスからの通信開始要求を待つ. この函数は, tcpinit() がうまく遠隔プロセスを起動できない場合に, 返された文字列を, COMMAND を起動するマシン上で shell から直接実行してみて, 起動できない理由を調べたり, あるいは COMMAND をデバッグする場合に用いる.

  * tcpclose() は番号 ID の入出力ストリームを閉じる. ID は tcpinit() により返された値である. これにより通信は終了し, 遠隔プロセスは終了する.

  * Asir が正常した場合には全ての入出力ストリームは自動的に閉じられ, 起動されているプロセスは全て終了するが, 異常終了した場合, 遠隔プロセスが終了しない場合もある. Asir が異常終了した場合, 遠隔プロセスを起動したマシン上で ps などを起動して, もし Asir から起動したプロセスが残っている場合, kill する必要がある.

  * ping() は, COMMAND として asir_ping を用いて tcpinit()を呼び出した後使用可能な函数で, 通信が正しく行われているかどうかをテストするために用いる.

  * ping() は引数をそのまま asir_ping に送る. asir_ping は送られたデータをそのまま Asir に返送し, ping() はそれをユーザに返す.

     [15] tcpinit("localhost","asir_ping");
     7
     [16] ping(xyz);
     xyz
     [17] tcpclose(7);
     0
     [18] tcpdebug("localhost","asir_ping");
     rsh localhost -n "asir_ping geisha 1040 otemoyan:0.0>&/dev/null&">/dev/null
     ------------------------------------
     /* マシン localhost 上で */
     % asir_ping geisha 1040 otemoyan:0.0
     ------------------------------------
     7
     [19] ping((x+y)^10);
     x^10+10*y*x^9+45*y^2*x^8+120*y^3*x^7+210*y^4*x^6+252*y^5*x^5+210*y^6*x^4
     +120*y^7*x^3+45*y^8*x^2+10*y^9*x+y^10
     [20] tcpclose(7);
     0

参照
     ifplot

陰函数の描画
======

ifplot, conplot, plot
---------------------

ifplot(POLY [,GEOMETRY] [,XRANGE] [,YRANGE] [,ID] [,NAME])
     :: 2 変数多項式の実数上での零点を表示する.

conplot(POLY [,GEOMETRY] [,XRANGE] [,YRANGE] [,ZRANGE] [,ID] [,NAME])
     :: 2 変数多項式の実数上での等高線を表示する.

plot(POLY [,GEOMETRY] [,XRANGE] [,ID] [,NAME])
     :: 1 変数多項式で表される函数のグラフを表示する.

plotover(POLY,ID,NUMBER)
     :: すでに存在しているウィンドウへ描画する.

return
     整数

poly
     多項式

geometry, xrange, yrange, zrange
     リスト

id, number
     整数

name
     文字列

  * ifplot() は, 2 変数の多項式 POLY の実数上での零点, すなわち実代数曲線のグラフの表示を行う. conplot() は, 同様の引数に対し, 等高線の表示を行う. plot() は, 1 変数多項式を 1 変数函数と見なしてそのグラフの表示を行う. UNIX 版 (X11 上),  Mac 版で動作する.

  * UNIX 版は, 遠隔プロセスにより実現されている. コマンドは asir_plot で, tcpinit() により起動しておく必要がある.

  * Mac 版では直接これらの函数を起動できる.

  * 引数の内, POLY は必須である. その他の引数はオプションである. オプションの形式およびそのデフォルト値 (カッコ内) は次の通り.

     geometry
          ウィンドウのサイズをドット単位で [X,Y] で指定する. (UNIX 版では [400,400], Mac 版では [200,200].)

     xrange, yrange
          変数の範囲の指定で, [V,VMIN,VMAX] で指定する. (いずれの変数も [V,-2,2].) この指定がない場合, POLY に含まれる変数の内変数順序の上の変数が x, 下の変数が y として扱われる. これを避けるためには XRANGE, YRANGE を指定する. また, POLY が 1 変数の場合, これらの指定は必須となる.

     zrange
          conplot() の場合のみ指定できる. 形式は [V,VMIN,VMAX [,STEP ]] で, STEP が指定された場合には, 等高線の間隔が (VMAX-VMIN)/STEP となる. ([Z,-2,2,16].)

     id
          遠隔プロセスの番号, すなわち tcpinit() が返した番号を指定する. (一番最近に作られ, かつアクティブなプロセスに対応する番号.)

     name
          ウィンドウの名前. (Plot.) 生成されたウィンドウのタイトルは NAME:N/M となる. これは, プロセス番号 N のプロセスの, M 番のウィンドウを意味する. この番号は, plotover() で用いられる.

  * 引数は, bigfloat を含んではいけない. すなわち引数に現れる浮動小数は, 全て倍精度浮動小数でなければならない.

  * 一つのプロセス上で描画できるウィンドウの数は最大 128 個である.

  * plotover() は, 指定したウィンドウ上に, 引数である 2 変数多項式の零点を上書きする.

  * 描画終了後のウィンドウ上で, マウスの左ボタンを押しながらのドラッグで範囲を指定しボタンを離すと新たなウィンドウが生成され, 指定した範囲が拡大して表示される. ドラッグは左上から右下へと行う. ドラッグを始めた後キャンセルする場合は, マウスポインタを始点の上か左に持っていってボタンを離せばよい. 新しいウインドウの形は, 指定領域と相似で, 最大辺が, 元のウィンドウの最大辺と一致するように定められる. 以下で説明する precise が on の場合, 選択した領域が同一 window 上で書き直される.

  * ウィンドウ内で右ボタンを押すと, その点の座標がウィンドウの下部に表示される.

  * conplot() で生成したウィンドウにおいて, ウィンドウの右側のマーカを中ボタンでドラッグすると, 対応する等高線の色が変わり, 右上のウィンドウに対応するレベルが表示される.

  * UNIX 版ではいくつかのボタン, Mac 版ではプルダウンメニューによりいくつかの設定変更, 操作ができる. UNIX 版では次のボタンがある.

     quit
          window を破壊する. 計算中の場合, 計算を中断する.

     wide (トグル)
          現在の表示部分を縦横各 10 倍した領域を表示する. 現在表示されている範囲はこの表示において中央部に長方形で示される. この表示で範囲指定を行うと, その範囲が新しいウィンドウに描画される.

     precise (トグル)
          選択領域を, 整数演算により, より正確に再描画する. このモードでは Sturm 列と二分法により, 区間内の零点の個数を正確に求めていくもので, デフォルトの計算法よりも正確な描画が期待できる. ただし, 描画時間は余計にかかる場合が多い. この説明から明らかなように, この機能は有理数係数の多項式の描画に対してのみ有効である. ((x^2+y^2-1)^2 の描画で試してみよ.)

     formula
          対応する式を表示する.

     noaxis (トグル)
          座標軸を消す.

  * asir_plot が起動されるマシンによっては, スタックを大量に使用するものもあるため, .cshrc でスタックサイズを大きめ (16MB 程度) に指定しておくのが安全である. スタックサイズは limit stacksize 16m などと指定する.

  * X では、ウインドウの各部分について resource により色付けや、ボタンの形を変えることができる。 resource の指定の仕方は以下の通り。（デフォルトを示しておく） plot*form*shapeStyle は、rectangle, oval, ellipse, roundedRectangle が、指定できる。

          plot*background:white
          plot*form*shapeStyle:rectangle
          plot*form*background:white
          plot*form*quit*background:white
          plot*form*wide*background:white
          plot*form*precise*background:white
          plot*form*formula*background:white
          plot*form*noaxis*background:white
          plot*form*xcoord*background:white
          plot*form*ycoord*background:white
          plot*form*level*background:white
          plot*form*xdone*background:white
          plot*form*ydone*background:white

     [0] tcpinit("geisha","asir_plot");
     7
     [1] ifplot(x^2+y^2-1)$
     [2] ifplot(x^5-2*y*x^2+y^5,[200,200])$
     [3] ifplot(x^6+3*y^2*x^4+(3*y^4-4*y^2)*x^2+y^6)$
     [4] ifplot(x^4+(2*y^2+3*y)*x^2+y^4-y^3)$
     [5] conplot(2*x^4-3*x^2*y+y^2-2*y^3+y^4,[y,-1,3],"Mask")$
     [6] conplot(x^6+(43/12*y^2-3)*x^4+(88/27*y^4+46/3*y^2+3)*x^2+64/729*y^6-
             16/27*y^4+4/3*y^2-1,[x,-3,3],[y,-3,3])$
     [7] plot(256*x^8-512*x^6+304*x^4-48*x^2+1,[x,-1,1])$
     [8] ifplot(364816*x^6+(9214800*y^2+8937600*y-121625)*x^4+(2520000*y^4-
             2250000*y^3-18877500*y^2-12656250*y+1880000)*x^2+4000000*y^6+
             3000000*y^5-8250000*y^4-4437500*y^3+6187500*y^2+1687500*y-1687500)$

参照
     tcpinit, tcpclose

その他
===

ctrl
----

ctrl("SWITCH",ONOFF)
     :: 環境設定

return
     0 または 1

switch
     スイッチ名

onoff
     フラグ (任意)

  * Asir の実行環境の設定変更を行う. フラグが 0 ならばスイッチ SWITCH を off にし, それ以外ならば on にする.

  * スイッチは文字列として入力する. すなわちダブルクォートで囲む.

  * スイッチは次の通り.

     cputime
          on の時 CPU time および GC time を表示, off の時 表示しない. cputime() を参照. ctrl("cputime",ONOFF) は cputime(ONOFF) と同じである.

     nez
          EZGCD のアルゴリズムの切替え. デフォルトで 1 であり, とくに切替える必要はない.

     echo
          on の時は標準入力を繰り返して出力し, off の時は標準入力を繰り返さない. output コマンドを用いる際に有効である.

     bigfloat
          on の時, 入力された浮動小数は bigfloat に変換され, 浮動小数演算は PARI (see pari) により行われる. デフォルトの有効桁数は 9 桁である. 有効桁数を増やしたい時には setprec() を用いる. off の時, 入力された浮動小数は, 倍精度浮動小数に変換される.

  * 成功した場合には 1 を, 失敗したとき又は用意されたスイッチ以外のものを指定した場合には 0 を返す.

参照
     cputime, output, pari, setprec, eval

debug
-----

debug
     :: デバッグモードに入る.

  * debug は無引数の函数であるが, () なしで呼び出せる.

  * デバッグモードに入るとプロンプトが (debug) となり, コマンド受け付け状態となる. quit を入力するとデバッガから抜ける.

  * デバッグモードについての詳細は see デバッガ.

     [1] debug;
     (debug) quit
     0
     [2]

error
-----

error(MESSAGE)
     :: プログラム中で強制的にエラーを発生させる.

message
     文字列

  * 一般に, 引数の間違いなど, 続行不可能なエラーが組み込み函数において発生した時, トップレベルに戻る前に, 可能ならばそのエラーの時点でデバッグモードに入る. error() は, ユーザ函数の内部でこの動作と同様の動作を行わせるための函数である.

  * 引数は, error() が呼び出される際に表示されるメッセージで, 文字列である.

  * ユーザ函数において, 変数をチェックして, あり得ない値の場合に error() を呼び出すようにしておけば, その時点で自動的にデバッグモードに入れる.

     % cat mod3
     def mod3(A) {
             if ( type(A) >= 2 )
                     error("invalid argument");
             else
                     return A % 3;
     }
     end$
     % asir
     [0] load("mod3");
     1
     [3] mod3(5);
     2
     [4] mod3(x);
     invalid argument
     stopped in mod3 at line 3 in file "./mod3"
     3                       error("invalid argument");
     (debug) print A
     A = x
     (debug) quit
     return to toplevel
     [4]

参照
     debug

help
----

help(["FUNCTION"])
     :: 函数の説明を表示する.

return
     0

function
     函数名

  * 無引数の時, 最小限の説明が表示される. 函数名が引数として与えられたとき, 標準ライブラリディレクトリにある help というディレクトリに同名のファイルがあれば, 環境変数 PAGER に設定されているコマンド, あるいは more を呼び出してそのファイルを表示する.

  * Mac 版では未対応.

time
----

time()
     :: セッション開始から現在までの CPU 時間および GC 時間を表示する

return
     リスト

  * CPU 時間および GC 時間の表示に関するコマンドである.

  * GC 時間とは, ガーベジコレクタにより消費されたと見なされる時間, CPU 時間は, 全体の CPU 時間から GC 時間を引いた残りで, 単位は秒である.

  * time() は引数なしで, セッション開始から現在までの CPU 時間, GC 時間, および現在までに要求されたメモリののべ容量の表示をする. すなわち, [CPU 時間 (秒), GC 時間 (秒), メモリ量 (ワード)] なるリストを返す. 1 ワードは通常 4 バイトである.

  * 計算の実行開始時, 終了時の time() から, その計算に対する CPU 時間, GC 時間がわかる.

  * メモリ量は多倍長数ではないため, ある値を越えると無意味な値となるためあくまでも目安として用いるべきである.

  * ctrl() や cputime() により cputime スイッチが on になっている場合には, トップレベルの文を一つの単位として, その実行時間が表示される. しかし, プログラムの内部などで, 特定の計算に対する計算時間を知りたい時には, time() などを使う必要がある.

  * getrusage() が使える UNIX 上では time() は信頼性のある値を返すが, DOS, Mac 上では時刻を用いるほか方法がないため経過時間そのものが表示される. よって, デバッグモードに入ったり, 割り込みプロンプトでの待ち状態があると, それも経過時間に加算される. 特に, PC98 の場合, 時刻は秒単位で返されるため, 短時間で終る計算に対しては, time() の返す値はほとんど無意味である. また, getrusage() が使えない UNIX (HP-UX など) においては clock() により CPU 時間を得ているが, この函数の性質上ある程度以上の時間 (HP-UX の場合 2147 秒) が経過するとやはり無意味な値となる.

     [72] T0=time();
     [0.24,0.03,22861]
     [73] G=hgrm(katsura(4),[u4,u3,u2,u1,u0])$
     [74] T1=time();
     [2.48,1.37,1934543]
     [75] ["CPU",T1[0]-T0[0],"GC",T1[1]-T0[1]];
     [CPU,2.24,GC,1.34]

参照
     cputime, tstart, tstop

cputime, tstart, tstop
----------------------

cputime(ONOFF)
     :: 引数が 0 ならば cputime の表示を止める. それ以外ならば表示を行う.

tstart()
     :: CPU time 計測開始.

tstop()
     :: CPU time 計測終了および表示.

return
     0

onoff
     フラグ (任意)

  * cputime() は, 引数が 0 ならば CPU time の表示を止める. それ以外ならば表示を行う.

  * tsart は引数なし, () なしで, CPU time 計測を開始する.

  * tstop は引数なし, () なしで, CPU time 計測を終了, および表示する.

  * cputime(ONOFF) は ctrl("cputime",ONOFF) と同じである.

  * tstart, tstop は, 入れ子にして使われることは想定していないため, そのような可能性がある場合には, time() による計測を行う必要がある.

  * cputime() による on, off は, 単に表示の on, off であり, トップレベルの一つの文に対する計測は常に行われている. よって, 計算を始めてからでも, 計算終了前にデバッガに入って cputime(1) を実行させれば計算時間は表示される.

     [49] tstart$
     [50] fctr(x^10-y^10);
     [[1,1],[x+y,1],[x^4-y*x^3+y^2*x^2-y^3*x+y^4,1],[x-y,1],
     [x^4+y*x^3+y^2*x^2+y^3*x+y^4,1]]
     [51] tstop$
     80msec + gc : 40msec
     [52] grm(katsura(4),[u4,u3,u2,u1,u0])$
     ^Cinterrupt ?(q/t/c/d/w/?) d
     stopped in gbcheck at line 186 in file "./gb/gr"
     186                     if ( !ZERO(H) )
     (debug) print cputime(1)
     cputime(1) = 0
     (debug) c
     580msec + gc : 320msec
     [53]

参照
     time, ctrl

heap
----

heap()
     :: 現在のヒープの大きさを返す. (単位:バイト)

return
     自然数

  * 現在のヒープの大きさ(単位 : バイト) を返す. ヒープとは, Asir のさまざまな数式や, ユーザプログラムなどがおかれるメモリの領域で, ガーベジコレクタにより管理されている. プログラムの動作中は, ヒープの大きさは単調非減少であり, 実メモリの量をこえて大きくなった場合には, OS によるスワップエリアへの読み書きがほとんどの計算時間を占めることになる.

  * 実メモリが少ない場合には, 起動時の -adj オプションにより, GC 主体の設定を行っておく必要がある.

     % asir -adj 16
     [0] load("fctrdata")$
     0
     [97] cputime(1)$
     0msec
     [98] heap();
     524288
     0msec
     [99] fctr(Wang[8])$
     3.190sec + gc : 3.420sec
     [100] heap();
     1118208
     0msec
     [101] quit;
     % asir
     [0] load("fctrdata")$
     0
     [97] cputime(1)$
     0msec
     [98] heap();
     827392
     0msec
     [99] fctr(Wang[8])$
     3.000sec + gc : 1.180sec
     [100] heap();
     1626112
     0msec
     [101] quit;

参照
     コマンドラインオプション

version
-------

version()
     :: Asir のバージョンを返す.

return
     自然数

  * Asir のバージョンを 10 進 6 桁の自然数で返す. 最初の 2 桁が西暦の下 2 桁, 次の 2 桁が月, 最後の 2 桁が日を表す.

     [0] version();
     940216

shell
-----

shell(COMMAND)
     :: COMMAND をシェルコマンドとして実行する.

return
     自然数

command
     文字列

  * COMMAND を C の system() 函数によりシェルコマンドとして実行する. シェルの終了ステータスを返す.

     [0] shell("ls");
     alg             da              katsura         ralg            suit
     algt            defs.h          kimura          ratint          test
     alpi            edet            kimura3         robot           texput.log
     asir.o          fee             mfee            sasa            wang
     asir_symtab     gr              mksym           shira           wang_data
     base            gr.h            mp              snf1            wt
     bgk             help            msubst          solve
     chou            hom             p               sp
     const           ifplot          proot           strum
     cyclic          is              r               sugar
     0
     [1]

グレブナ基底の計算
*********

分散表現多項式
=======

分散表現多項式とは, 多項式の内部形式の一つである. 通常の多項式 (type が 2) は, 再帰表現と呼ばれる形式で表現されている. すなわち, 特定の変数を主変数とする 1 変数多項式で, その他の変数は, その 1 変数多項式の係数に, 主変数を含まない多項式として現れる. この係数が, また, ある変数を主変数とする多項式となっていることから再帰表現と呼ばれる.

     (x+y+z)^2 = 1 x^2 + (2 y + (2 z)) x + ((2 z) y + (1 z^2 ))

これに対し, 多項式を, 変数の冪積と係数の積の和として表現したものを分散表現と呼ぶ.

     (x+y+z)^2 = 1 x^2 + 2 xy + 2 xz + 1 y^2 + 2 yz +1 z^2$

グレブナ基底計算においては, 単項式に注目して操作を行うため多項式が分散表現されている方がより効率のよい演算が可能になる. このため, 分散表現多項式が, 識別子 9 の型として Asir のトップレベルから利用可能となっている. ここで, 後の説明のために, いくつかの言葉を定義しておく.

項 (term)

     変数の冪積. すなわち, 係数 1 の単項式のこと. Asir においては,

          <<0,1,2,3,4>>

     という形で表示され, また, この形で入力可能である. この例は, 5 変数の項を示す. 各変数を a, b, c, d, e とするとこの項は b*c^2*d^3*e^4 を表す.

単項式 (monomial)

     項と係数の積.

          2*<<0,1,2,3,4>>

     という形で表示され, また, この形で入力可能である.

頭単項式 (head monomial)

頭項 (head term)
頭係数 (head coefficient)

     分散表現多項式における各単項式は, ある全順序により整列される. この時順序最大の単項式を頭単項式, それに現れる項, 係数をそれぞれ頭項, 頭係数と呼ぶ.

ファイルの読み込み
=========

グレブナ基底を計算するためのツールは, 組み込み函数としてではなく, Asir 言語で書かれたファイル gr を load() により読み込むことにより使用可能となる. gr は, Asir の標準ライブラリディレクトリに置かれている. よって, 環境変数 ASIR_LIBDIR を特に異なるパスに設定しない限り, ファイル名のみで読み込むことができる.

     [0] load("gr")$

函数, オプション
=========

函数
--

gr では数多くの函数, オプション等が定義されているが, 実際に使用するものはそう多くない. グレブナ基底計算のためのトップレベルは次の 4 つである. 以下で, PLIST は多項式のリスト, VLIST は変数 (不定元) のリストである.

gr(PLIST,VLIST)

     Gebauer-Moeller-Sugar アルゴリズムによるグレブナ基底計算函数. 一般にはこの函数を用いる.

grm(PLIST,VLIST)

     モジュラ演算を用いて gr() の高速化を図ったもの. 入力イデアルが 0 次元, すなわち入力多項式リストの多項式の共通零点の個数が有限個であると推測される時, gr() と比較して劇的に高速化される場合がある.

hgr(PLIST,VLIST)

     斉次化を経由してグレブナ基底を求める函数. Sugar による仮想的な斉次化に比較して, 安定して良いストラテジを与えるが, 不必要対が増加するのが難点であり, 通常は, hgrm() を用いる. 変数順序は, DegRevLex と Lex の場合にのみ有効.

hgrm(PLIST,VLIST)

     hgr() の欠点を, モジュラ演算により解消したもの. grm() と同様 0 次元イデアルに対して有効である. 特に, grm() でも計算が行き詰まってしまった場合など, 最後の手段として用いることが多い.

オプション
-----

グレブナ基底の計算においては, さまざまな状況設定が必要となる. それらは具体的にには大域変数の設定として行われる.

Ord

     単項式の順序は, 引数の VLIST で与えられた変数間の順序を元に, 大域変数 Ord の値により決められる. 詳細は後述する.

PRINT

     PRINT が 0 でないとき, グレブナ基底計算の途中におけるさまざまな情報を表示する. 大きな計算を行う場合, 途中経過を知ることで, 中断して他の設定での再計算を行うなどの決定をする場合に便利である.

NOREDUCE

     最終的に得られたグレブナ基底は, 相互正規化を行って, 互いに他の基底により簡約できない正規グレブナ基底として出力されるが, NOREDUCE が 0 でない時, この操作を行うことを抑制する.

NOSUGAR

     NOSUGAR が 0 でない場合, Sugar ストラテジの代わりに Buchberger の Normal ストラテジが用いられる.

NOCRIB

     NOCRIB が 0 でない場合, 不必要対検出規準のうち, 規準 B を適用しない.

NOGC

     NOGC が 0 でない場合, grm(), hgrm() において結果がグレブナ基底になっているかどうかのチェックを行わない.

NOMC

     NOMC が 0 でない場合, grm(), hgrm() において結果が入力イデアルと同等のイデアルであるかどうかのチェックを行わない.

これらの変数の初期値は全て 0 である. また, NOREDUCE 以下は, 通常は変更の必要はない. PRINT は必要に応じて on-off すればよい. 重要なのは, Ord および引数の変数順序の設定である.

Ord, 変数順序の設定
============

Ord は, 変数順序の型を設定する. Ord は 0 から 8 までの整数値をとれるが, 通常用いられるのは 0, 1, 2 の 3 つである.

0 (DegRevLex; 全次数逆辞書式順序)

     一般に, この順序によるグレブナ基底計算が最も高速である. ただし, 方程式を解くという目的に用いることは, 一般にはできない. この順序によるグレブナ基底は, 解の個数の計算, イデアルのメンバシップや, 他の変数順序への基底変換のためのソースとして用いられる.

1 (DegLex; 全次数辞書式順序)

     この順序も, 辞書式順序に比べて高速にグレブナ基底を求めることができるが, DegRevLex と同様直接その結果を用いることは困難である. しかし, 辞書式順序のグレブナ基底を求める際に, 斉次化後にこの順序でグレブナ基底を求めている.

2 (Lex; 辞書式順序)

     この順序によるグレブナ基底は, 方程式を解く場合に最適の形の基底を与えるが計算時間がかかり過ぎるのが難点である. 特に, 解が有限個の場合, 結果の係数が極めて長大な多倍長数になる場合が多い. この場合, grm(), hgrm() による計算が極めて有効になる場合が多い.

これらの順序の具体的な定義およびグレブナ基底に関する更に詳しい解説は [Becker,Weispfenning] などを参照のこと.

Ord の設定の他に, 変数の順序自体も計算時間に大きな影響を与える.

     [90] B=[x^10-t,x^8-z,x^31-x^6-x-y]$
     0msec
     [91] Ord=2$
     0msec
     [92] gr(B,[x,y,z,t])$
     [x^2-2*y^7+(-41*t^2-13*t-1)*y^2+(2*t^17-12*t^14+42*t^12+30*t^11-168*t^9
     -40*t^8+70*t^7+252*t^6+30*t^5-140*t^4-168*t^3+2*t^2-12*t+16)*z^2*y
     +(-12*t^16+72*t^13-28*t^11-180*t^10+112*t^8+240*t^7+28*t^6-127*t^5
     -167*t^4-55*t^3+30*t^2+58*t-15)*z^4,
     (y+t^2*z^2)*x+y^7+(20*t^2+6*t+1)*y^2+(-t^17+6*t^14-21*t^12-15*t^11+84*t^9
     +20*t^8-35*t^7-126*t^6-15*t^5+70*t^4+84*t^3-t^2+5*t-9)*z^2*y+(6*t^16-36*t^13
     +14*t^11+90*t^10-56*t^8-120*t^7-14*t^6+64*t^5+84*t^4+27*t^3-16*t^2-30*t+7)*z^4,
     (t^3-1)*x-y^6+(-6*t^13+24*t^10-20*t^8-36*t^7+40*t^5+24*t^4-6*t^3-20*t^2-6*t-1)*y
     +(t^17-6*t^14+9*t^12+15*t^11-36*t^9-20*t^8-5*t^7+54*t^6+15*t^5+10*t^4-36*t^3
     -11*t^2-5*t+9)*z^2,
     -y^8-8*t*y^3+16*z^2*y^2+(-8*t^16+48*t^13-56*t^11-120*t^10+224*t^8+160*t^7
     -56*t^6-336*t^5-112*t^4+112*t^3+224*t^2+24*t-56)*z^4*y+(t^24-8*t^21+20*t^19
     +28*t^18-120*t^16-56*t^15+14*t^14+300*t^13+70*t^12-56*t^11-400*t^10-84*t^9
     +84*t^8+268*t^7+84*t^6-56*t^5-63*t^4-36*t^3+46*t^2-12*t+1)*z,
     2*t*y^5+z*y^2+(-2*t^11+8*t^8-20*t^6-12*t^5+40*t^3+8*t^2-10*t-20)*z^3*y+8*t^14
     -32*t^11+48*t^8-t^7-32*t^5-6*t^4+9*t^2-t,
     -z*y^3+(t^7-2*t^4+3*t^2+t)*y+(-2*t^6+4*t^3+2*t-2)*z^2,
     2*t^2*y^3+z^2*y^2+(-2*t^5+4*t^2-6)*z^4*y+(4*t^8-t^7-8*t^5+2*t^4-4*t^3+5*t^2-t)*z,
     z^3*y^2+2*t^3*y+(-t^7+2*t^4+t^2-t)*z^2,
     -t*z*y^2-2*z^3*y+t^8-2*t^5-t^3+t^2,
     -t^3*y^2-2*t^2*z^2*y+(t^6-2*t^3-t+1)*z^4,
     z^5-t^4]
     530msec + gc : 280msec
     [93] gr(B,[t,z,y,x]);
     [x^10-t,x^8-z,x^31-x^6-x-y]
     0msec + gc : 10msec

順序 [x,y,z,t] におけるグレブナ基底は, 基底の数も多く, それぞれの式も大きい. しかし, 順序 [t,z,y,x] にもとでは, B がすでにグレブナ基底となっている. 大雑把にいえば, 辞書式順序でグレブナ基底を求めることは, 左側の (順序の高い) 変数を, 右側の (順序の低い) 変数で書き表すことであり, この例の場合は, t,  z, y が既に x で表されていることからこのような極端な結果となったわけである. 実際に現れる計算においては, このように選ぶべき変数順序が明らかであることは少なく, 試行錯誤が必要な場合もある.

有理式を係数とするグレブナ基底計算
=================

gr() などのトップレベル函数は, いずれも, 入力多項式リストに現れる変数 (不定元) と, 変数リストに現れる変数を比較して, 変数リストにない変数が入力多項式に現れている場合には, 自動的に, その変数を, 係数体の元として扱う.

     [63] Ord=2$
     [64] gr([a*x+b*y-c,d*x+e*y-f],[x,y]);
     [(-e*a+d*b)*x-f*b+e*c,(-e*a+d*b)*y+f*a-d*c]

この例では, a, b, c, d が係数体の元として扱われる. すなわち, 有理函数体 F = Q(a,b,c,d) 上の 2 変数多項式環 F[x,y] におけるグレブナ基底を求めることになる. 注意すべきことは, 係数が体として扱われていることである. すなわち, 係数の間に多項式としての共通因子があった場合には, 結果からその因子は除かれているため, 有理数体上の多項式環上の問題として考えた場合の結果とは一般には異なる.

グレブナ基底に関する函数
============

gr, grm, hgr, hgrm
------------------

gr(PLIST,VLIST)
grm(PLIST,VLIST)
hgr(PLIST,VLIST)
hgrm(PLIST,VLIST)
     :: グレブナ基底の計算

return
     リスト

plist, vlist
     リスト

  * 標準ライブラリの gr で定義されている.

  * いずれも, 多項式リスト PLIST の, 変数順序 VLIST に関するグレブナ基底を求める.

  * VLIST は不定元のリスト. VLIST に現れない不定元は, 係数体に属すると見なされる.

  * grm(), hgrm() はモジュラ演算を用いた高速化, hgr() hgrm() は斉次化を用いた安定化を行う.

  * 変数順序型は, 大域変数 Ord の値が用いられる.

  * 解が有限個と推測される場合には, grm(), hgrm() が有効.

     [0] load("gr")$
     [44] Ord=2$
     [45] load("cyclic")$
     [55] P=cyclic(5);
     [c4*c3*c2*c1*c0-1,(((c3+c4)*c2+c4*c3)*c1+c4*c3*c2)*c0+c4*c3*c2*c1,
     ((c2+c4)*c1+c4*c3)*c0+c3*c2*c1+c4*c3*c2,(c1+c4)*c0+c2*c1+c3*c2+c4*c3,
     c0+c1+c2+c3+c4]
     [56] G=grm(P,[c0,c1,c2,c3,c4]);
     [c0+c1+c2+c3+c4,...]

参照
     Ord

dp_ord
------

dp_ord(ORDER)
     :: 変数順序型の設定

return
     1

order
     整数

  * 変数順序型を ORDER に設定する. gr() 等のトップレベル函数は大域変数 Ord の値を dp_ord() の引数として変数順序型を設定している.

  * トップレベル函数以外の函数を直接呼び出す場合には, この函数により変数順序型を正しく設定しなければならない.

     [19] dp_ord(0)$
     [20] <<1,2,3>>+<<3,1,1>>;
     (1)*<<1,2,3>>+(1)*<<3,1,1>>
     [21] dp_ord(2)$
     [22] <<1,2,3>>+<<3,1,1>>;
     (1)*<<3,1,1>>+(1)*<<1,2,3>>

参照
     Ord

dp_ptod
-------

dp_ptod(POLY,VLIST)
     :: 多項式を分散表現多項式に変換する.

return
     分散表現多項式

poly
     多項式

vlist
     リスト

  * 変数順序 VLIST および現在の変数順序型に従って分散表現多項式に変換する.

  * VLIST に含まれない不定元は, 係数体に属するとして変換される.

     [50] dp_ord(0);
     1
     [51] dp_ptod((x+y+z)^2,[x,y,z]);
     (1)*<<2,0,0>>+(2)*<<1,1,0>>+(1)*<<0,2,0>>+(2)*<<1,0,1>>+(2)*<<0,1,1>>
     +(1)*<<0,0,2>>
     [52] dp_ptod((x+y+z)^2,[x,y]);
     (1)*<<2,0>>+(2)*<<1,1>>+(1)*<<0,2>>+(2*z)*<<1,0>>+(2*z)*<<0,1>>+(z^2)*<<0,0>>

参照
     dp_dtop, dp_ord

dp_dtop
-------

dp_dtop(DPOLY,VLIST)
     ::

return
     多項式

dpoly
     分散表現多項式

vlist
     リスト

  * 分散表現多項式を, 与えられた不定元リストを用いて多項式に変換する.

  * 不定元リストは, 長さ分散表現多項式の変数の個数と一致していれば何でもよい.

     [53] T=dp_ptod((x+y+z)^2,[x,y]);
     (1)*<<2,0>>+(2)*<<1,1>>+(1)*<<0,2>>+(2*z)*<<1,0>>+(2*z)*<<0,1>>+(z^2)*<<0,0>>
     [54] P=dp_dtop(T,[a,b]);
     z^2+(2*a+2*b)*z+a^2+2*b*a+b^2

dp_nf
-----

dp_nf(INDEXLIST,DPOLY,DPOLYARRAY,FULLREDUCE)
     :: 分散表現多項式の正規形を求める.

return
     分散表現多項式

indexlist
     リスト

dpoly
     分散表現多項式

dpolyarray
     配列

fullreduce
     フラグ

  * 分散表現多項式 DPOLY の正規形を求める.

  * DPOLYARRAY は分散表現多項式を要素とするベクトル, INDEXLIST は正規化計算に用いる DPOLYARRAY の要素のインデックスのリスト.

  * FULLREDUCE が 0 でないとき全ての項に対して簡約を行う. FULLREDUCE が 0 のとき頭項のみに対して簡約を行う.

  * INDEXLIST で指定された多項式は, 前の方のものが優先的に使われる.

  * 一般には INDEXLIST の与え方により函数の値は異なる可能性があるが, グレブナ基底に対しては一意的に定まる.

     [0] load("gr")$
     [45] load("katsura")$
     [50] K=katsura(4)$
     [51] length(K)$
     5
     [52] Ord=2$
     [53] dp_ord(2)$
     [54] DP1=newvect(5)$
     [55] V=[u0,u1,u2,u3,u4]$
     [56] for(I=0;I<5;I++)DP1[I]=dp_ptod(K[I],V);
     [57] G=gr(K,V)$
     [58] length(G);
     5
     [59] DP2=newvect(5)$
     [60] for(I=0;I<5;I++)DP2[I]=dp_ptod(G[I],V);
     [61] T=dp_ptod((u0-u1+u2-u3+u4)^2,V)$
     [62] dp_dtop(dp_nf([0,1,2,3,4],T,DP1,1),V);
     u4^2+(6*u3+2*u2+6*u1-2)*u4+9*u3^2+(6*u2+18*u1-6)*u3+u2^2+(6*u1-2)*u2+9*u1^2-6*u1+1
     [63] dp_dtop(dp_nf([4,3,2,1,0],T,DP1,1),V);
     -5*u4^2+(-4*u3-4*u2-4*u1)*u4-u3^2-3*u3-u2^2+(2*u1-1)*u2-2*u1^2-3*u1+1
     [64] dp_dtop(dp_nf([0,1,2,3,4],T,DP2,1),V);
     -1138087976845165778088612297273078520347097001020471455633353049221045677593
     0005716505560062087150928400876150217079820311439477560587583488*u4^15+...
     [65] dp_dtop(dp_nf([4,3,2,1,0],T,DP2,1),V);
     -1138087976845165778088612297273078520347097001020471455633353049221045677593
     0005716505560062087150928400876150217079820311439477560587583488*u4^15+...
     [66] @64==@65;
     1

参照
     dp_dtop, dp_ord, p_nf

dp_hm, dp_ht, dp_hc, dp_rest
----------------------------

dp_hm(DPOLY)
     :: 頭単項式を取り出す.

dp_ht(DPOLY)
     :: 頭項を取り出す.

dp_hc(DPOLY)
     :: 頭係数を取り出す.

dp_rest(DPOLY)
     :: 頭単項式を取り除いた残りを返す.

return
     dp_hm(), dp_ht(), dp_rest() : 分散表現多項式, dp_hc() : 数または多項式

dpoly
     分散表現多項式

  * これらは, 分散表現多項式の各部分を取り出すための函数である.

  * 分散表現多項式 P に対し次が成り立つ.

     P = dp_hm(P) + dp_rest(P)

     dp_hm(P) = dp_hc(P) dp_ht(P)

     [87] dp_ord(0)$
     [88] X=ptozp((a46^2+7/10*a46+7/48)*u3^4-50/27*a46^2-35/27*a46-49/216)$
     [89] T=dp_ptod(X,[u3,u4,a46])$
     [90] dp_hm(T);
     (2160)*<<4,0,2>>
     [91] dp_ht(T);
     (1)*<<4,0,2>>
     [92] dp_hc(T);
     2160
     [93] dp_rest(T);
     (1512)*<<4,0,1>>+(315)*<<4,0,0>>+(-4000)*<<0,0,2>>+(-2800)*<<0,0,1>>
     +(-490)*<<0,0,0>>

dp_td, dp_sugar, dp_true_sugar
------------------------------

dp_td(DPOLY)
     :: 頭項の全次数を返す.

dp_sugar(DPOLY)
     :: 多項式の sugar を返す.

dp_true_sugar([ONOFF])
     :: dp_sugar() が, 全次数を意味するか, 本来の sugar を意味するかの選択, 表示.

return
     自然数

dpoly
     分散表現多項式

onoff
     フラグ

  * dp_td() は, 頭項の全次数, すなわち各変数の指数の和を返す.

  * 分散表現多項式が生成されると, sugar と呼ばれるある整数が付与される. この値は dp_true_sugar() により設定される値が 0 の時多項式としての全次数, 0 でない時, 仮想的に斉次化して計算した場合に結果が持つ全次数の値となる. デフォルトでは 0 が設定されている. すなわち dp_sugar() は多項式としての全次数を返す.

  * dp_true_sugar() は, 引数がある場合, 引数が 0 ならば 0, 引数が 0 でないならば 1 を内部のフラグの値に設定する. 引数のあるなしにかかわらず, 現在 (設定後) の状態を返す.

  * sugar は, グレブナ基底計算における正規化対の選択のストラテジを決定するための重要な指針となる.

     [87] dp_ord(0)$
     [88] X=ptozp((a46^2+7/10*a46+7/48)*u3^4-50/27*a46^2-35/27*a46-49/216)$
     [89] T=dp_ptod(X,[u3,u4,a46])$
     [90] dp_td(dp_rest(T));
     5
     [91] dp_true_sugar();
     0
     [92] dp_sugar(T);
     6

dp_lcm
------

dp_lcm(DPOLY1,DPOLY2)
     :: 最小公倍項を返す.

return
     分散表現多項式

dpoly1, dpoly2
     分散表現多項式

  * それぞれの引数の頭項の最小公倍項を返す. 係数は 1 である.

     [100] dp_lcm(<<1,2,3,4,5>>,<<5,4,3,2,1>>);
     (1)*<<5,4,3,4,5>>

参照
     dp_ht

dp_redble
---------

dp_redble(DPOLY1,DPOLY2)
     :: 頭項どうしが整除可能かどうか調べる.

return
     整数

dpoly1, dpoly2
     分散表現多項式

  * DPOLY1 の頭項が DPOLY2 の頭項で割り切れれば 1, 割り切れなければ 0 を返す.

  * 多項式の簡約を行う際, どの項を簡約できるかを探すのに用いる.

     [148] C;
     (1)*<<1,1,1,0,0>>+(1)*<<0,1,1,1,0>>+(1)*<<1,1,0,0,1>>+(1)*<<1,0,0,1,1>>
     [149] T;
     (3)*<<2,1,0,0,0>>+(3)*<<1,2,0,0,0>>+(1)*<<0,3,0,0,0>>+(6)*<<1,1,1,0,0>>
     [150] for ( ; T; T = dp_rest(T)) print(dp_redble(T,C));
     0
     0
     0
     1

参照
     dp_red

dp_subd
-------

dp_subd(DPOLY1,DPOLY2)
     :: 頭項の商単項式を返す.

return
     分散表現多項式

dpoly1, dpoly2
     分散表現多項式

  * dp_ht(DPOLY1)/dp_ht(DPOLY2) を求める. 結果の係数は 1 である.

  * 割り切れることがあらかじめわかっている必要がある.

     [162] dp_subd(<<1,2,3,4,5>>,<<1,1,2,3,4>>);
     (1)*<<0,1,1,1,1>>

参照
     dp_red

dp_red
------

dp_red(DPOLY1,DPOLY2,DPOLY3)
     :: 一回の簡約操作

return
     リスト

dpoly1, dpoly2, dpoly3
     分散表現多項式

vlist

  * DPOLY1 + DPOLY2 なる分散表現多項式を DPOLY3 で 1 回簡約する.

  * 簡約される項は DPOLY2 の頭項である. 従って, DPOLY2 の頭項が DPOLY3 の頭項で割り切れることがあらかじめわかっていなければならない.

  * 引数が整数係数の時, 簡約は, 分数が現れないよう, 整数 A, B, 項 T により A(DPOLY1 + DPOLY2)-BT DPOLY3 として計算される.

  * 結果は, [A DPOLY1,A DPOLY2 - BT DPOLY3] なるリストである.

     [157] D=(3)*<<2,1,0,0,0>>+(3)*<<1,2,0,0,0>>+(1)*<<0,3,0,0,0>>;
     (3)*<<2,1,0,0,0>>+(3)*<<1,2,0,0,0>>+(1)*<<0,3,0,0,0>>
     [158] R=(6)*<<1,1,1,0,0>>;
     (6)*<<1,1,1,0,0>>
     [159] C=12*<<1,1,1,0,0>>+(1)*<<0,1,1,1,0>>+(1)*<<1,1,0,0,1>>;
     (12)*<<1,1,1,0,0>>+(1)*<<0,1,1,1,0>>+(1)*<<1,1,0,0,1>>
     [160] dp_red(D,R,C);
     [(6)*<<2,1,0,0,0>>+(6)*<<1,2,0,0,0>>+(2)*<<0,3,0,0,0>>,(-1)*<<0,1,1,1,0>>
     +(-1)*<<1,1,0,0,1>>]

参照
     dp_nf

p_nf
----

p_nf(POLY,PLIST,VLIST,OTYPE)
     :: 多項式の正規形を求める.

return
     多項式

poly
     多項式

plist,vlist
     リスト

otype
     整数

  * gr で定義されている.

  * 多項式の, 多項式リストによる正規形を求める.

  * dp_nf() に対する一つのインタフェースである.

  * POLY および PLIST は, 変数順序 VLIST および変数順序型 OTYPE に従って分散表現多項式に変換され, dp_nf() に渡される.

  * dp_nf() は FULLREDUCE が 1 で呼び出される.

  * 結果は多項式に変換されて出力される.

  * 内部で dp_ord(OTYPE) を実行するため, 大域変数 Ord と実際の設定が異なることもあり得る.

     [78] Ord = 2$
     [79] K = katsura(5)$
     [80] V = [u5,u4,u3,u2,u1,u0]$
     [81] NOCRIB = 1$
     [82] G = grm(K,V)$
     [83] p_nf(K[1],G,V,2);
     0
     [84] p_nf(K[1],G,V,1);
     2*u4*u0+(2*u3+2*u5)*u1+u2^2-u4

参照
     dp_ptod, dp_dtop, dp_ord, dp_nf

p_terms
-------

p_terms(POLY,VLIST)
     :: 多項式にあらわれる単項をリストにする.

return
     リスト

poly
     多項式

vlist
     リスト

  * gr で定義されている.

  * 多項式を単項に展開した時に現れる項をリストにして返す. 項の順序はその時の変数順序型および VLIST の順序による.

  * グレブナ基底はしばしば係数が巨大になるため, 実際にどの項が現れているのかを見るためなどに用いる.

     [232] Ord=2$
     [233] G=grm(katsura(5),[u5,u4,u3,u2,u1,u0])$
     [234] p_terms(G[0],[u5,u4,u3,u2,u1,u0]);
     [u5,u0^31,u0^30,u0^29,u0^28,u0^27,u0^26,u0^25,u0^24,u0^23,u0^22,u0^21,u0^20,
     u0^19,u0^18,u0^17,u0^16,u0^15,u0^14,u0^13,u0^12,u0^11,u0^10,u0^9,u0^8,u0^7,
     u0^6,u0^5,u0^4,u0^3,u0^2,u0,1]

katsura, hkatsura, cyclic, hcyclic
----------------------------------

katsura(N)

hkatsura(N)

cyclic(N)

hcyclic(N)
     :: 多項式リストの生成

return
     リスト

n
     整数

  * katsura() は katsura, cyclic() は cyclic で定義されている.

  * グレブナ基底計算でしばしばテスト, ベンチマークに用いられる katsura, cyclic およびその斉次化を生成する.

  * cyclic は Arnborg, Lazard, Davenport などの名で呼ばれることもある.

     [74] load("katsura")$
     [79] load("cyclic")$
     [89] katsura(5);
     [u0+2*u4+2*u3+2*u2+2*u1+2*u5-1,2*u4*u0-u4+2*u1*u3+u2^2+2*u5*u1,
     2*u3*u0+2*u1*u4-u3+(2*u1+2*u5)*u2,2*u2*u0+2*u2*u4+(2*u1+2*u5)*u3-u2+u1^2,
     2*u1*u0+(2*u3+2*u5)*u4+2*u2*u3+2*u1*u2-u1,
     u0^2-u0+2*u4^2+2*u3^2+2*u2^2+2*u1^2+2*u5^2]
     [90] hkatsura(5);
     [-t+u0+2*u4+2*u3+2*u2+2*u1+2*u5,
     -u4*t+2*u4*u0+2*u1*u3+u2^2+2*u5*u1,-u3*t+2*u3*u0+2*u1*u4+(2*u1+2*u5)*u2,
     -u2*t+2*u2*u0+2*u2*u4+(2*u1+2*u5)*u3+u1^2,
     -u1*t+2*u1*u0+(2*u3+2*u5)*u4+2*u2*u3+2*u1*u2,
     -u0*t+u0^2+2*u4^2+2*u3^2+2*u2^2+2*u1^2+2*u5^2]
     [91] cyclic(6);
     [c5*c4*c3*c2*c1*c0-1,
     ((((c4+c5)*c3+c5*c4)*c2+c5*c4*c3)*c1+c5*c4*c3*c2)*c0+c5*c4*c3*c2*c1,
     (((c3+c5)*c2+c5*c4)*c1+c5*c4*c3)*c0+c4*c3*c2*c1+c5*c4*c3*c2,
     ((c2+c5)*c1+c5*c4)*c0+c3*c2*c1+c4*c3*c2+c5*c4*c3,
     (c1+c5)*c0+c2*c1+c3*c2+c4*c3+c5*c4,c0+c1+c2+c3+c4+c5]
     [92] hcyclic(6);
     [-c^6+c5*c4*c3*c2*c1*c0,
     ((((c4+c5)*c3+c5*c4)*c2+c5*c4*c3)*c1+c5*c4*c3*c2)*c0+c5*c4*c3*c2*c1,
     (((c3+c5)*c2+c5*c4)*c1+c5*c4*c3)*c0+c4*c3*c2*c1+c5*c4*c3*c2,
     ((c2+c5)*c1+c5*c4)*c0+c3*c2*c1+c4*c3*c2+c5*c4*c3,
     (c1+c5)*c0+c2*c1+c3*c2+c4*c3+c5*c4,c0+c1+c2+c3+c4+c5]

参照
     dp_dtop, Ord

代数的数に関する演算
**********

代数的数の表現
=======

Asir においては, 代数体という対象は定義されない. 独立した対象として定義されるのは, 代数的数である. 代数体は, 有理数体に, 代数的数を有限個順次添加した体として仮想的に定義される. 新たな代数的数は, 有理数およびこれまで定義された代数的数の多項式を係数とする 1 変数多項式を定義多項式として定義される. 以下, ある定義多項式の根として定義された代数的数を, root と呼ぶことにする.

     [0] A0=newalg(x^2+1);
     (#0)
     [1] A1=newalg(x^3+A0*x+A0);
     (#1)
     [2]  [type(A0),ntype(A0)];
     [1,2]

この例では, A0 は x^2+1=0 の根, A1 は, その A0 を係数に含む x^3+A0*x+A0=0 の根として定義されている.

newalg() の引数すなわち定義多項式には次のような制限がある.

 1. 定義多項式は 1 変数多項式でなければならない.

 2. newalg() の引数である定義多項式は, 代数的数を含む式の簡単化のために用いられる. この簡単化は, 組み込み函数 srem() に相当する内部ルーチンを用いて行われる. このため, 定義多項式の主係数は, 有理数になっている必要がある.

 3. 定義多項式の係数は すでに定義されている root の有理数係数多項式でなければならない.

 4. 定義多項式は, その係数に含まれる全ての root を有理数に添加した体上で既約でなければならない.

newalg() が行う引数チェックは, 1 および 2 のみである. 特に, 引数の定義多項式の既約性は全くチェックされない. これは既約性のチェックが多大な計算量を必要とするためで, この点に関しては, ユーザの責任に任されている.

一旦 newalg() によって定義された代数的数は, 数としての識別子を持ち, また, 数の中では代数的数としての識別子を持つ. (type(), vtype() 参照.) さらに, 有理数と, root の有理式も同様に代数的数となる.

     [87] N=(A0^2+A1)/(A1^2-A0-1);
     ((#1+#0^2)/(#1^2-#0-1))
     [88] [type(N),ntype(N)];
     [1,2]

例からわかるように, rootは #N と表示される. しかし, ユーザはこの形では入力できない. root は変数に格納して用いるか, あるいは alg(N) により取り出す. また, 効率は落ちるが, 全く同じ引数 (変数は異なっていてもよい) により newalg() を呼べば, 新しい代数的数は定義されずに既に定義されたものが得られる.

     [90] alg(0);
     (#0)
     [91] newalg(t^2+1);
     (#0)

root の定義多項式は, defpoly() により取り出せる.

     [96] defpoly(A0);
     t#0^2+1
     [97] defpoly(A1);
     t#1^3+t#0*t#1+t#0

ここで現れた, t#0, t#1 はそれぞれ #0, #1 に対応する不定元である. これらもユーザが入力することはできない. var() で取り出すか, あるいは algv(N) により取り出す.

     [98] var(@);
     t#1
     [99] algv(0);
     t#0
     [100]

代数的数の演算
=======

前節で, 代数的数の表現, 定義について述べた. ここでは, 代数的数を用いた演算について述べる. 代数的数に関しては, 組み込み函数として提供されている機能はごく少数で, 大部分はユーザ定義函数により実現されている. ファイルは, sp で, gr と同様 Asir の標準ライブラリディレクトリにおかれている. なお, sp で定義された函数の中には gr のグレブナ基底函数を用いるものもあるので, 同時に load() しておくとよい.

     [0] load("gr")$
     [1] load("sp")$

あるいは, 常に用いるならば, $HOME/.asirrc に書いておくのもよい.

root は その他の数と同様, 四則演算が可能となる. しかし, 定義多項式による簡単化は自動的には行われないので, ユーザの判断で適宜行わなければならない. 特に, 分母が 0 になる場合に致命的なエラーとなるため, 実際に分母を持つ代数的数を生成する場合には細心の注意が必要となる.

代数的数の, 定義多項式による簡単化は, simpalg() で行う.

     [49] T=A0^2+1;
     (#0^2+1)
     [50] simpalg(T);
     0

simpalg() は有理式の形をした代数的数を, 多項式の形に簡単化する.

     [39] A0=newalg(x^2+1);
     (#0)
     [40] T=(A0^2+A0+1)/(A0+3);
     ((#0^2+#0+1)/(#0+3))
     [41] simpalg(T);
     (3/10*#0+1/10)
     [42] T=1/(A0^2+1);
     ((1)/(#0^2+1))
     [43] simpalg(T);
     div : division by 0
     stopped in invalgp at line 258 in file "/usr/local/lib/asir/sp"
     258                     return 1/A;
     (debug)

この例では, 分母が 0 の代数的数を簡単化しようとして 0 による除算が生じたため, ユーザ定義函数である simpalg() の中でデバッガが呼ばれたことを示す. simpalg() は, 代数的数を係数とする多項式の各係数を簡単化できる.

     [43] simpalg(1/A0*x+1/(A0+1));
     (-#0)*x+(-1/2*#0+1/2)

代数的数を係数とする多項式の基本演算は, 適宜 simpalg() を呼ぶことを除けば通常の場合と同様であるが, 因数分解などで頻繁に用いられるノルムの計算などにおいては, root を不定元に置き換える必要が出てくる. この場合, algptorat() を用いる.

     [83] A0=newalg(x^2+1);
     (#0)
     [84] A1=newalg(x^3+A0*x+A0);
     (#1)
     [85] T=(2*A0+A1*A0+A1^2)*x+(1+A1)/(2+A0);
     (#1^2+#0*#1+2*#0)*x+((#1+1)/(#0+2))
     [86] S=algptorat(T);
     (((t#0+2)*t#1^2+(t#0^2+2*t#0)*t#1+2*t#0^2+4*t#0)*x+t#1+1)/(t#0+2)
     [87] algptorat(coef(T,1));
     t#1^2+t#0*t#1+2*t#0

このように, algptorat() は, 多項式, 数に含まれる root を, 対応する不定元, すなわち #N に対する t#N に置き換える. 既に述べたように, この不定元はユーザが入力することはできない. これは, ユーザの入力した不定元と, root に対応する不定元が一致しないようにするためである.

逆に, root に対応する不定元を, 対応する root に置き換えるためには rattoalgp() を用いる.

     [88] rattoalgp(S,[alg(0)]);
     (((#0+2)/(#0+2))*t#1^2+((#0^2+2*#0)/(#0+2))*t#1+((2*#0^2+4*#0)/(#0+2)))*x
     +((1)/(#0+2))*t#1+((1)/(#0+2))
     [89] rattoalgp(S,[alg(0),alg(1)]);
     (((#0^3+6*#0^2+12*#0+8)*#1^2+(#0^4+6*#0^3+12*#0^2+8*#0)*#1+2*#0^4+12*#0^3
     +24*#0^2+16*#0)/(#0^3+6*#0^2+12*#0+8))*x+(((#0+2)*#1+#0+2)/(#0^2+4*#0+4))
     [90] rattoalgp(S,[alg(1),alg(0)]);
     (((#0+2)*#1^2+(#0^2+2*#0)*#1+2*#0^2+4*#0)/(#0+2))*x+((#1+1)/(#0+2))
     [91] simpalg(@89);
     (#1^2+#0*#1+2*#0)*x+((-1/5*#0+2/5)*#1-1/5*#0+2/5)
     [92] simpalg(@90);
     (#1^2+#0*#1+2*#0)*x+((-1/5*#0+2/5)*#1-1/5*#0+2/5)

rattoalgp() は, 置換の対象となる root のリストを第 2 引数にとり, 左から順に, 対応する不定元を置き換えて行く. この例は, 置換する順序を換えると簡単化を行わないことにより結果が一見異なるが, 簡単化により実は一致することを示している. algptorat(), rattoalgp() は, ユーザが独自の簡単化を行いたい場合などにも用いることができる.

代数体上での 1 変数多項式の演算
=================

sp では, 1 変数多項式に限り, GCD, 因数分解およびそれらの応用として最小分解体を求める函数を提供している.

GCD
---

代数体上での GCD は gcda() により計算される. この函数は, gr のグレブナ基底を用いている. モジュラ演算による方法が実用上最も高速とされているが, 現在 Asir 上では実現されていないため, 次善の策としてグレブナ基底を用いている.

     [0] X=x^6+3*x^5+6*x^4+x^3-3*x^2+12*x+16;
     x^6+3*x^5+6*x^4+x^3-3*x^2+12*x+16
     [1] A=newalg(X);
     (#0)
     [2] S = x^3+(3*A+3)*x^2+(3*A^2+6*A+3)*x+(A^3+3*A^2+3*A+4);
     x^3+(3*#0+3)*x^2+(3*#0^2+6*#0+3)*x+(#0^3+3*#0^2+3*#0+4)
     [3] load("gr")$
     [47] load("sp")$
     [86] gcda(X,S);
     12*x^2+(-#0^5-#0^4-2*#0^3+7*#0^2+13*#0+8)*x+(-2*#0^5-4*#0^4-8*#0^3+14*#0^2
     +16*#0-16)

無平方分解, 因数分解
-----------

無平方分解は, 多項式とその微分との GCD の計算から始まるもっとも一般的なアルゴリズムを採用している. このため, 無平方の場合に最も計算時間が多くかかることになる. 函数は asq() である.

     [116] A=newalg(x^2+x+1);
     (#4)
     [117] T=simpalg((x+A+1)*(x^2-2*A-3)^2*(x^3-x-A)^2);
     x^11+(#4+1)*x^10+(-4*#4-8)*x^9+(-10*#4-4)*x^8+(16*#4+20)*x^7+(24*#4-6)*x^6
     +(-29*#4-31)*x^5+(-15*#4+28)*x^4+(38*#4+29)*x^3+(#4-23)*x^2+(-21*#4-7)*x
     +(3*#4+8)
     [118] asq(T);
     [[x^5+(-2*#4-4)*x^3+(-#4)*x^2+(2*#4+3)*x+(#4-2),2],[x+(#4+1),1]]

結果は通常と同様に, [因子, 重複度] のリストとなるが, 全ての因子の積は, もとの多項式と定数倍の差はあり得る. これは, 因子を整数係数にして見やすくするためで, 因数分解でも同様である.

代数体上での因数分解は, Trager によるノルム法を改良したもので, 特にある多項式に対し, その根を添加した体上でその多項式自身を因数分解する場合に特に有効である.

     [119] af(T,[A]);
     [[x^3-x+(-#4),2],[x^2+(-2*#4-3),2],[x+(#4+1),1]]

引数は 2 つで, 第 2 引数は, root のリストである. 因数分解は有理数体に, それらの root を添加した体上で行われる. root の順序には制限がある. すなわち, 後で定義されたものほど前の方にこなければならない. 並べ換えは, 自動的には行われない. ユーザの責任となる.

     [120] B=newalg(x^2-2*A-3);
     (#5)
     [121] af(T,[B,A]);
     [[x+(#5),2],[x^3-x+(-#4),2],[x+(-#5),2],[x+(#4+1),1]]

最小分解体
-----

やや特殊な演算ではあるが, 前節の因数分解を反復適用することにより, 多項式の最小分解体を求めることができる. 函数は sp() である.

     [103] sp(x^5-2);
     [[x+(-#1),2*x+(#0^3*#1^3+#0^4*#1^2+2*#1+2*#0),2*x+(-#0^4*#1^2),2*x
     +(-#0^3*#1^3),x+(-#0)],[[(#1),t#1^4+t#0*t#1^3+t#0^2*t#1^2+t#0^3*t#1+t#0^4],
     [(#0),t#0^5-2]]]

sp() は 1 引数で, 結果は [1 次因子のリスト, [[root, algptorat(定義多項式)] のリスト] なるリストである. 第 2 要素の [root,algptorat(定義多項式)] のリストは, 右から順に, 最小分解体が得られるまで添加していった root を示す. その定義多項式は, その直前までの root を添加した体上で既約であることが保証されている.

結果の第 1 要素である 1 次因子のリストは, 第 2 要素の root を全て添加した体上での, sp() の引数の多項式の全ての因子を表す. その体は最小分解体となっているので, 因子は全て 1 次となるわけである. af() と同様, 全ての因子の積は, もとの多項式と定数倍の差はあり得る.

代数的数に関する函数のまとめ
==============

newalg
------

newalg(DEFPOLY)
     :: root を生成する.

return
     代数的数 (root)

defpoly
     多項式

  * DEFPOLY を定義多項式とする代数的数 (root) を生成する.

  * DEFPOLY に対する制限に関しては, see 代数的数の表現.

     [0] A0=newalg(x^2-2);
     (#0)

参照
     defpoly

defpoly
-------

defpoly(ALG)
     :: root の定義多項式を返す.

return
     多項式

alg
     代数的数 (root)

  * root ALG の定義多項式を返す.

  * root を #N とすれば, 定義多項式の主変数は t#N となる.

     [1] defpoly(A0);
     t#0^2-2

参照
     newalg, alg, algv

alg
---

alg(I)
     :: インデックスに対応する root を返す.

return
     代数的数 (root)

i
     整数

  * root #I を返す.

  * #I はユーザが直接入力できないため, alg(I) という形で入力する.

     [2] x+#0;
     syntax error
     0
     [3] alg(0);
     (#0)

参照
     newalg, algv

algv
----

algv(I)
     :: alg(I) に対応する不定元を返す.

return
     多項式

i
     整数

  * 多項式 t#I を返す.

  * t#I はユーザが直接入力できないため, algv(I) という形で入力する.

     [4] var(defpoly(A0));
     t#0
     [5] t#0;
     syntax error
     0
     [6] algv(0);
     t#0

参照
     newalg, defpoly, alg

simpalg
-------

simpalg(RAT)
     :: 有理式に含まれる代数的数を簡単化する.

return
     有理式

rat
     有理式

  * sp で定義されている.

  * 数, 多項式, 有理式に含まれる代数的数を, 含まれる root の定義多項式により簡単化する.

  * 数の場合, 分母があれば有理化され, 結果は root の多項式となる.

  * 多項式の場合, 各係数が簡単化される.

  * 有理式の場合, 分母分子が多項式として簡単化される.

     [7] simpalg((1+A0)/(1-A0));
     simpalg undefined
     return to toplevel
     [7] load("sp")$
     [46] simpalg((1+A0)/(1-A0));
     (-2*#0-3)
     [47] simpalg((2-A0)/(2+A0)*x^2-1/(3+A0));
     (-2*#0+3)*x^2+(1/7*#0-3/7)
     [48] simpalg((x+1/(A0-1))/(x-1/(A0+1)));
     (x+(#0+1))/(x+(-#0+1))

algptorat
---------

algptorat(POLY)
     :: 多項式に含まれる root を, 対応する不定元に置き換える.

return
     多項式

poly
     多項式

  * sp で定義されている.

  * 多項式に含まれる root #N を全て t#N に置き換える.

     [49] algptorat((-2*alg(0)+3)*x^2+(1/7*alg(0)-3/7));
     (-2*t#0+3)*x^2+1/7*t#0-3/7

参照
     defpoly, algv

rattoalgp
---------

rattoalgp(POLY,ALGLIST)
     :: 多項式に含まれる root に対応する不定元を root に置き換える.

return
     多項式

poly
     多項式

alglist
     リスト

  * sp で定義されている.

  * 第 2 引数は root のリストである. rattoalgp() は, この root に対応する不定元を, それぞれ root に置き換える.

     [51] rattoalgp((-2*algv(0)+3)*x^2+(1/7*algv(0)-3/7),[alg(0)]);
     (-2*#0+3)*x^2+(1/7*#0-3/7)

参照
     alg, algv

gcda
----

gcda(POLY1,POLY2)
     :: 代数体上の 1 変数多項式の GCD

return
     多項式

poly1, poly2
     多項式

  * sp で定義されている.

  * 2 つの 1 変数多項式の GCD を求める.

  * グレブナ基底を用いている. 従って gr も読み込んでおく必要がある.

     [52] X=simpalg((x-A0-2)^2*(x+A0-1)^3);
     x^5+(#0-7)*x^4+(-8*#0+15)*x^3+(17*#0-13)*x^2+(-6*#0+14)*x+(2*#0-2)
     [53] Y=simpalg((x-A0-2)^3*(x+A0-1)^2);
     x^5+(-#0-8)*x^4+(4*#0+21)*x^3+(#0-14)*x^2+(-12*#0-10)*x+(-2*#0-4)
     [54] gcda(X,Y);
     grm undefined
     stopped in gcda at line 357 in file "/usr/local/lib/asir/sp"
     357             L = grm(ML,cons(var(P1),VL));
     (debug) quit
     return to toplevel
     [54] load("gr")$
     [98] gcda(X,Y);
     -x^4+6*x^3+(2*#0-9)*x^2+(-6*#0)*x-2

参照
     gr, asq

sp_norm
-------

sp_norm(ALG,VAR,POLY,ALGLIST)
     :: 代数体上でのノルムの計算

return
     多項式

var
     POLY の主変数

poly
     1 変数多項式

alg
     root

alglist
     root のリスト

  * sp で定義されている.

  * POLY の, ALG に関するノルムをとる. すなわち, K = Q(ALGLIST ¥ {ALG}) とするとき, POLY に現れる ALG を, ALG の K 上の共役に置き換えたもの全ての積を返す.

  * 結果は K 上の多項式となる.

  * 計算は, res() および中国剰余定理により行なわれる.

     [0] load("sp")$
     [39] A0=newalg(x^2+1)$
     [40] A1=newalg(x^2+A0)$
     [41] sp_norm(A1,x,x^3+A0*x+A1,[A1,A0]);
     x^6+(2*#0)*x^4+(#0^2)*x^2+(#0)
     [42] sp_norm(A0,x,@@,[A0]);
     x^12+2*x^8+5*x^4+1

参照
     res, af

asq, af
-------

asq(POLY)
     :: 代数体上の 1 変数多項式の無平方分解

af(POLY,ALGLIST)
     :: 代数体上の 1 変数多項式の因数分解

return
     リスト

poly
     多項式

alglist
     root のリスト

  * いずれも sp で定義されている. また gr も必要である.

  * root を含まない場合は整数上の函数が呼び出され高速であるが, root を含む場合には, gcda() が起動されるためしばしば極めて時間がかかる.

  * af() は, 基礎体の指定, すなわち第 2 引数の, root のリストの指定が必要である.

  * 第 2 引数が空リストすなわち [] の場合, fctr() が呼び出される.

  * alglist で指定される root は, 後で定義されたものほど前の方に来なければならない.

  * 結果は, 通常の無平方分解, 因数分解と同様 [因子, 重複度] のリストである.

  * 重複度を込めた因子の全ての積は, POLY と定数倍の違いがあり得る.

     [99] asq(-x^4+6*x^3+(2*alg(0)-9)*x^2+(-6*alg(0))*x-2);
     [[-x^2+3*x+(#0),2]]
     [100] af(-x^2+3*x+alg(0),[alg(0)]);
     [[x+(#0-1),1],[-x+(#0+2),1]]

参照
     gcda, sqfr

sp
--

sp(POLY)
     :: 最小分解体を求める.

return
     リスト

poly
     多項式

  * sp で定義されている. また gr も必要である.

  * 有理数係数の 1 変数多項式 POLY の最小分解体, およびその体上での POLY の 1 次因子への分解を求める.

  * 結果は, POLY の因子のリストと, 最小分解体の, 逐次拡大による表現からなるリストである.

  * 最小分解体は, [root,algptorat(defpoly(root))] のリストとして表現されている. すなわち, 求める最小分解体は, 有理数体に, この root を全て添加した体として得られる. 添加は, 右の方の root から順に行われる.

     [101] L=sp(x^9-54);
     [[x+(-#2),-54*x+(#1^6*#2^4),54*x+(#1^6*#2^4+54*#2),54*x+(-#1^8*#2^2),
     -54*x+(#1^5*#2^5),54*x+(#1^5*#2^5+#1^8*#2^2),-54*x+(-#1^7*#2^3-54*#1),
     54*x+(-#1^7*#2^3),x+(-#1)],[[(#2),t#2^6+t#1^3*t#2^3+t#1^6],[(#1),t#1^9-54]]]
     [102] for(I=0,M=1;I<9;I++)M*=L[0][I];
     [111] M=simpalg(M);
     -1338925209984*x^9+72301961339136
     [112] ptozp(M);
     -x^9+54

参照
     af, defpoly, algptorat

文法の詳細
*****

     <式>: (see さまざまな式)
         (<式>)
         <式> <二項演算子> <式>
         + <式>
         - <式>
         <左辺値>
         <左辺値> <代入演算子> <式>
         <左辺値> ++
         <左辺値> --
         ++ <左辺値>
         -- <左辺値>
         ! <式>
         <式> ? <式> : <式>
         <函数> ( <式並び> )
         <文字列>
         <指数ベクトル>
         <アトム>
         <リスト>

     <左辺値>:
         <変数> [[<式>]]*

     <二項演算子>:
         + - * / % ^(冪)
         == != < > <= >= && ||

     <代入演算子>:
         = += -= *= /= %= ^=

     <式並び>:
         <空>
         <式> [, <式>]*

     <リスト>:
         [ <式並び> ]

     <変数>: (see 変数および不定元)
         大文字で始まる文字列 (X,Y,Japan など)

     <函数>:
        小文字で始まる文字列 (fctr,gcd など)

     <アトム>:
        <不定元>
        <数>

     <不定元>: (see 変数および不定元)
        小文字で始まる文字列 (a,bCD,c1_2 など)

     <数>: (see 数の型)
        <有理数>
        <浮動小数>
        <代数的数>
        <複素数>

     <有理数>:
        0, 1, -2, 3/4

     <浮動小数>:
        0.0, 1.2e10

     <代数的数>: (see 代数的数に関する演算)
        newalg(x^2+1), alg(0)^2+1

     <複素数>:
        1+@i, 2.3*@i

     <文字列>:
        " で囲まれた文字列

     <指数ベクトル>: (see グレブナ基底の計算)
        << <式並び> >>

     <文>: (see 文)
         <式> <終端>
         <複文>
         break <終端>
         continue <終端>
         return <終端>
         return <式> <終端>
         if ( <式並び> ) <文>
         if ( <式並び> ) <文> else <文>
         for ( <式並び> ; <式並び> ; <式並び> ) <文>
         do <文> while ( <式並び> ) <終端>
         while ( <式並び> ) <文>
         def <函数> ( <式並び> ) { <変数宣言> <文並び> }
         end(quit) <終端>

     <終端>:
         ; $

     <変数宣言>:
         [extern <変数> [, <変数>]* <終端>]*

     <複文>:
         { <文並び> }

     <文並び>:
         [<文>]*

Macintosh 版 Risa/Asir
*********************

ファイル構成
======

     dist --- asir    680X0 (X>=2) 用 asir
           |
           |- asir-sc コプロなしの 680X0 (X>=2) 用 asir
           |
           |- asir-00 68000 用 asir
           |
           |- params メモリ管理に関するパラメタ
           |
           |- lib    --- gr      グレブナ基底パッケージ
                      |
                      |- wang    因数分解のテスト
                      |
                      |- defs.h
                      |
                      |- ...

params
======

params の内容は次の通り.

     stacksize=xxx adj=xxx paristack=xxx fontsize=xxx rows=xxx cols=xxx

xxx はいずれも 10 進数. 意味は,

stacksize
     Asir が使用する stack の大きさ.  単位はバイト.

adj
     adj が大きいほど GC の頻度が増す.

paristack
     PARI 用の heap の大きさ. デフォルトは 64 KB. 単位はバイト.

fontsize
     表示用フォントのサイズ.

rows
     ウィンドウの行数.

cols
     一行の文字数.

Asir には デフォルトの partition size が設定されている. この値は command+iで参照, 変更できる. 使用可能なメモリのサイズはこの値により制限されるため, 必要に応じて変更する必要がある. System 7 の仮想記憶が on になっている場合, 実装メモリの量を越えて設定することはできるが, 実際に実装メモリの量を越える計算を行う場合には, 極端に実行速度は低下する.

使用法
===

Asir を double click すると, Asir なる window が開く. その後は UNIX 版の Asir と同様である.

UNIX 版との相違点
===========

emacs キーバインディングによるヒストリ置き換えを含むコマンドライン編集が組み込まれている. ! によるヒストリの参照は !! と !string のみである. ヒストリが格納されるファイルは asir と同じディレクトリの history というファイルで, 最大 100 行のコマンドがセーブされる.

ファイルの読み込みは,

     [1] load(":dir_a:dir_b:...:filename");

による. カレントディレクトリのファイルの場合は, 先頭の : は省略できる. これはユーザに苦痛を強いるので, mini finder による読み込みも可能である. File menu の Load または, command+'L' により mini finder が open する.

また, 割り込みは, command+'.' で行う.

MS-DOS/DOS-Extender 版 Risa/Asir
*******************************

動作環境
====

Asir を 80386, 80486 を CPU とする MS-DOS パソコン上で, DOS-Extender を用いて動作させることができる. DOS-Extender は, go32と run386 の 2 種類に対応しているが, ここでは go32 版について述べる.

まず, 使用するパソコン上で動作する go32 を入手する. これは, IBM-PC 互換機, PC98 であれば, anonymous ftp, JUNET, パソコン通信ネットワーク (日経 MIX, NIFTY など) で入手できる. FM 用はやや入手困難の可能性があるが, やはり NIFTY などで入手可能と思われる. 手に入らない場合のために, ver1.10 の go32.exe が, 配布バイナリに付属している.

go32 の設定は, それ自身のマニュアルを参照のこと. 特に, 浮動小数点演算プロセッサを持たない機種では, 環境変数 EMU を正しく emulatorを使用するように設定しなければならない. また, asir 実行中に shell を呼び出して中断する場合, かなり大きいファイルが GO32TMPで指定されるディレクトリにできるので, ここはある程度余裕のあるディレクトリを指定しておく必要がある (10MB 程度).

入手方法を含むインストレーションについての詳細は, see インストレーション.

DOS 版の使用法
=========

起動は次のように行う.

     A> go32 asir
     [0]

或いは, stub.exe を先頭に付けた asir.exe の場合,

     A> asir
     [0]

でよい. 以後は, UNIX 版とほぼ同様であるが, 実行中の割り込みは, X により行う. C は, go32 自体を終了させるので使用してはいけない. また, Z により, shell (通常 command.com) を呼び出す. このshell を exit で終了させることにより, Asir の実行を継続できる. Mac 版と同様コマンドライン編集が組み込まれている. なお, graphics, dynamic object loading は未サポートである.

既に述べたように, DOS 版は UNIX 版と比較してさまざまな点で欠点, 不安定な点が多い. これらをまとめて述べておく.

  * internal error で Asir 自体が終了する. (see エラー処理)

  * C は Asir 自体を終了させるため, 割り込みは X を用いる. (see 割り込み)

  * 割り込みの検出は, メモリ管理部で独自に行っているため, PARI が呼び出されている間は割り込みが効かない.

  * Z あるいは help() により他のプログラムが呼び出される場合, go32 は Asir によって使用されているメモリ領域のほとんどをディスクに退避する. このため, 大きな計算の途中では, この操作に多くの時間がかかる場合がある. また, スワップエリアとして指定されているディスクの空き容量が小さいと, 容量不足で Asir あるいは最悪の場合 MS-DOS まで落ちてしまうこともある.

  * time() により報告される CPU 時間は, 計算に要した実際の経過時間である. (see time)

C の函数による機能追加
************

この節では, 現在の所ソースによる配布を受けた場合にのみ可能なことがらが説明されている.

インクリメンタルローディング
==============

ソースディレクトリのサブディレクトリ o には, C で記述されたインクリメンタルローディング用のいくつかのファイルがある. これらの詳しい説明はライブラリのマニュアルを参照のこと. これらは, o で make することにより ロード可能な状態になる. 現在, インクリメンタルローディングはSun, VAX, DECStation, RISC NEWS でのみサポートされている. それ以外の機械については次節参照のこと.

例えば, o/xxx.c をコンパイルする場合,

     % cd o
     % make xxx.o

とすることにより xxx.o ができる. あとは, load("xxx.o")によりロードできる.

R3000, R4000 を CPU とするマシンの場合, CFLAGS に -G 0 を追加する必要がある. これは, global pointer register による大域データの参照を避けるための操作である. 更に言えば, 共にリンクするライブラリもすべて -G 0 option つきでコンパイルしたものである必要がある.

asir.o を用いた機能追加
===============

Asir に, C で記述された函数を追加する方法として, 前節で述べた, インクリメンタルローディングによる方法の他に, asir.o を用いて新たなバイナリファイルを生成する方法がある. 特に, インクリメンタルローディングがサポートされていない機種においてはこれが唯一の拡張方法となる. asir.o は, 標準ライブラリディレクトリ (デフォルトでは /usr/local/lib/asir) にインストールされている.

asir.o は, reg_sysf() というシンボルが未定義になっている他は, asir と全く同様の機能を持つ. reg_sysf() をもつ他のオブジェクトファイルとリンクすることにより, 実行可能ファイルが作れるが, reg_sysf() が, 組み込み函数登録用の函数であった場合, そこで登録された函数は, インクリメンタルロードした場合と同様に使用可能となる. ここで述べた, reg_sysf() を持つオブジェクトファイルとして, 前節の o で作られた xxx.o ファイルを用いることができる.

<R3000, R4000 を CPU とする機械の場合>

     % cc -Wl,-D -Wl,2000000 /.../asir.o xxx.o -o yyy

<上記以外の機械の場合>

     % cc /.../asir.o xxx.o -o yyy

により yyy ができ, yyy は, xxx.o に含まれる函数が組み込まれた Asir となる. ここで, 前者の 2000000 は実際には, インストール時に include/Risa.tmpl で HEAP_START_ADDR として指定した値を用いる. デフォルト値は, ここに示された値である.

添付のユーザ定義函数ファイル
**************

標準ライブラリディレクトリ (デフォルトでは /usr/local/lib/asir) にはいくつかのユーザ定義函数ファイルがおかれている. これらのうちの主なものについて説明する.

gr
     グレブナ基底計算パッケージ.  (see グレブナ基底の計算)

sp
     代数的数の演算および因数分解, 最小分解体. (see 代数的数に関する演算)

alpi
bgk
cyclic
katsura
kimura
     グレブナ基底計算において, ベンチマークその他で用いられる例. (see katsura hkatsura cyclic hcyclic)

defs.h
     いくつかのマクロ定義. (see プリプロセッサ)

fctrtest
     整数上の多項式の因数分解のテスト. REDUCE の factor.tst および重複度の大きいいくつかの例を含む. これは, load() すると直ちに計算が始まる. 入手した Asir が正しく動作しているかのテストにも使うことができる.

fctrdata
     fctrtest で使われている例を含む, 因数分解テスト用の例. Alg[] に収められている例は, af() (see asq af) 用の例である.

          [0] load("gr")$
          [45] load("sp")$
          [84] load("fctrdata")$
          [175] cputime(1)$
          0msec
          [176] Alg[5];
          x^9-15*x^6-87*x^3-125
          0msec
          [177] af(Alg[5],[newalg(Alg[5])]);
          [[1,1],[75*x^2+(10*#0^7-175*#0^4-470*#0)*x+(3*#0^8-45*#0^5-261*#0^2),1],
          [75*x^2+(-10*#0^7+175*#0^4+395*#0)*x+(3*#0^8-45*#0^5-261*#0^2),1],
          [25*x^2+(25*#0)*x+(#0^8-15*#0^5-87*#0^2),1],[x^2+(#0)*x+(#0^2),1],
          [x+(-#0),1]]
          3.600sec + gc : 1.040sec

ifplot
     描画 (see ifplot conplot plot) のための例. IS[] には有名な曲線の例, 変数 H, D, C, S にはトランプのハート, ダイヤ, クラブ, スペード (らしき) 曲線の例が入っている.

num
     数に関する簡単な演算函数の例.

mat
     行列に関する簡単な演算函数の例.

ratint
     有理函数の不定積分. sp, gr が必要. ratint() という函数が定義されているが, その返す結果はやや複雑である. 例で説明する.

          [0] load("gr")$
          [45] load("sp")$
          [84] load("ratint")$
          [102] ratint(x^6/(x^5+x+1),x);
          [1/2*x^2,
          [[(#2)*log(-140*x+(-2737*#2^2+552*#2-131)),161*t#2^3-23*t#2^2+15*t#2-1],
          [(#1)*log(-5*x+(-21*#1-4)),21*t#1^2+3*t#1+1]]]

     この例では, x^6/(x^5+x+1) の不定積分の計算を行っている. 結果は 2 つの要素からなるリストで, 第 1 要素は不定積分の有理部分, 第 2 要素は対数部分を表す. 対数部分は更にリストとなっていて, 各要素は, [root*log(poly),defpoly] という形をしている. これは, 不定積分においては, defpoly の全ての根 root に対して root*log(poly) を作りそれらを足し合わせるという意味である. ここで poly は root を含んでいて, root を入れ替える場合には poly に対しても同じ操作を行うものとする. この操作を, 結果の第 2 要素の各成分に対して行って, 全てを足し合わせたものが対数部分となる.

文献
**

[Becker,Weispfenning]
     Becker, T., Weispfenning, V., "Groebner Bases", Graduate Texts in Math. 141, Springer-Verlag, 1993.

[Boehm,Weiser]
     Boehm, H., Weiser, M., "Garbage Collection in an Uncooperative Environment", Software Practice & Experience, September 1988, 807-820.

[Batut et al.]
     Batut, C., Bernardi, D., Cohen, H., Olivier, M., "User's Guide to PARI-GP", 1993.

[Gebauer,Moeller]
     Gebauer, R., Moeller, H. M., "An installation of Buchberger's algorithm", J. of Symbolic Computation 6, 275-286.

[Giovini et al.]
     Giovini, A., Mora, T., Niesi, G., Robbiano, L., Traverso, C., ""One sugar cube, please" OR Selection strategies in the Buchberger algorithm", Proc. ISSAC'91, 49-54.

[Noro,Takeshima]
     Noro, M., Takeshima, T., "Risa/Asir -- A Computer Algebra System", Proc. ISSAC'92, 387-396.