天泣記

2009-06-02 (Tue)

#1

良い名前は語順の話も含むことにして、in? の話はそっちに入れるほうが適切か。

2009-06-03 (Wed)

#1

The Player Project tracker: player segfault with gazebo

#2

日記を http://www.a-k-r.org/d/ に移してみた。

2009-06-04 (Thu)

#1

多角形の車輪に深い意味があるかもしれない、中国の自転車 : Gizmodo Japan」を見て、ふと、ルーローの三角形を回転させたときに重心がどう動くかを図示してみたくなった。

ので、Asymptote で描いてみた。

real r3 = sqrt(3);
pair top = (0,r3/3);
pair upleft = (-(r3-1)/2,(3-r3)/6);
pair upright = ((r3-1)/2,(3-r3)/6);
pair downleft = (-1/2,-r3/6);
pair downright = (1/2,-r3/6);
pair bottom = (0,-(3-r3)/3);
path unit_reuleaux_triangle = 
  downleft{curl 1}..bottom..
  {curl 1}downright{curl 1}..upright..
  {curl 1}top{curl 1}..upleft..{curl 1}cycle;

for(int i=0; i <= 360; i += 10) {
  path rotated = scale(100)*rotate(i)*unit_reuleaux_triangle;
  fill(shift(i,-min(rotated).y)*rotated, gray);
  draw(shift(i,-min(rotated).y)*rotated);
  fill(shift(i,-min(rotated).y) * unitcircle, red);
}
for(int i=0; i <= 360; i += 10) {
  path rotated = scale(100)*rotate(i)*unit_reuleaux_triangle;
  fill(shift(i,-min(rotated).y) * unitcircle, red);
}

本当は、ちゃんと回転に応じて進むようにしたかったのだが、計算が面倒だったのでそれはさぼっている。

#2

回転に応じて進むようにするにはこんなかんじか。

real inch=72;

real r = 3inch;

pair o = (0,0);
pair a = (r,0);
pair b = rotate(60,o)*a;

pair center = (b.x, r*sqrt(3)/6);

pair O = rotate(30,o)*a;
pair A = rotate(30,a)*b;
pair B = rotate(30,b)*o;

path tri =
     o{curl 1}..B..{curl 1}a
      {curl 1}..O..{curl 1}b
      {curl 1}..A..{curl 1}cycle;

path roll(real phi, path fig) {
  if (phi <= 60) {
    pair p = rotate(phi, o) * a;
    real len = r*phi*pi/180;
    path fig2 = rotate(-90-phi)*shift(-p.x,-p.y)*fig;
    return shift(len,0)*fig2;
  }
  else if (phi <= 120) {
    real len = r*60*pi/180;
    return shift(len,0)*rotate(-90-phi)*shift(-b.x, -b.y)*fig;
  }
  else if (phi <= 240) {
    return shift(r*60*pi/180,0)*roll(phi-120, fig);
  }
  else {
    return shift(2*r*60*pi/180,0)*roll(phi-240, fig);
  }
}

for (real phi = 0; phi <= 360; phi += 10) {
  fill(roll(phi, tri),gray);
  draw(roll(phi, tri));
}

for (real phi = 0; phi <= 360; phi += 10) {
  fill(roll(phi, shift(center)*unitcircle), red);
}

そーか。頂点が地面に接して (刺さって) いるときの重心の移動は、頂点を中心とする弧になるのだな。

2009-06-05 (Fri)

#1

Asymptote ではアニメーションができるというので、せっかくなのでやってみた

import animation;

real inch=72;

real r = 3inch;

pair o = (0,0);
pair a = (r,0);
pair b = rotate(60,o)*a;

pair center = (b.x, r*sqrt(3)/6);

pair O = rotate(30,o)*a;
pair A = rotate(30,a)*b;
pair B = rotate(30,b)*o;

path tri =
     o{curl 1}..B..{curl 1}a
      {curl 1}..O..{curl 1}b
      {curl 1}..A..{curl 1}cycle;

path roll(real phi, path fig) {
  if (phi <= 60) {
    pair p = rotate(phi, o) * a;
    real len = r*phi*pi/180;
    path fig2 = rotate(-90-phi)*shift(-p.x,-p.y)*fig;
    return shift(len,0)*fig2;
  }
  else if (phi <= 120) {
    real len = r*60*pi/180;
    return shift(len,0)*rotate(-90-phi)*shift(-b.x, -b.y)*fig;
  }
  else if (phi <= 240) {
    return shift(r*60*pi/180,0)*roll(phi-120, fig);
  }
  else {
    return shift(2*r*60*pi/180,0)*roll(phi-240, fig);
  }
}

animation a;

fill(background, white);

for (real phi = 0; phi <= 360; phi += 10) {
  save();
  fill(roll(phi, tri),gray);
  draw(roll(phi, tri));
  a.add();
  restore();
}

a.movie(BBox(0.25cm),loops=10,delay=2);

うぅむ。なんか以前のフレームがちゃんと消えない

添付されているデモを試しても、 ギャラリーの結果と違って以前のフレームが残っている。バグかな

変換中には中間ファイルとしてたくさん eps ができるが、その 1枚 1枚はフレームごとの画像になっている

それを ImageMagick で変換しても変 (それと ImageMagick メモリ食いすぎで遅すぎ)

どうも透過が問題のようなので、eps を透過しない gif にしてから gifsicle で変換したらうまくいった

ルーローの三角形のアニメ

なお、Asymptote の最新版は 1.75 だが、Debian GNU/Linux lenny のは 1.43 でちょっと古いようだ。最新版でも問題があるかは分からない

2009-06-06 (Sat)

#1

ふと、ルーローの三角形とペンローズの三角形を組み合わせてみた

reuleaux-penrose-triangle.png

reuleaux-penrose-triangle.asy:

size(10cm, 10cm);

pair a1 = (0,1);
pair b1 = rotate(120)*a1;
pair c1 = rotate(-120)*a1;
real len1 = length(a1-b1);

path arc11 = arc(c1,len1,120,180);
path arc13 = arc(b1,len1,0,60);

pair a2 = 0.8 * a1;
pair b2 = 0.8 * b1;
pair c2 = 0.8 * c1;
real len2 = 0.8 * len1;
real off21 = 0;
real off22 = 10;
path arc22 = arc(a2,len2,-120+off21,-60+off22);
path arc23 = arc(b2,len2,0+off21,60+off22);

pair a3 = 0.6 * a1;
pair c3 = 0.6 * c1;
real len3 = 0.6 * len1;
real off3 = 15;
path arc31 = arc(c3,len3,120-off3,180+off3);
path arc32 = arc(a3,len3,-120-off3,-60+off3);

real[] tt22 = intersect(arc22, arc31);
real[] tt23 = intersect(arc23, arc32);
real[] tt31 = intersect(arc31, arc32);

path arc312 = subpath(arc31, tt31[0], tt22[1]);
arc32 = subpath(arc32, tt31[1], length(arc32));
arc22 = subpath(arc22, tt22[0], length(arc22));
arc23 = subpath(arc23, tt23[0], length(arc23));
arc32 = subpath(arc32, 0, tt23[1]);

real[] tt;

tt = intersect(arc11, arc23);
path arc111 = subpath(arc11, 0, tt[0]);
arc23 = subpath(arc23, 0, tt[1]);

tt = intersect(arc13, arc22);
path arc132 = subpath(arc13, tt[0], length(arc13));
arc22 = subpath(arc22, 0, tt[1]);

path area = arc111--reverse(arc23)--reverse(arc32)--arc312--arc22--arc132--cycle;
filldraw(area, rgb(0.5,0.8,1));
filldraw(rotate(120)*area, rgb(0.7,0.9,1));
filldraw(rotate(240)*area, rgb(0.7,0.8,0.9));

角の形はちょっとナニ

#2

輪郭線がなければこれで済むか。

reuleaux-penrose-triangle-noline.png

reuleaux-penrose-triangle-noline.asy:

size(10cm,10cm);

pair a = (0,1);
pair b = rotate(120)*a;
pair c = rotate(-120)*a;

real len3 = length(a-b);
real len2 = len3 * 0.9;
real len1 = len3 * 0.8;

path sector(pair center, real r1, real r2, real ang1, real ang2)
{
  return arc(center,r1,ang1,ang2)--arc(center,r2,ang2,ang1)--cycle;
}

