MAXIMAの概要

数式処理システムの中では古い汎用数式処理システムの一つの(DOE-)Macsyma を基にしたもので、このDOE-MacsymaをCommon Lisp処理系のgclに移植した ものである。現在、GPLに基づく数式処理として開発がMailing Listを軸と して進めらている(当初の中心的人物であったUniversity of Texasの W.Schelter氏は2001年の7月末にロシアで亡くなったとの事)。

MaximaはCommon Lisp処理系としてgclを標準的な環境としており、その上で 動作する数式処理系である。但し、gcl以外のclisp、cmuclやAllegro等の Common Lisp処理系でも動作する。更に、動作環境としては上述の Common Lisp処理系の動作するUNIX系のOSから、MacOS X及びCygnus上での 動作報告もある。しかし、gclで開発されて来た事もあって、gcl以外の Common Lisp処理系では一部のパッケージや機能が使えない個所が散見される。 その上、MacsymaのGCL等への移植で、本来の機能が十分に実装出来ていない 問題点も散見される。しかし、MaximaのMailing Listで現在活発な議論が 交されており、この問題点も近い将来解消されるのではないかと思われる。 (昔の小話を一つ。OSを航空会社に例える話があったが、その中で、 "DOS航空"が乗員・乗客が協力して飛行機を離陸させ、不時着すると、皆で 走って飛行機を再度離陸させると例えていたが、現時点のMaximaもそれに 似ている。因に、NT航空は地面に飛行機の絵を描いて、そこに置いた椅子に 座って飛んでいるふりをする(NT3.5.xの頃)。Widowos95航空は全てが快適 だが、途中で空中爆発する。Mac航空は何もかにもが同じで不気味で詮策 好きな客に"お客様は何も知る必要は無い"の一点張りで凹ませる。Unix航空 は飛行機を作りから開始するものの哲学的議論ばかり等。)

Maximaは前述の様にCommon Lisp処理系で記述されている。gclやclisp上の MaximaはMapleの様にC言語で記述されたものと比べて処理速度が速い部類に 入らない。大体、gclやclisp上のMaximaの場合、Mathematicaと比べて同程度 かやや遅い程度、これをcmucl上で動作させるとMathematicaと比べて速いもの になる。従って、Allegroの様な商用のCommon Lispを用いれば、非常に速い 処理が可能とも考えられる。但し、処理速度の比較では数式処理系の得手、 不得手によって順位が簡単に前後する為、あまり当てにはならない。しかし、 全体的にはgclやclisp上のMaximaはMathematicaと処理速度が同程度と思って いて良いだろう。

MaximaはPascal風の処理言語を持っている。しかし、詳細なプログラムを 作成する場合は、Common Lispで記述する事が多い。その為、Lispに関する 知識があった方がMaximaを使う上では良い。

グラフ表示はTCL/TKベースの2D、3D表示可能なインターフェイスを持っている。 更に、UNIX環境では幾つかの外部プログラムの利用も可能である。標準で 持っているインターフェイスには、デフォルトのOpenmath、xgraph、 Geomview、GNUPlotとIZICがあるが、IZICは古過ぎて現在のtcl/tkには 適合していない。又、Geomview以外ではデフォルトのグラフ表示で十分な 品質(昔のMathematicaに近い)が得られるだろう。

Maximaは汎用の数式処理システムで個人的な利用で課金されないのものと しては機能的に最も充実したものの一つである。他に汎用の数式処理系で 個人利用で課金されないものにMuPADとRisa/Asirがある。先ずMuPADは Maximaよりも機能及びライブラリに関して充実しているが、バイナリのみの 公開である。又、その処理速度に関しても、Maximaと比べて速いものでは 無い様である。次に、Risa/AsirはGroebner基底等の多項式の処理では非常に 優れているが、一般的な利用ではMaximaの方が現時点では充実している。 但し、OpenXM環境の核として専門的な利用ではRisa/Asirの方が優れている と思う。この様に、機能一つ一つを取って言えば、現時点のMaximaはMuPADや Risa/Asirと比べて特に優れている訳ではないが、そのアルゴリズムが枯れて いる事、全体的な機能のバランスが取れている事(不得意、得意分野が極端では 無い)等から、他の数式処理系に総合的に勝る面を 持っている。 その為、Maximaを使う事でMaxima内部に潜む虫を退治し、マニュアル等の 文書を整備し、パッケージを徐々に増して行けば、商用の汎用数式処理 システム(MathematicaやMaple)と機能的に勝るとも劣らないものになる事は 間違いない。更に、現時点のMaximaは汎用でありながら、パッケージの肥大化 がまだ生じていないオープンソースの数式処理システムであり、その上、 C言語よりも直感的な言語のLispで記述されているので、そのソースファイル を弄りながら遊ぶには最適だろう。このついでに虫退治等の作業も行えば 楽である。この御陰で、配布されたままの状態では上述の移植に関する虫等が 残っている事もあって信頼性に関しては"商用と同じレベル"と言い難い(とは 言え、Microsoft製品の品質と同程度)が、疑わしい結果が出た場合、Lispで 記述されたファイルを解析する事で、その結果が本当に正しいものであるか どうかを把握する事が比較的容易に行える。この様に、素のMaxima自体は 商用のものと比べ劣るとしても、使い込んで行けば、バイナリのみの商用の ものと比べて、より高い信頼性を確保する事が可能である。又、Common Lispに 移植されているので、Common Lispさえ動作すれば、その環境に移植可能 である。

Maximaの虫

Maximaの虫に関しては、maximaのMailing Listに参加されるか、archiveを 参照する事を薦める。現時点で動作が最も怪しいのは配列処理である。 どうも従来のMaximaが持っている配列とデータ構造が変更されている可能性 が高く、昔のLISPで記述したプログラムで問題が生じる可能性がある。 ここで、単純に利用する場合は配列をarrayで定義し、make_arrayで初期化 する手順を踏む事が一番問題が無い様に感じる。 他に積分計算で幾つか問題がある。古いものでは、Maxima5.6のintegrate命令 で3^log(x)を積分すると正しい答を返さない。これはrischを用いたり、evで 'rischオプションを設定する事で、integrate内部でrischintを強制的に 使わせる事で対処可能である。この問題点は5.9pre以降で修正されているが、 sqrt(x+1/x-2)の場合はintegrateでもrischintでも積分に失敗する。 これは種明かしをすれば、x+1/x-2=(x-1)^2/xとなり、xを0以上とするとx=1 で折り返しが生じている。ところが、積分計算でsqrt(x+1/x-2)を安易に (x-1)/sqrt(x)としている節がある。この処理はsin.lisp内部で定義された intformに関連しており、この辺りの処理に問題が残っていると考えられる。 この問題点は、最新版のMaxima5.9でも修正されていないので注意が必要で ある。尚、虫取り物語に私個人の様々な 虫取りの試行錯誤の過程を載せている。この中でMaximaの本体に関連した事で、 信頼の出来るものは以下のインストール記事に纏めるが、shareファイルの様に maxima本体とはあまり関係無いなものを纏めるのは二度手間になり兼ねない為、 本体以外のものは虫取り物語の方を参照されたい。特にshareファイルは保守が 十分であったとはとても言えない程度で、古い定義等がゴロゴロしている。 この状況はMaxima5.9でも同様である。但し、Macsymaを記述していたmaclisp とgccやclispの違いによるものが多いので、その辺の問題点が分かれば案外 簡単に使える事が多い。但し、私はLISPERで無い為、過剰に信頼しない様に されたい。尚、現在のMaximaは5.9.0で、間も無く5.9.1が出る予定である。 但し、ここで解説しているものは昔の版である5.6である。5.6と5.9.0の違い はディレクトリ構成の違いや、それまでgclを中心にしていたmaximaがclispや cmuclに主軸を移した点が大きく、それ以外は5.6の細かな虫取り版であるのが 実情である。その為、Maxima 5.6で使えたパッケージ、例えば、affineが5.9.0 では使えなくなる場合もある。尚、Maxima-5.9.0のインストールは5.6や 5.9-pre版と比べても非常に容易なものとなっている。その為、maxima-5.6の インストール作業自体は参考にならないかもしれないが、虫取りの方法や パッケージに含まれていても使えないものを使える様に修正を加えると 言った事に関しては、この記事自体は依然意味があると感じている。 又、Maxima-5.9preに関しては、 Maxima-5.9pre安宅さんのレポートを参照されたい。 又、maxima-5.9.1となるmaxima-2004-04-24に関しては maxima-2004-04-24を参照されたい。

その他

以下にMaximaのインストールに関連した事項を纏めている。ここで、maxima 以外の様々な数式処理に関しては 数値・数式処理システム概要に概要等を纏めているので、興味があれば 参照されたい。

MAXIMAのインストール

gcl環境でMaximaをインストールする事に関しては山内さんのWebペイジ 数式処理システムMaximaも参照されたい。様々なパッチを用意されて おり、ただ感謝。この頁で想定しているのはUNIX系のOS(主にx86或いはPPC で動作するLinux)で、他のMS-WindowsやMacOS Xは想定していない。

