ニュートンフラクタルを生成する


24

あなたは皆、関数の根を近似するニュートン法を知っていますよね?このタスクの私の目標は、このアルゴリズムの興味深い側面を紹介することです。

ニュートンのアルゴリズムは、特定の、しかしほとんどすべての複雑な入力値に対してのみ収束します。複素平面上のすべての入力値に対するメソッドの収束を想像すると、通常、次のような美しいフラクタルが得られます。

f(x)= x ^ 3-1のニュートンフラクタル ウィキメディアコモンズの画像

仕様書

このタスクの目標は、そのようなフラクタルを生成することです。つまり、入力として多項式を取得し、対応するフラクタルを出力として選択した形式の画像として印刷する必要があります。

入力

入力は、空白で区切られた複素数のリストです。これらは<Real part><iImaginary part>、この番号のようにスタイルで書き留められています5.32i3.05。入力番号の小数点以下の桁数は4以下で、1000より小さいと想定できます。最初の数値はゼロであってはなりません。たとえば、これはプログラムへの入力になります。

1-2i7.5 23.0004i-3.8 i12 0 5.1233i0.1

数値は、多項式の係数として解釈され、最高のパワーから始まります。この仕様の残りの部分では、入力多項式はPと呼ばれます。上記の入力は、この多項式に等しくなります。

f(x)= x 5 +(-2 + 7.5 i)x 4 +(23.0004-3.8 i)x 3 + 12 i x 2 + 5.1233 + 0.1 i

入力は、stdin、プログラムに渡された引数、またはプログラムに表示されるプロンプトのいずれかから送られます。入力に先頭または末尾の空白文字が含まれていないと想定できます。

レンダリング

次の方法でフラクタルをレンダリングする必要があります。

  • Pの根と同じ数の色と発散のための追加の色を選択します
  • 可視面の各数値について、メソッドが収束するかどうか、および収束する場合はどのルートに到達するかを決定します。結果に応じてポイントに色を付けます。
  • 定規などの派手なものを印刷しないでください
  • 方向の多項式の根である点に黒い点を印刷します。各ルートの周囲に最大4ピクセルを印刷できます。
  • 可能であれば、すべてのルートが識別可能であり、広範囲に広がるように、可視プレーンを選択する方法を見つけます。出力フレームを完全に配置する必要はありませんが、許容できない方法でフレームを選択する回答を受け入れることを拒否する権利を留保します。常に同じ座標で、すべてのルートが1つのポイントにあるなど。
  • 出力画像のサイズは1024 * 1024ピクセルにする必要があります。
  • レンダリング時間は最大10分です
  • 単精度浮動小数点値を使用するだけで十分です

出力

出力は、ブランドXオペレーティングシステムの標準ソフトウェアで読み取り可能な、選択したファイル形式のラスターグラフィックスイメージでなければなりません。まれな形式を使用する場合は、視聴者をダウンロードできるWebサイトへのリンクを追加することを検討してください。

ファイルをstdoutに出力します。お使いの言語が標準出力への出力をサポートしていない場合、またはこのオプションの利便性が低い場合、別の方法を見つけてください。いずれにしても、生成されたイメージを保存できる必要があります。

制限事項

  • 画像処理ライブラリなし
  • フラクタル生成ライブラリなし
  • 最短のコードが勝ちます

拡張機能

このタスクが気に入ったら、収束の速度やその他の基準に従ってポイントに色を付けてみてください。興味深い結果が見たいです。


6
これがコードゴルフに適しているかどうかは完全にはわかりません。私の目には、タスクは非常に複雑です。しかし、私は間違っていると証明されるかもしれません。
ジョーイ

5
@ジョーイ:確かに。これが自分自身のコードチャレンジになりたいです。
ジョーイアダムス

2
...またはPPM。
ジョーイ

1
@Joey:私の意図は、多くの人が非常に簡単なタスクを嫌うので、かなり難しいタスクを作成することでした。
-FUZxxl

1
それは簡単に別のタスクに分割され、言語がネイティブに複雑な浮動小数点数をサポートしている場合、大きなチャンクを保存できます。私は1600文字で動作する完全にゴルフされていないバージョンを持っています。そのうち340は複素数クラスです。まだ根を特定して色を使用していませんが、NRコードのバグだと思われるものを追跡しようとしています。(-0.5 + 0.866iから始まるx ^ 3-1のルートを見つけることは確かに分岐しないはずです!)
ピーターテイラー

回答:


13

