뉴턴 프랙탈 생성


24

모두 함수의 근사를 근사화하는 Newton 방법을 알고 있습니까? 이 작업의 목표는이 알고리즘의 흥미로운 측면을 소개하는 것입니다.

뉴턴의 알고리즘은 특정이지만 대부분의 복잡한 입력 값에 대해서만 수렴합니다. 복잡한 평면에서 모든 입력 값에 대한 방법의 수렴을 묘사하면 일반적으로 다음과 같은 아름다운 프랙탈이 나타납니다.

f (x) = x ^ 3-1에 대한 뉴턴 프랙탈 위키 미디어 공용 이미지

명세서

이 작업의 목표는 이러한 프랙탈을 생성하는 것입니다. 즉, 입력으로 다항식을 가져오고 해당 프랙탈을 출력 형식으로 선택한 형식으로 이미지로 인쇄해야합니다.

입력

입력은 공백으로 구분 된 복소수 목록입니다. <Real part><iImaginary part>이 번호와 같이 스타일로 기록됩니다 5.32i3.05. 입력 번호의 소수점 이하 자릿수는 4 자리 이하이고 1000보다 작다고 가정 할 수 있습니다. 첫 번째 숫자는 0이 아니어야합니다. 예를 들어, 이것은 프로그램에 대한 입력일 수 있습니다.

1-2i7.5 23.0004i-3.8 i120 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 개의 픽셀을 인쇄 할 수 있습니다.
  • 가능한 한 모든 뿌리가 구별되고 넓게 퍼지는 방식으로 보이는 평면을 선택하는 방법을 찾으십시오. 출력 프레임을 완벽하게 배치 할 필요는 없지만 예를 들어 프레임을 허용 할 수없는 방식으로 선택하는 답변을 거부 할 권리가 있습니다. 항상 같은 좌표에서 모든 뿌리는 한 지점에 있습니다.
  • 출력 이미지의 크기는 1024 * 1024 픽셀이어야합니다.
  • 렌더링 시간은 최대 10 분입니다.
  • 단 정밀도 부동 소수점 값을 사용하면 충분합니다

산출

출력은 선택한 파일 형식의 래스터 그래픽 이미지 여야하며 브랜드 X 운영 체제의 표준 소프트웨어로 읽을 수 있습니다. 드문 형식을 사용하려면 웹 사이트에 뷰어를 다운로드 할 수있는 링크를 추가하십시오.

파일을 stdout으로 출력하십시오. 귀하의 언어가 stdout에 무언가를 넣는 것을 지원하지 않거나이 옵션이 덜 편리하다고 생각되면 다른 방법을 찾으십시오. 어떤 식 으로든 생성 된 이미지를 저장할 수 있어야합니다.

제한 사항

  • 이미지 처리 라이브러리가 없습니다
  • 프랙탈 생성 라이브러리가 없음
  • 가장 짧은 코드가 승리합니다

확장

이 작업이 마음에 들면 수렴 속도 또는 다른 기준에 따라 점을 색칠 할 수 있습니다. 흥미로운 결과를보고 싶습니다.


6
이것이 코드 골프로 적합한 지 확실하지 않습니다. 내 눈에는 작업이 너무 복잡합니다. 그래도 틀렸다는 것이 증명 될 수 있습니다.
Joey

5
@Joey : 그렇습니다. 이것이 코드 도전 자체 가되기를 바랍니다 .
Joey Adams

2
또는 그 문제에 대한 PPM.
Joey

1
@Joey : 많은 사람들이 매우 쉬운 작업을 싫어하기 때문에 다소 어려운 작업을 만들려고했습니다.
FUZxxl

1
별도의 작업으로 쉽게 분류되며 언어가 기본적으로 복잡한 부동 소수점 숫자를 지원하면 큰 청크를 저장할 수 있습니다. 1600 자로 실행되는 완전 골프 버전이 있는데 그 중 340은 복소수 클래스입니다. 아직 뿌리를 식별하고 색상을 사용하지는 않지만 NR 코드의 버그라고 추정하는 것을 추적하려고합니다. (-0.5 + 0.866i에서 시작하여 x ^ 3-1의 근점을 찾으면 반드시 분기되지 않아야합니다!)
Peter Taylor

답변:


13

Python, 827777

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

자바, 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).

스케일은 다항식의 복소수 근의 절대 값에 구속 된 Fujiwara를 사용하여 선택됩니다. 그런 다음 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, 이미지는 이전 버전에서 가져온 것입니다. 나중에 수렴 속도로 업로드하겠습니다. 그러나 근을 표시하는 문제는 표시 할 픽셀을 결정하는 것입니다. 부동 소수점을 사용하면 정확한 평등 테스트를 사용할 수 없으므로 엡실론과 비교 해야하는 고전적인 문제입니다. 결과적으로 루트에 대한 "정규"값이 없습니다. 한 단계로 수렴하는 픽셀을 표시 할 수는 있지만 아무것도 표시하지는 않으며 단일 루트에 대해 4 픽셀 블록을 표시 할 수 있습니다.
피터 테일러

@ 피터 테일러 : 보시다시피 Keith Randall도 그 문제에 대한 해결책을 찾았습니다. 이 요구 사항을 추가 어려움으로 추가했습니다. 이를 수행하는 한 가지 방법은 각 루트에 대해 가장 가까운 픽셀을 계산 한 다음 각 픽셀이 동일한 지 확인하는 것입니다.
FUZxxl

@ FUZxxl, 당신은 내 요점을 이해하지 못했습니다. 루트의 "가장 가까운 픽셀"이 잘 정의되어 있지 않습니다. 그러나 나는 당신이 그것을 던지는 모든 테스트 사례에서 작동 할 수있는 것을 해킹 할 수 있으며, 그것이 당신을 행복하게 할 것이라는 인상을 얻습니다. 더 논리적이기 때문에 검은 색이 아닌 흰색으로 채색합니다.
피터 테일러

@ 피터 테일러 : 좋아.
FUZxxl

6
내 프로파일 사진은 곧 x^6-9x^3+8루트로 선택하고 Wolfram Alpha를 사용하여 다항식을 단순화하여 신중하게 설계된로 변경됩니다 . 좋아, 나는 김프에서 나중에 색조를 바꾸어 바람 피다.
피터 테일러

3

파이썬, 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()

아래 그림은 Newton Fractal of log (z) 함수에 대한 것입니다.

log (z)에 대한 뉴턴 프랙탈


을 사용하여 더 짧은 (1 문자) 이름을 사용하고 공백을 제거하여 공백을 제거 할 수 있습니다 ;. 또한 가능한 모든 공간을 제거하십시오.
mbomb007

일부 일반 골프는 이것을 353 바이트로 줄입니다 ! 테스트하지 않았으므로 ( matplotlib여기서는 안 됨) 여전히 작동한다는 보장은 없습니다.
Khuldraeseth na'Barya
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.