更に、gcl-2.4.3環境に関しては、安宅さんからレポートを頂いており、 安宅さんの御好意により インストールレポートにその内容を公開している。GCL環境で 構築したい方は是非参考にされたい。

他にMS-Windows上でもCygnus上にCLISPやGCLをインストールしたその上で Maximaのインストールを行った報告もある。他に、Windows-CE上にも移植 されている。又、MacOS X環境の場合、CLISP上にMaximaをインストールし たとの報告もある。この様に、何らかのCommon Lispが動作する環境であれば、 インストールに挑戦する価値が十分ある。

準備するもの

MAXIMAのインストールには最低gcl等のCommon Lisp処理系が必要である。 gcl以外にはclisp、cmucl等が使える。他には、商用のものにAllegroが あり、インストールに成功したとの報告のある。5.6以前であればclisp 環境等で構築するよりは、gcl環境で構築する方が標準的で、楽でもある。 maxima-5.9preよりgcl環境からclispやcmucl環境を標準としたものの、 それ以前がgclを前提として移植されて来た経緯もあって、現在の安定版 の5.9.0に関して言えば、gcl以外では機能的にやや限定され、5.6の虫取り 版としての側面もある。以降、本家ftpサイトとは、 http://www.ma.utexas.edu/users/Wfs/pub/maximaの事を指すが、 このサイトのMaximaの更新は止まっており、現在は、 sourceforge を拠点に行っている。従って、5.9.0で上手く使えない機能が必要でない限り、 Maximaの入手はsourceforgeの物を用いた方が良い。このsourceforgeで 現行の安定版5.9.0があり、更に、次期バージョンのmaxima-5.9.1も snapとして公開されている。

尚、コンパイルに関して言えば、5.6は以下で説明する様にやや複雑で ある。これに対して、5.9.0は非常に簡単である。

5.6と5.9.0の違いは機能的には5.9.0で一部のパッケージが使えない事 と、5.6の虫が幾つか退治されている事を除くと、ディレクトリ構成が 大きく変更されている違いがある。その一方で、以前のパッケージが そのディレクトリ構成の変更に追い付いていない側面もあるので、 5.9.0自体は5.6の虫取り版と考えていた方が良いだろう。

  1. maxima(必須)

    2004年5月10日現在の最新版はmaxima-5.9.0。 尚、現在sourceforgeにてmaxima-5.9.1が開発中である。 ここでのインストールは主に5.6の事について述べているが、 5.9開発版から5.6と比べてディレクトリ構成が大幅に変更されて いる。最新のclispやgclを用いていれば、5.9.0のコンパイルが容易 で、その上、コンパイルの問題も少ない。但し、虫取り版と云った 側面が強いので5.6が問題無く動作しているのなら、無理に移行する 必要は無いが、5.9.0に移行するのも良いだろう。

  2. gcl(5.6以前であれば必須)

    maximaのコンパイルの為にはソースが必要である。コンパイルには gcl-2.0以上が必要。Common LISPとしては比較的処理の速いものに 分類され、各CPUに対応したnative codeを生成するものである。 因にgclはKCL(Kyoto Common Lisp)を基にしている。

    尚、MaximaはSchelter氏が管理されていた時期にはGCLを標準環境 であった。しかし、5.9.0からGCLは標準では無くなっており、 コンパイルも随分と難しくなっている。その為、無理に GCLに拘る必要は5.6でaffineを利用する場合に限られると思う。

  3. clisp(gclの他の選択肢の一つ。但し、5.9以降では標準)

    gclの様にclispのソースは不要。標準でreadlineが使えて結構便利。 又、問題が生じた場合のMaximaの再構築もgclと比べて簡単に行える。 Maxima-5.6ではgclを用いる場合と比べMaximaの利用に関してはやや 情報量が少なくて面倒な事も多いが、Maxima-5.9開発版以降から、 configureとmakeを実行する事で、コンパイルが行える様に正式に対応 した。clisp版の場合、コンパイルを行うとnative codeでは無く 、byte codeが生成される為、処理速度はそこそこ速いものの全体的に gcl程速くない(但し、処理によって大きく逆転する事もある)。 サポートする環境はgclと比べて比較にならない程多く、色々な環境で Maximaを動かしたい時にはclispの環境で構築するのが良いだろう。 実際、PowerMacのLinux環境(SuSE Linux for PPC)でも使えている。 更に、日本語の表示等もGCLの様にパッチを当てずに対処可能である。 尚、clispの情報や入手に関しては http://clisp.cons.org/を 参照して頂きたい。

    現在、clisp固有の問題としては、古いclispではmaximaが上手く コンパイル出来なかったり、動作に異常が見られる事がある。 例えば、clisp-2.6ではMaximaのコンパイルが5.6でも5.9の開発版 でも正常に行えない。又、clisp-2.6よりも古いバージョンでは 5.6のコンパイルが行えるものの、5.9の開発版では 正常に行えない問題がある。更に、5.6ではdescribe等を用いて infoファイルの閲覧が出来ない問題を持っている。但し、clispの 2.8以降で、5.9の開発版がコンパイル可能で、describe命令も使える 様になっている。その為、clisp環境の場合はclisp-2.6よりも古い バージョンを用いていれば5.6、5.9.0や5.9.1の開発版を使いたければ、 少なくともclispが3.0、出来るだけ新しいclispを導入した方が良い。

    他のclispの問題点に関しては、 ここではMaxima-5.9系では無く、5.6に関して述べる事とする。 これは単純に、Maxima-5.6のコンパイルが困難であった事と、 現在、configure;makeで実行している手間を手動で行っている事が 何かと面白い為で、その事もあって敢て更新している。

    尚、5.6での問題点は、先ず、前述のdescribe命令が動作しない事、 todd_coxeter命令の処理でエラーが出る事、timerとtrace命令が そのままで動作しない点等がある。後者に関してはCommon Lispへの 移植でGCLでは問題にならない古風な構文がCLISPで引掛っている為 である。この様に、構文に関して融通が効くGCLで開発されている 経緯から、この様な虫が所々に残されているのが現状である。 それは5.9.0で解決された訳でも無いので、この記事自体が、maximaの 内部を調べる指針の一つとなると考える所以でもある。 又、CLISPのバージョンが2.6の場合、コンパイルに失敗する (正確には(load "compile-clisp.lisp")を実行した段階でエラーが発生 する)。その為、2.6より前か、2.6より新しいものを用いる必要がある。

    CLISPは手軽に利用可能な点と対応するプラットホームの幅の広さで 大きな長所がある為に、MaximaのMailing Listでも、従来のGCL一辺倒 からCLISPをもう一本の柱としつつある。その為、CLISPのバグの報告や 様々な修正事項に関しては、Mailing Listのアーカイブを参照する事を 強く薦める。尚、深く考え込まずにさっさと使いたければ、 CLISPの最新版とmaxima-5.9.0の組合せを薦める。

  4. affine(オプション)

    基本的に5.6向けのパッケージと思った方が良い。 本家のftpサイトのaffine.tgzを入手する。Groebner基底を扱いたければ あった方が楽しいが、そうで無ければ特に必要は無い。尚、この パッケージはgclで利用可能だが、clispでは使えない。因に、Groebner 基底の計算だけなら、share/grob1.lispをload("grob1.lisp")で読み 込めば、stand命令で行える(とは言え、不十分かもしれない)。もしも、 Groebner基底を頻繁に扱うのであれば、MaximaよりもRisa/Asir、 SingularやMacaulay2を使う事を強く薦める。

  5. xgraph(オプション)

    本家のftpサイトのxgraph-11a.tgzを入手する。点列の棒グラフ表示等に 使えるが、こちらも特に必要な物では無い。xgraphは他の可視化ツールと 比べてより組み込まれた扱いになっており、あった方が便利だろう。

  6. Geomview(オプション)

    http://www.geomview.org/から入手する。3D表示で秀逸。 尚、組み込みのグラフ表示で十分ならば不要。しかし、可視化ツール として持っていて損は無い。この際に入れてしまうのも如何?

  7. GNU TeXmacs(オプション)

    TeXのWYSWYGなエディタ。Maximaだけで無く、Reduce,MuPAD,Macaulay2, pariやScilab等の数値・数式処理システムのフロントエンドとしても 使える。gcl上のmaximaであればGNU TeXmacsをインストールするだけで 使えるが、clisp上のmaximaの場合は、maximaの起動スクリプトの修正が 必要である。更に、clispのスタートアップロゴに含まれる"\"等の記号 がLaTeXデータに落した後に問題となるが、こちらはスクリプトで修正 すれば良いだろう。

尚、マニュアル等で述べられている可視化ツールizicに関しては、 現在のtcl,tkでは古過ぎて使えない様である。最新のtcl,tkでは用いられ なくなった命令を使っている様で、コンパイルを実行するとdangerous等と 文句を言ってくる。現在調査中だが、望み薄。

コンパイル概要