Python、827 777文字

import re,random
N=1024
M=N*N
R=range
P=map(lambda x:eval(re.sub('i','+',x)+'j'if 'i'in x else x),raw_input().split())[::-1]
Q=[i*P[i]for i in R(len(P))][1:]
E=lambda p,x:sum(x**k*p[k]for k in R(len(p)))
def Z(x):
 for j in R(99):
  f=E(P,x);g=E(Q,x)
  if abs(f)<1e-9:return x,1
  if abs(x)>1e5or g==0:break
  x-=f/g
 return x,0
T=[]
a=9e9
b=-a
for i in R(999):
 x,f=Z((random.randrange(-9999,9999)+1j*random.randrange(-9999,9999))/99)
 if f:a=min(a,x.real,x.imag);b=max(b,x.real,x.imag);T+=[x]
s=b-a
a,b=a-s/2,b+s/2
s=b-a
C=[[255]*3]*M
H=lambda x,k:int(x.real*k)+87*int(x.imag*k)&255
for i in R(M):
 x,f=Z(a+i%N*s/N+(a+i/N*s/N)*1j)
 if f:C[i]=H(x,99),H(x,57),H(x,76)
for r in T:C[N*int(N*(r.imag-a)/s)+int(N*(r.real-a)/s)]=0,0,0
print'P3',N,N,255
for c in C:print'%d %d %d'%c

多数のランダムサンプルの収束点を見つけることにより、表示境界(およびルート)を見つけます。次に、各開始点の収束点を計算し、ハッシュ関数を使用して各収束点のランダムな色を取得することにより、グラフを描画します。非常によく見ると、マークされたルートを見ることができます。

多項式の例の結果は次のとおりです。

例の多項式の結果


良い!私はこれが好き。
FUZxxl

14

Java、1093 1058 1099 1077文字

public class F{double r,i,a,b;F(double R,double I){r=R;i=I;}F a(F c){return
new F(r+c.r,i+c.i);}F m(F c){return new F(r*c.r-i*c.i,r*c.i+i*c.r);}F
r(){a=r*r+i*i;return new F(-r/a,i/a);}double l(F c){a=r-c.r;b=i-c.i;return
Math.sqrt(a*a+b*b);}public static void main(String[]a){int
n=a.length,i=0,j,x,K=1024,r[]=new int[n];String o="P3\n"+K+" "+K+"\n255 ",s[];F z=new
F(0,0),P[]=new F[n],R[]=new F[n],c,d,e,p,q;for(;i<n;)P[i]=new
F((s=a[i++].split("i"))[0].isEmpty()?0:Float.parseFloat(s[0]),s.length==1?0:Float.parseFloat(s[1]));double
B=Math.pow(P[n-1].m(P[0].r()).l(z)/2,1./n),b,S;for(i=1;i<n;){b=Math.pow(P[i].m(P[i-1].r()).l(z),1./i++);B=b>B?b:B;}S=6*B/K;for(x=0;x<K*K;){e=d=c=new
F(x%K*S-3*B,x++/K*S-3*B);for(j=51;j-->1;){p=P[0];q=p.m(new
F(n-1,0));for(i=1;i<n;){if(i<n-1)q=q.m(c).a(P[i].m(new
F(n-1-i,0)));p=p.m(c).a(P[i++]);}c=c.a(d=q.r().m(p));if(d.l(z)<S/2)break;}i=j>0?0:n;for(;i<n;i++){if(R[i]==null)R[i]=c;if(R[i].l(c)<S)break;}i=java.awt.Color.HSBtoRGB(i*1f/n,j<1||e.l(c)<S&&r[i]++<1?0:1,j*.02f);for(j=0;j++<3;){o+=(i&255)+" ";i>>=8;}System.out.println(o);o="";}}}

入力はコマンドライン引数です(例:run)java F 1 0 0 -1。出力は、PPM形式(ASCII pixmap)で標準出力に出力されます。

スケールは、多項式の複素根の絶対値にバインドされた藤原を使用して選択されます。次に、その境界に1.5を掛けます。収束率によって明るさを調整するので、根は最も明るいパッチになります。したがって、おおよその根の位置をマークするために黒ではなく白を使用するのが論理的です(「正しく」実行することさえできないため、41文字のコストがかかります。0.5ピクセル以内に収束するすべての点にラベルを付けるとその後、いくつかのルートはラベルなしで出てきます。自分自身の0.6ピクセル以内に収束するすべてのポイントにラベルを付けると、複数のピクセルにわたってラベル付けされたいくつかのルートが出ます。したがって、各ルートについて、自分自身の1ピクセル以内に収束するように遭遇した最初のポイントにラベルを付けます)。