picture fillpart(pen pen)
{
  picture pic;
  fill(pic, sector(a, len1, len2, -120, -60), pen);
  clip(pic, shift(c)*scale(len1)*unitcircle);

  fill(pic, sector(b, len2, len3, 0, 80), pen);
  clip(pic, shift(c)*scale(len3)*unitcircle);
  clip(pic, shift(a)*scale(len2)*unitcircle);
  return pic;
}

add(fillpart(rgb(0.5,0.8,1)));
add(rotate(120)*fillpart(rgb(0.7,0.9,1)));
add(rotate(240)*fillpart(rgb(0.7,0.8,0.9)));

2009-06-07 (Sun)

#1

ぐるぐる

spiral.png

spiral.asy:

size(10cm);

import graph;

draw(polargraph(identity, 0, 20));

xaxis(Bottom(), LeftTicks());
yaxis(Left(), RightTicks());
#2

ルーローの三角形を回したときの動作を図示するとき、どういう間隔で状態を描いたらいいか。

たとえば、接地している位置が一定間隔になるように描くのは望ましくない。角が地面に刺さっているときは接地している位置がしばらく変わらないので、その間の状態変化を図示できない。

ましな方法はいくつか考えられるが、重心の横方向の移動が一定間隔になるように描くことを考えた。

が、これをやるにはどうも x + r/sqrt(3) * sin(pi/6-x/r) = y を x について解く必要があって、解けなくて困った。(ちなみに Wolfram Alpha でも解けなかった)

結局、Asymptote には Newton 法の実装が入っているので、それを使ってなんとか描けた。

reuleaux-center-movement.png

reuleaux-center-movement.asy:

size(15cm);

pair a = (0,1);
pair b = rotate(120)*a;
pair c = rotate(-120)*a;
real r = length(a-b);

path tri = arc(c,r,120,180)--arc(a,r,240,300)--arc(b,r,0,60)--cycle;

real outlinelen = arclength(tri);
real edgelen = outlinelen/3;

real cyclelen = pi*r/3;

typedef real realfunc(real);
realfunc move1(real y) {
  return new real(real x) {
    return x + r/sqrt(3) * sin(pi/6-x/r) - y;
  };
}

real move1prime(real y) {
  return 1 + r/sqrt(3) * cos(pi/6-pi/r);
}

transform ms[];
for (real x = 0.001; x < cyclelen*6; x += cyclelen/10) {
  int n = floor(x/cyclelen);
  real x2 = fmod(x, cyclelen);
  if (x2 < (pi/3-1/sqrt(3))*r) {
    real x3 = newton(move1(x2+r/(2*sqrt(3))), move1prime, x2);
    real t = arctime(tri, x3);
    pair p = point(tri, t);
    pair d = dir(tri, t);
    transform mat = shift(n*edgelen+x3,0)*rotate(-degrees(atan2(d.y,d.x)))*shift(-p);
    ms.push(mat);
  }
  else {
    real x3 = x2 - (pi/3-1/(2*sqrt(3)))*r;
    real deg = degrees(asin(sqrt(3)*x3/r));
    transform mat = shift((n+1)*edgelen)*rotate(-60-deg)*shift(-c);
    ms.push(mat);
  }
}

for (int i = 0; i < ms.length; ++i)
  filldraw(ms[i]*tri, gray);
for (int i = 0; i < ms.length; ++i)
  dot(ms[i]*(0,0), red);

#3

asymptote-1.76 を入れたら、アニメーションの問題は直っていた。

#4

buildcycle というのを見つけて、使ってみると輪郭線をつけてもこれで描けた。

reuleaux-penrose-triangle-buildcycle.png

reuleaux-penrose-triangle-buildcycle.asy:

size(10cm,10cm);

pair a = (0,1);
pair b = rotate(120)*a;
pair c = rotate(-120)*a;

real len3 = length(a-b);
real len2 = len3 * 0.9;
real len1 = len3 * 0.8;

path p = buildcycle(
  arc(b, len3, 0, 80),
  arc(c, len3, 90, 150),
  arc(b, len2, 80, 0),
  arc(a, len1, -60, -120),
  arc(c, len1, 150, 240),
  arc(a, len2, -120, -30));

filldraw(p, rgb(0.5,0.8,1));
filldraw(rotate(120)*p, rgb(0.7,0.9,1));
filldraw(rotate(240)*p, rgb(0.7,0.8,0.9));
#5

buildcycle の説明はマニュアルには

path buildcycle(... path[] p);
  This returns the path surrounding a region bounded by
  a list of two or more consecutively intersecting paths,
  following the behaviour of the MetaPost buildcycle command. 

と、1文しか書いてなくてしかも MetaPost を参照していてよくわからないのだが、複数の曲線を与えると、その交点でそれらの部分曲線をつないで閉曲線を作る、というもののようだ。

図で説明すると以下のようなかんじ。p1, p2, p3, p4, p5, p6 という円弧 (のそれぞれ一部分) をつないで、青く塗られた部分の領域を囲う閉曲線を構成する。

ユーザの立場からは、交点を自分で計算する必要がないのが良い。

しかし、複数の曲線から取り出せる閉曲線が複数あったらどうなるのか。仕様がいまひとつ曖昧な気はする。

reuleaux-penrose-triangle-structure.png

reuleaux-penrose-triangle-structure.asy:

size(10cm);

pair a = (0,1);
pair b = rotate(120)*a;
pair c = rotate(-120)*a;

real len3 = length(a-b);
real len2 = len3 * 0.9;
real len1 = len3 * 0.8;

path p1 = arc(b, len3, 0, 80);
path p2 = arc(c, len3, 90, 150);
path p3 = arc(b, len2, 80, 0);
path p4 = arc(a, len1, -60, -120);
path p5 = arc(c, len1, 150, 240);
path p6 = arc(a, len2, -120, -30);

path p = buildcycle(p1, p2, p3, p4, p5, p6);

fill(p, rgb(0.5,0.8,1));

draw(shift(a)*scale(len1)*unitcircle, gray);
draw(shift(a)*scale(len2)*unitcircle, gray);
draw(shift(a)*scale(len3)*unitcircle, gray);
draw(shift(b)*scale(len1)*unitcircle, gray);
draw(shift(b)*scale(len2)*unitcircle, gray);
draw(shift(b)*scale(len3)*unitcircle, gray);
draw(shift(c)*scale(len1)*unitcircle, gray);
draw(shift(c)*scale(len2)*unitcircle, gray);
draw(shift(c)*scale(len3)*unitcircle, gray);

pen pen = red+1.2;
draw(p1, pen, EndArrow); label("p1", point(p1, length(p1)/3), NE);
draw(p2, pen, EndArrow); label("p2", point(p2, length(p2)/2), N);
draw(p3, pen, EndArrow); label("p3", point(p3, length(p3)/2), SW);
draw(p4, pen, EndArrow); label("p4", point(p4, length(p4)/2), NE);
draw(p5, pen, EndArrow); label("p5", point(p5, length(p5)/5*4), NE);
draw(p6, pen, EndArrow); label("p6", point(p6, length(p6)/2), S);

dot(a); label("a", a, N);
dot(b); label("b", b, SW);
dot(c); label("c", c, SE);
#6

Asymptote tracker: maxtimes and mintimes problem

#7

Asymptote をいくらか使ってみた感想:

あと、マニュアル

Asymptote is the only language we know of that treats functions as variables,
but allows overloading by distinguishing variables based on their signatures. 

Asymptote は関数を変数として扱う言語の中で、我々が知る限り唯一、
変数をそのシグネチャによって区別してオーバーロードできる言語である。

と書いてある。

% asy
Welcome to Asymptote version 1.43 (to view the manual, type help)
> int x, x()
> x = new int() { return 2; }
> x = 3
> x()
2
> x+0
3
> x()
2
> x+0
3
> x
-: 1.1: warning: writing overloaded variable 'x'
3
> 

x という名前の、int な変数と、引数なしで int を返す関数が両方同時に存在し、使い方によって選ばれる。選べないときもあるが。

後から、int 引数をとって int を返す関数 x を加えても、いままであった x は残る。

> int x(int)
> x = new int(int v) { return v; }
> x()
2
> x(10)
10
> x()
2
> x+0
3

こだわりが感じられる。

2009-06-08 (Mon)

#1

buildcycle は Asy - Contours Domaines のページが詳しいような気がする

そういう気がするのだが、フランス語なのがきつい

2009-06-09 (Tue)

#1

Asymptote tracker: hidden surface is drawn in GIF by animation and three

2009-06-10 (Wed)

#1

半透明で、上が円、下が六角形円な柱

