アーノルドの猫マップ


21

チャレンジ

同じ幅と高さのカラーラスターイメージ*が与えられた場合、Arnoldのcat mapで変換されたイメージを出力します。(*詳細は以下を参照)

定義

画像のサイズNが与えられると、ピクセルの座標が0との間の数として与えられると仮定しN-1ます。

Arnoldの猫マップは、次のように定義されます。

座標のピクセル[x,y]がに移動し[(2*x + y) mod N, (x + y) mod N]ます。

これはトーラス上の線形変換に他なりません。黄色、紫、緑の部分は、のために最初の正方形にマッピングされますmod N

視覚化

このマップ(呼び出しましょうf)には次のプロパティがあります。

  • これは全単射であり、可逆を意味します。これは、行列を使用した線形変換[[2,1],[1,1]]です。行列式が1あり、整数エントリのみを持つため、逆行列にも整数エントリのみがあり、で与えられます[[1,-1],[-1,2]]。これは、整数座標でも全単射であることを意味します。

  • これは、画像の全単射マップのグループのねじれ要素です。N x Nつまり、十分に何度も適用すると、元の画像が元に戻りますf(f(...f(x)...)) = x。マップ自体に適用される結果、同一性が得られる回数は、またはに等しい3*N。以下では、Arnoldの猫マップの反復アプリケーションの指定回数後の猫の画像と、繰り返しアプリケーションがどのように見えるかのアニメーションを見ることができます。

複数の繰り返しアプリケーション

詳細

  • プログラムは必ずしも画像を処理する必要はありませんが、2D配列/行列、文字列、または同様の2D構造も受け入れられます。

  • (0,0)ポイントが左下にあるか左上にあるかは関係ありません。(または、あなたの言語でこれがより便利な場合は、他のコーナーで。)提出で使用する規則を指定してください。

テストケース

