書いてみた

文字列を適当な長さで区切って diff を表示する

【追記】end 引数を使うのを忘れてたので, ちょっと修正

@atsuoishimoto さんには負けました.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def limit_characters1(s, start, maximum, end=None):
    """
    >>> for i in limit_characters1("12345", 0, 2):
    ...     print(i)
    12
    34
    5

    >>> for i in limit_characters1("123456789", 1, 3):
    ...     print(i)
    234
    567
    89

    >>> for i in limit_characters1("123456789", 2, 3):
    ...     print(i)
    345
    678
    9

    >>> for i in limit_characters1("123456789", 3, 3):
    ...     print(i)
    456
    789
    """
    return (s[start + i * maximum:min((end or len(s)), start + (i + 1) * maximum)] \
                for i in range(((end or len(s)) - start - 1) / maximum + 1))

def _test():
    import doctest
    doctest.testmod()

if __name__ == '__main__':
    _test()

ネタ募集中

今のとこ集まってるのが

です.
2つ目以降はとある数学の変態さん大好きな follower さんから依頼が来たので, なんだか重そうなものばかりです.


自分で考えていたネタは

です.

ついでに開発の方でやりたいこととしては

  • bloggart というブログエンジンを AppEngine 上で動かしてはてダから移行.
  • Python のソース読みおよび改造

です.


結局何にするかと言うと, 最近 Twitter のタイムラインでちょこちょこ上がってる圏論の具体例としての代数学について話すことにしようと思っています.