pillar.png

pillar.asy:

import three;

triple mid1(triple a, triple b) { return point(a--b,1/3); }
triple mid2(triple a, triple b) { return point(a--b,2/3); }

void spread(path3 c1, path3 c2, triple[][][] Q) {
  for (int i = 0; i < length(c1); ++i) {
    triple p11 = point(c1,i), p12 = postcontrol(c1, i), p13 = precontrol(c1, i+1), p14 = point(c1, i+1);
    triple p41 = point(c2,i), p42 = postcontrol(c2, i), p43 = precontrol(c2, i+1), p44 = point(c2, i+1);
    triple p21 = mid1(p11,p41), p22 = mid1(p12,p42), p23 = mid1(p13,p43), p24 = mid1(p14,p44);
    triple p31 = mid2(p11,p41), p32 = mid2(p12,p42), p33 = mid2(p13,p43), p34 = mid2(p14,p44);
    triple[] curve1 = { p11, p12, p13, p14 };
    triple[] curve2 = { p21, p22, p23, p24 };
    triple[] curve3 = { p31, p32, p33, p34 };
    triple[] curve4 = { p41, p42, p43, p44 };
    Q.push(new triple[][] { curve1, curve2, curve3, curve4 });
  }
}

currentprojection=perspective(250,-250,150);

size(10cm);

path3 vertex = rotate(-130,Z)*X;

int n = 6;

guide3 circle = vertex;
guide3 square = vertex;

for (int i = 1; i < n; ++i) {
  circle = circle .. rotate(360/n*i,Z)*vertex;
  square = square -- rotate(360/n*i,Z)*vertex;
}
circle = circle .. cycle;
square = square -- cycle;

path3 c1 = circle;
path3 c2 = scale3(2)*shift(0,0,-1)*square;

triple[][][] Q;

spread(c1, c2, Q);

draw(surface(Q),cyan+opacity(0.5));
draw(surface(c1),cyan+opacity(0.5));
draw(surface(c2),cyan+opacity(0.5));

2009-06-11 (Thu)

#1

ブリリアントカットな赤いやつを作ってみた (Culet は作らなかったので、57面である)

なお、視点を設定する方法はよくわかっていないので、

% asy -f pdf -V brilliant.asy

で起動した acroread で対話的に動かして、スクリーンショットをとって画像を得た。

以下を参考にした

なお、ブリリアントカットをちゃんと理解した結果、Ruby のロゴのやつはブリリアントカットではないということがわかった。Star Facet と Pavilion Facet がなくなっている

... 検索したら [ruby-talk:142211] を見つけた。simplified というのはわかった上でそうやっているようだ。

brilliant.png

brilliant.asy:

import three;

real diameter = 1;
real table_ratio = 0.6;

real crown_ratio = 0.15;
real pavilion_ratio = 0.45;

real upper_half_ratio = 0.6;
real lower_half_ratio = 0.8;

real table_d = diameter*table_ratio;

real crown_h = diameter*crown_ratio;
real pavilion_h = diameter*pavilion_ratio;

triple top_v = (0,0,crown_h);
triple bot_v = (0,0,-pavilion_h);

triple girdle_v = (diameter/2, 0, 0);
triple table_v = (table_d/2, 0, crown_h);

triple bezel_center_v = point(girdle_v--table_v, upper_half_ratio);
triple pavilion_center_v = point(girdle_v--bot_v--girdle_v, lower_half_ratio);

triple bezel_v1 = (bezel_center_v.x, bezel_center_v.x*tan(radians(360/16)), bezel_center_v.z);
triple bezel_v2 = (bezel_center_v.x, -bezel_center_v.x*tan(radians(360/16)), bezel_center_v.z);
path3 bezel = table_v--bezel_v1--girdle_v--bezel_v2--cycle;

transform3 rot = rotate(360/8,Z);

triple girdle1_v = rotate(360/16,Z)*girdle_v;
triple girdle2_v = rotate(-360/16,Z)*girdle_v;

path3 star = table_v--rot*table_v--bezel_v1--cycle;
path3 upper_girdle1 = girdle_v--bezel_v1--girdle1_v--cycle;
path3 upper_girdle2 = girdle_v--girdle2_v--bezel_v2--cycle;

triple pavilion_v1 = (pavilion_center_v.x, pavilion_center_v.x*tan(radians(360/16)), pavilion_center_v.z);
triple pavilion_v2 = (pavilion_center_v.x, -pavilion_center_v.x*tan(radians(360/16)), pavilion_center_v.z);
path3 pavilion = girdle_v--pavilion_v1--bot_v--pavilion_v2--cycle;

path3 lower_girdle = girdle_v--pavilion_v1--rot*girdle_v--cycle;
path3 lower_girdle1 = girdle_v--pavilion_v1--girdle1_v--cycle;
path3 lower_girdle2 = girdle2_v--girdle_v--pavilion_v2--cycle;

pen pen = red+opacity(0.8);

guide3 table;
for (int i = 0; i < 8; ++i) {
  table = table--rotate(360*i/8,Z)*table_v;
  draw(surface(rotate(360*i/8,Z)*bezel), pen);
  draw(surface(rotate(360*i/8,Z)*star), pen);
  draw(surface(rotate(360*i/8,Z)*upper_girdle1), pen);
  draw(surface(rotate(360*i/8,Z)*upper_girdle2), pen);
  draw(surface(rotate(360*i/8,Z)*pavilion), pen);
  draw(surface(rotate(360*i/8,Z)*lower_girdle1), pen);
  draw(surface(rotate(360*i/8,Z)*lower_girdle2), pen);
}
table = table--cycle;
draw(surface(table), pen);
#2

大阪中之島の三井ビルのやつは、Table が 8角でなく 6角なのをはじめとして、さらに (ロゴ以上に) 簡略化されているようだ

#3

画像検索すると、Ruby Quiz のロゴは上部はちゃんとブリリアントカットになっている気がする。下部は簡略化されているが。

2009-06-12 (Fri)

#1

ブリリアントカットの形を決定するパラメータは、ダイヤモンドの鑑定書で定義されているようだ

というか、鑑定書には形を測定した結果が数値で書いてあるので、その数値から形を作ることができる (完全に軸対称になっているとか、数値に現れない部分がすべて理想的と仮定すれば)

鑑定書にも発行元によっていろいろ種類があってどんなパラメータが書いてあるかは微妙に異なるようだが、 GIA の形式でパラメータを指定するようにしてみた

まぁ、length という名前のくせに百分率なのは気にいらないが。

diamond.png

diamond.asy:

import three;

real diameter = 40;

real table_size = 56;
real crown_angle = 34;
real pavilion_angle = 41.2;
real star_length = 55;
real lower_half_length = 80;

real radius = diameter/2;
real table_outer_diameter = diameter * table_size / 100;
real table_outer_radius = diameter/2 * table_size / 100;

real top_z = (radius-table_outer_radius)*tan(radians(crown_angle));
real bot_z = -radius*tan(radians(pavilion_angle));

triple top_v = (0, 0, top_z);
triple bot_v = (0, 0, bot_z);

triple girdle_v = (radius, 0, 0);
triple table_v = (table_outer_radius, 0, top_z);

real ang1 = 360/16;
real ang2 = 360/8;
real ang1_rad = radians(ang1);
real ang2_rad = radians(ang2);

transform3 rot2 = rotate(ang2,Z);

real table_inner_diameter = table_outer_diameter * cos(ang1_rad);
real table_inner_radius = table_outer_radius * cos(ang1_rad);

triple starline_a = (0, 0, radius * top_z / (radius - table_outer_radius));
triple starline_d = (girdle_v.x, girdle_v.x*tan(ang1_rad), 0);
triple starline_b = point(starline_a--starline_d, table_outer_radius/abs(starline_d));
triple starline_c = point(starline_a--starline_d, radius/abs(starline_d));

triple star_v1 = point(starline_b--starline_c, star_length/100);
triple star_v2 = (star_v1.x, -star_v1.y, star_v1.z);

triple girdle1_v = rotate(ang1,Z)*girdle_v;
triple girdle2_v = rotate(-ang1,Z)*girdle_v;

path3 star = table_v--rot2*table_v--star_v1--cycle;
path3 bezel = table_v--star_v1--girdle_v--star_v2--cycle;
path3 upper_girdle1 = girdle_v--star_v1--girdle1_v--cycle;
path3 upper_girdle2 = girdle_v--girdle2_v--star_v2--cycle;

