Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

유/무한 멱급수 계산 함수 #24

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

유/무한 멱급수 계산 함수 #24

wants to merge 2 commits into from

Conversation

qria
Copy link

@qria qria commented Aug 15, 2016

멱급수(power series)를 계산하는 유틸리티 함수를 만들어 보았습니다 ㅎㅎ
게다가 coefficient를 iterator로 줘서 무한길이의 멱급수도 계산이 가능합니다! (와우!)
python calc.py 로 테스트를 할 수 있고 인자로 x=1일때의 테스트도 가능하게 해놓았습니다.

뭔가 더 하고싶은게 많았는데 시간이 부족해서 이걸로 만족합니다 ㅠㅠ

@jckdotim
Copy link

안녕하세요! (주)스포카 김재석 CTO 입니다. 현재 코딩 이벤트 심사를 진행중인데요, 워낙 출중한 제출물이 많아 심사가 지연되고 있습니다. ㅜㅜ 이번주 금요일까지는 심사가 완료될 예정이니 조금만 기다려주세요!

@qria
Copy link
Author

qria commented Aug 31, 2016

아 혹시 해설을 달면 조금 편해질까요?

@jckdotim
Copy link

jckdotim commented Sep 1, 2016

간단히 달아주시면 더 좋습니다. ^^

@qria
Copy link
Author

qria commented Sep 1, 2016

오 이런 해설을 너무 길게 써버렸는데 짧은걸 원하시는군요, 다시 요약하겠습니다.
긴 버전도 투자한 아침이 아까워서 일단 올려봅니다... (안읽으셔도 됩니다.)

-- 짧은 버전
본래 list나 generator를 인자로 받는 함수에 string을 넣으면 오작동하면서 에러 메세지가 eval되면서 계산값이 출력되는 함수를 짰습니다.
위 오작동이 여러 군데에 걸쳐서 조금씩 일어나고 오작동 만을 위한 코드는 없어 코드 리뷰를 통과할 정도로 정상적인 스크립트 처럼 보이는 특징이 있습니다.
원래는 import해서 쓰는 유틸리티 함수 스크립트이나 메인으로 실행할 경우 유닛 테스트가 돌아간다는 컨셉을 가지고 있습니다.

-- 긴 버전

저는 뭔가 심사위원님들이 커피를 홀짝이면서 느긋하게 코드를 뜯어보면서 머리위에 ????를 띄우는걸 상상했기때문에 일부러 이 코드가 대체 뭐하는건지 조차 이해하게 어렵게 짜 놓았는데, 그럴 시간이 없이 바쁘신거같아서 해설을 좀 달아 보았습니다.

기본적으로 독창성과 python에 대한 이해를 중점적으로 평가한다고 하시길래 좀 다른 형태의 난독화를 python의 특징들인 duck typing, operator overloading, iterator 등을 마구 악용해서 짠 유틸리티 스크립트입니다.

제 코드는 underhanded라고도 불리는 기법을 사용하는데요 인자가 list, tuple, 혹은 generator일 경우에 정상적으로 동작하지만 string이 인자로 주어질 경우에는 숨겨진 동작을 하는 함수를 구현했습니다. Underhanded는 이렇게 code review를 통과할 정도로 남의 눈에는 정상적으로 보이나 특정 조건이 만족되면 숨겨진 기능이 발동하는 기법을 말합니다.

외국에서는 이런 underhanded 방식이 인기가 있어 아예 obfuscated c contest와 따로 underhanded c contest가 열린다고 합니다. 2004년 obfuscated V contest의 주제가 underhanded 룰 이였던거에서부터 영감을 얻어 2005년부터 열렸다고 하네요.