ここでは上記のプログラムのインストールに必要な事柄を纏めている。 尚、その他のどうでも良い情報等は インストール記録に纏めている。この記事ではSuSE Linux 7.1 for IntelとPPCの両方の環境を用いており、gclでコンパイルするものはIntel版、 CLISPはIntelとPPCの両方で行っている。又、内容はmaxima-5.6に関するもの の為、CLISP環境のコンパイルはともすれば変則的な作業を行っている。 このMaxima-5.9開発版になると、maximaのrootディレクトリで./bootstrap を実行してconfigureを生成し、それからconfigureを実行する方式となって いる(無論、これも変則的であるが…)。又、clisp等を用いる場合は configureを実行する際に対応するオプションを設定すれば良い様になって いる。このオプションの内容は./configure --helpで 見る事が可能である。その後に、makeを行えば良い。尚、lispのメモリ イメージファイルはclispで構築した場合はsrc/binary-clisp/に置かれる。 尚、このディレクトリにはコンパイルで生成されたオブジェクトファイルが 置かれている。このディレクトリ構成は安定版の5.9.0でも同じものと なっている。但し、コンパイルはconfigureを実行し、それからmakeを行う だけになっている。その為、単純に利用する場合には以下の5.6の インストールの様な作業を行わなくても良い。而し、5.9でも5.6で見られ る問題を幾つか抱えたままとなっているので、その修正を行いたい場合には、 以下の5.6のインストールに関する報告が役に立つ事もあるだろう。 尚、5.9.xの入手はsourceforgeより入手可能である。ここで、5.9.0の開発版 に関しては、安宅さんのレポート や私のmaxima-5.9preを参照されたい。 又、次期5.9.1の開発版であるmaxima-2004-04-24のインストールに 関してはmaxima-2004-04-24の インストールを参照されたい。

maxima-5.6のインストール

以降、maxima-5.6のインストールについて述べる。但し、そのままで コンパイルが上手く出来なかったり、パッケージが使える様に修正を 加える手法がmaxima-5.9.0でも使える場合もあるので、maxima-5.9.0 を使っていて動作が怪しい場合や、maximaの虫の状態等、maximaの雑多 な情報を得るには使えると思う。但し、5.9.0のコンパイルや 5.9.0を使うだけであればあまり参考にはならない事をここで断わっておく。

maximaのコンパイルにはCommon Lisp処理系が必要である。5.6以前ではgcl (gnuのcommon-Lisp、後述のGeomviewの制御言語の意味では無い)を用いるが、 5.6以前でも他のcommon lisp処理系でコンパイルが可能なものがある。一応、 ソースレベルで対応しているのが、clispとcmuclであり、その他に Allegro Common Lisp環境へのインストール報告もある。基本的に、clispが あれば、後述の工夫をすればインストールが可能であるが、gclを用いる場合 には、gclのソース込でコンパイルしなければならない事に注意する。

Maxima-5.6のインストールをGCLとCLISPで動作を確認している。ここで、 GCLとCLISPにはインストールの留意点や実際の動作で細かい違いが生じる。 先ず、GCLを用いる場合、GCLはバイナリパッケージだけでインストールは 出来ず、Buildに用いた*.oファイルを必要とする。これに対し、CLISPでは CLISP本体とMaximaのソースファイルだけで済む。更に、Maximaは Common Lisp処理系に移植されているとは言え、所々に古風なLISPの構文が 残っており、この古風な構文に関しては、GCLは期待通りの動作をするが、 CLISPの場合はそうでは無い。その為に、clispでまともに動作しない命令が 幾つか出る。その為、clispで利用する場合はgcl上のものよりも注意が必要 になる。最後に、処理速度でCLISPとGCLを比較すると、GCLの方がやや 高速である。これはgclがCPUに対応したnative codeを出力するのに対し、 clispでは機種に依存しないbyte codeを出力する為である。その代り、 clispの方がコンパクトになる点とgclよりも幅広い環境に対応している。 その為、利用する環境の特性や目的に応じてGCLやCLISPを選択する事になる だろう。ここでMaximaは調整途上の面も持っている為、ファイルの入れ換え や修正等の保守の面で、CLISPの方が気楽に使える場面が多い。若し、処理速度 が大きな問題であるなら、使用目的に応じて他の数式処理を併用する事を強く 勧める。

次に、グラフ表示ではtk8.0以上を必要とする。これはOpenMathに対応した 書式のデータ表示に用いる。その他にgeomviewやgnuplotにも対応している。 この内、見栄えの点ではgeomviewが最良である。しかし、 geomviewはUNIX 環境のみで現在動作し、それ以外のMS-Windows環境で使いたいなら、 デフォルトのtkを用いた方が良い。

最後にgcl、clisp共にaffineやsymの様なパッケージのコンパイルは各々の ディレクトリに移動して行う。尚、現時点ではCLISPはaffineが使えない。 但し、symに関しては幾つかのファイル修正を行えば無保証だが利用可能と なる。この点に関しては5.9.0でも同様であった。

以降、maxima-5.6のインストールで行う作業を順番に並べておく。

以上の作業で、Maximaが利用可能となっている筈である。 若し、Maxima-5.6がコンパイル出来い場合は、素直にaffineやtodd_coxeter 等を使うのを諦めて、最新のmaxima-5.9.0のソースファイルを入手し、 そちらを試す方が良いだろう。

Maximaは商用のものと比べて武骨過ぎ、処理速度等に難があるかもしれない。 処理速度に関してはcmuclや商用のCommon Lisp処理系で構築すれば或程度は 改善される。しかし、より高速な処理や緻密な処理が必要であるならば、 Maximaの様な汎用数式処理ではなく、Groebner基底を含む多項式一般の処理 ならRisa/AsirやSingular、数論関係ならPARI-GP、可換環ならMacaulay2、 群論一般ならGapと、より専門に特化した数式処理システム、数値行列の 処理が主であるなら、OctaveやScilabの様なMATLABクローン、二、三次元 空間に嵌め込まれた代数曲面を簡便に描くのが目的ならsurfの利用を考慮 した方が良い。更に、複雑な処理を行う場合、その値の検証を必ず行う事は、 Maximaに限らず、一般の商用の 数式処理に関しても言える。とは言え、 Maximaは特に用心して使う方が良いだろう。尚、Maximaの個々のプログラム は80年代に記述・修正されたものが多い。従って、アルゴリズム的には 枯れていると思われるが、その一方で、Common Lisp処理系への移植となる と、実際は90年代のものが多く、虫の多くも、この辺の事情に由来する様 に思える。但し、MaximaはCommon Lispで記述されている為、その動作を学ぶ にはとても判り易いのではないかと思う。

Symmetries

対称式を扱う為のパッケージがSymmetriesである。ソースファイルには 標準で附属しており、maxima-5.6や5.9preではsrcと同じディレクトリに、 5.9.0ではshareにsymと云う名前のディレクトリに纏められている。gcl 向けの場合、コンパイルはsymディレクトリでmakeを実行するだけで良いが、 clispの場合はmaximaを用いる個所をclisp向けのmaxima実行スクリプト で置換える必要がある。又、maxima-5.9.0の場合、ファイル名の修飾子が 従来のlspではなくlispに変更されているが、makefile等では修正されてい ないので、その点の修正も必要になる。他に、以下に記述した括弧の数等 の修正も必要である。猶、ここでは簡単にmaxima-5.6の修正について述べ、 maxima-5.9.0に関しては必要に応じて述べるが、ファイル名の修飾子は 5.6向けのlspでは無くてlispである事を忘れない事。

gclの場合、compile.lspで修正を行う個所が一部あるが、それを修正すると、 Symmetriesパッケージの利用に大きな問題は無い。しかし、clispの場合は そのままでmakeが出来ない。clisp向けのmaxima実行スクリプトでmakefile の中身を置換える必要があるが、それ以外に、幾つかのlspファイルで、 括弧")"の数が多過ぎる為、(compile-lisp)の実行で、ファイル読込に失敗 する問題がある。この対処方法は非常に容易で、問題の個所の括弧を削れば 良い。これに対し、operators.lspの方が非常に厄介である。これは文法的 にCLISPに適合しておらず、更に、変数$operが未設定の為、operationを 実行しても、対応する関数とは全く別の関数を勝手にでっちあげる為である。 その為、$operに変数$ratの値を初期化で与える様にすれば、この問題を回避 する事が可能である。又、gclでは問題が無いものの、clispで問題が出る 個所に、schur.lspがある。例えば、mon2schur([1,2]);を実行すると、 意味不明な文字列が生成されてMAXIMA Breakに落ちるが、これは schur.lspのプログラムの差し替えが必要である。尚、上記の括弧の 数の問題等の構文的な問題点の探し方はclispをsymディレクトリ上で起動し、 それから(load "compile.lsp")を実行する。もし、エラーが出れば、 行を表示するので、その行を調べると良い。例えば、以下の例では、 clisp上でcompile.lsp読み込んでコンパイルを行い、operations.lspの 個所でコンパイルに問題が生じた所を示している。