triple pavilionline_a = (0, 0, bot_z);
triple pavilionline_c = starline_d;
triple pavilionline_b = point(pavilionline_a--pavilionline_c, radius/abs(pavilionline_c));
triple pavilion_v1 = point(pavilionline_b--pavilionline_a, lower_half_length/100);
triple pavilion_v2 = (pavilion_v1.x, -pavilion_v1.y, pavilion_v1.z);

path3 pavilion = girdle_v--pavilion_v1--bot_v--pavilion_v2--cycle;
path3 lower_girdle = girdle_v--pavilion_v1--rot2*girdle_v--cycle;
path3 lower_girdle1 = girdle_v--pavilion_v1--girdle1_v--cycle;
path3 lower_girdle2 = girdle2_v--girdle_v--pavilion_v2--cycle;

pen pen = white+opacity(0.8);

guide3 table;
for (int i = 0; i < 8; ++i) {
  table = table--rotate(360*i/8,Z)*table_v;
  draw(surface(rotate(360*i/8,Z)*bezel), pen);
  draw(surface(rotate(360*i/8,Z)*star), pen);
  draw(surface(rotate(360*i/8,Z)*upper_girdle1), pen);
  draw(surface(rotate(360*i/8,Z)*upper_girdle2), pen);
  draw(surface(rotate(360*i/8,Z)*pavilion), pen);
  draw(surface(rotate(360*i/8,Z)*lower_girdle1), pen);
  draw(surface(rotate(360*i/8,Z)*lower_girdle2), pen);
}
table = table--cycle;
draw(surface(table), pen);

currentprojection = orthographic((diameter, diameter/3, diameter/2), (0,0.5,1));

2009-06-16 (Tue)

#1

GNU R を使ってみる

とりあえず正弦波

> curve(sin(x), xlim=c(0,2*pi))

高階関数

> f <- function(x) { if (x < 0) return(-x) else return(x) }

では f のグラフを、と思ったらうまく出ない

> curve(f(x), xlim=c(-2,2))
Warning message:
In if (x < 0) return(-x) else return(x) :
   条件が長さが2以上なので,最初の一つだけが使われます 

なんとなく f の引数にはベクトルが渡されているような気がする

sin は引数にベクトルを渡すと各要素に sin を適用するが、f はそうやると動かない

> sin(c(0,1,2))
[1] 0.0000000 0.8414710 0.9092974
> f(c(0,1,2))
[1] 0 1 2
Warning message:
In if (x < 0) return(-x) else return(x) :
   条件が長さが2以上なので,最初の一つだけが使われます 
#2

gnuplot を長年使っていることもあるのだろうが、比較すると、カッコが必要なのはどうもひっかかる。

入力していて、気分はすでに引数の中身に向いているのに、カッコの入力を強いられる、という感じ。

2009-06-18 (Thu)

#1

ピタゴラスの定理 (三平方の定理) の証明のアニメを描いてみる

pythagorean-theorem.gif

import animation;

void right_triangle_frame(picture pic, real a, real b, real t) {
  real c = hypot(a, b);

  path a_box = shift(0,-a)*scale(a)*unitsquare;
  path b_box = shift(-b,0)*scale(b)*unitsquare;
  path a_box_0 = a_box;
  path b_box_0 = b_box;

  transform c_trans = shift(0,b)*rotate(degrees((a,-b)))*scale(c);
  pair c0 = c_trans*(0,0);
  pair c1 = c_trans*(1,0);
  pair c2 = c_trans*(1,1);
  pair c3 = c_trans*(0,1);
  path c_box_0 = c0--c1--c2--c3--cycle;

  if (0 < t) { real tt = t < 0.2 ? t : 0.2; t -= tt; }

  if (0 < t) {
    real tt = t < 1 ? t : 1; t -= tt;
    b_box = shift(tt*a) * slant(-tt*a/b) * b_box;
  }
  if (0 < t) { real tt = t < 0.2 ? t : 0.2; t -= tt; }
  if (0 < t) {
    real tt = t < 1 ? t : 1; t -= tt;
    b_box = rotate(tt*90, (0,b)) * b_box;
  }
  if (0 < t) { real tt = t < 0.2 ? t : 0.2; t -= tt; }
  if (0 < t) {
    real tt = t < 1 ? t : 1; t -= tt;
    real d = degrees((b,-a));
    b_box = rotate(-d) * shift(tt*b*a/c) * slant(-tt*a/b) * rotate(d) * b_box;
  }
  if (0 < t) { real tt = t < 0.2 ? t : 0.2; t -= tt; }

  if (0 < t) {
    real tt = t < 1 ? t : 1; t -= tt;
    real d = degrees((b,-a));
    a_box = rotate(-90) * shift(-tt*b) * slant(tt*b/a) * rotate(90) * a_box;
  }
  if (0 < t) { real tt = t < 0.2 ? t : 0.2; t -= tt; }
  if (0 < t) {
    real tt = t < 1 ? t : 1; t -= tt;
    a_box = rotate(-tt*90, (a,0)) * a_box;
  }
  if (0 < t) { real tt = t < 0.2 ? t : 0.2; t -= tt; }
  if (0 < t) {
    real tt = t < 1 ? t : 1; t -= tt;
    real d = degrees((b,-a));
    a_box = rotate(-d) * shift(tt*a*b/c) * slant(tt*b/a) * rotate(d) * a_box;
  }

  fill(pic, b_box, lightgreen);
  fill(pic, a_box, lightcyan);

  draw(pic, (0,0)--(a,0)--(0,b)--cycle);
  draw(pic, a_box_0);
  draw(pic, b_box_0);
  draw(pic, c_box_0);

  label("$a$", (a/2,-a), S);
  label("$a$", (a,-a/2), E);

  label("$b$", (-b/2,b), N);
  label("$b$", (-b,b/2), W);

  label("$c$", point(c2--c3, 0.5), NE);
  label("$c$", point(c1--c2, 0.5), SE);

  label("$a^2$", point(min(a_box_0)--max(a_box_0), 0.5));
  label("$b^2$", point(min(b_box_0)--max(b_box_0), 0.5));
  label("$c^2$", point(min(c_box_0)--max(c_box_0), 0.5));

  label("$a^2$", point(min(a_box)--max(a_box), 0.5));
  label("$b^2$", point(min(b_box)--max(b_box), 0.5));

  label("$a^2+b^2=c^2$", (-b/2,1.3a));
}

real a = 4;
real b = 3;

real tmax = 7.6;

if (true) {
  size(10cm);
  animation anim;

  for (real t = 0; t <= tmax; t += 0.1) {
    save();
    picture pic;
    right_triangle_frame(pic, a, b, t);
    add(pic);
    anim.add();
    restore();
  }

  anim.movie();
}
else {
  size(30cm);
  int w = ceil(sqrt(tmax/0.1));
  real t = 0;

  for (int y = 0; y < w; ++y) {
    for (int x = 0; x < w; ++x) {
      picture pic;
      right_triangle_frame(pic, a, b, t);
      add(shift(x*12,-y*12) * pic);
      t += 0.1;
    }
  }
}

2009-06-19 (Fri)

#1

<URL:http://www.zusaku.com/anitry.html> にはいろいろなアニメがある

#2

ふと、BMI のグラフを書きたくなった

GNU R: 
  w <- seq(50, 100, len=50)
  h <- seq(1.5, 2, len=50)
  f <- outer(w, h, function(w, h) w/h^2)
  contour(w, h, f, levels=c(18.5, 25, 30, 40))

bmi-gnu-r.png

gnuplot:
  set contour
  set cntrparam levels discrete 18.5, 25, 30, 40 
  unset surface   
  set view 0,0 
  unset ztics
  splot [50:100] [1.5:2] x/y**2 

bmi-gnuplot.png

asymptote:
  import contour;
  import graph;
  size(10cm,10cm,IgnoreAspect);
  real bmi(real w, real h) { return w/h^2; } 
  real[] c = new real[] { 18.5, 25, 30, 40 };
  Label[] Labels=sequence(new Label(int i) { return Label((string)c[i], (0,0), UnFill(1bp)); },c.length);
  draw(Labels, contour(bmi, (50,1.5), (100,2), c), fontsize(6));
  xaxis(Bottom(), LeftTicks());
  yaxis(Left(), RightTicks());

bmi-asymptote.png

