For Development HEAD DRAFTSearch (procedure/syntax/module):

9.1 gauche.array - 配列

Module: gauche.array

このモジュールは多次元配列のデータタイプとそれに関する操作を提供します。 プリミティブなAPIはSRFI-25で定義されているものに従います。 任意のSchemeオブジェクトを保持できるSRFI-25の汎用配列の他に、 均一な数値ベクタ(ユニフォームベクタ参照)を使って 数値要素を効率良く保持する配列型も提供されます。 また、SRFI-10を使った配列の外部表現も実装されます。

N次元の配列の各エレメントはN個の整数のインデックス [ i_0 i_1i_N-1 ]でアクセスされます。 配列は、各次元のインデックスの下限s_kおよび上限e_kを決める shapeを持っています。ここで、s_k <= e_kであり、 k次元目のインデックスi_ks_k <= i_k < e_k を満たすものとします。 (s_k == e_k であるような配列も作れますが、 その配列にはデータをストアすることはできません。 また、0次元の配列は作れます。それは一つだけデータを保持できます)。 Shapeはそれ自体が [ D x 2 ] の配列です。 ここでDはそのshapeが表現する配列の次元数です。

配列のプリミティブに対しインデックスを渡すにはいくつか方法があります。 各インデックスをばらばらの引数として渡すこともできますし、 ベクタや1次元の配列にパックして渡すこともできます。 後者においてインデックスがパックされたベクタや配列を「インデックスオブジェクト」 と呼ぶことがあります。Gaucheでは、配列の要素に次々とアクセスするような処理では ベクタをインデックスオブジェクトとして使うと若干効率が良いでしょう。

配列はequal?手続きで比較することが出来ます。 二つの配列のshapeが等しく、また対応する各要素がequal?の意味で 等しい場合に二つの配列はequal?であると見なされます。

内部的には、配列は1次元のインデックスでアクセスされるバッキングストレージと、 多次元のインデックスをバッキングストレージへのインデックスにマップする手続きとから 構成されています。

Class: <array-base>

{gauche.array} 配列に関する汎用操作を実装している、抽象ベースクラスです。 実際に配列のインスタンスを作るには、以下のいずれかの具体クラスを使って下さい。

Class: <array>
Class: <u8array>
Class: <s8array>
Class: <u16array>
Class: <s16array>
Class: <u32array>
Class: <s32array>
Class: <u64array>
Class: <s64array>
Class: <f16array>
Class: <f32array>
Class: <f64array>

{gauche.array} 具体配列クラスです。<array>クラスはSRFI-25互換の配列、 すなわち、任意のSchemeオブジェクトを格納できる配列を実装します。 <u8array>から<f64array>までは、 それぞれ<u8vector>から<f64vector>をバッキングストレージとして 用いる配列を実装し、制限された範囲の整数もしくは非正確な実数のみを 効率良く格納することができます。

Reader Syntax: #,(<array> shape obj …)

配列はこの形式で書き出されます。 (配列が例えば<u8array>であるなら、<array>の部分は<u8array> となります。) shapeは偶数個の整数のリストで、 2n番目の整数がn次元目のインデックスの下限を、2n+1番目の 整数がn次元目のインデックスの上限(+1)を表します。 その後に、配列の要素がrow-majorの順で書き出されます。

この構文が読み込まれると、もとの配列とequal?である配列が作成されます。

; 次のような配列:
;   8 3 4
;   1 5 9
;   6 7 2
#,(<array> (0 3 0 3) 8 3 4 1 5 9 6 7 2)

; 4x4の単位行列
#,(<array> (0 4 0 4) 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1)
Function: array? obj

[SRFI-25]{gauche.array} objが配列であれば#tが、そうでなければ#fが返されます。 (is-a? obj <array-base>)と等価です。

Function: make-array shape :optional init

[SRFI-25]{gauche.array} Shapeがshapeである配列を作成します。 Shapeは [ D x 2 ] の配列で、 0 <= k < D なる各kに対して要素 [ k 0 ] は 要素[ k 1 ]以下でなければなりません。 initが与えられた場合は、配列の各要素がinitで初期化されます。 initが与えられなかった場合の配列の要素の初期値は不定です。

(make-array (shape 0 2 0 2 0 2) 5)
 ⇒ #,(<array> (0 2 0 2 0 2) 5 5 5 5 5 5 5 5)
Function: make-u8array shape :optional init
Function: make-s8array shape :optional init

Function: make-f32array shape :optional init
Function: make-f64array shape :optional init

{gauche.array} make-arrayと似ていますが、均一な数値配列を返します。

Function: array-copy array

{gauche.array} arrayと同じクラス、shape、内容を持つコピーを返します。

Function: shape bound …

[SRFI-25]{gauche.array} 偶数個の正確な整数を引数に取り、配列のshapeとして使える2次元の配列を返します。

(shape 0 2 1 3 3 5)
 ⇒ #,(<array> (0 3 0 2) 0 2 1 3 3 5)

(shape)
 ⇒ #,(<array> (0 0 0 2))
Function: array shape init …

[SRFI-25]{gauche.array} Shapeがshapeであるような配列を作成し、 その要素をinit …で初期化します。

(array (shape 0 2 1 3) 'a 'b 'c 'd)
 ⇒ #,(<array> (0 2 1 3) a b c d)
Function: u8array shape init …
Function: s8array shape init …

Function: f32array shape init …
Function: f64array shape init …

{gauche.array} arrayと同様ですが、init …で初期化された 均一な数値配列を返します。

(u8array (shape 0 2 0 2) 1 2 3 4)
 ⇒ #,(<u8array> (0 2 0 2) 1 2 3 4)
Function: array-rank array

[SRFI-25]{gauche.array} 配列arrayの次元数を返します。

(array-rank (make-array (shape 0 2 0 2 0 2))) ⇒ 3
(array-rank (make-array (shape))) ⇒ 0
Function: array-shape array

{gauche.array} 配列arrayのshapeを表す配列を返します。

Function: array-start array dim
Function: array-end array dim
Function: array-length array dim

[SRFI-25+]{gauche.array} array-startは配列arraydim番目の次元の インデックスの下限を返します。 array-endは上限+1を、そしてarray-lengthは両者の差を返します。 array-startarray-endはSRFI-25で定義されています。

(define a (make-array (shape 1 5 0 2)))

(array-start a 0)  ⇒ 1
(array-end a 0)    ⇒ 5
(array-length a 0) ⇒ 4
(array-start a 1)  ⇒ 0
(array-end a 1)    ⇒ 2
(array-length a 1) ⇒ 2
Function: array-size array

{gauche.array} 配列arrayの全要素数を返します。

(array-size (make-array (shape 5 9 1 3))) ⇒ 8
(array-size (make-array (shape))) ⇒ 1
(array-size (make-array (shape 0 0 0 2))) ⇒ 0
Function: array-ref array k …
Function: array-ref array index

[SRFI-25]{gauche.array} 配列arrayの要素を取り出します。最初の形式では、 要素は整数のインデックスk …で指定されます。 2番目の形式では、要素はベクタまたは1次元配列のインデックスオブジェクトindex で指定されます。

Function: array-set! array k … value
Function: array-set! array index value

[SRFI-25]{gauche.array} 配列arrayの要素にvalueをセットします。 最初の形式では、 要素は整数のインデックスk …で指定されます。 2番目の形式では、要素はベクタまたは1次元配列のインデックスオブジェクトindex で指定されます。

Function: share-array array shape proc

[SRFI-25]{gauche.array} Shapeがshapeであり、与えられた配列arrayとバッキングストレージを 共有する新しい配列を作成して返します。 procは、新しい配列へのインデックスを古い配列へのインデックスへ マップする手続きです。新しい配列の次元数をn、古い配列の次元数をmと した時、procn個の引数を取りm個の値を返す手続きでなければ なりません。さらに、各マッピングはaffineマッピング、すなわち、 出力は入力の線形合成(プラス定数)でなければなりません。 (share-arrayprocがaffineマッピングであるという事実に基づいた 最適化を行います。新しい配列にアクセスする度にprocが呼ばれるというわけでは ありません)。