이 코드는 그래서 유틸리티 스크립트의 형태를 띄고 있습니다. 이건 제가 되게 애용하는 패턴인데 한 파일 내에 유틸리티 함수와 그 함수의 유닛 테스트를 같이 넣어주는것입니다. 유닛 테스트를 if name == 'main' 안에 넣어두면 import해서 쓸 경우에는 테스트가 실행되지 않지만 테스트하고 싶을 때 간단하게 스크립트를 실행하는 것만으로도 가능하기 때문에 매우 편리합니다. 어떤 한 프로젝트에 속한게 아니라 독립적인 스크립트 일 때 많이 씁니다. 예를들어서 project euler문제를 풀 때 소수생성 스크립트를 이렇게 구조해서 가지고 있으면 매우 편하겠죠?

아무튼 제가 짠 스크립트는 정상적으로 동작할 때는 멱급수(power series)를 계산하는 함수로 동작합니다. 멱급수가 뭐냐면 간단히 말해 c0 + c1 * x + c2 * x ** 2 + c3 * x ** 3 + c4 * x **4 + ... 이렇게 생긴 식을 말합니다. 수학 뿐 아니라 과학 및 공학에서 analysis하는데 굉장히 많이 쓰이는 개념입니다. 테일러 전개 아시죠? 그것도 멱급수의 일종입니다.

그런데 이걸 계산하는 스크립트를 짜는데에는 문제가 있는데, 바로 식이 무한하다는 것, 그리고 주어진 값에 따라 계산결과가 없을 수도 (발산) 있다는 것입니다. 그래서 이 스크립트에서는 Domb-Sykes 방법을 사용해서 수렴반경(계산결과가 존재하는 범위)를 추측하고, 이 수렴반경 밖의 범위에서는 에러를 내뱉는 방법을 사용합니다.

궁금하신 분들을 위해 간단히 Domb-Sykes 방법을 설명하면, 미적분학같은데서 기억나실지는 모르겠지만 멱급수의 수렴반경은 $$ \lim_{n\to\infty} \frac{c_n}{c_{n-1}} $$ 의 값이 존재할 경우 그 값입니다. 그걸 이용해서 첫 유한개의 coefficients를 보고 이 식의 값을 선형회귀로 추측합니다. 참 쉽죠?

그래서 이걸 계산해주는 함수인 calc_power_series(coefficients, x)의 구조는 다음과 같습니다.

  1. 유한급수인지 무한급수인지 판별
  2. 무한급수일 경우 주어진 x 값이 수렴반경 내의 값인지 추측
  3. 급수의 값 계산 (무한급수는 오차범위 내 까지만 계산)
  4. 무한급수 계산에서 timeout이 날 경우 error_precision(오차범위) 값의 수정을 제안

그런데 이렇게 열심히 무한 급수의 값을 계산하는 함수를 짜긴 했지만 (그리고 실제로 사용도 가능하지만) 사실은 모두 계산기를 숨기기 위한 포석일 뿐입니다.

Coefficient자리에 string을 넣고 x에 1을 넣으면, 일단 (1)에서 .len()을 체크해 유한급수라고 판단합니다.
(2)부분은 그래서 스킵되고요.
(3)에서는 string 끼리 + 연산이 정의되어있고 string, int 끼리 * 연산도 정의되어 있기 때문에 급수의 값 finite에 고스란히 다시 그 string값이 재조립되어 들어갑니다.
(4)는 원래는 유한급수이면 스킵되지만 list나 tuple이 아닐경우 실행되게 해놓아서 (4)가 실행이 되는데, 여기서 정상적이라면 err값이 중간에 오차범위 값으로 재정의되나 그 부분을 스킵했기 때문에 err 값이 에러 메세지인 상태로 남아있습니다. 그 뒤 셀프 코드 인젝션이 시전되어서 "10 * {error}" 부분에 원래 숫자가 들어가야 하나 에러 메세지가 들어가면서 "10 * x is (-r, r) or coefficients is list or finite"가 되며 이걸 eval 하면 or 의 성질에 의해 "finite"값, 즉, 아까 잘못 대입되었던 string값이 eval되어버립니다. 끝!

여기까지 읽느라 수고하셨습니다 ㅎㅎ 내년에도 이렇게 재미있는 대회가 개최되었으면 좋겠네요 ㅎㅎ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants