대수 곡선 플로터


14

대수 곡선은 {(x,y) in R^2 : f(x,y)=0 }다항식 의 0 의 집합으로 설명 할 수있는 "2D 평면"의 특정 "1D 하위 집합"입니다 f. 여기서 우리는 2D 평면을 실제 평면으로 간주하여 R^2그러한 곡선이 어떻게 생겼는지, 기본적으로 연필로 그릴 수있는 것을 쉽게 상상할 수 있도록합니다.

예 :

  • 0 = x^2 + y^2 -1 반지름의 원 1
  • 0 = x^2 + 2y^2 -1 타원
  • 0 = xy단면 형상, 기본적으로 X 축 결합하고, Y 축
  • 0 = y^2 - x 포물선
  • 0 = y^2 - (x^3 - x + 1)타원 곡선
  • 0 = x^3 + y^3 - 3xy 데카르트의 포 리움
  • 0 = x^4 - (x^2 - y^2) lemniscate
  • 0 = (x^2 + y^2)^2 - (x^3 - 3xy^2) 삼엽
  • 0 = (x^2 + y^2 - 1)^3 + 27x^2y^2 천체

직무

다항식 f(아래 정의 참조)과 x / y- 범위가 주어지면 곡선을 흰색 배경에 검은 선으로 표시하는 최소 100x100 픽셀의 흑백 이미지를 출력합니다.

세부

색깔 : 당신은 당신의 선택의 다른 2 개의 색깔을 사용할 수 있습니다, 다만 구별하기 쉬워야합니다.

줄거리 : 픽셀 이미지 대신이 이미지를 아스키 아트로 출력 할 수 있습니다. 여기서 배경 "픽셀"은 공백 / 밑줄 또는 "비어있는"다른 문자 여야하며 " 같은 "전체 M또는 X#.

앨리어싱에 대해 걱정할 필요가 없습니다.

다른쪽으로 라인의 한쪽에서 다항식 변화의 부호가 (수단은 예를 들면 행진 사각형 알고리즘을 사용할 수 있음), 제대로 "등의 병적 인 경우 플롯이없는 곳에서만 플롯 라인에 필요한 0 = x^2기호가하는 곳을 선의 한쪽에서 다른쪽으로 갈 때 변하지 않지만 선은 연속적이고 서로 다른 부호의 영역을 분리해야합니다 f(x,y).

다항식 : 다항식은 (m+1) x (n+1)(실제) 계수 목록의 매트릭스 / 목록으로 제공됩니다. 아래 예에서 계수의 항은 해당 위치에 제공됩니다.

[   1 * 1,   1 * x,   1 * x^2,   1 * x^3,  ... , 1 * x^n ]
[   y * 1,   y * x,   y * x^2,   y * x^4,  ... , y * x^n ]
[   ...  ,   ...   ,   ...   ,    ...   ,  ... ,   ...   ]
[ y^m * 1, y^m * x, y^m * x^2, y^m * x^3 , ..., y^m * x^n]

원하는 경우 행렬을 정사각형으로 가정하고 (필요한 제로 패딩으로 항상 수행 할 수 있음) 원하는 경우 행렬의 크기가 추가 입력으로 제공된다고 가정 할 수도 있습니다.

다음에서 위의 예는 다음과 같이 정의 된 행렬로 표시됩니다.

Circle:       Ellipse:      Parabola:  Cross:    Elliptic Curve: e.t.c
[-1, 0, 1]    [-1, 0, 1]    [ 0,-1]    [ 0, 0]   [-1, 1, 0,-1]
[ 0, 0, 0]    [ 0, 0, 0]    [ 0, 0]    [ 0, 1]   [ 0, 0, 0, 0]
[ 1, 0, 0]    [ 2, 0, 0]    [ 1, 0]              [ 1, 0, 0, 0]

x 범위 / y 범위의 테스트 사례 :

( pastbin에서 읽을 수는 없지만 더 나은 복사 붙여 넣기 가능한 형식으로 제공 됩니다 .)

Circle:     
[-1, 0, 1]   [-2,2]   [-2,2]
[ 0, 0, 0]
[ 1, 0, 0]

Ellipse:
[-1, 0, 1]   [-2,2]   [-1,1]
[ 0, 0, 0]
[ 2, 0, 0]