これで締め切ったわけではないので, まだまだ受け付けますよ(^-^/

それでは.

帰ってきました.

ちょっと立て込んでた用事が済んで, また時間が作れそうなので明日あたりから連載を再開します.
順序の話はグラフの話にまで発展してますが, ある程度のところで収めて次の話題に行こうかと考えてます.


そこで話題を募集しようかと思います. 次に取り扱って欲しい話題などがありましたら, この記事にコメントするなり Twitter で Mention ください. 「フェルマーの最終定理の証明を解説して!」とか「P≠NP を解いて!」とかいう無茶なものでない限り, ご希望の話題を取り上げます.


それでは.

しばらくお休み

「順序のはなし」「グラフのはなし」「点線で楕円を描く」とそれぞれ続き物として書いてきましたが, 私事で2月頭まで忙しくなってしまったのでいったんお休みします.

楽しみに待ってる人がいたら, 突然休んでしまってすみません.

また2月の再開を楽しみにしていてください.


まぁ, また突然書くかもしれませんけどね. 日記のタイトルどおり.


それでは.

点線で楕円を描く・まとめ

【追記・2011/01/22】最初に書いた内容に大幅に誤りがあったので, 再度編集しています. おっちょこちょいですみません.

【追記・2011/02/03】修正完了. ソースコードを色々変えました.

昨日一昨日の記事には数式に間違いがあったので訂正したまとめ記事を書きます。

【修正・2013/03/12】数式に対するコメントの通り, 修正しました.

楕円の弧長

まず、 x = a \cos \varphi,\quad y = b \sin \varphi とパラメータ表示して、点 (a, 0) から左回りに弧長 u(\varphi) を測っていくことにします。

\begin{align*} u &= \int_0^{\varphi} \sqrt{dx^2 + dy ^2} \\ &= \int_0^{\varphi} \sqrt{a^2 \sin^2 \varphi + b^2 \cos^2 \varphi} d\varphi \end{align*}

となり、この逆関数  \varphi (u)微分を考えます。(ここの時点で式の形に間違いがありましたね.)

\frac{d \varphi}{du} = \frac{1}{\frac{du}{d \varphi}}  = \frac{1}{\sqrt{a^2 \sin^2 \varphi + b^2 \cos^2 \varphi}}

これを差分形にして、

\begin{align*} \Delta \varphi &= \frac{\Delta u}{\sqrt{a^2 \sin^2 \varphi + b^2 \cos^2 \varphi}} \\ \varphi_0 &= 0 \\ \varphi_n &= \varphi_{n - 1} + \frac{\Delta u}{\sqrt{a^2 \sin^2 \varphi_{n-1} + b^2 \cos^2 \varphi_{n-1}}} \end{align*}

\sin\cos を間違えていましたね。

ここで ab の大小については何も言っていないことに注意してください。

これを実装します。

Python ソースコード

開発をローカルから Github に移したので, 最新のソースはこちらを見てください.

import sys
import math

DIVISION = 1000.0
CYCLE = 10

def angles(du, a, b):
    phi = 0
    while phi <= 2 * math.pi:
        yield phi
        phi += du / math.sqrt((a * math.sin(phi))**2 + (b * math.cos(phi))**2)

def coordinate(du, a, b):
    for angle in angles(du, a, b):
        yield (a * math.cos(angle), b * math.sin(angle))

def circumference(a, b):
    """Return a length of a circumference of an ellipse.

    @param a, b length of two semi-axes

    reference: http://en.wikipedia.org/wiki/Ellipse#Circumference
    """
    expr = ((a - b)/(a + b))**2
    return math.pi * (a + b) * (1 + (3 * expr)/(10 + math.sqrt(4 - 3 * expr)))

def draw(argv=None):
    if not argv:
        argv = sys.argv
    filename = argv[1]
    a = float(argv[2])
    b = float(argv[3])
    du = circumference(a, b) / DIVISION

    with open(filename, 'w') as out_file:
        print >> out_file, 'plot "-" w l'
        print >> out_file, '#x\ty'
        for i, coord in enumerate(coordinate(du, a, b)):
            i %= CYCLE * 2
            if i < CYCLE:
                print >> out_file, '{0}\t{1}'.format(*coord)
            else:
                print >> out_file, ''
        print >> out_file, 'end'
        print >> out_file, 'pause -1'


if __name__ == '__main__':
    draw(sys.argv)

コマンド

$ python ellipse.py ellipse.dat 1.0 0.5
gnuplot> plot "ellipse.dat" w l

出力結果

以下のようにちゃんと点線が等長、等間隔で描けています。(実際にプログラムで点線の長さと間隔を測ったところ、1 % 程度の誤差はありましたがだいたい同じでした。)

ab には大小の制限は無いので縦長の楕円も描けます。

あとがき

昨日一昨日の記事を書いてから、色々な方からコメントやツッコミをいただきました。ありがとうございます。

今まで何かを作ったり、記事を書いたりして公開したことはあったけれど、今回もらった反応は今までで一番多いものでした。
そして、何かを発表して反応をもらう喜びを強く感じました。


これは病み付きになりそうです。


もしかして、オープンソースで活動してる人の中には、この喜びを原動力にやってる人もいるのかなぁ? と思ったり。

それでは、お休みなさい。

点線で楕円を描く・その2

[追記] この記事には誤りが含まれています。訂正した記事はこちらです。



昨日の記事の続きです。

昨日は計算式までは出したのですが、実際に計算せずにはいられなかったのでやってみました。

Numpy とかあるのは知ってるのですが、標準の Python だけでどこまでできるかやってみました。
描画は gnuplot 使ってやってます。

ソースコード

ちゃちゃっと書いたので、コメントとかは省いてます。

import sys
import math

def delta(phi, du, k2):
    return phi + du / math.sqrt(1 - k2 * math.sin(phi)**2)

def draw(argv=None):
    if not argv:
        argv = sys.argv
    filename = argv[1]
    a = float(argv[2])
    b = float(argv[3])
    du = float(argv[4])

    k2 = 1 - (b/a)**2
    phi = 0

    with open(filename, 'w') as out_file:
        print >> out_file, '#x\ty'
        i = 0
        while phi <= 2 * math.pi:
            i += 1
            i %= 10
            if i < 5:
                print >> out_file, '{0}\t{1}'.format(a * math.cos(phi), b * math.sin(phi))
            else:
                print >> out_file, ''
            phi = delta(phi, du, k2)

                

if __name__ == '__main__':
    draw(sys.argv)

コマンド

$ python ellipse.py ellipse.dat 1.0 0.5 0.01
gnuplot> plot "ellipse.dat" w l

plot 結果


あとがき

思ったより誤差が発散しなかったので楽でした。

今日ばっかりは俺ってすげーって思いました :P

それでは。