コンパイルエラーが生じた場合

[18]>(load "compile.lsp")
…出力を省略…
Compiling file /usr/local/maxima-5.6/sym/operations.lsp ...
WARNING in function #:TOP-LEVEL-FORM-2 in line 24 :
OPERATIONS is neither declared nor bound,
it will be treated as if it were declared SPECIAL.
*** - READ from #<BUFFERED FILE-STREAM CHARACTER 
#P"/usr/local/maxima-5.6/sym/operations.lsp" @34>: 
an object cannot start with #\)
1. Break MAXIMA[19]> 
	      

この例で、@34がoperations.lspで問題のある行番号を示している。 実際、この行は括弧")"が多過ぎる。このBreakから抜ける為には、 ctrl+Dを押せば良い。尚、このMAXIMA Breakの状態では、CLISPの命令が そのまま利用可能であり、それ迄に設定された変数の参照や関数の実行が 行えるので便利が良い。

以降に、修正個所を述べる。尚、この修正を行うとSymmetriesパッケージ が利用可能となるが、確認したのはManualのSymmetries.texiに含まれる 幾つかの例題のみで検証しているので完全とは言えない。全体的な動作の 保証はしないので、注意して使う事。

  1. makefileの修正(clisp、maxima-5.9pre以降)

    makefileの個所を安易にclisp向けのmaximaを起動するスクリプトに 修正する程度で良い。gclの場合は修正は特に不要。尚、この修正は maxima-5.6向けのものであるが、maxima-5.9.0でも問題点がそのまま 残っている。その上、5.9開発版ではファイルの修飾子がlspよりlispに 変更されているので、以下の修正はそれに合せて読み直す必要がある。 又、compile.lispの内容はファイル名が全く反映されていないので、 その点も修正する必要がある。

    all:
            echo '(proclaim (quote(optimize (safety 0))))(in-package "MAXIMA")(load "compile.lsp")' \
            | /usr/local/bin/macsyma
    
    
    all:
            echo 'load("compile.lsp");' |  /usr/bin/clisp -norc -M /usr/local/maxima/src/maxima-clisp.mem
    
    
    doc:
            latex docsym.tex
    
    clean:
            rm -f *.aux *.dvi *.toc *.log
            rm -f *.o
    
    tar:
            (cd .. ; tar cvf - sym/makefile sym/*.lsp sym/*.tex sym/doconline sym/*.mac src/max_ext.lisp doc/macsym.doc doc/macsym-index.LISP ) | gzip -c > sym.tgz
    		  

    尚、このmakefileは5.6向けのものである。5.9pre以降ではメモリイメージ 名がmaxima.memとなり、置かれる場所もsrcではなくsrc/binary-clispに なるので、その点の修正が必要になる。

  2. compile.lsp

    このファイルでは、存在しないファイルresolvante.lspを指定して いるので、gclでもclispでもコンパイルの問題となる。 これはmaxima-2004-04-24でも同じである。以下に示す様に resolvante.lspの個所をresolv1.lspで置換える必要がある。 修正後のcompile.lspを以下に示す。

    修正後のcompile.lsp

    ;; Fichier compile.lsp
    (proclaim '(optimize (safety 0)))
    ;       ***************************************************************
    ;       *                    MODULE SYM                               *
    ;       *       MANIPULATIONS DE FONCTIONS SYMETRIQUES                *
    ;       *        (version01: Commonlisp pour Maxima)                 *
    ;       *                                                             *
    ;       *                ----------------------                       *
    ;       *                  Annick VALIBOUZE                           *
    ;       *                    GDR MEDICIS                              *
    ;       *  (Mathe'matiques Effectives, De'veloppements Informatiques, *
    ;       *           Calculs et Ingenierie, Syste`mes)                 *
    ;       *             LITP (Equipe Calcul Formel)                     *
    ;       *                 Universite' Paris 6,                        *
    ;       *        4 place Jussieu, 75252 Paris cedex 05.               *
    ;       *              e-mail : avb@sysal.ibp.fr                      *
    ;       ***************************************************************
    
    (compile-file '|arite.lsp|)
    (compile-file '|chbase.lsp|)
    (compile-file '|direct.lsp|)
    (compile-file '|elem.lsp|)
    (compile-file '|kak.lsp|)
    (compile-file '|ecrivain.lsp|)
    (compile-file '|lecteur.lsp|)
    (compile-file '|macros.lsp|)
    (compile-file '|multmon.lsp|)
    (compile-file '|partpol.lsp|)
    (compile-file '|permut.lsp|)
    (compile-file '|pui.lsp|)
    (compile-file '|resolv1.lsp|)
    (compile-file '|schur.lsp|)
    (compile-file '|treillis.lsp|)
    (compile-file '|tri.lsp|)
    (compile-file '|util.lsp|)
    (compile-file '|operations.lsp|)
    ;(compile-file '|resolvante.lsp|)
    		  
  3. direct.lsp

    このファイルでは122行目の")"が一つ多い。それを消去する。 以下に該当する個所を含む命令を示すが、^で示した個所の ")"を削除する。関数定義の末尾の括弧が多過ぎても、gclで コンパイルが出来なくなる問題は無いが、あって気持の良い ものでは無い。

    122行目の修正個所を含む関数

        114 (defun contient (list$pol $pol)
        115    (catch 'trouve
        116        (progn
        117          (mapc #'(lambda ($pol2)
        118                   (and (meval (list '($is)
        119                                     (list '(mequal) $pol $pol2)))
        120                               (throw 'trouve t)))
        121                list$pol)
        122          nil))))
                           ^この")"を一つ削除
    		  
  4. operations.lsp

    operations.lspが最も修正すべき個所が多い。先ず、括弧が多い個所は 34行、50行と79行の3個所にある。

    34行目の修正個所を含む関数

         33 (defun $ratfmult (ll)
         34   (meval (list '($rat) (cons '(mtimes) ll))))))
                                                         ^^これらの")"を削除
    		  

    50行目の修正個所を含む関数

         49 (defun $expandfadd (l)
         50   (meval (list '($expand) (cons '(mplus) l))))))
                                                          ^^これらの")"を削除
    		  

    79行目の修正個所を含む関数

         78 (defun $mevalfadd (l)
         79    (meval (cons '(mplus) l)))))
                                         ^^これらの")"を削除
    		  

    次に、このファイルの末尾側の関数$operationの定義にも問題がある。 元の$operationの定義を以下に示す。

    元の$operation

         95 (defun $operation ()
         96   (cond
         97     ((equal $oper prefixe))
         98     (t (mapc '(lambda (corps nom_oper)
         99                 (setf (symbol-function nom_oper) corps))
        100             (mapcar '(lambda (suffixe)
        101                        (symbol-function
        102                            (flet ((franz.concat (&rest args)
        103                                    "equivalent to Franz Lisp 'concat'."
        104                                    (values
        105                                     (intern
        106                                      (format nil "~{~A~}" args)))))
        107                              (franz.concat $oper suffixe))))
        108                     '(moins mult add divi exp fadd fmult))
        109             '($moins_sym $mult_sym $add_sym $divi_sym $exp_sym
        110                  $fadd_sym $fmult_sym))
        111       (setq prefixe $oper))))
    		  

    この関数をCLISPで使う上で問題になるのがlambdaの扱いである。 元のoperations.lspでは簡単に'(lambdaとしているが、実際は #'(lambdaの様に、#を付ける必要がある。これはCommon Lispの X3J13でfunction特殊形式の評価に変更が加った為であり、 funcal,apply,mapcar等ではcarを取るとlambdaが得られるlambda式 を関数引数として受け入れない仕様になっている。それを避ける為に、 #を付ける必要がある。この問題点を修正したものが以下のoperation である。この点に関してCLISPはより厳密である一方で、gclは緩い (つまり、過去の遺産の修正が少なく済ませる可能性がある)事が分る。

    修正後の$operation

        95 (defun $operation ()
        96   (cond
        97     ((equal $oper prefixe))
        98     (t (mapc #'(lambda (corps nom_oper)
        99                 (setf (symbol-function nom_oper) corps))
       100              (mapcar #'(lambda (suffixe)
       101                         (symbol-function
       102                             (flet ((franz.concat (&rest args)
       103                                     "equivalent to Franz Lisp 'concat'."
       104                                     (values
       105                                      (intern
       106                                       (format nil "~{~A~}" args)))))
       107                               (franz.concat $oper suffixe))))
       108                      '(moins mult add divi exp fadd fmult))
       109              '($moins_sym $mult_sym $add_sym $divi_sym $exp_sym
       110                   $fadd_sym $fmult_sym))
       111        (setq prefixe $oper))))
    		  

    このoperationsで実行している事は$moins_sym,$mult_sym等に対し、 $operの値とmoins,mult等を繋げた関数を対応させる事である。 そこで、問題になるのが変数$operの値である。gclの場合は問題が 無い様だが、clispの場合はこの変数の値が未設定となる為に、立ち 上げるべき関数が未定義になっている。ここで、operations.lspで 初期化を行っている変数はprefixeのみである。operations.lsp内の フランス語の註釈を見ると、$oper=$ratと仮定しているらしいので、 (setq $oper '$rat)を追加して$operの初期化を行う。今回、 この$operの初期化行を(setq prefixe 'depart)の次行に追加している。 尚、関数operationで$fadd_symに対応する関数は変数$operの初期化に よって、operations.lspで定義された関数$ratfaddが対応する様に なる。この$ratfaddはoperations.lsp内部で定義されている。

  5. util.lsp

    141行目と294行目の末尾の括弧")"が一つ多い。これらを消去する。

    141行目の修正個所を含む関数

        138 (defun $degre (mon)
        139   (if (or (constantp mon) (null mon)) 0
        140       (+  (* (car mon) (cadr mon))
        141           ($degre (cddr mon))))))
                                            ^この")"を削除
    		  

    294行目の修正個所を含む関数

        284 (defun lex_mon (m1 m2)
        285   (and (not (equal m1 m2))
        286        (catch 'trouve
        287                (mapc #'(lambda (e1 e2)
        288 
        289                       (or (eql e1 e2)
        290                           (cond
        291                             ((> e1 e2)
        292                              (throw 'trouve t))
        293                              (t (throw 'trouve nil)))))
        294                    m1 m2)))))
                                        ^この")"を削除
    		  
  6. schur.lsp

    上記の修正を行うと、makeをsymディレクトリで実行しても、エラー で停止する事は無い。しかし、実際にSymmetriesパッケージの mon2schurを実行するとエラーが発生している。以下にその状況と Berak MAXIMAでのデバッグの様子を示す。

    mon2schurのエラーとデバッグの様子

    (C6) mon2schur([1,2]);
    
    *** - argument to ZEROP should be a number: ((MRAT SIMP NIL (#:X32423 #:X22422 #:X12421)) 2 . 1)
    1. Break MAXIMA[4]> 
    (略)
    1. Break MAXIMA[12]> (treinat (duale12 '(1 2)))
    ((4 1) (3 1 1 1) (2 2))
    2. Break MAXIMA[13]> (duale21 '(4 1))
    (1 1 1 1)
    2. Break MAXIMA[13]> (duale21 '(3 1 1 1))
    (((MRAT SIMP ($X3 $X2 $X1) (#:X32423 #:X22422 #:X12421)) 2 . 1) 1 1)
    2. Break MAXIMA[13]> (duale21 '(2 2))
    (2 2)
    		

    因に、答は"2 X1 X2 X3 + X1^2 X2"となる。尚、"1. Break MAXIMA[4]>" と云ったプロンプトが現われているが、その実体はLISPのプロンプト であり、上の例に示す様に、命令の定義や実行、変数の設定等が 通常のLISPとほぼ同様に行える。上の例では、schur.lspに含まれる 各種命令を実行し、mon2schurの何処で問題が生じているかを調べて いる。この例では、警告にZEROPの引数が数でなければならない事を 主張している為、ZEROPを含む関数が怪しい事になる。 ここで、schur.lspで定義された関数で、ZEROPを含む関数には good_line0のみがあり、それから遡ると、結局duale21が怪しい事が 判る。更に、(duale21 '(3 1 1 1))を実行すると問題のリストが生成 されるので、このduale21に問題がある事が判る。ここで、 (#:X32423 #:X22422 #:X12421)はX1 X2 X3の残骸で、2.1がX2 X1の卵 に思える。ここでduale21の内容を更に調べると、問題の変な文字列を 含むリストを出力しているのは、schur.lspの2duale21に含まれる $fadd_symの個所である。以上から、duale21と2duale21を修正すれば 良さそうである。これらの関数を定義した個所の上の行にはduale21と 2duale21の古い定義も残されており、こちらの2duale21では問題の $fadd_symも含まない和と積の古い形式で記述されている。 その為以下の修正、つまり、コメントアウトした古い関数定義を用い る事にして、現在のものをコメントアウトする。以下にその該当個所 を示す。

    修正後のduale21と2duale21

        197  (defun duale21 (partition)
        198    (let ((m1 (cadr partition)))
        199   (2duale21 (cddr partition) (list m1)
        200            (* m1 (car partition))
        201           m1)))
        202  (defun 2duale21 (part2 part1 p1 p2)
        203    (cond ((null part2)
        204           (nconc part1
        205                  (make-list
        206                      (- p1 p2) :initial-element 1)))
        207         (t (let ((nxpart (+ (cadr part2) (car part1))))
        208           (2duale21 (cddr part2)
        209                    (cons nxpart
        210                          part1)
        211                        (+ p1 (* (car part2) (cadr part2)))
        212                       (+ p2 nxpart))))))
        213 ;(defun duale21 (partition)
        214 ;  (let ((lmultiplicites_lparts
        215 ;            (chmultiplicites_parts partition nil nil)))
        216 ;    (2duale21 (car lmultiplicites_lparts)
        217 ;        (cons 0 (cdr lmultiplicites_lparts)) nil)))
        218 ;(defun 2duale21 (lmulti lpart partition1_duale)
        219 ;  (cond
        220 ;    ((null (cdr lmulti))
        221 ;     (nconc partition1_duale
        222 ;            (make-list
        223 ;                (- (cadr lpart) (car lpart))
        224 ;                 :initial-element  (car lmulti))))
        225 ;    (t (2duale21 (cdr lmulti) (cdr lpart)
        226 ;           (nconc partition1_duale
        227 ;                  (make-list
        228 ;                        (- (cadr lpart) (car lpart))
        229 ;                       :initial-element  ($fadd_sym lmulti)))))))
        230 ;
    		  
  7. resolv1.lsp

    resolvante命令を使う際に、Cayleyスイッチを設定していると、 resolvante命令でresolcayley.lspを呼出す個所でエラーが発生する かもしれない。その個所を以下に示す。

    resolvanteの問題個所

         58 (defun resolvante ($pol $var $fonction_resolvante $list_var)
         59      (cond  ((equal '$cayley $resolvante)
         60                  (print " resolvante de Cayley ")
         61                  (load "resolcayley.lsp")
    		  

    ここで、61行目のload命令の実行で失敗する事がある。 この場合、61行目を;(load "resolcayley.lsp")で置換えると良いが、 Cayleyスイッチを使う場合には、load("resolcayley.lsp");を実行し なければならない。他には (load "/usr/local/maxima/sym/resolcayley.lsp")の様に直接指定 する方法がある。この場合は、resolcayley.lspを他のディレクトリに 移すと問題が生じるが、ディレクトリの変更を行わなければ、面倒が 少ない方法である。他のまっとうな方法に関しては調査中。

  8. コンパイル

    これらの処理の後に、clisp上で(load "compile.lsp")でエラーが 出なくなると、修正したmakefileを用いて、makeを実行する。以上で、 Symmetries.texiに含まれる命令を実行すれば自動的に読込が実行され、 命令が実行される筈である。もしエラーが出る場合や強制的にパッケージ を読み込みたければ、load("sym1");を実行すると良い。

    ponpoko@clavius:~ > macsyma 
      i i i i i i i       ooooo    o        ooooooo   ooooo   ooooo 
      I I I I I I I      8     8   8           8     8     o  8    8
      I  \ `+' /  I      8         8           8     8        8    8
       \  `-+-'  /       8         8           8      ooooo   8oooo
        `-__|__-'        8         8           8           8  8
            |            8     o   8           8     o     8  8
      ------+------       ooooo    8oooooo  ooo8ooo   ooooo   8
    
    Copyright (c) Bruno Haible, Michael Stoll 1992, 1993
    Copyright (c) Bruno Haible, Marcus Daniels 1994-1997
    Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998
    Copyright (c) Bruno Haible, Sam Steingold 1999
    
    Maxima 5.6 日 7月 8 14:00:42 JST 2001 (with enhancements by W. Schelter).
    Licensed under the GNU Public License (see file COPYING)
    (C1) RATSIMP(PUIREDUC(3,[2]));
    RESOLVANTE 
    GENERALE 
     
    NOTE: To compile the system do 
     cd  /usr/local/maxima-5.6/sym/ ;make 
    ;; Loading of file /usr/local/maxima-5.6/sym/macros.fas is finished.
    (…略…)
    ;; Loading of file /usr/local/maxima-5.6/sym/resolv1.fas is finished.Warning - you are redefining the MACSYMA function RESOLVANTE_PRODUIT_SYM
    Warning - you are redefining the MACSYMA function RESOLVANTE_UNITAIRE
    Warning - you are redefining the MACSYMA function RESOLVANTE_ALTERNEE1
    Warning - you are redefining the MACSYMA function RESOLVANTE_KLEIN
    Warning - you are redefining the MACSYMA function RESOLVANTE_KLEIN3
    Warning - you are redefining the MACSYMA function RESOLVANTE_VIERER
    Warning - you are redefining the MACSYMA function RESOLVANTE_DIEDRALE
    Warning - you are redefining the MACSYMA function RESOLVANTE_BIPARTITE
                                                      3
                                          3 P1 P2 - P1
    (D1)                      [2, P1, P2, -------------]
                                                2
    (C2) mon2schur([1,2]);
                                       2
    (D2)/R/                       X2 X1  + 2 X3 X2 X1
    (C3) 
     
    		  

timer

CLISP上のmaximaではtimerとtraceがそのままでは使えない。その様子を 以下に示す。

clispでのtimerの動作エラー

(C1) timer(integrate);

*** - SYSTEM::%PUTD: argument (LAMBDA (&REST TRACE-ARGS) (TIMER-HANDLER '$INTEGRATE (COPY-LIST TRACE-ARGS))) is not a function.
To get a function in the current environment, write (FUNCTION ...).
To get a function in the global environment, write (COERCE '... 'FUNCTION).
1. Break MAXIMA[1]> 
	      

ここで引掛っているのがmtrace.lispの196行目からの

    196          (trace-fshadow fun (car temp)
    197                         (make-trace-hook fun (car temp) handler))
	      

のmake-trace-hookの個所である。ここでmake-trace-hookはcommon lisp では

    646 (defun make-trace-hook (fun type handler)
    647   (CASE (GET! TYPE 'HOOK-TYPE)
    648     ((EXPR)
    649      `(lambda (&rest trace-args)
    650         (,handler ',fun (copy-list trace-args))))
    651     ((FEXPR)
    652       `(LAMBDA ("e &rest TRACE-ARGL)
    653         (,HANDLER ',FUN (copy-list TRACE-ARGL))))
    654 ;;;???
    655     ((MACRO)
    656       `(lambda ("e &rest TRACE-FORM)
    657         (,HANDLER (CAAR TRACE-FORM) (copy-list TRACE-FORM))))))
	      

となっている。この原因としては以前のload等にあったのと同様の問題と 考えられる。つまり、これは古いLISPとCommon Lispでlambdaの扱いが 異っている為で、gclは比較的寛容であるのに対し、clispがより厳格で ある様だ。この場合、warnningにある様にfunctionを用いても良いが、 make-trace-hookの返却値を利用するtrace-fshadowの他の個所で、 cdrを用いている為、ここの個所はそのままとする。

そこでmake-trace-hookを呼出している個所で、引数を関数型として評価 させる様に修正を加える。ここでエラーメッセージで文句を言って いるsetfのある個所は、trace-fshadowである。以下にその個所を示す。

trace-fshadowの定義

    306 #+cl
    307 (defun trace-fshadow (fun type value)
    308    (let ((shadow (get! type 'shadow)))
    309       (cond ((memq shadow '(expr subr))
    310              (setf (trace-oldfun fun) (and (fboundp fun) (symbol-function fun)))
    311              (setf (symbol-function  fun)  value))
    312             ((memq shadow '(fexpr fsubr))
    313              (setf (trace-oldfun fun) (symbol-function fun))
    314              (setf (symbol-function  fun)  (cons 'nlambda (cdr value))))
    315             (t (setplist fun
    316                          `(,shadow ,value ,@(symbol-plist fun)))))))
	      

timerのエラーに関係している個所は、311行のvalueである。 このvalueを関数型に型を変更させる為、valueをevalで評価させる。 その修正を以下に示す。

trace-fshadowに修正を加えた(311行)もの

    307 (defun trace-fshadow (fun type value)
    308    (let ((shadow (get! type 'shadow)))
    309       (cond ((memq shadow '(expr subr))
    310              (setf (trace-oldfun fun) (and (fboundp fun) (symbol-function fun)))
    311              (setf (symbol-function  fun)  (eval value)))
    312             ((memq shadow '(fexpr fsubr))
    313              (setf (trace-oldfun fun) (symbol-function fun))
    314              (setf (symbol-function  fun)  (cons 'nlambda (cdr value))))
    315             (t (setplist fun
    316                          `(,shadow ,value ,@(symbol-plist fun)))))))
	      

この修正によって、timerは取り敢えず利用可能となる。ここでtraceの動作 の確認も行ったが、traceに関しても問題は無さそうである。この動作の一例 を以下に示す。

timerとtraceの動作確認


(C1) timer(integrate);
(D1)                              [INTEGRATE]
(C2) trace(integrate,expand);

INTEGRATE is already traced.
(D2)                               [EXPAND]
(C3) integrate(expand((x+1)^2),x,0,3);
                       2
1 Enter EXPAND [(x + 1) ]
                2
1 Exit  EXPAND x  + 2 x + 1
1 Enter EXPAND [3, 1, 0]
1 Exit  EXPAND 3
1 Enter EXPAND [0, 1, 0]
1 Exit  EXPAND 0
1 Enter EXPAND [3, 1, 0]
1 Exit  EXPAND 3
1 Enter EXPAND [3, 1, 0]
1 Exit  EXPAND 3
(D3)                                  21
(C4) timer_info(integrate);
              [ FUNCTION   TIME//CALL  CALLS  RUNTIME   GCTIME ]
              [                                                ]
(D4)          [ INTEGRATE   0.03 SEC     1    0.03 SEC    0    ]
              [                                                ]
              [   TOTAL     0.03 SEC     1    0.03 SEC    0    ]
(C5) 
	      

この様に、timerとtraceは動作する様に修正が出来た。しかし、traceを 行った関数に対してuntraceを実行すると、元の関数がまともに動作しない 問題が発生する。ここで、untraceを実行すると、 "This function was no longer defined as an interpreted-trace"と 云ったメッセージが表示されている。このメッセージを出力する命令は 以下に示すtrace-unfshadow命令である:

trace-unfshadowの定義

    334 (defun trace-unfshadow (fun type &aux new-fun)
    335   (cond ((and (fboundp fun)
    336               (consp (setq new-fun (symbol-function fun)))
    337               (consp (second new-fun))
    338               (among 'trace-args (second new-fun)))
    339   (cond ((memq type '(expr subr fexpr fsubr))
    340          (let ((oldf (trace-oldfun fun)))
    341            (if (not (null oldf))
    342              (setf (symbol-function  fun)  oldf)
    343              (fmakunbound fun))))
    344          (t (remprop fun (get! type 'shadow))
    345             (fmakunbound fun))))
    346         (t  (format t "~%This function was no longer defined as an interpreted-trace"))))
	      

この事からtrace-unfshadowの処理で、335から338行迄の以下に抜き出した 条件がTの場合にuntrace処理を実行する仕様となっているが、この判別で NILが返されている事が分る。

(and (fboundp fun)
(consp (setq new-fun (symbol-function func)))
(consp (second new-fun))
(among 'trace-args (second new-fun)))
    

この理由はCLISPではnew-funcがLIST(CONS型)で無い為、conspとamongの 処理が出来ずにNILとなっている事が分る。その為にuntraceを実行しても、 trace用のタグが残ったままとなっており、この為にエラーが生じている のがその理由である。

ここで、new-funcの型が違う理由を以下の簡単な例で示す。 この例では単純に与えられた数を二倍にする関数tamaをdefunで 定義したものである。このtamaをsymbol-functionを用いて関数定義 を呼出したもののgclとclispでの形式の違いを示している。

gclでの動作

>(defun tama (x) (* x 2))

TAMA

>(type-of `tama)    

SYMBOL

>(setf aa (symbol-function `tama))

(LAMBDA-BLOCK TAMA (X) (* X 2))

>aa

(LAMBDA-BLOCK TAMA (X) (* X 2))

>(type-of aa)

CONS
	      

clispでの動作

[117]> (defun tama (x) (* x 2))
TAMA
[118]> (type-of `tama)
SYMBOL
[119]> (setf aa (symbol-function `tama))
#<CLOSURE TAMA (X) (DECLARE (SYSTEM::IN-DEFUN TAMA)) (BLOCK TAMA (* X 2))>
[120]> (type-of aa)
FUNCTION
	      

この意味は、gclで(symbol-function `tama)の結果はリストになるのに対し、 clispでは関数型になる事を示している。その為、gclではLISTとして処理が 出来ていても、clispでは関数型となる為に、cdr等でエラーが生じる。 その為に本来のuntrace処理が行えていない事を意味している。従って、 この様な処理がmaximaの他のプログラムで行われていれば、それらが 全て虫となるので注意が必要である。但し、問題となっている判定式自体 は、結局の所、funに値が設定され、そのfunの中にtrace-argsが含まれて いる事で判別している。しかし、その親のプログラムmacsyma-untrace-sub でtraceフラグが立っているかを判別する様になっている事と、他の、Franz 等でこの処理が省略されている事と、untrace処理自体、昔の関数に戻す 処理を行うだけである為、(trace-oldfun fun)に昔の関数が返されれば良い 事になる。その為、以下の様に暫定的に対処している。

trace-unfshadowの修正

    334 (defun trace-unfshadow (fun type &aux new-fun)
    335   (cond ((and(fboundp fun)
    336              (functionp (trace-oldfun fun)))
    337   (cond ((memq type '(expr subr fexpr fsubr))
    338          (let ((oldf (trace-oldfun fun)))
    339            (if (not (null oldf))
    340              (setf (symbol-function  fun)  oldf)
    341              (fmakunbound fun))))
    342          (t (remprop fun (get! type 'shadow))
    343             (fmakunbound fun))))
    344         (t  (format t "~%This function was no longer defined as an interpreted-trace"))))
    345 ;  (cond ((and (fboundp fun)
    346 ;             (consp (setq new-fun (symbol-function func))
    347 ;             (consp (second new-fun))
    348 ;             (among 'trace-args (second new-fun)))
    349 ;  (cond ((memq type '(expr subr fexpr fsubr))
    350 ;        (let ((oldf (trace-oldfun fun)))
    351 ;          (if (not (null oldf))
    352 ;            (setf (symbol-function  fun)  oldf)
    353 ;            (fmakunbound fun))))
    354 ;        (t (remprop fun (get! type 'shadow))
    355 ;           (fmakunbound fun))))
    356 ;       (t  (format t "~%This function was no longer defined as an interpreted-trace"))))
    357 
	      

この処理を行うとuntrace処理が正常に実行され、関数の動作にも問題が 無くなる。

修正後のtraceとuntraceの処理

(C1) trace(integrate,expand);
(D1)                          [INTEGRATE, EXPAND]
(C2) integrate(expand((x+1)^2),x,0,1);
                       2
1 Enter EXPAND [(x + 1) ]
                2
1 Exit  EXPAND x  + 2 x + 1
                    2
1 Enter INTEGRATE [x  + 2 x + 1, x, 0, 1]
 1 Enter EXPAND [1, 1, 0]
 1 Exit  EXPAND 1
 1 Enter EXPAND [0, 1, 0]
 1 Exit  EXPAND 0
 1 Enter EXPAND [1, 1, 0]
 1 Exit  EXPAND 1
 1 Enter EXPAND [1, 1, 0]
 1 Exit  EXPAND 1
                  7
1 Exit  INTEGRATE -
                  3
                                       7
(D2)                                   -
                                       3
(C3) untrace();               
(D3)                          [EXPAND, INTEGRATE]
(C4) integrate(expand((x+1)^2),x,0,1);
                                       7
(D4)                                   -
                                       3
(C5) 
	      

affine

affineはMaximaでGroebner基底を扱う為のパッケージである。 尚、与えられた多項式と順序関係に関するGroebner基底の計算はaffineが 無くてもshare/grob1.lispで計算可能である。但し、affineは他にも面白い 使い方が出来る。

このGroebner(Grobner)基底に関しては、最近、日本語の書籍が色々と出て いるので、詳細はそちらを参照されたい。簡単に言えば、一番単純で性質の 良いイデアルの生成元である。尚、Groebner基底は数式処理系で計算時に 設定された順序関係等で異なるのが一般的である。このGroebner基底の扱い に特に優れているのが国産のRisa/Asirである。

本家のサイトにはSun4向けのバイナリがあるが、それ以外の環境では コンパイルしなければならない。このaffineの展開では予め専用の ディレクトリを作っておく事を薦める。今回は非常に安易に /usr/local/lib/maxima-5.6にaffineと云う名前のディレクトリを mkdirし、そこでaffine.tgzを展開している。このaffineを展開すると バラバラとファイルが現われ、ディレクトリも何も含んでいない。 そのファイルの中にmakefileがあり、それを環境に合せて適宜修正する。 尚、このmakefileはgcl環境のものであり、clispでは使えない。

例えば、私の環境に合せると;

SRC = /usr/local/maxima-5.6/src
SAVEDKCLDIR =/usr/src/packages/BUILD/gcl-2.3/unixport
MAXDIR=/usr/local/lib/maxima-5.6
	    

となる。先ず、SRCはmaximaのソースのあるディレクトリ、 SAVEDKCLDIRはgclのunixportディレクトリの指定、MAXDIRは maximaがインストールされているディレクトリである。 ここでの設定ではSAVEDKCLDIRをGCLを構築したディレクトリの中の unixportディレクトリを指定しているが、maximaのコンパイルとは 異なり、gclのインストール先のunixportディレクトリ(SuSEの 場合は/usr/lib/gcl-2.3/unixport/でも良のではないかと思う。

準備が出来るとmakeを実行するが、ここではaffineパッケージを 読み込む手間を省く為、強引に読み込み不要のmaximaを生成してしまう。 この場合はmake saved_affineを実行する。ここでmaximaを利用するので、 maximaへのパスが通っていないとコンパイルに失敗するので注意する。 コンパイルが完了するとaffineディレクトリ上にsaved_affineが出来上る。 このsaved_affineを適当なパスの通ったディレクトリにコピーしても 良いが、実際は機能的に限定されている。例えば、グラフ表示が行えない。

ここでmaximaの正体だが、これは単なるシェルスクリプトである。 その中身を以下に示しておこう;

#!/bin/sh
export MAXIMA_DIRECTORY
MAXIMA_DIRECTORY=/usr/local/lib/maxima-5.6
exec /usr/local/lib/maxima-5.6/src/saved_maxima -dir /usr/local/lib/maxima-5.6/src/ $@
	    

と、この様に安易で、環境変数MAXIMA_DIRECTORYを設定した後に、 src/saved_maximaを実行しているだけである。 そこで、affineと云う代物を同様にでっちあげる。

#!/bin/sh
export MAXIMA_DIRECTORY
MAXIMA_DIRECTORY=/usr/local/lib/maxima-5.6
exec /usr/local/lib/maxima-5.6/affine/saved_affine -dir /usr/local/lib/maxima-5.6/src/ $@
	    

変更点はexecの後の部分でsaved_affineを指定しているだけである。 このaffineをパスの通った適当なディレクトリ(/usr/local/bin等) に置く。これでグラフ表示に支障が無い為、十分では無いかと思っている。

尚、affine(saved_affineも含め)を起動させると

GCL (GNU Common Lisp)  Version(2.3) Wed May 16 23:46:46 JST 2001
Licensed under GNU Library General Public License
Contains Enhancements by W. Schelter
Maxima 5.6 Wed May 16 23:46:41 JST 2001 (with enhancements by W. Schelter).
Licensed under the GNU Public License (see file COPYING)
(C2) 
	    

となり、(C1),(D1)行が抜けている。ここでaffineパッケージの読み込み を行っているのだろう。

非常に安易な検証で、連立一次方程式{2*x+y=1,x+2*y=2}をGroebner基底 を用いて解いてみる;

(C3) grobner_basis([2*x+y-1,x+2*y-2]);
(D3)/R/                        [- y + 1, - x]
	    

grobner_basisの答えは[-y+1,-x]となり、これから解はy=1,x=0である 事が判る。尚、risa/asirでは連立一次方程式はこの様にして解いている。

尚、Affineパッケージを用いていると、POLYSIMPはGROBNER_BASISで計算 したイデアルの剰余を計算する。この様子を以下に示す。

(C14) GROBNER_BASIS([3*X^2+1,Y*X]);

eliminated one
 . 0 . 0
                                          2
(D14)/R/                       [- Y, - 3 X  - 1]
(C15)  POLYSIMP(Y^2*X+X^3*9+2);

(D15)/R/                           - 3 X + 2
(C16)  POLYSIMP(Y^2*X+X^3*9+2*Z);

(D16)/R/                           2 Z - 3 X

	    

上の例で、多項式環Q[X,Y,Z]の元の多項式Y^2*X+X^3*9+2*ZはPOLYSIMP によって剰余環Q[X,Y,Z]/<-Y,3*X^2-1>の元の2*Z-3*Xに簡易化 されている。

上の計算に続いて以下の処理を行う。ここでは、非常に安易に GROBNER_BASIS([X,Y])を計算し、次に与えられた多項式をPOLYSIMPで 簡易化する。

 
(C17)GROBNER_BASIS([X,Y]);

(D17)/R/                          [- Y, - X]
(C18)  POLYSIMP(Y^2*X+X^3*9+2*Z);

(D18)/R/                              2 Z
	    

(C17)に示す様に、先程のGROBNER_BASISの結果は再設定されており、 (D18)の2*ZはQ[X,Y,Z]/<X,Y>の元である。

因に、複素数を多項式で表現する事も可能である。次の例では、 X^2-1のGROBNER_BASISを計算する(計算しなくても、答えは符号を 除いて同じものになる)と、POLYSIMPではX^2=-1として多項式を簡易化 する。その為、実数係数の多項式環R[X]に対し、R[X]/<X^2-1>は 複素数Cと同じ代数構造を持つ。


(C19) GROBNER_BASIS([X^2+1]);

                                      2
(D19)/R/                           [-x  - 1]
(C20) POLYSIMP(X^2+2*X+1);

(D20)/R/                              2 X
(C21) POLYSIMP(X^4+3*X^3+9*X+1);

(D21)/R/                            6 X + 2

	    

上の例でやっている事は、結局、X^2=-1の関係を入れて簡易化している 事になるが、それは結局、X=i(=sqrt(-1))として、計算を行っているのと 同じである。これはガウス平面で純虚数を考える幾何学的な見方と別の 見方である。

xgraph

MAXIMAの本家のftpサイトからxgraph-11a.tgzを入手し、適当な ディレクトリに展開する。次に、xmkmf -aを実行してmakeすれば良い筈 だが、glibc2.xの環境ではstrcpyの引数の問題でコンパイルに失敗する。 xtb.cの49行の"extern char *strcpy();"の個所を安易にコメントアウト するとコンパイルに成功する。インストールはmake installを行う だけで良く、/usr/X11R6/binにxgraphがインストールされる。

Geomview

現在、geomviewもそれ自身のサイト(http://www.geomview.org/) があり、そこからgeomview本体や関連するアプリケーションの ソースが入手可能である。従来のGeometry Centerのサイトもある が、こちらは古い版のソースとバイナリのみの配布を行っている。

コンパイルには少なくともMesaGLが必要である。又、外部モジュール の幾つかでxformsの開発環境が必要となるが、Geomviewのコンパイル に必須のものでは無い。コンパイル自体は適当なディレクトリで展開し、 configureを実行するだけである。前述の様に、ここで注意する事は XFORMSを用いるかどうかである。Geomviewの幾つかのモジュールで それを用いており、xforms抜きでは普通の可視化ツールに近い有様に なってしまう。例えば、様々な多様体の可視化(或いは散歩が出来る) 外部モジュールのManiviewが使えない。因にdebianではnon-freeなもの を排除する方針により、Geomviewもconfigure --without-xformsで コンパイルされている。尚、configureでprefixを特に指定しないと prefixは/usr/local/Geomviewになり、バイナリや例題等はそこに インストールされる。

ソースは現在http://www.geomview.org/から入手可能である。 Geometry Centerのサイトには古い1.6.9のソースとバイナリがあるが、 こちらのコンパイルは現在のglibc2の環境では相当難しいと思われる。 Geomviewのコンパイルは1.8.xでは昔のものと比べて格段に易しく なっている。と云うのも、以前のものでは機種に応じた変数の設定 が必要で、現在の様にconfigureで出来る筈のものでは無かった為で ある。とは云え、glibc 2.2の環境でコンパイルに失敗する事がある。 この件に関してはglibc-develに附属の FAQ 2.34 When compiling C++ programs, I get a compilation error in streambuf.hによると この現象はg++が2.95.2の場合に生じ、その理由はfpos_t型の 変数がglibc2.2で変更された為である。対処方法は /usr/include/g++/streambuf.hにpatchを当てる。このpatchは http://clisp.cons.org/~haible/gccinclude-glibc-2.2-compat.diff にある。patch にも参考迄に置いておく。

GNU TeXmacs

http://www.texmacs.org から入手可能。インストールにはguileが必要。尚、redhat系の場合は guilde-develが必要で、SuSEの場合はguileがインストールされていれば 良い。後はconfigureを実行し、make,make installを行えば/usr/local 以下にインストールされる。Maxima等のフロントエンドとして利用する為 には、真中のツールバーの左端にあるディスプレイのアイコンを押して、 maximaを選択すると良い。するとmaximaが立ち上げられる。又、最上部 のInsertメニューからsessionを選択すると上述のアイコンを押して得ら れるのと同じメニューが出るので、そこからmaximaを選ぶ。尚、一旦、 sessionを選択すると、新しいバッファを開かない限り、sessionメニュー が選択出来ない。ここで、以下にGNU TeXmacsでMaximaを利用している様子 を示しておく:

この様に出力結果のレンダリングが行われ、更に、画像の貼り付けも行な える。このGNU TeXmacsが上手く動作すれば、一見すると商用のツールとの 違いが分らなくなる。

GCL上のMaximaで利用する場合には、特に修正を行う必要は無い。 但し、CLISP上のMaximaで利用する場合には、GNU TeXmacsでmaximaを起動 するスクリプトtm_maximaの修正が必要である。このスクリプトは、 /usr/libexec/TeXmacs-0.3.5.8/binか/usr/local/libexec/TeXmacs-0.3.5.8/bin のどちらかにインストールされている(TeXmacsのバージョンが0.3.5.8 の場合)。前者はRPMをインストールした場合で、後者は自力でインストール した場合のデフォルトディレクトリである。

この修正個所を以下に示す。

export TEXMACS_MAXIMA_PATH
#exec maxima -load "$TEXMACS_MAXIMA_PATH/texmacs.lisp" | maxima_filter  
      
export MAXIMA_DIRECTORY=/usr/local/maxima-5.6 
export MAXIMA_DIRECTORY 
exec /usr/lib/clisp/base/lisp.run -norc -M /usr/local/maxima-5.6/src/maxima-clisp.mem -i \
 "$TEXMACS_MAXIMA_PATH/texmacs.lisp" | maxima_filter
	      

ここで、clispを呼出している個所は、CLISP版のmaximaを実行する スクリプトに"-i"オプションを追加したものである。"-i"オプションを 用いると、その後に指定したファイルを起動時に読込む仕様となっている。 尚、このCLISPにメモリイメージを指定して起動する様に修正しなければ TeXmacs上でmaximaを指定しても、一切の応答が返ってこないので注意する。

このGNU TeXmacsでmaximaを用いると、その計算結果をLaTeXやPS等の形式で 出力する事が可能である。しかし、以前のセッションをLaTeXで出力し、それ を読込んでもGNU TeXmacs上で上手く表示されない。その為、後でGNU TeXmacs で編集する事を考えると、TeXmacs形式かVerbatimで保存する方が良い。 この場合、単にファイル名を指定してGNU TeXmacsの形式を選択して出力し ても、その修飾子".tm"を付けなければ空のファイルが出力されるだけの様だ。 但し、ファイルに修飾子".tm"を付けていればこの様な問題は無い。 又、LaTeXで出力するとTeXmacsで\verb命令でverbatimにする語句を記号で 囲むが、その記号が日本語で文字化けするものである。一応、latex2htlml やSuSEのTeX環境で使えなくはないものである事を確認しているが、pLaTeX等 で問題が無いかどうかは環境が無いので分らない。この点に関しては、 GNU TeXmacsの修正が必要と思える。 TeXmacs-(version)/src/Convert/Tex/totex.gen.ccの480、482行目が \verbの記号を決めている個所で、そのverbの後にある記号を"+"等にして おくと良い。修正後の関連個所付近を以下に示しておく。

totex.gen.ccの修正個所の前後

    476   else if ((n == 3) && (t[0] == "input")) {
    477     print ("\\bgroup\\ttfamily ");
    478     tex (t[1]);
    479     print ("\\egroup");
    480     print ("\\verb+");
    481     tex (t[2]);
    482     print ("+");
    483     ret ();
	      

尚、 TeXmacsで出力したLaTeXファイルをlatex2htmlでhtmlに変換した実例 に示す様に、CLISPのシンボル(7枝の燭台)が意味不明な代物となっている 他は特に問題は無い。LaTeXのコンパイルエラーはこの燭台で用いている記号 に反応するものである。この辺の修正は少し難しく思えるので、出力した ファイルからこの個所を差し替える/削るスクリプトを準備すれば良いの だろう。参考迄に安易なawkのスクリプトを以下に示しておく。

安易なawkのスクリプトmike


#/bin/sh

# 引数を二つ取るスクリプト。mike hoge.tex > hogehoge.texの様に使う。
# この場合、hoge.texがclisp maximaでLaTeX形式でExportしたもので、
# hogehoge.texがロゴの修正を加えたもの。

cat $1 | awk 'BEGIN{n=0;F[1]="\\bgroup\\ttfamily";
F[2]="\\begin{verbatim}";
F[3]="  i i i i i i i       ooooo    o        ooooooo   ooooo   ooooo";
F[4]="  I I I I I I I      8     8   8           8     8     o  8    8";
F[5]="  I  \\ \x60+\x27 /  I      8         8           8     8        8    8";
F[6]="   \\  \x60-+-\x27  /       8         8           8      ooooo   8oooo";
F[7]="    \x60-__|__-\x27        8         8           8           8  8";
F[8]="        |            8     o   8           8     o     8  8";
F[9]="  ------+------       ooooo    8oooooo  ooo8ooo   ooooo   8";
F[10]="\\end{verbatim}";}
{n=n+1;if(n>27 || n<14){print $0}else{print F[n-13]}}'
	      

GNU TeXmacsを終了するとmaximaもちゃんと終了する為、Quit();を実行せず に終了するとmaximaが残ってしまうxmaximaよりは安心して使える。 但し、demoを実行しても応答が無く、何らかのエラーが発生していても、 それが表に表示されないと云う欠点を持っているので、xmaximaと比べて 本来のFront endとしての機能では劣る面を持つ。とは言え、誰か日本語化に 挑戦しないかな? 皆を幸福にするチャンスだ!


Maximaで遊ぼうの目次に戻る
ponpoko
Last modified: Wed May 12 22:39:54 JST 2004