gnuplot で等高線を描くのは簡単でないと前から思っていたが、GNU R より長くなっている。等高線の機能は splot のおまけみたいなかんじなので、余計な部分を削る記述が多い。もし、等高線を描く専用のコマンドが用意されるなら、"set contour", "unset surface", "set view 0,0", "unset ztics" の 4つは指定する必要はなくて、2行で済むだろう。

2009-06-20 (Sat)

#1

そうか、bmi=w/h^2 を h=sqrt(w/bmi) と解いて普通にグラフを描けば、等高線を描く必要はないか。

gnuplot:

bmi-gnuplot-2.png

bmi-gnuplot-2.gp:

set label "under weight" at 54,1.95
set label "normal range" at 72,1.9
set label "over weight" at 86,1.82
set label "obese" at 90,1.65

set xlabel 'weight[kg]'
set ylabel 'height[m]'

f(w,bmi) = sqrt(w/bmi)
plot [50:100] [1.5:2] \
  f(x,18.5) title '', \
  f(x,25) title '', \
  f(x,30) title ''

GNU R:

bmi-gnu_r-2.png

bmi-gnu_r-2.R:

f <- function(w,bmi) { sqrt(w/bmi) }
curve(f(x,18.5),xlim=c(50,100),ylim=c(1.5,2),xlab="",ylab="")
par(new=T)
curve(f(x,25),xlim=c(50,100),ylim=c(1.5,2),xlab="",ylab="")
par(new=T)
curve(f(x,30),xlim=c(50,100),ylim=c(1.5,2),xlab="weight[kg]",ylab="height[m]")
text(60,1.95, "under weight")
text(76,1.9, "normal range")
text(89,1.8, "over weight")
text(95,1.65, "obese")

asymptote:

bmi-asymptote-2.png

bmi-asymptote-2.asy:

import graph;
size(10cm,10cm,IgnoreAspect);
real f(real w, real bmi) { return sqrt(w/bmi); } 
draw(graph(new real(real w) { return f(w, 18.5); }, 50, 100));
draw(graph(new real(real w) { return f(w, 25); }, 50, 100));
draw(graph(new real(real w) { return f(w, 30); }, 50, 100));
clip((50,1.5)--(100,1.5)--(100,2)--(50,2)--cycle);

xaxis("weight[kg]", Bottom(), LeftTicks());
yaxis("height[m]", Left(), RightTicks());
label("under weight", (60, 1.95));
label("normal range", (80, 1.94));
label("over weight", (95, 1.87));
label("obese", (95, 1.7));
#2

とくに意味はないが、とあるロボット の BMI を計算してみよう。

% ruby -e 'p 550.0*1000/57**2'
169.28285626346567

combattler-v-bmi.png

combattler-v-bmi.gp:

set label "under weight" at 10e3,97
set label "obese" at 280e3,90

set xlabel 'weight[kg]'
set ylabel 'height[m]'

f(w,bmi) = sqrt(w/bmi)
plot [0:1000000] [0:100] \
  f(x,18.5) title '', \
  f(x,25) title '', \
  f(x,30) title '', \
  '-' title ''
550000 57
e

gnuplot で、データファイルに '-' を指定するとデータを別ファイルにせずに埋め込むことができる。

ファイル名を示さなくていいので、日記に書くには便利である。

#3

パラメータを与えるとグラフを表示するアプリケーションを考えよう。

具体的には、体重と身長を引数で与えると、BMI のグラフの上に引数で与えた点を表示するとか。

gnuplot, GNU R, asymptote のどれを使うのがいいか考えると、スピードの点で gnuplot が一番よい。

asymptote は latex や gv を起動することもあって当然のように遅い。GNU R もなんか遅い。

というわけで、gnuplot を使うことする。

グラフを表示したらユーザが見終わるまで表示しておかなければならない。これは gnuplot の pause -1 で、改行を入力するまで待てるので、これを使おう。

さて、gnuplot にグラフを表示する指示を送りこまなければならないが、これをどうするか。テンポラリファイルを使えば簡単だが、作らなくていいなら作りたくはない。標準入力からも送りこめるが、それをやると pause -1 が動かない。しばらく考えて、/dev/fd を使うとできることに気がついた。

#!/usr/bin/ruby1.9

w = ARGV[0].to_f
h = ARGV[1].to_f

gp = <<"End"
set label "under weight" at 54,195
set label "normal range" at 72,190
set label "over weight" at 86,182
set label "obese" at 90,165
set xlabel 'weight[kg]'
set ylabel 'height[cm]'
f(w,bmi) = sqrt(w/bmi)*100
plot [50:100] [150:200] \
  f(x,18.5) title '', \
  f(x,25) title '', \
  f(x,30) title '', \
  '-' title ''
#{w} #{h}
e
pause -1
End

IO.pipe {|r, w|
  pid = spawn("gnuplot", "/dev/fd/#{r.fileno}", r=>r)
  w << gp
  w.close
  Process.wait pid
}

なお、spawn を使っているので、Ruby 1.9 でしか動かない。

2009-06-21 (Sun)

#1

ひとはなぜエスケープを忘れるのか。

さて、日記のシステムに、asymptote, gnuplot, GNU R で書くと画像を生成してくれる機構をつけたのだが、そこで、ついエスケープをさぼってしまった。

さぼっていることは書いていてわかってはいたのだが、ついやってしまった。

具体的には、まず gnuplot で、png ファイルを生成するには出力ファイルを set output "..." というように指定する必要がある。ここで、出力ファイル名は変化するので、

f.puts "set output \"#{dst_path}\""

というように書いてしまったのだが、もちろんこれはエスケープをしていなくて間違いである。dst_path に double quote などが入っていると、変なことが起こるかもしれない。

なんでわかっているのにしなかったのかというと、gnuplot の構文での文字列のエスケープ規則を知らなかったからである。そして、それを調べるのが面倒だったからである。正直なところ、ちゃんとドキュメントで定義されているかどうか怪しいとも思ったのである。

また、GNU R でも、

f.puts "png(\"#{dst_path}\")"

というように、出力ファイル名を指定する必要があって、やはりエスケープをしなかった。これも書いていてわかってはいたのだが、GNU R のエスケープ規則を調べるのが面倒だったのである。

あとから調べた結果、エスケープのやりかたは以下に定義されていた。

ただ、gnuplot は backquote が double quote の中でも効くということが明確には書いていない。効かないとも書いてないが。あと、"\0041" が "!" になる。うぅむ。

まぁともかく、どちらも C っぽく \ooo が使えるので、以下のような関数を使ってエスケープするように書き直した。ちなみに、エスケープ関数で double quote をつけるのは、二重エスケープを防ぐ工夫である。エスケープ時に double quote をつけておけば、二重エスケープすると、double quote が文字列の中に出てくるのですぐにわかる。あと、呼出側で double quote をつける必要もなくなってよい。

def dq_oct_escape(string)
  '"' + string.gsub(/[^A-Za-z]/) {|c| sprintf("\\%03o", c.ord) } + '"'
end

... f.puts "set output #{dq_oct_escape dst_path}" ...
... f.puts "png(#{dq_oct_escape dst_path})" ...

なお、aysmptote は出力ファイル名をコマンドラインオプションで指定するので asymptote という言語内でのエスケープは不要である。

で、普通の人がエスケープを忘れる (そして injection 系のセキュリティホールが生まれる) のも、同じような流れでさぼってしまうということなのかもしれない、と思った。

今回はふたつとも定義が見つかったわけだが、最初に探さなかった理由には、ちゃんと定義されているかどうか確信は持てなかったという点もある。(GNU R はまともな言語だからあるだろうと思ったが)

あと、試して確認する方法も知らなかったという点もある。gnuplot では print "..." とすれば試せるが、GNU R では print("...") とするとエスケープした結果が出てくるので確認にならず、cat("...") とする必要がある。cat は知らなかったので、調べる必要があった。

そういうように、普通の人が、SQL や shell についてエスケープの規則が定義されているかどうか知らなければ、やはり探さないかもしれない。また、試す方法を知らなければエスケープをよく理解できないかもしれない。そして、動いてしまって、そのままにしてしまうと、セキュリティホールが残るかもしれない。

#2

Asymptote みたいなものは他にどういうものがあるかと思って、「作図ツール」で検索したら、教育用のが出てくる。

それはそれで興味深いが、探しているのはそういうのじゃないので、さらに探していくと、wikipedia: List of vector graphics markup languages が意図に近いリストのようだ。

2D のやつをひとつひとつ見ていくと、以下が近いかんじである。

どちらもあまりそそられない。

#3

(やはりというかなんというか) gnuplot の文字列リテラルはちょっと注意しないといけないようだ。

