誤差のない音律データを求めて。
音律計算やその他について、気になった事をまったりと書いていこうと思います。
(元ブログ(goo)からの引越し。電波度を減らそうと試みた事もあるがちょっと難しそうだ。)

配列・ベクトル・行列(7)

エクセルで順列列挙(順列の書き出し)

作りやすさから尾固定循環型(仮)を採用

(前頁「配列・ベクトル・行列(6)」の順列の種類で言うと4.尾固定小行列循環シフト型(仮) r070404追記)

 

まずは半自動・半手作業で作成してみる

1行目のF11:K11部分(薄緑色)は

 F11= 1

 G11= =F11+1

 11行= G11を必要部分までコピペ(今回はG11:L11)

2x2行列に対応する順列増分(下に拡張)(薄青色)

 F12= =MOD(F11-2,2)+1

 G12= F12をコピペ

3x3行列に対応する順列増分(右に拡張)(薄赤色)

 H12= =H11

3x3行列に対応する順列増分(下に拡張)(薄青色)

 F13= =MOD(F11-2,3)+1

 F13:H16= F13をコピペ

4x4行列に対応する順列増分(右に拡張)(薄赤色)

 I12= =I11

 I12:I16= I12をコピペ

4x4行列に対応する順列増分(下に拡張)(薄青色)

 F17= =MOD(F11-2,4)+1

 F17:I34= F17をコピペ

5x5行列に対応する順列増分(右に拡張)(薄赤色)

 J12= =J11

 J12:J34= J12をコピペ

5x5行列に対応する順列増分(下に拡張)(薄青色)

 F35= =MOD(F11-2,5)+1

 F35:J130= F35をコピペ

以下同様 (不正確さを減らすため「順列」を「順列増分」に修正 r070404)

 

次に作業セル(A~D列)を駆使して全て同じ式にしたバージョン

 A列= データの行番号

  A11= =ROW()-ROW($F$11)+1

  A11:A733= A11をコピペ

 B列= A列の「階乗の逆関数」の切り上げ(「階乗の逆関数」は用意できなかったので代替手段で)

  B11= 1

  B12= =IF(C11<A12,1,0)+B11

  B12:B733= B12をコピペ

 C列= B列の階乗

  C11= =FACT(B11)

  C11:C733= C11をコピペ

 D列= B列-1の階乗

  D11= =FACT(B11-1)

  D11:D733= D11をコピペ

 F~L列= ifで場合分けして順列部分全てを1つの式にまとめた

  F11= =IF($A11>1,IF(F$11>$B11,F$11,MOD(INDIRECT("r[-"&$D11&"]c[0]",0)-2,$B11)+1),F$9)

  F11:L733= F11をコピペ

(列の説明はr070404に追記)

 

作業セルA~D列を使わずに同一の式で順列を列挙して行列式も計算した

 F11= =IF(ROW()-ROW($F$11)+1>1,IF(F$11>MATCH(ROW()-ROW($F$11),FACT({1,2,3,4,5,6,7}),1)+1,F$11,MOD(INDIRECT("r[-"&(FACT(MATCH(ROW()-ROW($F$11),FACT({1,2,3,4,5,6,7}),1)))&"]c[0]",0)-2,MATCH(ROW()-ROW($F$11),FACT({1,2,3,4,5,6,7}),1)+1)+1),COLUMN()-COLUMN($F$11)+1)

 F11:L733= F11をコピペ

 Q11= {=-1^SUM(IF({1;2;3;4;5;6;7}<{1,2,3,4,5,6,7},1,0)*IF(TRANSPOSE($F11:$L11)>$F11:$L11,1,0))} (配列数式)

 Q11:Q733= Q11をコピペ

 R11= =INDEX($R$1:$X$7,F11,R$9)

 R11:X733= R11をコピペ

 Z11= =PRODUCT($Q11:S11)

 Z11:Z12= Z11をコピペ

 AA11:AA16= Z11をコピペ

 AB11:AB34= Z11をコピペ

 AC11:AC130= Z11をコピペ

 AD11:AD730= Z11をコピペ

 Z7= =SUM(Z11:Z733)

 Z7:AD7= Z7をコピペ

 Z5= =MDETERM(R1:S2)

 AA5= =MDETERM(R1:T3)

 AB5= =MDETERM(R1:U4)

 AC5= =MDETERM(R1:V5)

 AD5= =MDETERM(R1:W6)

 

余談1 Q11について r070404追記

 次頁「配列・ベクトル・行列(8)」で説明

 

余談2 mod関数について r070404追記

 mod関数は「0始まりの循環(仮)」(正しい単語が分からない)なので、順列で利用するために「1始まりの循環(仮)」に修正する

 =mod(対象-1, 循環の数)+1

 そしてそれではただの同じ数になってしまうので循環させるために対象を「+1」か「-1」する。「+1」は今回の順列列挙において「・・・3 2 1」で終了しないので「-1」を採用

 =mod(対象-1-1, 循環の数)+1

この式がこの頁の最初の図の薄青部分

 

余談3 r070404追記

 2番目の画像の「階乗の逆関数」の切り上げの代替手段について

  b12= {=match(A12-1,fact({1,2,3,4,5,6,7}),1)+1} (配列数式 エクセル・リブレオフィス)

  b12= =ArrayFormula(match(A12-1,fact({1,2,3,4,5,6,7}),1)+1) (配列数式 グーグルドライブ)

 もし大きい数が必要なら配列定数を拡大したり配列セル式(仮)(column(範囲))を活用すればよい

 

余談4 r070425追記

 たとえば「現セルの6つ上」を今回はindirect関数とr1c1形式を使って実現した。検索してみると他にも使えそうな方法があるようなので後で試してみたい。

 1. indirect関数とaddress関数(こっちの方が正統派かも)

 2. offset関数(循環参照になりそう?)

ただindirect関数もoffset関数も揮発性関数と言って処理が重くなるので可能なら避けた方が良いらしい。index関数で実現できないかも試してみたい。