Cross:
[ 0, 0]      [-1,2]   [-2,1]
[ 0, 1]

Parabola:
[ 0,-1]      [-1,3]   [-2,2]
[ 0, 0]
[ 1, 0]

Elliptic Curve:
[-1, 1, 0,-1]    [-2,2]   [-3,3]
[ 0, 0, 0, 0]  
[ 1, 0, 0, 0]  

Folium of Descartes:
[  0,  0,  0,  1]    [-3,3]   [-3,3]
[  0, -3,  0,  0]
[  0,  0,  0,  0]
[  1,  0,  0,  0]

Lemniscate:
[  0,  0, -1,  0,  1]    [-2,2]   [-1,1]
[  0,  0,  0,  0,  0]
[  1,  0,  0,  0,  0]

Trifolium:
[ 0, 0, 0,-1, 1]    [-1,1]   [-1,1]
[ 0, 0, 0, 0, 0]
[ 0, 3, 2, 0, 0]
[ 0, 0, 0, 0, 0]
[ 1, 0, 0, 0, 0]

Astroid:
[ -1,  0,  3,  0, -3,  0,  1]    [-1,1]   [-1,1]
[  0,  0,  0,  0,  0,  0,  0]
[  3,  0, 21,  0,  3,  0,  0]
[  0,  0,  0,  0,  0,  0,  0]
[ -3,  0,  3,  0,  0,  0,  0]
[  0,  0,  0,  0,  0,  0,  0]
[  1,  0,  0,  0,  0,  0,  0]

이 pdf 에서 일부 곡선에 대한 영감을 얻었습니다 .


" 앨리어싱에 대해 걱정할 필요가 없습니다 "는 중앙이 선 위에 있는지 여부에 따라 각 픽셀에 색상을 지정할 수 있다는 의미입니까?
피터 테일러

앨리어싱 연결이 보이지 않습니다. 그러나 아닙니다. 서로 다른 표지판의 영역을 구분하는 연속적인 선이 있어야합니다.
flawr

행렬은 mx n가 아니라 (m+1)x (n+1)입니다. 입력으로 무엇을 취 합니까 : m, n또는 m+1,n+1? 아니면 선택할 수 있습니까?
Luis Mendo

그래프 기능을 새 창에 표시 할 수 있습니까?
R. Kap

1
@LuisMendo 예, 축은 원하는 방향으로 될 수 있습니다. (그들이 직교하는 한)
flawr

답변:


10

하스켈, 283 275 바이트

이 함수 g는 행렬과 두 범위를 인수로 사용하여 호출해야합니다. 행렬은 목록의 목록 일 뿐이며 범위는 각각 두 요소 목록입니다.