まず、double quote の中で、back quote が効く。shell と同じといわれればそうではあるのだが。

gnuplot> print "`expr 1 + 2`" 
3

また、octal で書くと、4桁読むことがある。先頭が 0 だと最大 4桁になるようだ。

gnuplot> print "\0123456"  
S456

なお、hex は使えない。

gnuplot> print "\x21"  
x21

これらを考えて、防衛的プログラミングでいくと、A-Za-z 以外はエスケープするというのが簡単かな。今回は人間が読む所で使うわけじゃないし。

0-9 をそのままにできないのは、"\n0" をエスケープして "\0120" にすると、0 が \012 につながって解釈されて "P" になっちゃうからである。

#4

そういや、GNU Octave があったよな、と思って調べると、グラフを描くには gnuplot を使っているのか。

#5

なんとなく π をモンテカルロで。

数を増やしていくとゆっくりとπに収束していく感じがしないでもない。

pi.png

pi.R:

pi.montecarlo <- function(n) {
  x <- runif(n)
  y <- runif(n)
  z2 <- x * x + y * y
  (sum(z2 < 1) / n)*4
}

x <- seq(100, 10000, by=100)
y <- c()
for (i in x) y <- c(y, pi.montecarlo(i)) 
plot(x,y, xlab="n", ylab="pi")
abline(pi,0)
#6

Low-discrepancy sequence を使って準モンテカルロにすると収束が速くなるというので、試してみる

LDS は Debian package になっているものでは r-cran-foptions が提供しているようで、それの runif.sobol を使った

たしかにこの場合あからさまに収束が良い

pi2.png

pi2.R:

library(fOptions)

pi.montecarlo <- function(n) {
  x <- runif(n)
  y <- runif(n)
  z2 <- x * x + y * y
  4 * sum(z2 < 1) / n
}

pi.quasimontecarlo <- function(n) {
  xy <- runif.sobol(n,2)
  x <- xy[,1]
  y <- xy[,2]
  z2 <- x * x + y * y
  4 * sum(z2 < 1) / n
}

n <- seq(100, 10000, by=100)
pi1 <- c()
pi2 <- c()
for (i in n) {
  pi1 <- c(pi1, pi.montecarlo(i))
  pi2 <- c(pi2, pi.quasimontecarlo(i))
}
plot(n,pi1, ylim=c(3.0,3.3), ylab="pi")
par(new=T)
plot(n,pi2, ylim=c(3.0,3.3), ylab="", pch=2, col="red")
abline(pi,0)

2009-06-22 (Mon)

#1

GNU R は、ベクトル単位で処理をすると、速いという。

まぁプリミティブが大きくなれば、インタプリタオーバーヘッドが相対的に減るから、それはそうだろうなとは思うわけであるが、ちゃんとした説明を探してみる。

そうすると、「Rの基礎とプログラミング技法」という本が見つかった。すばらしいことに「効率的なプログラミング」という章がある。

そして、なんともすばらしいことに、Google ブックスで読める。

<URL:http://books.google.co.jp/books?id=IhpJr05ZuQ8C&lpg=PP10&ots=ydOWWKp6fs&dq=R%20%E7%B5%B1%E8%A8%88%20%E5%8A%B9%E7%8E%87%20%E4%BD%9C%E6%B3%95&as_brr=3&pg=PA101>

が、しかし、ちょうどいいところで切れている。なかなか。

#2

「Rの基礎とプログラミング技法」を買ってきた。

#3

ふむ。GNU R はあたりまえのように日本語が通ってすばらしい。

bmi-fiction.png

bmi-fiction.R:

xlim = c(20,150)
ylim = c(100,200)

f <- function(w,bmi) { 100*sqrt(w/bmi) }
curve(f(x,18.5),xlim=xlim,ylim=ylim,xlab="",ylab="")
par(new=T)
curve(f(x,25),xlim=xlim,ylim=ylim,xlab="",ylab="")
par(new=T)
curve(f(x,30),xlim=xlim,ylim=ylim,xlab="体重[kg]",ylab="身長[cm]")

text(60,195, "低体重")
text(80,195, "通常")
text(105,195, "前肥満")
text(125,195, "肥満")

par(cex=0.7)

text(129.3, 129.3, "ドラえもん")

# ハヤテのごとく!
text(57, 168, "ハヤテ")
text(29, 138, "ナギ")
text(42, 158, "マリア")
text(45, 161, "ヒナギク")
text(80, 181, "クラウス")


# グラップラー刃牙
text(71, 167, "刃牙")
text(110, 178, "愚地独歩")

データは wikipedia からとってきた。身長はともかく、体重まで設定されているキャラクターはそんなに多くない?

2009-06-23 (Tue)

#1

wikipedia には、「ハヤテのごとく!」のキャラクターのデータがたくさん載っていたのでプロットしてみた。

bmi-hayate.png

bmi-hayate.R:

xlim = c(20,85)
ylim = c(120,190)

f <- function(w,bmi) { 100*sqrt(w/bmi) }
curve(f(x,18.5),xlim=xlim,ylim=ylim,xlab="",ylab="")
par(new=T)
curve(f(x,25),xlim=xlim,ylim=ylim,xlab="",ylab="")
par(new=T)
curve(f(x,30),xlim=xlim,ylim=ylim,xlab="体重[kg]",ylab="身長[cm]")

par(cex=1)

text(60,189, "低体重")
text(75,189, "通常")
text(82,175, "前肥満")
text(82,155, "肥満")

par(cex=0.6)

text(25, 125, "大河内タイガ")
text(29, 138, "ナギ")
text(30, 144, "伊澄")
text(31, 142, "咲夜")
text(32, 139, "ワタル")
text(39, 149, "日比野文")
text(40, 150, "橘美琴")
text(40, 152, "紫子")
text(41, 156, "牧村")
text(42, 151, "花菱美希")
text(42, 154, "シャルナ")
text(42, 158, "マリア")
text(43, 160, "愛歌")
text(44, 157, "瀬川泉")
text(45, 158, "千桜")
text(45, 161, "サキ")
text(45, 161, "ヒナギク")
text(47, 162, "西沢歩")
text(48, 167, "朝風理沙")
text(49, 165, "雪路")
text(52, 165, "東宮")
text(53, 163, "ソニア")
text(56, 166, "薫京ノ介")
text(57, 168, "ハヤテ")
text(60, 173, "一条")
text(60, 175, "神父")
text(72, 178, "野々原")
text(80, 181, "クラウス")
text(82, 187, "ヒムロ")

あー、低体重が多いですな。

2009-06-24 (Wed)

#1

cvs.m17n.org を明日置き換える。

14:00 頃の予定。

IP アドレスが変わるので、DNS の変更が行き渡るまではアクセスできないかも。

2009-06-25 (Thu)

#1

Python Issue 5753: CVE-2008-5983 python: untrusted python modules search path に vim を調べてわかったことをコメントしてみた。

#2

cvs.m17n.org の置き換え完了

#3

リポジトリを比較してみるとなんかちゃんとコピーされていないのがある。

うぅむ。rsync を使ったのだが、そういうことってあるのかなぁ。使い方を間違えた?

ともかく、変なところは手動でコピーした。

2009-06-27 (Sat)

#1

GNU R でエラトステネスのふるい。

この前のπもそうなのだが、なるべくベクトルを使っている。今回も、最内ループは自分でループを書かずに済んでいる

> n <- 1000
> p <- rep(TRUE, n)
> p[1] <- FALSE
> 
> for (i in 2:floor(sqrt(n))) {
+   if (p[i])
+     p[seq(2*i, n, i)] <- FALSE
+ }
> 
> print(which(p))
  [1]   2   3   5   7  11  13  17  19  23  29  31  37  41  43  47  53  59  61
 [19]  67  71  73  79  83  89  97 101 103 107 109 113 127 131 137 139 149 151
 [37] 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251
 [55] 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359
 [73] 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463
 [91] 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593
[109] 599 601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701
[127] 709 719 727 733 739 743 751 757 761 769 773 787 797 809 811 821 823 827
[145] 829 839 853 857 859 863 877 881 883 887 907 911 919 929 937 941 947 953
[163] 967 971 977 983 991 997

ついでに、どんな感じでフラグを変えていくかを図示してみる。

赤のがフラグが偽になったところ (素数でないことが判明したところ) で、黒のはすでに偽だったところをあらためて偽にしたところである

prime.png

prime.R:

n <- 200
p <- rep(TRUE, n)
p[1] <- FALSE

nn = floor(sqrt(n))

x.f <- c()
y.f <- c()
x.t <- c()
y.t <- c()

for (i in 2:nn) {
  if (p[i]) {
    is <- seq(2*i, n, i)
    ts <- is[p[is]]
    fs <- is[!p[is]]
    p[is] <- FALSE
    x.f <- c(x.f, rep(i, length(fs)))
    y.f <- c(y.f, fs)
    x.t <- c(x.t, rep(i, length(ts)))
    y.t <- c(y.t, ts)
  }
}

plot(x.f,y.f, xlim=c(0,nn), ylim=c(0,n), xlab="", ylab="")
par(new=T)
plot(x.t,y.t, xlim=c(0,nn), ylim=c(0,n), xlab="", ylab="", col="red")
#2

Rabin-Karp な文字列検索アルゴリズムを GNU R で。文字単位のループはすべてベクトルでやる。

といっても、rolling hash は文字列の各文字の和である。もっとまともな hash にするにはちょっと頭をひねらないといけないようだ。感触としてはできなくはないが、ループで素直に書くのに比べると、かなり厄介そう。

> str <- c(8, 9, 5, 3, 6, 9, 4, 6, 5, 7)
> pat <-          c(3, 6, 9)
> 
> n <- length(pat)
> 
> rollhash <- function(s) {
+   cs = cumsum(s)
+   cs[n:length(s)] - c(0,cs[seq_len(length(s)-n)])
+ }
> 
> h <- rollhash(pat)
> pos <- which(rollhash(str) == h)
> pos <- pos[sapply(pos, function(i) identical(str[i:(i+n-1)], pat))]
> print(pos)
[1] 4

2009-06-30 (Tue)

#1

net/http の速度ネタが ruby-core に出ていたので、思い立って測ってみる。

net-http-speed.png

net-http-speed.gp:

set logscale xyz

set xlabel 'bufsize[kb]'
set ylabel 'filesize[kb]'
set zlabel 'transfer speed[kb/sec]'

set view 115, 156

splot \
  "-" title 'nonblock' with linespoints, \
  "-" title 'timeout' with linespoints
1 1 16.917199107313238 0.05911144
1 2 37.78381311219223 0.05293272
1 4 35.517603496587306 0.112620211
1 8 52.507058113610825 0.152360469
1 16 90.41921143766858 0.176953545
1 32 91.72871538569268 0.348854771
1 64 90.49225095201312 0.707242878
1 128 91.0966878452754 1.405100482
1 256 91.04336098539279 2.811846984
1 512 90.69648858096649 5.645202014
1 1024 91.01318641689463 11.251116902

4 1 238.93892004386916 0.00418517
4 2 315.6564161980353 0.006336003
4 4 252.3426864150053 0.01585146
4 8 376.14082336285884 0.02126863
4 16 335.54030072841397 0.047684287
4 32 365.882620990551 0.08745974300000001
4 64 361.4354762338216 0.177071716
4 128 362.3587576873101 0.353241083
4 256 363.18756389033183 0.70486995
4 512 362.40318230877676 1.412791126
4 1024 363.5486107994212 2.816679722
4 2048 361.4194560945875 5.666546074
4 4096 363.3411363828818 11.27315239

16 1 12.426210830175885 0.080475055
16 2 710.4384364244628 0.002815163
16 4 496.8311488288758 0.008051025
16 8 1083.6839728287916 0.007382226
16 16 1237.098320940572 0.012933491
16 32 1101.9385061150526 0.029039733
16 64 1128.5817923783345 0.05670834
16 128 1149.829183442607 0.111320883
16 256 1103.3342947713672 0.232023967
16 512 1161.466345908075 0.440822071
16 1024 1118.8249954799853 0.915245909
16 2048 1047.824355655007 1.954526051
16 4096 1176.004659553259 3.482979397
16 8192 1137.4884616951429 7.201831294
16 16384 990.8688276956257 16.534983786

64 1 614.3030639593921 0.001627861
64 2 1350.5164037098687 0.001480915
64 4 620.4791308824717 0.006446631
64 8 2931.34890783436 0.002729119
64 16 3946.031118894657 0.004054707
64 32 4489.335933220005 0.007128003
64 64 3935.6595910271635 0.016261569
64 128 4277.793492727484 0.029921968
64 256 4301.690239957187 0.059511491
64 512 4146.271250166539 0.123484444
64 1024 4434.0032712465345 0.230942545
64 2048 4523.664620443963 0.452730291
64 4096 4505.1886915901 0.909173906
64 8192 4492.224518966448 1.823595407
64 16384 4481.079551403229 3.656261803
64 32768 4505.464535324183 7.27294594
64 65536 4480.903998883284 14.625620191

256 1 653.2011428407195 0.001530922
256 2 316.66172674372945 0.006315888
256 4 2600.94089036709 0.001537905
256 8 5373.682524179892 0.001488737
256 16 6024.266498489227 0.002655925
256 32 11050.109137093525 0.002895899
256 64 11802.719752349432 0.005422479
256 128 16016.975992429978 0.007991521
256 256 12267.903015709337 0.020867462
256 512 17575.05320057852 0.029132202
256 1024 15123.627159759928 0.06770862499999999
256 2048 15535.003719943115 0.131831317
256 4096 16133.333557057294 0.253884294
256 8192 15550.524717832386 0.526798944
256 16384 15976.82036406538 1.025485649
256 32768 15893.733519849167 2.061693054
256 65536 15918.22044945737 4.117043121
256 131072 15277.719149034518 8.579291104999999

1024 1 9.383577674971093 0.106569161
1024 2 1150.9791091536792 0.001737651
1024 4 564.4855603182457 0.007086098
1024 8 4336.212578485448 0.001844928
1024 16 9412.113507735874 0.001699937
1024 32 14672.141820922841 0.002181004
1024 64 25412.18363320372 0.002518477
1024 128 35031.85846472333 0.003653817
1024 256 44187.63450474292 0.005793476
1024 512 41551.83103986704 0.01232196
1024 1024 35510.729424714045 0.028836355
1024 2048 43494.98793534411 0.047085885
1024 4096 47796.49019963658 0.085696669
1024 8192 44906.07878820859 0.182425191
1024 16384 44445.05414127277 0.368634943
1024 32768 45064.217713586295 0.727140105
1024 65536 47112.70435480578 1.391047296
1024 131072 47013.74004530361 2.787950924

4096 1 644.4980810069638 0.001551595
4096 2 1694.4600475973828 0.001180317
4096 4 1820.2618810768306 0.002197486
4096 8 6137.237844049718 0.001303518
4096 16 12907.983022775328 0.001239543
4096 32 21918.363684559128 0.001459963
4096 64 39020.74989345506 0.001640153
4096 128 46596.32078363362 0.002746998
4096 256 75933.31986703364 0.003371379
4096 512 80294.69407329494 0.006376511
4096 1024 83375.86262263336 0.012281732
4096 2048 86641.44588327908 0.023637648
4096 4096 91041.14461834701 0.044990647
4096 8192 89599.61528165189 0.091428964
4096 16384 91216.72922831144 0.179616175
4096 32768 92566.47477993513 0.353994252
4096 65536 82946.74739586437 0.790097286
4096 131072 81335.24892059014 1.611503029

16384 1 478.0375221211864 0.002091886
16384 2 1262.6262626262628 0.001584
16384 4 2773.228912020699 0.001442362
16384 8 5481.689785693337 0.001459404
16384 16 9694.090845748839 0.00165049
16384 32 18007.452834541895 0.001777042
16384 64 31520.463429613574 0.002030427
16384 128 54688.67829000466 0.002340521
16384 256 32173.41470526136 0.00795688
16384 512 95127.50243857123 0.00538225
16384 1024 108438.94305070516 0.009443102
16384 2048 91340.61123549282 0.022421571
16384 4096 34449.18035635407 0.118899781
16384 8192 95206.57333517006 0.08604447899999999
16384 16384 95019.46463641898 0.172427829
16384 32768 96131.52661021311 0.340866323
16384 65536 109206.55136593782 0.600110517
16384 131072 109101.95049960302 1.201371739

e
1 1 8.053655903943467 0.124167212
1 2 12.163673219123902 0.164424016
1 4 5.781612935557612 0.691848459
1 8 9.143440995975736 0.874944127
1 16 7.924418426461169 2.019075614
1 32 8.62306705241375 3.710976594
1 64 8.658171693302558 7.391860807
1 128 8.748393468005155 14.631257781