Function: array-for-each-index array proc :optional index

{gauche.array} arrayの各インデックスに対してprocを呼びます。 index引数が省略された場合は、 procはインデックス (i, j,k,…) に対して (proc i j k …) のように呼ばれます。 最初は各次元のインデックスの最小値から始まり、後の方の次元が優先的にインクリメントされます。

gosh> (define a (array (shape 0 2 0 2) 1 2 3 4))
a
gosh> a
#,(<array> (0 2 0 2) 1 2 3 4)
gosh> (array-for-each-index a (^(i j) (print i","j)))
0,0
0,1
1,0
1,1

この形式の呼び出しは簡単なのですが、あまり効率が良くありません。 インデックスオブジェクトを省略可能引数indexに渡すことで、 より良い性能を引き出すことができます。 インデックスオブジェクトはループの度に、各インデックスを表す値に書き換えられます。 インデックスオブジェクトに使えるのは、変更可能な、ベクタ・1次元の配列・ s8vector・s16vectorあるいはs32vectorで、その長さは配列arrayの ランクと一致していなければなりません。インデックスオブジェクトを使うと、 ループ中に一切アロケーションが行われないため速度的に有利です。 ただし、ループの度にインデックスオブジェクトの内容が書き換えられることに 注意する必要があります。

gosh> (array-for-each-index a (cut format #t "~s\n" <>) (vector 0 0))
#(0 0)
#(0 1)
#(1 0)
#(1 1)

gosh> (array-for-each-index a (cut format #t "~s\n" <>) (s8vector 0 0))
#s8(0 0)
#s8(0 1)
#s8(1 0)
#s8(1 1)

戻り値は未定義です。

Function: shape-for-each shape proc :optional index

{gauche.array} シェイプshapeが表現する全ての可能なインデックスに対してprocを呼びます。 省略可能なindex引数の動作はarray-for-each-indexと同様です。 戻り値は未定義です。

gosh> (shape-for-each (shape 0 2 0 2) (^(i j) (print i","j)))
0,0
0,1
1,0
1,1
Function: tabulate-array shape proc :optional index

{gauche.array} shapeが表現する各インデックスについてprocを呼び出し、 その戻り値から配列を構築して返します。省略可能なインデックスオブジェクトの用途は array-for-each-indexと同じです。 次の例は与えられたシェイプに対する単位行列を生成します:

(tabulate-array (shape 0 3 0 3) (^(i j) (if (= i j) 1 0)))
  ⇒ #,(<array> (0 3 0 3) 1 0 0 0 1 0 0 0 1)
Function: array-retabulate! array proc :optional index
Function: array-retabulate! array shape proc :optional index

{gauche.array} 配列arrayの各インデックスに対してprocを呼び、その戻り値で arrayの要素を置き換えます。 省略可能なインデックスオブジェクトの用途は array-for-each-indexと同じです。 二番目の呼び出し形式は第二引数にシェイプを取ります。 それはarrayのシェイプと一致しなければなりません。 意味的には冗長ですが、shapeがリテラルである場合、 何らかの最適化がなされる可能性があります。 戻り値は未定義です。

Function: array-map proc array0 array1 …
Function: array-map shape proc array0 array1 …

{gauche.array} 引数array0, array1, …は同じシェイプを持つ 配列でなければなりません。各入力配列の対応する要素について、 それらを引数としてprocが呼ばれ、その戻り値から 新たな配列が作られて返されます。 二番目の呼び出し形式は第二引数にシェイプを取ります。 それは入力配列のシェイプと一致しなければなりません。 意味的には冗長ですが、shapeがリテラルである場合、 何らかの最適化がなされる可能性があります。

(array-map - (array (shape 0 2 0 2) 1 2 3 4))
  ⇒ #,(<array> (0 2 0 2) -1 -2 -3 -4)
Function: array-map! array proc array0 array1 …
Function: array-map! array shape proc array0 array1 …

{gauche.array} array-mapと似ていますが、procの結果は 与えられたarrayに格納されます。arrayのシェイプは 入力配列のシェイプと同じでなければなりません。 戻り値は未定義です。

Function: array->vector array
Function: array->list array

{gauche.array} arrayの全要素を並べたベクタもしくはリストを作って返します。

(array->vector
 (tabulate-array (shape 1 3 1 4)
                 (^(i j) (+ (* 10 i) j))))
 ⇒ #(11 12 13 21 22 23)
Function: array-concatenate a b :optional dimension

{gauche.array} 指定の次元で配列を結合します。指定の次元の大きさは一致していなければなりません。 それ以外のシェイプは異なっていても構いません。配列のランクはいくつであっても 構いませんが、両配列のランクは同じでなければなりません。

;;  [a b]              [a b]
;;  [c d] (+)       => [c d]
;;            [e f]    [e f]
(array-concatenate
 (array (shape 0 2 0 2) 'a 'b 'c 'd)
 (array (shape 0 1 0 2) 'e 'f))
 ⇒ #,(<array> (0 3 0 2) a b c d e f)

;;  [a b]     [e]    [a b e]
;;  [c d] (+) [f] => [c d f]
(array-concatenate
 (array (shape 0 2 0 2) 'a 'b 'c 'd)
 (array (shape 0 2 0 1) 'e 'f)
 1)
 ⇒ #,(<array> (0 2 0 3) a b e c d f)

;; 結合次元の大きさが同じであればインデックスの範囲は異なっていてもよい
(array-concatenate
 (array (shape 0 2 0 2) 'a 'b 'c 'd)
 (array (shape 1 3 0 1) 'e 'f) 1)
 ⇒ #,(<array> (0 2 0 3) a b e c d f)
Function: array-transpose array :optional dim1 dim2

{gauche.array} arrayはランク2以上の配列でなければなりません。 配列のdim1番目の次元とdim2番目の次元を転置します。 デフォルトは0番目と1番目です。

Function: array-rotate-90 array :optional dim1 dim2

{gauche.array} arrayはランク2以上の配列でなければなりません。 配列のdim1番目の次元とdim2番目の次元をそれぞれ行と列とみなした行列を 考え、その行列を時計まわりに90度回転した新たな配列を作って返します。

;; [1 2 3]      [4 1]
;; [4 5 6]  =>  [5 2]
;;              [6 3]
(array-rotate-90 (array (shape 0 2 0 3) 1 2 3 4 5 6))
 ⇒ #,(<array> (0 3 0 2) 4 1 5 2 6 3)

arrayのランクが2より大きい場合は、arrayは「部分配列の行列」 と考えられます。

Function: array-flip array :optional dimension
Function: array-flip! array :optional dimension

{gauche.array} 配列の内容を、指定番目の次元 (デフォルトは0) で裏返しにします。 array-flip!arrayを直接変更してそれを返します。 array-fliparrayには触らず、裏返した内容で新たな配列を作って返します。

;; [1 2 3]  =>  [4 5 6]
;; [4 5 6]      [1 2 3]
(array-flip (array (shape 0 2 0 3) 1 2 3 4 5 6))
 ⇒ #,(<array> (0 2 0 3) 4 5 6 1 2 3)

;; [1 2 3]  =>  [3 2 1]
;; [4 5 6]      [6 5 4]
(array-flip (array (shape 0 2 0 3) 1 2 3 4 5 6) 1)
 ⇒ #,(<array> (0 2 0 3) 3 2 1 6 5 4)
Function: identity-array dimension :optional class

{gauche.array} ランク2で行列ともにdimensionである単位行列を作って返します。 配列のクラスをclassに渡せば、結果はそのインスタンスになります。 デフォルトは<array>クラスです。

(identity-array 3)
 ⇒ #,(<array> (0 3 0 3) 1 0 0 0 1 0 0 0 1)

(identity-array 3 <f32array>)
 ⇒ #,(<f32array> (0 3 0 3) 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0)
Function: array-inverse array

{gauche.array} arrayを行列とみなし、その逆行列を返します。 arrayは2次元で、正方行列となるシェイプを持っていなければなりません。 そうでない場合はエラーが投げられます。

arrayが正則行列でない場合は#fが返されます。

Function: determinant array
Function: determinant! array

{gauche.array} arrayを行列とみなし、その行列式を計算します。 arrayは2次元で、正方行列となるシェイプを持っていなければなりません。 そうでない場合はエラーが投げられます。

また、determinant!は計算過程でarrayの内容を破壊します。 determinantは計算の前にarrayをコピーするオーバヘッドが ありますが、arrayは変更されません。

Function: array-mul a b

{gauche.array} 配列abはともに2次元でなければなりません。 それらを行列とみなして乗算を行います。aの行数とbの列数は 一致していなければなりません。

;;           [6 5]
;; [1 2 3] x [4 3] => [20 14]
;; [4 5 6]   [2 1]    [56 41]

(array-mul (array (shape 0 2 0 3) 1 2 3 4 5 6)
           (array (shape 0 3 0 2) 6 5 4 3 2 1))
 ⇒ #,(<array> (0 2 0 2) 20 14 56 41)
Function: array-expt array pow

{gauche.array} arraypow乗を返します。arrayは正方行列、 powは非負の正確な整数でなければなりません。

Function: array-div-left a b
Function: array-div-right a b

{gauche.array} array-mulの逆を行います。 array-div-left(array-mul B M)Aと 等しくなるような行列Mを、 array-div-right(array-mul M B)Aと 等しくなるような行列Mを返します。 ABは2次元の正方行列でなければなりません。 Bが正則行列でない場合はエラーが通知されます。

Function: array-add-elements array array-or-scalar …
Function: array-add-elements! array array-or-scalar …
Function: array-sub-elements array array-or-scalar …
Function: array-sub-elements! array array-or-scalar …
Function: array-mul-elements array array-or-scalar …
Function: array-mul-elements! array array-or-scalar …
Function: array-div-elements array array-or-scalar …
Function: array-div-elements! array array-or-scalar …

{gauche.array} 要素ごとの計算をする手続きです。2つ目以降の引数は、 最初の引数の配列と同じ形の配列か、数値でなければなりません。 数値の場合は、要素が全てその数値である、最初の引数の配列と同じ形の配列だと解釈されます。

要素ごとに加算、減算、乗算、除算を行い、結果を最初の引数の配列と同じ形の配列で返します。

!で終わっている手続きは、最初の配列を結果を作るために再利用するかもしれません。 したがって最初の配列は変更可能である必要があります。ただし、必ず再利用されるとは 限らないので、呼び出し側は常に戻り値を使う必要があります。

(array-add-elements (array (shape 0 2 0 2) 1 2 3 4)
                    (array (shape 0 2 0 2) 5 6 7 8)
                    10)
 ⇒ #,(<array> (0 2 0 2) 16 18 20 22)

(array-div-elements (array (shape 0 2 0 2) 1 3 5 7)
                    100
                    (array (shape 0 2 0 2) 2 4 6 8))
 ⇒ #,(<array> (0 2 0 2) 1/200 3/400 1/120 7/800)

ひとつだけ引数が渡された場合は、これらの手続きはその引数をそのまま返します。

形が同じであれば、異なる型の配列同士での演算もできます。 結果は最初の引数の配列の型になります。

(array-mul-elements (make-u8array (shape 0 2 0 2) 3)
                    (array (shape 0 2 0 2) 1 3 5 7))
 ⇒ #,(<u8array> (0 2 0 2) 3 9 15 21)
Function: array-negate-elements array
Function: array-negate-elements! array

arrayと同じ型、shapeだけれども各要素の符号が元の配列から反転されているような 配列を返します。

(array-negate-elements (array (shape 0 2 0 2) 1 2 3 4))
  ⇒ #,(<array> (0 2 0 2) -1 -2 -3 -4)
Function: array-reciprocate-elements array
Function: array-reciprocate-elements! array

arrayと同じ型、shapeだけれども各要素が元の配列の要素の逆数になっているような 配列を返します。

(array-reciprocate-elements (array (shape 0 2 0 2) 1 2 3 4))
  ⇒ #,(<array> (0 2 0 2) 1 1/2 1/3 1/4)


For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT