2010년 8월 18일 수요일

일부를 제외하고 치환하려면

예를 들어 {f[x], g[x], h[x]}이 있는데, xy로 치환한다고 하자. 이건 쉽다.
{f[x], g[x], h[x]}
% /. x -> y
이렇게 하면, {f[y], g[y], h[y]}를 얻을 수 있다. 그러면 h[x]x만 치환한다면? 물론 여기선 ReplaceAll[{f[x], g[x], h[x]}, h[x] -> h[y]]로 바꾸는 게 가장 쉽지만, 일반적으로는 아래처럼 하면 된다.
{f[x], g[x], h[x]}
% // MapAt[# /. x -> y &, #, 3] &
그럼 f[x]만을 제외하고 치환하려면? ReplaceAll은 한번 치환한 건 다시 치환하지 않으므로, 다음과 같이 쉽게 해결할 수 있다.
{f[x], g[x], h[x]}
% /. {f[x] -> f[x], x -> y}

2010년 8월 10일 화요일

회절 무늬

빛의 회절에는 프레넬 회절(Fresnel diffraction, near-field diffraction)프라운호퍼 회절(Fraunhofer diffraction, far-field diffraction)이 있는데, 흔히 회절이라 하면 프라운호퍼 회절을 일컫는다. 프라운호퍼 회절 무늬를 계산해보면 입사하는 빛의 2차원 푸리에 변환이 되는 것을 알 수 있다. 따라서, Fast Fourier Transform(FFT)을 이용해서 회절 무늬를 쉽게 그려볼 수 있다.

구멍에 들어가는 빛의 세기가 일정하다는 가정을 사용하면, 구멍의 모양이 바로 구멍을 통과하는 빛의 모양이므로 구멍의 모양을 바로 푸리에 변환하면 된다. 김프(GIMP)를 이용해서 구멍의 모양을 미리 만들어 두었다.
김프로 만든 임의의 슬릿 모양
이 이미지 파일을 불러들여, 수치 자료로 변환한다.
img = Import["spiral_aperture.png"]
data = img // ImageData;
이 자료의 모양을 확인해보면,
Dimensions[data]
{400, 400, 3}과 같이 3차원인 것을 알 수 있다. 마지막 차원은 RGB 채널 정보인데, 빛의 세기만 고려하므로 이 채널 중 하나만 뽑아 쓰면 된다.
data = img // ImageData // #[[All, All, 1]] &;
이제 자료에 FFT를 적용하면 된다. 다만, FFT에선 파수(wave number)가 0부터 2k까지로 정의되므로, RotateLeft를 이용해서 파수의 범위가 -k에서 k까지 되도록 결과 배열을 조정해줘야 올바른 회절 무늬를 볼 수 있다. 또한, ListDensityPlot은 이미지 자료와 y축 방향이 반대이므로 결과 배열을 y축에 대해서 거꾸로 그려야 한다.
data // Fourier // Abs // 
   RotateLeft[#, Ceiling[Dimensions[#]/2]] & // Reverse // 
 ListDensityPlot
꽈리 모양의 슬릿을 통과한 빛의 회절 무늬

2010년 8월 4일 수요일

변수 대입하기

다음과 같이 eq1eq2가 주어졌을 때, eq1eq2a를 대입하려면 어떻게 해야 할까?
F == m a
eq1 = %;
a == D[x[t], {t, 2}]
eq2 = %;
가장 일반적인 방법은 속 편하게 Eliminate 함수를 이용해서 a를 제거하는 것이다.
Eliminate[{eq1, eq2}, a]
강력한 방법이긴 하지만, 이 예와 같이 간단한 경우엔 닭 잡는 데 소 잡는 칼을 쓰는 격이다. 필요 이상으로 시간이 오래 걸리기도 하고, 때론 방정식의 형태를 보기 어렵게 만들어 놓기도 한다. 이럴 땐, 다음처럼 바로 대입하는 편이 더 낫다.
eq1 /. Rule @@ eq2

2010년 8월 3일 화요일

두 방정식의 양변을 더하라.

다음 두 방정식의 양변을 더하면?
A == B
C == D
%% + %
결과는 (A == B) + (C == D) 이다. 당연히 우리가 원하는 결과가 아니다. 매스매티카가 이 정도도 처리 못할까?
A == B
C == D
%% + % // Thread[#, Equal] &
이렇게 Thread를 이용해서 Plus를 각 변끼리 적용해주면 된다. 두 방정식이 목록으로 주어졌다면, ListPlus로 교체하는 것만으로도 더하는 효과를 줄 수 있다.
{A == B, C == D}
Plus @@ % // Thread[#, Equal] &
그럼, 양변을 빼려면 어떻게 해야 할까? 앞의 예를 이용해서,
A == B
C == D
%% - % // Thread[#, Equal] &
이렇게? 안타깝게도 결과는 A - (C == D) == B - (C == D) 이다. 빼기가 두 번째 방정식의 양변에 적용되지 않아서 이런 결과가 나온다. 그러므로 양변을 더하기 전에 C == D의 양변에에 각각 -1을 곱해주어야 한다.
A == B
C == D
%% + (-1 # &) /@ % // Thread[#, Equal] & 

2010년 8월 2일 월요일

변수의 값 맞바꾸기

C++매스매티카, 파이썬에서 변수의 값을 맞바꾸는 코드를 비교해보자. C++은 아래와 같다. 표준적인 swap 함수의 형태를 보여준다.
template <T>
void swap(T &x, T &y)
{
    T tmp(x);
    x = y;
    y = tmp;
}
매스매티카에선 좀 더 간단하다. 목록을 만들어 교환해주면 된다.
{x, y} = {y, x}
파이썬은? 변수를 나열하면 자동으로 튜플을 만들어 주므로, 코드가 더 간단해진다.
x, y = y, x