この記事は、式神巨大数2021への投稿用です。

投稿の要綱

  • プログラムの名前は、「くまくま3変数ψ数出力プログラム」です。
  • プログラムの部門は、プログラム化部門です。
  • プログラムのソースは、下記のソースコードにあるコードです。
  • プログラムの言語は、Javascriptです。
  • プログラムの実行方法は、 thenumber() です。
  • プログラムの出力方式は、目的の巨大数が関数 thenumber() の戻り値として出力されるという方式です。
  • プログラムが出力する巨大数の情報は、「このプログラムが出力する巨大数は ユーザーブログ:Kanrokoti/くまくま3変数ψ で定義されているくまくま3変数ψ数です。」です。

説明

  • 巨大数「くまくま3変数ψ数」は引数無しの関数 thenumber() として実装されています。
  • 巨大非可算順序数を得る関数 \(g(n)\) は g(n) として実装されています。
  • FGH \(f_X(n)\) は関数 fgh(X,n) として実装されています。
  • 関数の合成 \(f_X^m(n)\) は composition(X,n,m) として実装されています。
  • 展開関数 \(X[Y]\) は Kuma3ary.prototype.expand として実装されています。
  • dom 関数 \({\textrm{dom}}(X)\) は Kuma3ary.prototype.dom として実装されています。
  • 二項関係 \(X<Y\) は Kuma3ary.prototype.lt(X,Y) として実装されています。

テストの仕方

ソースコード

 /* https://googology.wikia.org/ja/wiki/%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%83%96%E3%83%AD%E3%82%B0:Kanrokoti/%E3%81%8F%E3%81%BE%E3%81%8F%E3%81%BE3%E5%A4%89%E6%95%B0%CF%88#.E5.B7.A8.E5.A4.A7.E9.96.A2.E6.95.B0 */
 var thenumber = function(){
   var googolplex=1;
   for(i=0;i<100;i++)googolplex*=10;

   //I name F^10^100(10^100) "Kumakuma 3 variables Psi number.
   var _thenumber=F(googolplex);
   for(i=1;i<googolplex;i++)_thenumber = F(_thenumber);

   return _thenumber;
 }

 var F=function(n){
   //F(n)=f_{p_0(0,g(n))}(n).
   return fgh(new Kuma3ary(",",[0,0,g(n)]),n);
 }

 var g=function(n){
   //1. If n=0, then g(n)=p_0(0,0).
   if(n==0)return Kuma3ary.k0;
   //2. Otherwise, then g(n)=p_{g(n-1)}(0,0).
   else return new Kuma3ary(",", [g(n-1),Kuma3ary.k0,Kuma3ary.k0])
 }

 var fgh=function(X,n){
   //1. If X=0, then f_X(n)=n+1
   if(X.iszero()) return n+1;
   //2. If X=$1 or X=Y+$1 for some Y in T, then f_X(n)=f_X[0]^n(n)
   else if(X.isone() || (X.isadd() && X.a[X.a.length-1].isone())) return composition(X.expand(Kuma3ary.k0),n,n);
   //3. If neither or them, them f_X(n)=f_{X[$n]}(n)
   else return fgh(X.expand(new Kuma3ary(n)),n);
 };

 /* composition(X,n,m) = f_X^m(n) */
   var composition=function(X,n,m){
   if(m==0)return n;
   else if(m==1)return fgh(X,n);
   else return composition(X,fgh(X,n),m-1);
 }

 /* @fn new Kuma3ary(t,a)
  * @brief initialize a new object for kuma kuma 3-ary Psi by t and a.
  * @param t = {"0", "1", "2", ... , "9", "w","+",","} = initialize type
  *  When t = "0" -- "9", the object is initialized as the natural number.
  *  When t = "w"       , the object is initialized as the first transfinite ordinal.
  *  When t = "+" and a=[a0,a1,...,aN], the object is initialized as the ordinal which indicates a0+a1+a2...aN.
  *  When t = "," and a=[a0,a1,...,aN], the object is initialized as the ordinal which indicates (a0,a1,a2,...,aN).
  * @param a = parameter set for "+" and ",". see reference for t.
  */
 Kuma3ary = function(t,a){
   /* programmer memo: Define conversion from suger syntax to the object here. */
   switch(t){
     case "0":
       this.t="0";
       this.a=null;
     return;
     case "1":
       this.t=",";
       this.a=[new Kuma3ary("0"), new Kuma3ary("0"), new Kuma3ary("0")];
     return;
     case "w":
       this.t=",";
       this.a=[new Kuma3ary("0"), new Kuma3ary("0"), new Kuma3ary("1")];
     return;
     case "W":
       this.t=",";
       this.a=[new Kuma3ary("0"), new Kuma3ary("1"), new Kuma3ary("0")];
     return;
     case "e":
       this.t=",";
       this.a=[new Kuma3ary("0"), new Kuma3ary("0"), new Kuma3ary("W")];
     return;
     case "z":
       var k=Kuma3ary.parse("(0,0,(0,1,W))");
       this.t=k.t;
       this.a=k.a;
     return;
     case "G":
       var k=Kuma3ary.parse("(0,0,(0,1,(0,1,W)))");
       this.t=k.t;
       this.a=k.a;
     return;
     default:
     break;
   }
   if(isFinite(t)){ //nat
     if(t==0){
       this.t="0";
       this.a=null;
     }else if(t==1){
       this.t=",";
       this.a=[new Kuma3ary("0"), new Kuma3ary("0"), new Kuma3ary("0")];
     }else{
       this.t="+";
       this.a=new Array(parseInt(t));
       for(var i=0;i<this.a.length;i++){
         this.a[i]=new Kuma3ary("1");
       }
     }
     return;
   }
   
   /* programmer memo:  "+", "," can be parsed by Ordinal built-in function. */
   if(t=="+"||t==","){
     Ordinal.call(this,t,a);
   }else{
     var o=Ordinal.parse(t);
     this.t=o.t;
     this.a=o.a;
   }
 }

 /* @fn Kuma3ary.toSugar
  * @brief Callback for sugar for toString(sugar). 
  * @detail When you use kuma.toString(), if you add the function for the parameter of toString() like kuma.toString(Kuma3ary.toSugar), toString will become to use the sugar syntax defined in the function. 
  * @param str = input string from toString().
  * @returns str = modified string which is finally output by toString(). */
 Kuma3ary.toSugar = function(str){
   /* programmer memo: Define conversion from the object to the suger syntax here. */
   switch(str){
     case "(0)": case "(0,0)": case "(0,0,0)":
     return "1";
     
     case "(1)": case "(0,0,1)": case "(0,0,1)":
     return "w";
     
     case "(1,0)": case "(0,1,0)":
     return "W";
     
     case "(0,W)": case "(0,0,W)":
     return "e";
     
     case "(0,(0,1,W))": case "(0,0,(0,1,W))":
     return "z";
     
     case "(0,(0,1,(0,1,W)))": case "(0,0,(0,1,(0,1,W)))":
     return "G";
   }
   return str;
 }

 /* programmer memo: Please put the code as following to make the type Kuma3ary the extension of the type Ordinal. */
 /* ------------------0---------------------------------- begin */
 Kuma3ary.prototype = Object.create(Ordinal.prototype);
 Object.defineProperty(Kuma3ary.prototype, 'constructor', 
   {value:Kuma3ary, enumerable:false, writable:true});
 Kuma3ary.parse     = Ordinal.parse;
 Kuma3ary.add       = Ordinal.add;
 Kuma3ary.cat       = Ordinal.cat;
 /* ----------------------------------------------------- end */

 Kuma3ary.prototype.normalize = function(){
   Ordinal.prototype.normalize();
   if(this.t==","){
     if(this.a.length==1) this.a=[].concat([Kuma3ary.k0,Kuma3ary.k0],this.a);
     if(this.a.length==2) this.a=[].concat([Kuma3ary.k0            ],this.a);
   }
 }
 Kuma3ary.prototype.iszero=function(){return this.eq(Kuma3ary.k0);}
 Kuma3ary.prototype.isone =function(){return this.eq(Kuma3ary.k1);}
 Kuma3ary.prototype.isw   =function(){return this.eq(Kuma3ary.kw);}
 Kuma3ary.prototype.isPT  =function(){return this.t==",";}
 Kuma3ary.prototype.isadd =function(){return this.t=="+";}
 Kuma3ary.prototype.slice =function(s,e){ return new Kuma3ary(this.t, this.a.slice(s,e));}
 Kuma3ary.prototype.eq    =function(x){return Kuma3ary.eq(this,x);}
 Kuma3ary.prototype.lt    =function(x){return Kuma3ary.lt(this,x);}
 Kuma3ary.prototype.isfinite=function(){
   if(this.t=="0") return true;
   if(this.t=="+"){
     for(var i=0;i<this.a.length;i++){
       if(!this.a[i].isone()) return false;
     }
     return true;
   }else{
     return this.isone();
   }
 }
 Kuma3ary.prototype.toint=function(){
   switch(this.t){
     case "0": return 0;
     case "+": return this.isfinite()?this.a.length:-1;
     case ",": return this.isone()?1:-1;
     default : return -1;
   }
 }
 Kuma3ary.prototype.mul=function(n){
   if(n==0)return Kuma3ary.k0;
   if(n==1)return this;
   var a=new Array(n);
   for(var i=0;i<a.length;i++) a[i]=this;
   return new Kuma3ary("+",a);
 }

 Kuma3ary.eq=function(x,y){
   if(x.t!=y.t) return false;
   if(x.a instanceof Array && y.a instanceof Array){
     if(x.a.length!=y.a.length) return false;
     for(var i=0;i<x.a.length;i++){
       if(!Kuma3ary.eq(x.a[i],y.a[i])) return false;
     }
   }
   return true;
 }
 Kuma3ary.k0=new Kuma3ary("0");
 Kuma3ary.k1=new Kuma3ary("1");
 Kuma3ary.kw=new Kuma3ary("w");
 Kuma3ary.kW=new Kuma3ary("W");
 /* original part -------------------------------------------------------------------------------*/

 /** @fn lt(x,y)
   * @brief compare x and y and returns ordering of them.  
   * @param x = Kuma3ary ordinal notation.
   * @param y = Kuma3ary ordinal notation.
   * @returns = {true:x<y, false:x>=y}.
   * */
 /*-----------------------------------------------------------------------------
 Kanrokoti, "くまくま3変数ψ", 巨大数研究 Wiki, 2021-01-03T22:42:55.
   revision 33606, https://googology.wikia.org/ja/wiki/%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%83%96%E3%83%AD%E3%82%B0:Kanrokoti/%E3%81%8F%E3%81%BE%E3%81%8F%E3%81%BE3%E5%A4%89%E6%95%B0%CF%88?oldid=33606
   ---------------------------------------------------------------------------*/
 /* 順序 ここでは、表記間の大小関係を定義する。 */
 /* X,Y∈Tに対し、2項関係X<Yを以下のように再帰的に定める: */
 Kuma3ary.lt=function(X,Y){
   if(!X instanceof Kuma3ary) throw new Error("X is not Kuma3ary object.");
   if(!Y instanceof Kuma3ary) throw new Error("Y is not Kuma3ary object.");
   var eq = Kuma3ary.eq;
   var lt = Kuma3ary.lt;
   /* 1.         もしX=0ならば、X<Yは  Y≠0と同値である。 */
   /* 1       */ if(X.iszero()) return !Y.iszero();
   /* 2.         ここでX=ψ_{X_1}(X_2,X_3)を満たすX_1,X_2,X_3∈Tが存在するとする。 */
   /* 2       */ if(X.isPT  ()){
   /*         */   var X_1 = X.a[0]; var X_2 = X.a[1]; var X_3 = X.a[2];
   /* 2-1.         もしY=0ならば、X<Yは  偽である。 */
   /* 2-1     */   if(Y.iszero()) return false;
   /* 2-2.         ここでY=ψ_{Y_1}(Y_2,Y_3)を満たすY_1,Y_2,Y_3∈Tが存在するとする。 */
   /* 2-2     */   if(Y.isPT()){
   /*         */     var Y_1 = Y.a[0]; var Y_2 = Y.a[1]; var Y_3 = Y.a[2];
   /* 2-2-1.         もし   X_1= Y_1 かつ    X_2=Y_2 ならば、X<Yは     X_3<Y_3と同値である。*/
   /* 2-2-1   */     if( eq(X_1, Y_1) &&  eq(X_2,Y_2))       return lt(X_3,Y_3);
   /* 2-2-2.         もし   X_1= Y_1 かつ    X_2≠Y_2ならば、X<Yは     X_2<Y_2と同値である。*/
   /* 2-2-2   */     if( eq(X_1, Y_1) && !eq(X_2,Y_2))       return lt(X_2,Y_2);
   /* 2-2-3.         もし   X_1≠Y_1ならば、                 X<Yは     X_1<Y_1と同値である。 */
   /* 2-2-3   */     if(!eq(X_1, Y_1)                )       return lt(X_1,Y_1);
   /*         */   }
   /* 2-3.         もしY=Y_1+...+Y_{m'}を満たすY_1,...,Y_{m'}∈PT (2≦m'<∞)が存在するならば、 */
   /* 2-3     */   if(Y.isadd()){
   /*         */     var Y_1 = Y.a[0]; var Y_2 = Y.a[1]; var Y_3 = Y.a[2];
   /* ??           X<Yは     X=Y_1  または X<Y_1と同値である。 */
   /*         */     return eq(X,Y_1) ||  lt(X,Y_1);
   /*         */   }
   /*         */ }
   /* 3.         ここでX=X_1+...+X_mを満たすX_1,...,X_m∈PT (2≦m<∞)が存在するとする。 */
   /* 3       */ if(X.isadd()){
   /*         */   var X_1 = X.a[0]; var X_2 = X.a[1]; var X_3 = X.a[2]; var Xm = X.a.length;
   /* 3-1.         もしY=0ならば、X<Yは  偽である。 */
   /* 3-1     */   if(Y.iszero()) return false; 
   /* 3-2.         もしY=ψ_{Y_1}(Y_2,Y_3)を満たすY_1,Y_2,Y_3∈Tが存在するならば、
                                  X<Yは     X_1<Y と同値である。 */
   /* 3-2     */   if(Y.isPT  ()) return lt(X_1,Y); 
   /* 3-3.         ここでY=Y_1+...+Y_{m'}を満たすY_1,...,Y_{m'}∈PT (2≦m'<∞)が存在するとする。 */
   /* 3-3     */   if(Y.isadd ()){ 
   /*         */     var Y_1 = Y.a[0]; var Y_2 = Y.a[1]; var Y_3 = X.a[2]; var Ym = Y.a.length;
   /*         */     var X_2Xm = X.slice(1); /* X_2+X_3+...+Xm */
   /*         */     var Y_2Ym = Y.slice(1); /* Y_2+Y_3+...+Ym */
   /* 3-3-1.         ここでX_1=Y_1とする。 */
   /* 3-3-1   */     if(eq(X_1,Y_1)){
   /* 3-3-1-1.         もしm= 2かつ m'=2ならば、X<Yは   X_2         < Y_2と同値である。            */
   /* 3-3-1-1 */       if(Xm==2 && Ym==2)     return lt(X_2         , Y_2  );
   /* 3-3-1-2.         もしm= 2かつ m'>2ならば、X<Yは   X_2         < Y_2+...+Y_{m'}と同値である。 */
   /* 3-3-1-2 */       if(Xm==2 && Ym> 2)     return lt(X_2         , Y_2Ym);
   /* 3-3-1-3.         もしm> 2かつ m'=2ならば、X<Yは   X_2+...+X_m < Y_2と同値である。            */
   /* 3-3-1-3 */       if(Xm> 2 && Ym==2)     return lt(X_2Xm       , Y_2  );
   /* 3-3-1-4.         もしm> 2かつ m'>2ならば、X<Yは   X_2+...+X_m < Y_2+...+Y_{m'}と同値である。 */
   /* 3-3-1-4 */       if(Xm> 2 && Ym> 2)     return lt(X_2Xm       , Y_2Ym);
   /*         */     }
   /* 3-3-2.         もし   X_1≠Y_1ならば、X<Yは   X_1<Y_1と同値である。 */
   /* 3-3-2   */     if(!eq(X_1 ,Y_1))    return lt(X_1,Y_1);
   /*         */   }
   /*         */ }
 }

 /* 共終数 */
 /* ここでは、共終数という概念を定義する。 */
 Kuma3ary.prototype.dom=function(){
   var dom = function(A){return A.dom();};
   var lt = Kuma3ary.lt;
   var kw = Kuma3ary.kw;
   var k0 = Kuma3ary.k0;
   var X  = this;
   /* 1.      もし  X=0ならば、dom(X) = 0である。 */
   /* 1       */ if(X.iszero()) return k0;
   /* 2.         ここでX=ψ_{X_1}(X_2,X_3)を満たすX_1,X_2,X_3∈Tが存在するとする。 */
   /* 2       */ if(X.isPT  ()){
   /*         */   var X_1 = X.a[0]; var X_2 = X.a[1]; var X_3 = X.a[2];
   /* 2-1.         ここでdom(X_3)=0とする。 */
   /* 2-1     */   if(   dom(X_3).iszero()){
   /* 2-1-1.        ここでdom(X_2)=0とする。 */
   /* 2-1-1   */     if(  dom(X_2).iszero()){
   /* 2-1-1-1.         もしdom(X_1)=0    または dom(X_1)=$1ならば、dom(X)=Xである。 */
   /* 2-1-1-1 */       if( dom(X_1).iszero() || dom(X_1).isone())  return X ;
   /* 2-1-1-2.         もしdom(X_1)≠0        ,          $1ならば、dom(X)=dom(X_1)である。 */
   /* 2-1-1-2 */       if(!dom(X_1).iszero() &&!dom(X_1).isone())  return dom(X_1);
                     }
   /* 2-1-2.         もしdom(X_2)=$1ならば、dom(X)=Xである。 */
                     if( dom(X_2).isone()) return  X;
   /* 2-1-3.         ここでdom(X_2)≠0       ,            $1とする。 */
   /* 2-1-3   */     if(  !dom(X_2).iszero() && !dom(X_2).isone()){
   /* 2-1-3-1.         もし  dom(X_2)<Xならば、dom(X)=dom(X_2)である。 */
   /* 2-1-3-1 */       if(lt(dom(X_2),X))      return dom(X_2);
   /* 2-1-3-2.         そうでないならば、      dom(X)=$ωである。 */
   /* 2-1-3-2 */       else                    return kw;
   /*         */     }
   /*         */   }
   /* 2-2.         もしdom(X_3)=$1   またはdom(X_3)=$ωならば、dom(X)=$ωである。 */
   /* 2-2     */   if( dom(X_3).isone() || dom(X_3).isw())     return kw;
   /* 2-3.             dom(X_3)≠0       ,            $1      ,            $ωとする。 */
   /* 2-3     */   if(!dom(X_3).iszero() && !dom(X_3).isone() && !dom(X_3).isw()){
   /* 2-3-1.         もし  dom(X_3)<Xならば、dom(X)=dom(X_3)である。 */
   /* 2-3-1   */     if(lt(dom(X_3),X))return       dom(X_3);
   /* 2-3-2.         そうでないならば、dom(X)=$ωである。 */
   /* 2-3-2   */     else              return kw;
   /*         */   }
   /*         */ }
   /* 3.         もしX=X_1+...+X_mを満たすX_1,...,X_m∈PT (2≦m<∞)が存在するならば、*/
   /* 3       */ if(X.isadd()){
   /*              dom(X)= dom(X_  m            )である。 */
                   return  dom(X.a[X.a.length-1]);
                 }
   throw new Error("You Died");
   return null;
 }

 /* 基本列 */
 /* ここでは、基本列という概念を先で定義した共終数を用いて定義する。 */
 Kuma3ary.prototype.expand=function(Y){
   if(!Y instanceof Kuma3ary) throw new Error("Y is not Kuma3ary object.");
   var dom = function(A){return A.dom();};
   var lt = Kuma3ary.lt;
   var k0 = Kuma3ary.k0;
   var kw = Kuma3ary.kw;
   var X  = this;
   var newk = function(X_1,X_2,X_3){return new Kuma3ary(",",[X_1,X_2,X_3]);};
   /* 1.            もしX=0ならば、    X[Y]=0である。 */
                     if(X.iszero()) return k0;
   /* 2. ここでX=ψ_{X_1}(X_2,X_3)を満たすX_1,X_2,X_3∈Tが存在するとする。 */
   /* 2           */ else if(X.isPT  ()){
   /*             */   var X_1 = X.a[0]; var X_2 = X.a[1]; var X_3 = X.a[2];
   /* 2-1.             ここでdom(X_3)=0とする。 */
   /* 2-1         */   if(   dom(X_3).iszero()){
   /* 2-1-1.             ここでdom(X_2)=0とする。 */
   /* 2-1-1       */     if(   dom(X_2).iszero()){
   /* 2-1-1-1.             もしdom(X_1)=0ならば、 X[Y]   =0である。 */
   /* 2-1-1-1     */       if( dom(X_1).iszero()) return k0;
   /* 2-1-1-2.             もしdom(X_1)=$1ならば、X[Y]  = Yである。 */
   /* 2-1-1-2     */       if( dom(X_1).isone ()) return  Y;
   /* 2-1-1-3.             もしdom(X_1)≠0       ,          $1ならば、   X[Y]=ψ_{X_1 [      Y]}(X_2,X_3)である。 */
   /* 2-1-1-3     */       if(!dom(X_1).iszero()&&!dom(X_1).isone())  return newk(X_1.expand(Y), X_2,X_3);
   /*             */     }
   /* 2-1-2.             もしdom(X_2)=$1ならば、X[Y]  =Yである。 */
   /* 2-1-2       */     if(   dom(X_2).isone ()) return Y;
   /* 2-1-3.             ここでdom(X_2)≠0       ,          $1とする。 */
   /* 2-1-3       */     if(  !dom(X_2).iszero()&&!dom(X_2).isone()){
   /* 2-1-3-1.             もし  dom(X_2)<Xならば、X[Y]=ψ_{X_1}(X_2[       Y],X_3)である。 */
   /* 2-1-3-1     */       if(lt(dom(X_2),X))   return newk(X_1, X_2.expand(Y),X_3);
   /* 2-1-3-2.             そうでないならば、dom(X_2)=ψ_{P}(Q,0) (P,Q∈T)とおく。 */
   /* 2-1-3-2     */       else{
   /*             */         var P=dom(X_2).a[0]; 
   /*             */         var Q=dom(X_2).a[1];
   /* 2-1-3-2-1.             ここでQ=0とする。 */
   /* 2-1-3-2-1   */         if(   Q.iszero()){
   /* 2-1-3-2-1-1.             もしY=$h (1≦h<∞)かつ X[Y[0]]=ψ_{X_1}(Γ,X_3)となるΓ∈Tが一意に存在するならば、*/
   /* 2-1-3-2-1-1 */           if(!Y.iszero() && Y.isfinite()){
   /*             */             var Gamma=X.expand(Y.expand(k0)).a[1];
   /* ?????                    X[Y]=ψ_{X_1}(X_2[        ψ_{P       [ 0]}(Γ   ,  0)],X_3)である。 */
   /*             */             return newk(X_1, X_2.expand(newk(P.expand(k0), Gamma, k0)),X_3);
   /*             */           }
   /* 2-1-3-2-1-2.             そうでないならば */
   /*             */           else{
   /*                            X[Y]=   ψ_{X_1}(X_2[        ψ_{P       [ 0]}(Q    ,  0)],X_3)である。 */
   /*             */             return newk(X_1, X_2.expand(newk(P.expand(k0), Q,     k0)),X_3);
   /*             */           }
   /*             */         }
   /* 2-1-3-2-2.             ここでQ≠0とする。 */
   /* 2-1-3-2-2   */         if(  !Q.iszero()){
   /* 2-1-3-2-2-1.             もしY=$h (1≦h<∞)かつ*/ 
   /* 2-1-3-2-2-1 */           if(!Y.iszero() && Y.isfinite()){
   /*                            X[Y[0]]=ψ_{X_1}(Γ,X_3)となるΓ∈Tが一意に存在するならば、 */
   /*             */             var Gamma=X.expand(Y.expand(k0)).a[1];
   /* ?????                 X[Y]=   ψ_{X_1}(X_2       [ ψ_{P}(Q[0],Γ)],X_3)である。 */
   /*             */             return newk(X_1, X_2.expand(newk(P.expand(k0), Q, Gamma)),X_3);
   /*             */           }
   /* 2-1-3-2-2-2.             そうでないならば、 */
   /* 2-1-3-2-2-2 */           else{
   /*                            X[Y]=   ψ_{X_1}(X_2       [ ψ_{P}(Q       [ 0], 0)],X_3)である。*/
   /*             */             return newk(X_1, X_2.expand(newk(P, Q.expand(k0),k0)),X_3);
   /*             */           }
   /*             */         }
   /*             */       }
   /*             */     }
   /*             */   }
   /* 2-2.             ここでdom(X_3)=$1とする。 */
   /* 2-2         */   if(   dom(X_3).isone()){
   /* 2-2-1.             もしY=$1ならば、X[Y]=ψ_{X_1}(X_2,X_3[0])である。 */
   /* 2-2-1       */     if(Y.isone()) return newk(X_1,X_2,X_3.expand(k0));
                         var k=Y.toint();
   /* 2-2-2.             もしY=$k (2≦k<∞)ならば、 */
   /* 2-2-2       */     if(2<=k && k!=-1)
   /* ???               X[Y]=   ψ_{X_1}(X_2,X_3[        0])+
                               ...+ψ_{X_1}(X_2,X_3[        0]) (ψ_{X_1}(X_2,X_3[0])がk個)である。 */
                           return newk(X_1, X_2,X_3.expand(k0)).mul(k);
   /* 2-2-3.             そのいずれでもないならば、X[Y]=0である。 */
   /* 2-2-3       */     else                   return k0;
   /*             */   }
   /* 2-3.             もしdom(X_3)=$ωならば、X[Y]=ψ_{X_1}(X_2,X_3[Y])である。 */
   /* 2-3         */   if( dom(X_3).eq(kw)) return newk(X_1,X_2,X_3.expand(Y));
   /* 2-4.             ここでdom(X_3)≠0        ,           $1,                     $ωとする。 */
   /* 2-4         */   if(  !dom(X_3).iszero() && !dom(X_3).isone() && !dom(X_3).eq(kw)){
   /* 2-4-1.             もしdom(X_3)<   Xならば、X[Y]=ψ_{X_1}(X_2,X_3[       Y])である。 */
   /* 2-4-1       */     if( dom(X_3).lt(X)) return   newk(X_1, X_2,X_3.expand(Y));
   /* 2-4-2.             そうでないならば、dom(X_3)=ψ_{P}(Q,0) (P,Q∈T)とおく。 */
   /* 2-4-2       */     else{
                           var P=dom(X_3).a[0];
                           var Q=dom(X_3).a[1];
                           var h=Y.toint();
   /* 2-4-2-1.             ここでQ=0とする。 */
   /* 2-4-2-1     */       if(Q.iszero()){
   /* 2-4-2-1-1.             もしY=$h (1≦h<∞)かつ*/
   /* 2-4-2-1-1   */         if(1<=h && h!=-1){
   /* ???             ?    X[Y[0]]=ψ_{X_1}(X_2,Γ)となるΓ∈Tが一意に存在するならば、 */
   /*             */           var Gamma=X.expand(Y.expand(k0)).a[2];
   /*                             X[Y]=ψ_{X_1}(X_2,X_3       [ψ_{ P       [0 ]}(Γ   , 0)])である。 */
   /*             */           return newk(X_1, X_2,X_3.expand(newk(P.expand(k0), Gamma,k0)));
   /* 2-4-2-1-2.             そうでないならば、*/
   /* 2-4-2-1-2   */         }else{
   /*                          X[Y]=   ψ_{X_1}(X_2,X_3       [ψ_{ P       [0 ]}(Q     ,0)])である。 */
   /*             */           return newk(X_1, X_2,X_3.expand(newk(P.expand(k0), Q    ,k0)));
   /*             */         }
   /* 2-4-2-2.             ここでQ≠0とする。 */
   /*             */       }
   /* 2-4-2-2     */       if(!Q.iszero()){
   /*             */         var h=Y.toint();
   /* 2-4-2-2-1.             もしY=$h (1≦h<∞)かつ*/
   /* 2-4-2-2-1   */         if( 1<=h && h!=-1){
   /*                          X[Y[0]]=ψ_{X_1}(X_2,Γ)となるΓ∈Tが一意に存在するならば、 */
   /*             */           var Gamma=X.expand(Y.expand(k0)).a[2];
   /* ???              ?   X[Y]=   ψ_{X_1}(X_2,X_3       [ ψ_{P}(Q       [ 0],Γ    )])である。 */
   /*             */           return newk(X_1, X_2,X_3.expand(newk(P, Q.expand(k0), Gamma)));
   /* 2-4-2-2-2.             そうでないならば、*/
   /* 2-4-2-2-2   */         }else{
   /*                          X[Y]=   ψ_{X_1}(X_2,X_3[        ψ_{P}(Q       [0 ],     0)])である。 */
   /*             */           return newk(X_1, X_2,X_3.expand(newk(P, Q.expand(k0),    k0)));
   /*             */         }
   /*             */       }
   /*             */     }
   /*             */   }
   /*             */ }
   /* 3.             ここでX=X_1+...+X_mを満たすX_1,...,X_m∈PT (2≦m<∞)が存在するとする。 */
   /* 3           */ if(X.isadd()){
   /*             */   var m=X.a.length;
                       var X_m_Y          = X.a[m-1].expand(Y);
                       var X_1_t0__X__mm1 = X.slice(0,m-1);
   /* 3-1.             もしX_m[Y]=0        かつm= 2ならば、X[Y]=X_1である。 */
   /* 3-1         */   if( X_m_Y .iszero() &&  m==2)     return X.a[0];
   /* 3-2.             もしX_m[Y]=0        かつm> 2ならば、X[Y]=X_1+...+X_{m-1}である。 */
   /* 3-2         */   if( X_m_Y .iszero() &&  m> 2)     return X_1_t0__X__mm1;
   /* 3-3.             もしX_m[Y]≠0ならば、               X[Y]=X_1+...+X_{m-1}  +        X_m[Y]である。 */
   /* 3-3         */   if(!X_m_Y .iszero())              return X_1_t0__X__mm1  .addright(X_m_Y);
                     }
 }

 Kuma3ary.prototype.countzero=function(){
   var retval=0;
   if(this.iszero()) return 1;
   else{
     for(var i=0;i<this.a.length;i++) retval += this.a[i].countzero();
   }
 }
 Kuma3ary.prototype.isstd=function(){
   var X=this;
   var lt=Kuma3ary.lt;
   var lt=Kuma3ary.eq;
   if(X.iszero())return true;
   else if(X.isPT()){
     /* make S minimum (0,0,C) which S<X 
        C=((((...(0,0,0),0,0),0,0)...),0,0) */
     var C=Kuma3ary.k0;
     var S;
     while(1){
       S=new Kuma3ary(",",[0,0,C]);
       if(lt(X,S)){
         break;
       }
       C=new Kuma3ary(",",[C,0,0]); //upgrade C
     }
     if(eq(S,X)) return true;
     
     /* apply [0] to S while X.countzero()<S.countzero() */
     Xcountzero = X.countzero();
     while(Xcountzero<S.countzero()){
       S=S.expand(Kuma3ary.k0);
     }
     if(eq(S,X)) return true;
     
     
     L=L.expand(n);
     var n=0;
     var L2=L.expand(n);
     while(lt(L2,X)){
       n++;
       L2=L.expand(n);
     }
     if(X.equal(L2))return true;
     L.expand(n+1)
     
   }
   else{ /* + */
     for(var i=0;i<X.a.length-1;i++){
       if(lt(X.a[i],X.a[i+1]))return false;
     }
     return true;
   }
 }

 /* ordinal.js ------------------------------
  * The definition for abstruct ordinal object.
  * It has built-in function for
  *   - Ordinal.parse() ... parsing string -> ordinal,
  *   - obj.toString() .... convert ordinal -> string.
  * It supports additive tree type ordinal notation like
  *   - (0,0,(0,0,0))+(0,0)+0
  *   - and so on.
  */

 /* constructor -----------------------------*/

 /* @fn Ordinal(t,a)
  * @brief Ordinal abstruct type.
  * @param t = {"+", ",", others} = initialize type
  *  When t = "+" and a=[a0,a1,...,aN], the object is initialized as the ordinal which indicates a0+a1+a2...aN.
  *  When t = "," and a=[a0,a1,...,aN], the object is initialized as the ordinal which indicates (a0,a1,a2,...,aN).
  *  When t is other than the above, the object is initialized by calling Originaltype(t).
  * @param a = parameter set for "+" and ",". see reference for t.
  * @details
  * It requires:
  *   - The constructors definitions of Originaltype 
  *     other than Originaltype("+") and Originaltype(",").
  *     For example, Originaltype("0") or Originaltype("1") or other sugar syntax.
  *     This function calls Originaltype(t) when the constructor is missing.
  * */
 Ordinal = function(t,a){
   // string
   if((typeof t)!="undefined" && t=="s"){
     var o=Ordinal.parse(t);
     this.t=o.t;
     this.a=o.a;
     return;
   }
   //other
   if((typeof t)=="undefined" || (typeof a)=="undefined"){
     this.t = "0";
     this.a = [];
     return;
   }else{
     this.t = t;
     this.a = a;
     return;
   }
 };

 /* prototype functions -----------------------------*/

 /* @fn ordinal.clone()
  * @brief create a clone of this object with deep copy.
  * */
 Ordinal.prototype.clone = function(){
   Orgtype = this.constructor;
   switch(this.t){
     case "0":
     return new Orgtype("0");
     case ",":
     case "+":
       var a=new Array(this.a.length);
       for(var i=0;i<this.a.length;i++){
         a[i]=this.a[i].clone();
       }
     return new Orgtype(this.t, a);
     default:
     throw new Error("the t is not supported.");
     return;
   }
 }
 /* @fn ordinal.toString(sugar)
  * @brief output the string expression of the ordinal.
  * @param sugar is the function to make the string into sugar syntax.
  *  sugar can be omitted and it can be null. The normal string expression is returned in the cases.
  *  
  * */
 Ordinal.prototype.toString = function(sugar){
   if(typeof(sugar)!="function") sugar=null;
   var outstr="";
   switch(this.t){
     case "0":
       outstr+="0";
     break;
     case "+":
       for(var i=0;i<this.a.length;i++){
         if(i>0)outstr+="+";
         outstr+=this.a[i].toString(sugar);
       }
     break;
     case ",":
       outstr+="(";
       for(var i=0;i<this.a.length;i++){
         if(i>0)outstr+=",";
         outstr+=this.a[i].toString(sugar);
       }
       outstr+=")";
     break;
     default:
       return "error:this.type="+this.type;
     break;
   }
   if(typeof(sugar)=="function"){
     outstr=sugar(outstr);
   }
   return outstr;
 }

 /* @fn ordinal.toTree()
  * @brief output the tree expression of the ordinal.
  * */
 Ordinal.prototype.toTree = function(){
   var outstr="";
   switch(this.t){
     case "0":
       outstr+="0";
     break;
     case "+":
       outstr+="+^{";
       for(var i=0;i<this.a.length;i++){
         if(i>0)outstr+=",";
         outstr+=this.a[i].toTree();
       }
       outstr+="}";
     break;
     case ",":
       outstr+="psi^{";
       for(var i=0;i<this.a.length;i++){
         if(i>0)outstr+=",";
         outstr+=this.a[i].toTree();
       }
       outstr+="}";
     break;
     default:
       return "error:this.type="+this.type;
     break;
   }
   return outstr;
 }

 /* static functions -----------------------------*/

 /* @fn parse(text)
  * @brief parse string into ordinal object. 
  * @param text input string.*/
 Ordinal.parse = function(text){
   text=text.replace(/[\n\s]/g, "");
   
   /* depth analysis */
   var depth=Array(text.length);
   var now=0;
   var prevope="";
   for(var i=0;i<text.length;i++){
     var c=text[i];
     switch(c){
       case "(":
         depth[i]=now;
         now++;
       break;
       case ")":
         now--;
         for(var j=i;j>=0;j--){
           if((text[j]=="("||text[j]==",") && depth[j]<=now){
             depth[i]=depth[j];
             now=depth[j];
             break;
           }
         }
       break;
       case "+":
         var ibegin=0;
         for(var j=i;j>=0;j--){
           if(depth[j]<now){
             ibegin=j+1;
             break;
           }
         }
         Ordinal.debug(text, depth, now, "before upgrade");//debug

         if(ibegin>0 && text[ibegin-1]=="+"){ // leading +
           // already acsent -> nop
           now--;
           depth[i]=now;
           now++;
         }else{
           //acent left parameter of +
           for(var j=ibegin;j<i;j++){
             depth[j]++;
           }
           depth[i]=now;
           now++;
         }
         Ordinal.debug(text, depth, now, "after upgrade");//debug
       break;
       case ",":
         for(var j=i;j>=0;j--){
           if((text[j]=="("||text[j]==",") && depth[j]<now){
             depth[i]=depth[j];
             now=depth[j];
             break;
           }
         }
         depth[i]=now;
         now++;
       break;
       default:
         depth[i]=now;
       break;
     }
   }
   Ordinal.debug(text, depth, now, "final");//debug
   var retval = Ordinal.makeobjtree(text, depth, this.prototype.constructor);
   return retval;
 }

 /* inner functions -----------------------------*/

 /* @fn Ordinal.makeobjtree
  * @brief (inner function.) make an object tree of Orgtype from text and depth recursively with top down parsing.
  * @param text is input string. 
  * @param depth[i] is depth of the nest of the i th charactor of text. 
  * ex. text="(0,(0,0,0)+(0,0,0),0)",
  *    depth=[021232323212323232010]. */
 Ordinal.makeobjtree = function(text,depth,Orgtype){
   /* make object tree */
   var childbegin=0;
   var stack=[];
   var type="";
   for(var i=0;i<text.length;i++){
     var c=text[i];
     if(depth[i]==0){
       if(i>childbegin){
         var subdepth = depth.slice(childbegin,i);
         var subtext  = text.slice(childbegin,i);
         for(var j=0;j<subdepth.length;j++)subdepth[j]--;
         stack.push(Ordinal.makeobjtree(subtext, subdepth, Orgtype));
         childbegin=i+1;
         switch(text[i]){
           case "+":                     type="+"; break;
           case "(": case ",": case ")": type=","; break;
           default:break;
         }
       }else{
         childbegin=1;
       }
     }
   }
   if(i>childbegin){
     var subdepth = depth.slice(childbegin,i);
     var subtext  = text.slice(childbegin,i);
     for(var j=0;j<subdepth.length;j++)subdepth[j]--;
     stack.push(Ordinal.makeobjtree(subtext, subdepth, Orgtype));
   }
   var o;
   if(type==""){
     o = new Orgtype(text);
   }else{
     o = new Orgtype(type, stack);
   }
   o.normalize(); //after normalization
   return o;
 }
 /** @fn normalize()
   @brief normalizes x such as (1+1)+(1+1).
 */
 Ordinal.prototype.normalize = function(){
   if(this.t!="+"&&this.t!=",") return;
   
   for(var i=0;i<this.a.length;i++){
     //normalize children
     this.a[i].normalize();
     //check duplicated tree
     if(this.t=="+"){
       if(this.a[i].t=="+"){
         this.a=[].concat(this.a.slice(0,i), this.a[i].a, this.a.slice(i+1));
       }
     }
   }
   return this;
 }
 /**@fn o=Ordinal.add(a,b)
  * @brief return new object for a+b.
  * @details
  * Ordinal.add(a,b)      returns new Object added a and b.
  * ex.
  *  w^1+w^2+w^3+w^4+w^5+w^6 = Ordinal.add(w^1+w^2+w^3, w^4+w^5+w^6)
  *  
  * @param a = Added object in left  side of +. It should be object of Ordinal.
  * @param b = Added object in right side of +. It should be object of Ordinal.
  *            This parameter can be omitted.
  * @returns = a+b.
  */
 Ordinal.add = function(a,b){
   if(!(a instanceof Ordinal)){
     throw new Error("a is not instance of Ordinal");
     return null;
   }

   var o=a.clone();
   return o.addright(b);
 }
 /** @fn this=this.addright(b)
  *  @brief renew this into this+b.
  *  @param a = Added object. It should be object of Ordinal.
  *  @returns this = same as this.
  * ex.
  * x = w^1+w^2+w^3;
  * x.addright(w^4+w^5+w^6); // x = (w^1+w^2+w^3+w^4+w^5+w^6)
  */
 Ordinal.prototype.addright=function(b){
   if(!(b instanceof Ordinal)){
     throw new Error("b is not instance of Ordinal");
     return null;
   }
   var left;
   if(this.t=="+"){
     left=this.clone().a;
   }else{
     left=this.clone();
   }
   var right;
   if(b.t=="+"){
     right=b.a;
   }else{
     right=b;
   }
   
   this.t = "+";
   this.a = [].concat(left).concat(right);
   return this;
 }
 /** @fn this=this.addleft(a)
  *  @brief renew this into a+this.
  *  @param a = Added object. It should be object of Ordinal.
  *  @returns this = same as this.
  * ex.
  * x = w^4+w^5+w^6;
  * x.addleft(w^1+w^2+w^3); // x = (w^1+w^2+w^3+w^4+w^5+w^6)
  */
 Ordinal.prototype.addleft=function(a){
   if(!(b instanceof Ordinal)){
     throw new Error("b is not instance of Ordinal");
     return null;
   }
   var left;
   if(a.t=="+"){
     left=a.a;
   }else{
     left=a;
   }
   var right;
   if(this.t=="+"){
     right=this.clone().a;
   }else{
     right=this.clone();
   }
   
   this.t = "+";
   this.a = [].concat(left).concat(right);
   return this;
 }

 /**@fn o=Ordinal.cat(a,b,o)
  * @brief return new object which is concatenation of a and b.
  * @details
  * Ordinal.cat(a,b)      returns new Object that is the concatenation of a and b.
  * If a= (a0,a1,...,aN)  and b= (b0,b1,...,bN)  then o=( a0,a1,...,aN , b0,b1,...,bN ).
  * If a= (a0,a1,...,aN)  and b=[(b0,b1,...,bN)] then o=( a0,a1,...,aN ,(b0,b1,...,bN)).
  * If a=[(a0,a1,...,aN)] and b= (b0,b1,...,bN)  then o=((a0,a1,...,aN), b0,b1,...,bN ).
  * If a=[(a0,a1,...,aN)] and b=[(b0,b1,...,bN)] then o=((a0,a1,...,aN),(b0,b1,...,bN)).
  * ex.
  *  ( a,b,c , d,e)  = Ordinal.add( (a,b,c) , (d,e) ). (o will have 5 elements.)
  *  ((a,b,c), d,e)  = Ordinal.add([(a,b,c)], (d,e) ). (o will have 3 elements.)
  *  ( a,b,c ,(d,e)) = Ordinal.add( (a,b,c) ,[(d,e)]). (o will have 4 elements.)
  *  ((a,b,c),(d,e)) = Ordinal.add([(a,b,c)],[(d,e)]). (o will have 2 elements.)
  *  
  * @param o Destination object. It is omitted.
  *          When o is Ordinal, this object is renewed.
  *          When o is omitted, A new Object has type of a is created.
  * @param a = Concatenated object in the left side. It should be object of Ordinal.
  * @param b = concatenated object in the right side. It should be object of Ordinal.
  * @param a_wrapped When this is false or a is not , returns (a,b1,b2,...), otherwise returns (a1,a2,
  * @returns o = same as o.
  */
 Ordinal.cat = function(a,b,a_wrapped,b_wrapped){
   if(typeof a_wrapped == "undefined") a_wrapped=false;
   if(typeof b_wrapped == "undefined") b_wrapped=false;
   if(!(b instanceof Ordinal)){
     throw new Error("b is not instance of Ordinal");
     return null;
   }
   var o=a.clone();
   return o.catright(b,a_wrapped,b_wrapped);
 }
 /** @fn this=this.catright(b)
  *  @brief make this object (a1,a2,...b) when this object=(a1,a2,...).
  *  @param b = concatenated object. It should be object of Ordinal or [Ordinal].
  *  When b= Ordinal , this will be (a1,a2,...,b).
  *  When b=[Ordinal], this will be (a1,a2,...,b1,b2,...).
  *  @returns this = same as this.
  *  @details
  * ex.
  * x = ((a,b,c));
  * x.addright( (d,e,f) ); // x = (a,b,c, d,e,f )
  * x =  (a,b,c) ;
  * x.addright([(d,e,f)]); // x = (a,b,c,(d,e,f))
  *
  * If you need ((a,b,c), d,e,f) from this=(a,b,c) and (d,e,f), 
  *  use Ordinal.cat([this], (d,e,f) ,this) instead of this function.
  * If you need ((a,b,c),(d,e,f)), from this=(a,b,c) and (d,e,f),
  *  use Ordinal.cat([this],[(d,e,f)],this) instead of this function.
  */
 Ordinal.prototype.catright=function(b,a_wrapped,b_wrapped){
   if(typeof a_wrapped == "undefined") a_wrapped=false;
   if(typeof b_wrapped == "undefined") b_wrapped=false;
   if(!(b instanceof Ordinal)){
     throw new Error("b is not instance of Ordinal");
     return null;
   }
   var a=this.clone();
   var left;
   if(a.t=="," && !a_wrapped){
     left=a.a;
   }else{
     left=a;
   }
   var right;
   if(b.t=="," && !b_wrapped){
     right=b.a;
   }else{
     right=b;
   }
   this.t = ",";
   this.a = [].concat(left).concat(right);
   return this;
 }
 /** @fn this=this.catleft(a)
  *  @brief make this object (a,b1,b2,...) when this object=(b1,b2,...).
  *  @param a = concatenated object. It should be object of Ordinal or [Ordinal].
  *  When b= Ordinal , this will be (b,a1,a2,...).
  *  When b=[Ordinal], this will be (b1,b2,...,a1,a2,...,).
  *  @returns this = same as this.
  *  @details
  * ex.
  * x = ((d,e,f));
  * x.addleft( (a,b,c) ); // x = ( a,b,c ,d,e,f)
  * x =  (a,b,c) ;
  * x.addleft([(a,b,c)]); // x = ((a,b,c),d,e,f)
  *
  * If you need ( a,b,c ,(d,e,f)) from this=(a,b,c) and (d,e,f), 
  *  use Ordinal.cat( (a,b,c) ,[this]) instead of this fuction.
  * If you need ((a,b,c),(d,e,f)) from this=(a,b,c) and (d,e,f), 
  *  use Ordinal.cat([(a,b,c)],[this]) instead of this fuction.
  */
 Ordinal.prototype.catleft=function(a,a_wrapped,b_wrapped){
   if(typeof a_wrapped == "undefined") a_wrapped=false;
   if(typeof b_wrapped == "undefined") b_wrapped=false;
   if(b instanceof Array){
     b=b[0];
     b_wrapped=true;
   }
   if(!(b instanceof Ordinal)){
     throw new Error("b is not instance of Ordinal");
     return null;
   }
   var a=this.clone();
   var left;
   if(a.t=="," && !a_wrapped){
     left=a.a;
   }else{
     left=a;
   }
   var right;
   if(b.t=="," && !b_wrapped){
     right=b.a;
   }else{
     right=b;
   }
   this.t = ",";
   this.a = [].concat(left).concat(right);
   return this;
 }

 /** @fn Ordinal.debug 
   * @brief output text and depth and now with comment into cosole log. 
   * @param text  = text of makeobjtree ()
   * @param depth = depth of makeobjtree()
   * @param now   = current depth of the line
   * @param comment = the comment you like, which indicates place. */
 Ordinal.debug=function(text, depth, now, comment){
   if(0){ /* for debug */
     var depthstr="";
     var scalestr="";
     var nowstr  ="";
     for(var j=0;j<text.length;j++){
       scalestr+=(      j +"").slice(0,1);
       depthstr+=(depth[j]+"").slice(0,1);
       nowstr  +=j==now?"Vnow":" ";
     }
     console.log(" ");
     console.log(nowstr);
     console.log(scalestr+" "+comment);
     console.log(text    +" ");
     console.log(depthstr);
   }
 }
 Array.prototype.clone = function(){
     if ( this[0].constructor == Array ) {
         var ar, n;
         ar = new Array( this.length );
         for ( n = 0; n < ar.length; n++ ) {
             ar[n] = this[n].clone();
         }
         return ar;
     }
     return [].concat(this);
 }
 Array.prototype.toString = function(){
   var s="[";
   var i=0;
   for(i=0;i<this.length-1;i++){
     s+=this[i].toString()+", ";
   }
   if(this.length==0){
     s+="]";
   }else{
     s+=this[i].toString()+"]";
   }
   return s;
 }
特に記載のない限り、コミュニティのコンテンツはCC-BY-SA ライセンスの下で利用可能です。