import Data.List
t=transpose
u=tail
z=zipWith
l%x=sum$z(*)l$iterate(*x)1                                   --generate powers and multiply with coefficients
e m y x=[l%x|l<-m]%y                                         --evaluate the encoded polynomial
a#b=[a,a+(b-a)/102..b]                                       --create a range
g m[u,w][i,j]=unlines$v[map((0<).e m y)$u#w|y<-i#j]          --evaluate the function on the grid, get the sign
f g=u[u$u$map fst$scanl(\(r,l)c->(c==l,c))(1<0,1<0) l|l<-g]  --find +- or -+ transitions within lines
a&b|a&&b=' '|0<1='#'                                         --helper function for creating the string
v g=z(z(&))(f g)(t$f$t g)                                    --create the string

더 흥미로운 경우에 대한 결과는 다음과 같습니다. 결과를 100x100에서 약 40x40으로 축소하여 콘솔에 맞지 않도록해야합니다 (하드 코딩 된 102를 더 작은 숫자로 변경하십시오). 또한 y 축이 아래쪽을 향하고 있습니다.


여기 당신이 만들 수있는 아주 작은 골프가 있습니다. 마지막 줄은 $바이트를 저장하는 데 사용할 수있을 때 parens를 사용 합니다. 사용하는 두 위치는 모두 map가능 (<$>)하며 e한 번만 사용할 수 있으므로 (0<)내부 정의를 가져올 수 있습니다 . 또한 3 바이트를 저장 e하도록 이름 (!)을 지정할 수 있습니다 .
Post Rock Garf Hunter

그리고 z정의에 삽입 v하면 4 개의 괄호 ( z(&)f g)를 제거 할 수 있습니다 .
Post Rock Garf Hunter

#단일 문자 (예 :) 로 이름 을 바꾸고 s대신 패턴을 패턴에서 일치 시킬 수도 있습니다 g. (예 s[a,b]=[a,a+(b-a)/102..b];g m u i=unlines$v[m!y<$>s u|y<-s i])
포스트 록 Garf 헌터

6

MATLAB, 114 (100) 92 바이트

작업에 적합한 도구? Matlab이 printf다항식을 문자열로 생성하는 흥미로운 방식을 사용 합니다. 이 다항식은 ezplot지정된 도메인에 암시 적 곡선 을 나타내는 데 제공 될 수 있습니다 . 가독성을 위해 코드에는 개행 문자가 표시됩니다. 필요하지 않으며 크기에 포함되지 않습니다.

function P(A,W,H,h,w)
t=0:h*w-1;
ezplot(sprintf('+%d*x^%.0f*y^%d',[A(:)';t/h;rem(t,h)]),[W,H])

확장 가능한 스 니펫으로 골프 진행.


테스트 사례 출력 (전체보기를 보려면 클릭) : 테스트 사례


2
사용하여 정말 좋은 솔루션 sprintf/ezplot!
flawr

fix대신에 사용 floor하면 두 자리 바이트 수에 도달하는 데 도움이 될 수 있습니다 :-)
Luis Mendo

[h,w]=size(A);t=0:h*w-1;다른 3 바이트를 저장 하는 데 사용할 수도 있습니다 !
flawr

@LuisMendo 사실, 나는 더 잘할 수 있습니다. Matlab의 printf에 정수 자리 표시자가 없어서 슬프지만 여전히 같은 것을 지원합니다 %.0f. 그것은 바닥을 완전히 떨어 뜨려 printf고칠 수 있다는 것을 의미 합니다!
알그 미르

@flawr 나는 나중에 반복에서 두 번째 부분을 사용합니다. 마지막으로 최고의 버전으로 내 서식이 명확하지 않다는 것을 알고 있습니다. 이 수정을 명확하게하기 위해 서식을 편집했습니다.
algmyr

6

파이썬 2, 261 바이트

E=enumerate
M,[a,c],[b,d]=input()
e=(c-a)/199.
I=200
J=-int((b-d)/e-1)
print'P2',I,J,255
i=I*J
while i:i-=1;x,y=c-i%I*e,b+i/I*e;u,v,w=map(sum,zip(*((z*p/x,z*q/y,z)for q,R in E(M)for p,t in E(R)for z in[t*x**p*y**q])));print int(255*min(1,(w*w/(u*u+v*v))**.5/e))

입력 형식 : matrix,xbounds,ybounds(예 [[-1,0,1],[0,0,0],[1,0,0]],[-2,2],[-2,2]). 출력 형식 : 일반 PGM .

1 차 근사값 d ( x , y ) = |를 사용하여 모든 픽셀 중심에서 곡선까지의 거리를 추정합니다. p ( x , y ) | / | ∇ p ( x , y ) |, 여기서 ∇ p 는 다항식 p 의 기울기입니다 . (이것은 ( x , y )에서 ( x , y , p ( x , y )) 의 접선 평면 과 xy – 평면 의 교차점 까지의 거리입니다 . 그런 다음 d (x , y )는 d ( x , y )에 비례하여 곡선의 픽셀 너비보다 작으므로 앤티 앨리어싱 된 선이 필요합니다 (필수 사항은 아님).

산출

다음은 거리 함수를 16 으로 나눈 동일한 그래프입니다 .


잠깐, 코드에서 실제 그래픽 플로팅은 어디에서 발생합니까?
R. Kap

@ R.Kap이 코드는 이미지를 일반 PGM 형식으로 표준 출력에 씁니다. 거기에 하나의 print이미지 헤더에 대한 문 하나 print의 문 while각 픽셀의 값에 대한 루프.
Anders Kaseorg

와우, 정말 멋지다! 플로팅 알고리즘에 대해 좀 더 깊이 들어가시겠습니까?
flawr

@flawr 나는 설명을 조금 확장했다; 그게 당신의 질문에 대답합니까?
Anders Kaseorg

@AndersKaseorg 네, 대단히 감사합니다!
flawr

5

Python 3.5 + MatPlotLib + Numpy, 352 바이트 :

from matplotlib.pyplot import*;from numpy import*
def R(M,S,U,r=range):N=linspace;E='+'.join([str(y)+'*'+m for y,m in[q for i,g in zip(M,[[i+'*'+p for p in['1']+['x^%d'%p for p in r(1,len(M[0]))]]for i in['1']+['y^%d'%i for i in r(1,len(M))]])for q in zip(i,g)if q[0]]]);x,y=meshgrid(N(*S,200),N(*U,200));contour(x,y,eval(E.replace('^','**')),0);show()

명명 된 함수. 꽤 길지만 이봐, 나는 그 일을 완수 할 수있어서 기쁘다. m by n행렬 인 3 개의 입력을 취 합니다.x -range 및 y-range의 을 모두 배열로 합니다 (예 :) [[-1,0,1],[0,0,0],[1,0,0]],[-2,2],[-2,2]. 완성 된 그래프를 새로운 대화식 창으로 출력합니다. 내가 할 수있을 때이 시간을 더 많이 줄 이겠지만 지금은 기쁘다.

테스트 케이스의 최종 출력 :

최종 출력


5

MATL , 67 61 바이트

8Wt:qwq/t2:"wid*2M1)+i:q!^]!2&!w[1IK2]&!**ss&eZS5Y62&Y+|4=0YG

이 코드는 언어의 릴리스 18.5.0에서 실행되며 문제보다 우선합니다. 입력 옵션을 사용하여 m, n매개 변수를. 행렬에는 행 구분 기호로 세미콜론이 있습니다. 정확한 입력 형식 (포물선을 예로 사용)은 다음과 같습니다.

[-1,3]
3  
[-2,2]
2
[0,-1; 0, 0; 1, 0]

코드는 255 × 255 크기 의 이미지 를 생성합니다 . @SueverMATL Online 컴파일러를 사용하여 테스트 할 수 있는데, 여기에는 매우 흥미로운 기능 중 그래픽 출력이 포함됩니다. 예를 들어보십시오

이 컴파일러는 아직 실험 단계에 있습니다. MATL 대화방 에서 @Suever에 문제를보고하십시오 . "실행"버튼이 작동하지 않으면 페이지를 새로 고치고 다시 클릭하십시오.

ASCII 출력 을 선호하는 경우 코드를 약간 수정해야합니다 (변경 사항은 위 코드의 처음 두 문자와 마지막 네 문자에만 영향을 미침).

101t:qwq/t2:"wid*2M1)+i:q!^]!2&!w[1IK2]&!**ss&eZS5Y62&Y+|4<42*c

문자 *를 사용 하여 곡선을 나타내는 100 × 100 ASCII 그리드를 생성합니다 . 또한 이것을 테스트 할 수 있습니다 @Dennis ' 온라인으로보십시오! 플랫폼:

ASCII 출력의 가로 세로 비율은 문자가 너비보다 약간 높기 때문에 변경됩니다.

설명

이 코드는 먼저 x - y 그리드 에서 2 변수 다항식을 계산합니다 . 이것은 방송 을 많이 사용 하여 각 차원이 x 값, y 값, x 지수, y를 나타내는 중간 4D 배열을 계산합니다. 지수를 각각 .

이 함수에서 제로 레벨 라인이 계산됩니다. 부호 변경 만 감지하는 챌린지 지정이 필요하므로 코드는 2 × 2 블록으로 2D 컨벌루션 을 적용 하고 블록의 4 개 값이 동일한 부호를 가지지 않으면 픽셀을 선에 속하는 것으로 표시합니다.

8W      % Push 2^8, that is, 256. (The ASCII-output version pushes 101 instead)
t:q     % Duplicate. Push range [0 1 ... 255]
wq      % Swap. Subtract 1 to obtain 255
/       % Divide. Gives normalized range [0 1/255 2/255... 1]
t       % Duplicate
2:"     % For loop: do this twice
  w     %   Swap top two elements in the stack
  i     %   Input two-number array defining x range (resp. y in second iteration)
  d     %   Difference of the two entries
  *     %   Multiply by normalized range
  2M1)  %   Push the array again and get its first entry
  +     %   Add. This gives the range for x values (resp. y)
  i     %   Input m (n in second iteration)
  :q    %   Range [0 1 ...m-1] (resp. [0 1 ...n-1])
  !     %   Convert to column array
  ^     %   Power, element-wise with broadcast. This gives a matrix of size m×256
        %   (resp. n×256) of powers of x (resp. y) for the range of values computed
        %   previously
]       % End for loop
!       % Transpose. This transforms the n×256 matrix of powers of y into 256×n
2       % Push 2
&!      % Permute dimensions 1 and 3: transforms the 256×n matrix into a 4D array
        % of size 1×n×256×1
w       % Swap top two elements in the stack: bring 256×m matrix to top
[1IK2]  % Push vector [1 3 4 2]
&!      % Permute dimensions as indicated by the vector: transforms the m×256 matrix
        % into a 4D array of size m×1×1×256
*       % Multiply element-wise with broadcast: gives 4D array of size m×n×256×256
        % with mixed powers of x and y for at the grid of x, y values
*       % Implicitly input m×n matrix. Multiply element-wise with broadcast: gives
        % 4D array of size m×n×256×256
ss      % Sum along first two dimensions: gives 4D array of size 1×1×256×256
&e      % Squeeze singleton dimensions: gives matrix of size 256×256. This is the
        % two-variable polynomial evaluated at the x, y grid.
        % Now we need to find the zero level curve of this function. We do this by 
        % detecting when the sign of the function changes along any of the two axes
ZS      % Matrix of sign values (1, 0 or -1)
5Y6     % Predefined literal: matrix [1 1; 1 1]
2&Y+    % Compute 2D convolution, keeping only the valid (central) part
|4=     % True if absolute value of result is 4, which indicates no sign changes.
        % (The ASCII version computes a negated version of this, for better display)
0YG     % Display as image. (The ASCII-output version does the following instead:
        % multiply by 42 and convert to char. 42 is ASCII for '*', and character 0 
        % is shown as space. The 2D char array is then implicitly displayed)

모든 테스트 사례

다음은 시도하려는 경우 적절한 형식의 모든 입력입니다.

Circle:
[-2,2]
3
[-2,2]
3
[-1, 0, 1; 0, 0, 0; 1, 0, 0]

Ellipse:
[-2,2]
3
[-1,1]
3
[-1, 0, 1; 0, 0, 0; 2, 0, 0]

Cross:
[-1,2]
2
[-2,1]
2
[0, 0; 0, 1]

Parabola:
[-1,3]
3  
[-2,2]
2
[0,-1; 0, 0; 1, 0]

Elliptic Curve:
[-2,2]
3
[-3,3]
4
[-1, 1, 0,-1; 0, 0, 0, 0; 1, 0, 0, 0]

Folium of Descartes:
[-3,3]
4
[-3,3]
4
[0,  0,  0,  1; 0, -3,  0,  0; 0,  0,  0,  0; 1,  0,  0,  0]


Lemniscate:
[-2,2]
3
[-1,1]
5
[0,  0, -1,  0,  1; 0,  0,  0,  0,  0; 1,  0,  0,  0,  0]

Trifolium:
[-1,1]
5
[-1,1]
5
[0, 0, 0,-1, 1; 0, 0, 0, 0, 0; 0, 3, 2, 0, 0; 0, 0, 0, 0, 0; 1, 0, 0, 0, 0]

Astroid
[-1,1]
7
[-1,1]
7
[-1,  0,  3,  0, -3,  0,  1; 0,  0,  0,  0,  0,  0,  0; 3,  0, 21,  0,  3,  0,  0; 0,  0,  0,  0,  0,  0,  0; -3,  0,  3,  0,  0,  0,  0; 0,  0,  0,  0,  0,  0,  0; 1,  0,  0,  0,  0,  0,  0]

2
Perl보다 여전히 읽기 쉽습니다. 훌륭한 직업, 또한 멋진 온라인 컴파일러!
flawr

@flawr 은 Perl LOL 보다 읽기 쉽습니다 . 온라인 컴파일러는 모두 Suever의 작품입니다!
Luis Mendo

1
@flawr 지금 컨볼 루션과 함께!
Luis Mendo

1
<3 컨볼 루션!
flawr
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.