例の多項式の画像(GIMPでpngに変換): x ^ 5 +(-2 + 7.5i)x ^ 4 +(23.0004-3.8i)x ^ 3 + 12i x ^ 2 +(5.1233 + 0.1i)の根


@FUZxxl、画像は古いバージョンのものです。収束率のあるものを後でアップロードします。しかし、根をマークする際の問題は、マークするピクセルを決定することです。浮動小数点では正確な等価性テストを使用できないため、イプシロンと比較する必要があるのは古典的な問題です。その結果、ルートの「標準」値がありません。1つのステップで収束するピクセルをマークできますが、それは何もマークすることを保証するものではなく、単一のルートに対して4ピクセルのブロックをマークすることができます。
ピーターテイラー

@Peter Taylor:ご存知のように、Keith Randallもその問題の解決策を見つけました。この要件を追加の難易度として追加しました。そのための1つのアプローチは、各ルートに最も近いピクセルを計算し、各ピクセルが等しいかどうかをチェックすることです。
FUZxxl

@FUZxxl、あなたは私の意味を理解していません。ルートの「最も近いピクセル」は明確に定義されていません。しかし、私はあなたが投げたすべてのテストケースでうまくいくかもしれない何かをハックすることができ、それがあなたを幸せにするだろうという印象を得る。それはより論理的だから、黒ではなく白に色を付けます。
ピーターテイラー

@ピーター・テイラー:わかりました。
FUZxxl

6
私のプロフィール写真はすぐにに変わりx^6-9x^3+8、根を選択し、Wolfram Alphaを使用して多項式を簡略化することで慎重に設計されます。OK、その後GIMPで色相を入れ替えてごまかしました。
ピーターテイラー

3

Python、633バイト

import numpy as np
import matplotlib.pyplot as plt
from colorsys import hls_to_rgb
def f(z):
    return (z**4 - 1)
def df(z):
    return (4*z**3) 
def cz(z):
    r = np.abs(z)
    arg = np.angle(z)   
    h = (arg + np.pi)  / (3 * np.pi)
    l = 1.0 - 1.0/(1.0 + r**0.1)
    s = 0.8 
    c = np.vectorize(hls_to_rgb) (h,l,s)
    c = np.array(c)
    c = c.swapaxes(0,2) 
    return c    
x, y = np.ogrid[-1.5:1.5:2001j, -1.5:1.5:2001j]
z = x + 1j*y    
for i in range(10):
    z -= (f(z) / df(z))
zz = z
zz[np.isnan(zz)]=0
zz=cz(zz)
plt.figure()
plt.imshow(zz, interpolation='nearest')
plt.axis('off')
plt.savefig('plots/nf.svg')
plt.close()

スピードアップと美化後(756バイト)

import numpy as np
from numba import jit
import matplotlib.pyplot as plt
from colorsys import hls_to_rgb 

@jit(nopython=True, parallel=True, nogil=True)
def f(z):
    return (z**4 - 1)   

@jit(nopython=True, parallel=True, nogil=True)
def df(z):
    return (4*z**3) 

def cz(z):
    r = np.abs(z)
    arg = np.angle(z)   

    h = (arg + np.pi)  / (3 * np.pi)
    l = 1.0 - 1.0/(1.0 + r**0.1)
    s = 0.8 

    c = np.vectorize(hls_to_rgb) (h,l,s)
    c = np.array(c)
    c = c.swapaxes(0,2) 
    return c    

x, y = np.ogrid[-1.5:1.5:2001j, -1.5:1.5:2001j]
z = x + 1j*y    

for i in range(10):
    z -= (f(z) / df(z))

zz = z
zz[np.isnan(zz)]=0
zz=cz(zz)
plt.figure()
plt.imshow(zz, interpolation='nearest')
plt.axis('off')
plt.savefig('plots/nf.svg')
plt.close()

以下のプロットは、log(z)関数のニュートンフラクタルに関するものです。

log(z)のニュートンフラクタル


短い(1文字​​)名を使用し、複数行を組み合わせて空白を削除できます ;。また、可能なすべてのスペースを削除します。
mbomb007

いくつかの通常のゴルフはこれをわずか353バイトに減らします!テストしていません(matplotlibここではありません)。
クルドラエセスナバルヤ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.