4 1 41.88854680839852 0.023872874
4 2 48.05015013389534 0.041623179
4 4 50.36078656347019 0.07942687700000001
4 8 28.36914300514062 0.281996534
4 16 37.107683624351615 0.431177547
4 32 32.35203134992718 0.989118725
4 64 34.537659393767 1.853049718
4 128 36.01945568837091 3.553635044
4 256 33.7205301595125 7.591814209
4 512 33.73786885546867 15.175825189

16 1 134.5238152891159 0.007433628
16 2 172.84133701070562 0.011571306
16 4 190.62435098365503 0.020983678
16 8 197.4267252560088 0.040521363
16 16 78.89552030939825 0.202799854
16 32 209.35913722209776 0.152847401
16 64 116.18972506194196 0.550823233
16 128 132.2768559969764 0.96766739
16 256 120.5057108581351 2.124380647
16 512 138.8130739580862 3.688413385
16 1024 131.1271443141716 7.809214525
16 2048 135.67376214626253 15.095033613

64 1 327.49711638789023 0.003053462
64 2 503.27518911194323 0.003973969
64 4 561.0789885597396 0.007129121
64 8 725.6507000533716 0.011024588
64 16 786.5400966343163 0.020342256
64 32 818.0061978284594 0.039119508
64 64 821.7178064669422 0.077885619
64 128 472.25336593790246 0.271040948
64 256 590.8826479663572 0.433250157
64 512 517.7977592449622 0.988803043
64 1024 550.1050031458566 1.861462801
64 2048 532.9332861293921 3.842882502
64 4096 527.2432099683771 7.768710763
64 8192 538.2131642602606 15.220735099

256 1 502.3921401754454 0.001990477
256 2 907.2471354805756 0.002204471
256 4 1624.1128790933228 0.002462883
256 8 2222.1117338887875 0.003600179
256 16 2616.625449364536 0.006114746
256 32 2814.1761661968017 0.011371001
256 64 3097.24487485824 0.020663526
256 128 475.8084310503214 0.26901583
256 256 3257.2192447506095 0.078594648
256 512 1802.1069283876882 0.284111887
256 1024 2339.2412744941234 0.437748774
256 2048 1775.6685271054475 1.153368418
256 4096 2180.5115838128745 1.878458262
256 8192 2102.4064018948366 3.896487374
256 16384 2145.351507277596 7.636976945
256 32768 2122.138389882138 15.441028802

1024 1 574.1971862041087 0.001741562
1024 2 1440.4603711346144 0.001388445
1024 4 2797.0639220010753 0.001430071
1024 8 4541.84687390357 0.001761398
1024 16 6834.44955556856 0.002341081
1024 32 8836.334787738811 0.003621411
1024 64 10332.905217390602 0.006193805
1024 128 11140.653183459053 0.011489452
1024 256 11388.628863358786 0.022478562
1024 512 3352.2276318650133 0.152734258
1024 1024 12119.002927970043 0.0844954
1024 2048 8638.192969664087 0.237086623
1024 4096 7454.607885231973 0.549458813
1024 8192 8098.755160630692 1.011513478
1024 16384 8088.486941289888 2.02559516
1024 32768 8080.861025369842 4.055013432
1024 65536 7716.577014834922 8.492884846999999
1024 131072 7625.77121168297 17.188032051

4096 1 566.6525003541578 0.00176475
4096 2 1425.545199761649 0.001402972
4096 4 2876.290735467541 0.00139068
4096 8 4709.927349370636 0.00169854
4096 16 9577.37441069218 0.001670604
4096 32 15704.057044987216 0.00203769
4096 64 21762.21582881569 0.002940877
4096 128 26279.41215418706 0.004870733
4096 256 33431.71748004773 0.007657399
4096 512 35709.652625984636 0.01433786
4096 1024 14186.727031190185 0.072180144
4096 2048 25674.4617157295 0.079767982
4096 4096 25810.550533875736 0.158694794
4096 8192 25762.65834002789 0.317979608
4096 16384 25752.884048335894 0.636200589
4096 32768 25351.517046253528 1.292545923
4096 65536 26293.71724882327 2.492458536
4096 131072 26095.359384726216 5.022808771

16384 1 643.8026590337423 0.001553271
16384 2 1465.5246321716363 0.001364699
16384 4 3415.595094863884 0.001171099
16384 8 6349.523825397619 0.001259937
16384 16 11090.762642429652 0.001442642
16384 32 19430.952414204756 0.001646857
16384 64 32508.97679519395 0.001968687
16384 128 5233.430631531158 0.024458144
16384 256 61546.332367504685 0.004159468
16384 512 79222.19892663205 0.006462835
16384 1024 78494.40374761719 0.013045516
16384 2048 60786.44481276439 0.033691722
16384 4096 62135.80073546276 0.06592012899999999
16384 8192 63467.20225795729 0.129074541
16384 16384 62662.137420040846 0.261465706
16384 32768 62597.09421950412 0.523474778
16384 65536 58136.53398182915 1.127277385
16384 131072 58211.788338098624 2.251640153

e

まず以下のようにしてデータを作る。

% cd /var/www/tmp
% ruby -e '
s = 1
18.times {
  open("#{s}k", "w") {|f|
    f.seek s*1024-1
    f.write "a"
  }
  s *= 2
}
'

で、測る。

% cat net-http-speed-test
require "net/http"

def test(b)
  s = 1
  18.times {
    t1 = Time.now
    Net::HTTP.start("127.0.0.1", 80) {|http|
      http.request_get("/tmp/#{s}k") {|res|
        res.read_body {|seg|}
      }
    }
    t2 = Time.now
    t = t2-t1
    puts "#{b} #{s} #{s/t} #{t}"
    s *= 2
    break if t > 10
  } 
end 

bufsizes = [1,4,16,64,256,1024,4096,16384]

bufsizes.each {|b|
  class Net::BufferedIO; remove_const(:BUFSIZE) end
  Net::BufferedIO.const_set(:BUFSIZE, b)
  test(b); puts
}
puts "e"

class Net::BufferedIO; def rbuf_fill; timeout(@read_timeout) { @rbuf << @io.sysread(BUFSIZE) } end end
bufsizes.each {|b|
  class Net::BufferedIO; remove_const(:BUFSIZE) end
  Net::BufferedIO.const_set(:BUFSIZE, b)
  test(b); puts
}
puts "e"
% ruby net-http-speed-test

理屈としては、

なのだが、localhost 相手で通信速度が速いせいだろうが、その限界まではまだけっこうありそうな感じ

#2

「Rの基礎とプログラミング技法」を拾い読みしているのだが、とりあえず、スコープの説明が変だと思う。p.80 あたりから。実際の挙動はレキシカルスコープなのに、説明はダイナミックスコープくさい。

それはそれとして、言語仕様ですばらしいと思ったのは、ベクトルのように大きな構造が、immutable であるらしい、ということである。(あまり明瞭な説明は見つけられていないのだが、おそらくそうなのだと思う)

いや、vec[i] <- x というようないかにも書き換えっぽい構文はあるのだが、これは vec <- "[<-"(vec, i, x) という、"[<-" という変な名前の関数を呼び出した結果を代入しなおすという意味で、元の vec は変化しないのだ。(概念的には)

> a <- c(1,2,3)
> a
[1] 1 2 3
> b <- a
> b
[1] 1 2 3
> a[2] <- 1000
> a
[1]    1 1000    3
> b
[1] 1 2 3
> 

では、すべてが immutable かというとそういうわけではなく、少なくとも変数は書き換えられる。

クロージャでカウンタを作るという例の奴は以下のように実装できる。(n <- n+1 はうまくいかず assign を使う必要がある。どうやら <- を使うと、外側の変数を書き換えるのでなく、新しい変数が内側にできるようだ)

> mkcounter <- function() {
+   n <- 0
+   c <- function() {
+     assign("n", n+1, environment(c))
+     n
+   }
+ }
> a <- mkcounter()
> a()
[1] 1
> a()
[1] 2
> a()
[1] 3
> b <- mkcounter()
> b()
[1] 1
> a()
[1] 4
> b()
[1] 2
> a()
[1] 5
> b()
[1] 3

これを使うと、呼び出された側で引数を書き換えられることも確認できる。

> f <- function(g) { g() }
> f(a)
[1] 6
> f(a)
[1] 7
> f(a)
[1] 8
> a()
[1] 9

[latest]


田中哲