マトリックス形式([1,2,3,4]最上行、1インデックスあり(0,0)2インデックスあり(1,0)5インデックスあり(0,1)

 1     2     3     4
 5     6     7     8
 9    10    11    12
13    14    15    16

maps to:

 1    14    11     8
12     5     2    15
 3    16     9     6
10     7     4    13

 --------------------

 1     2     3
 4     5     6
 7     8     9

 map to:

 1     8     6
 9     4     2
 5     3     7

画像として(左下は(0,0)):


1
貧しいレナ。あなたが十分に長く繰り返し続けることを願っています
ルイスメンドー

2
入力として画像サイズを使用できますか?常に正方形ですか?
xnor

1
はい、画像は常に正方形であり、サイズについてはわかりませんが、それ許可することに反対はありますか?
-flawr

回答:



7

MATL、23バイト

tt&n:qt&+&y\tb+&y\b*+Q(

(0,0)ポイントは、上部チャレンジテキストの例のように、残されています。

オンラインでお試しください!

説明

MATLのマトリックスには、2つではなく1つのインデックスを使用してインデックスを付けることができます。これは線形インデックス付けと呼ばれ、優先順を使用します。これは、各エントリの値が線形インデックスと一致する次の4×4マトリックスで示されています。

1   5   9  13
2   6  10  14
3   7  11  15
4   8  12  16

チャレンジでマッピングを実装するには、2つの同様のアプローチがあります。

  1. アーノルドの線形インデックスの逆マッピングを表すインデックスマトリックスを作成し、それを使用して元のマトリックスから値を選択します。4×4の場合、インデックス行列は次のようになります

     1  8 11 14
    15  2  5 12
     9 16  3  6
     7 10 13  4
    

    たとえば、x = 2 5でのオリジナルがy = 1でx = 3、y = 2になることを伝えます。この操作は参照インデックス付けと呼ばれます。インデックス付けマトリックスを使用して、元のマトリックスから選択する要素を指示します。これはfunctonで、2つの入力を取ります(デフォルト構成)。)

  2. アーノルドの線形インデックス直接マッピングを表すインデックスマトリックスを作成し、それを使用して元のマトリックスに値を書き込みます。4×4の場合、インデックス行列は次のようになります

     1 10  3 12
     6 15  8 13
    11  4  9  2
    16  5 14  7
    

    そのエントリを伝える 新しい行列 x = 2、y = 1が線形インデックス10、つまりx = 3、y = 2 のエントリに上書きされることを伝えます。これは、割り当てインデックス付けと呼ばれます。インデックス付けマトリックス、データマトリックス、および元のマトリックスを使用し、指定されたインデックスで元のマトリックスにデータを書き込みます。これはfunctionで(、3つの入力を取ります(デフォルト構成)。

方法1はより簡単ですが、方法2はより短いことが判明しました。

tt     % Take the input implicitly and push two more copies
&n     % Get its size as two (equal) numbers: N, N
:qt    % Push range [0  1 ... N-1] twice. This represents the original x values
&+     % Matrix of all pairwise additions. This represents x+y
&y     % Push a copy of N onto the top of the stack
\      % Modulo. This is the new y coordinate: y_new
t      % Push another copy
b+     % Bubble up the remaining copy of [0 1 ... N-1] and add. This is 2*x+y
&y     % Push a copy of N onto the top of the stack
\      % Modulo. This is the new x coordinate: x_new
b*+    % Bubble up the remaining copy of N, multiply, add. This computes
       % x_new*N+y_new, which is the linear index for those x_new, y_new 
Q      % Add 1, because MATL uses 1-based indexing
(      % Assigmnent indexing: write the values of the original matrix into
       % (another copy of) the original matrix at the entries given by the
       % indexing matrix. Implicitly display the result

5

Mathematica、44バイト

(n=MapIndexed[RotateLeft[#,1-#2]&,#]&)@*n

Lynnの素晴らしいアルゴリズムの移植。最後の前に、UTF-8エンコーディングのU + F3C7という目に見えない3バイト文字があり]ます。Mathematicaはそれを上付き文字としてレンダリングしT、行列の転置をとる。

Mathematica、54バイト

Table[#2[[Mod[2x-y-1,#]+1,Mod[y-x,#]+1]],{x,#},{y,#}]&

正の整数##2次元#xの2D配列の2つの引数を取り#、同様の形状の2D配列を返す名前のない関数。与えられたテストケースのように、座標{0,0}のポイントは左上にあり、x軸は水平です。[[1,-1],[-1,2]]質問で言及された逆行列を使用した簡単な実装。-1最初の座標は配列がMathematicaで本質的に1インデックスであるという事実を説明するためのものです。我々は追加の引数として行列の次元を取ることが許されていない場合は、この解決策は、(最初に置き換える9台のバイト長くなる#-notに#2-with a=Length@#と後続のすべて#とS a秒)。


ダン、私にbeatられた
ジョンファンミン

3

Python 2、89 82 77 73バイト

def f(a):exec'a=[l[-i:]+l[:-i]for i,l in enumerate(zip(*a))];'*2;return a

入力はリストのリストです
exec内の文字列はリストのリストを転置し、各インデックスを行インデックスで循環的に回転させます(0ベース-3行目は右に2回回転します)。
このプロセスは、入力に対して2回行われます。

変換をN回行う+4バイト

def f(a,n):exec'a=[l[-i:]+l[:-i]for i,l in enumerate(zip(*a))];'*2*n;return a

2

Haskell、55バイト

m#n|r<-[0..n-1]=[[m!!mod(2*y-x)n!!mod(x-y)n|x<-r]|y<-r]

使用例:[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]] # 4-> [[1,14,11,8],[12,5,2,15],[3,16,9,6],[10,7,4,13]]

0,0左上隅です。これは逆変換を使用します。


1

Python、69バイト

lambda M:eval("[r[-i:]+r[:-i]for i,r in enumerate(zip(*"*2+"M))]))]")

Rodの転置シフト2回法の改善。M -> [r[-i:]+r[:-i]for i,r in enumerate(zip(*M))]文字列を作成および評価して、操作を2回適用します

[r[-i:]+r[:-i]for i,r in enumerate(zip(*[r[-i:]+r[:-i]for i,r in enumerate(zip(*M))]))]

これは、画像が正方形で、その長さが入力として取得できると仮定して、直接変換(70バイト)をわずかに打ち負かします。

lambda M,n:[[M[(2*j-i)%n][(i-j)%n]for i in range(n)]for j in range(n)]

1

ImageJマクロ、29バイト

v=getPixel((x+y)%w,(2*y+x)%h)
  • レナのオープン画像
  • プロセスメニューから数学/マクロを選択...

これはf ^(-1)を実行しませんか?移動先の座標でピクセル値を取得します。あなたはおそらく意味しv=getPixel((2*y-x)%w,(x-y)%h)ます。
ロビン・コッホ

@RobinKochありがとう、2*x+y変更されました2*y+x
rahnema1

それは私が書いたことでも、私が意図したことでもありません。アプローチには逆変換が必要です。ためf(x,y) = (2x+y, x+y)、この逆変換によって記述されますf^(-1) = (x-y, 2y-x)。(私の他のコメントは間違っていました。)あなたのコードはそうですv=getPixel((x-y)%w,(2*y-x)%h)
ロビン・コッホ

数式をテストしたところ、結果は質問のレナの画像と同じ
です-rahnema1

@RobinKoch ImageJダウンロードして、両方の式をテストできます
rahnema1

1

Java、160

ゴルフ:

int[][]f(int[][]m){int x=0,y,l=m.length,r[][]=new int[l][];for(;x<l;++x)r[x]=new int[l];for(x=0;x<l;++x)for(y=0;y<l;++y)r[(x+y)%l][(2*x+y)%l]=m[y][x];return r;}

ゴルフをしていない:

  int[][] f(int[][] m) {
    int x = 0, y, l = m.length, r[][] = new int[l][];
    for (; x < l; ++x) {
      r[x] = new int[l];
    }
    for (x = 0; x < l; ++x) {
      for (y = 0; y < l; ++y) {
        r[(x + y) % l][(2 * x + y) % l] = m[y][x];
      }
    }
    return r;
  }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.