良い名前は語順の話も含むことにして、in? の話はそっちに入れるほうが適切か。
「多角形の車輪に深い意味があるかもしれない、中国の自転車 : 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); }
本当は、ちゃんと回転に応じて進むようにしたかったのだが、計算が面倒だったのでそれはさぼっている。
回転に応じて進むようにするにはこんなかんじか。
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); }
そーか。頂点が地面に接して (刺さって) いるときの重心の移動は、頂点を中心とする弧になるのだな。
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 でちょっと古いようだ。最新版でも問題があるかは分からない
ふと、ルーローの三角形とペンローズの三角形を組み合わせてみた
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));
角の形はちょっとナニ
輪郭線がなければこれで済むか。
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)));
ぐるぐる
spiral.asy:
size(10cm); import graph; draw(polargraph(identity, 0, 20)); xaxis(Bottom(), LeftTicks()); yaxis(Left(), RightTicks());
ルーローの三角形を回したときの動作を図示するとき、どういう間隔で状態を描いたらいいか。
たとえば、接地している位置が一定間隔になるように描くのは望ましくない。角が地面に刺さっているときは接地している位置がしばらく変わらないので、その間の状態変化を図示できない。
ましな方法はいくつか考えられるが、重心の横方向の移動が一定間隔になるように描くことを考えた。
が、これをやるにはどうも x + r/sqrt(3) * sin(pi/6-x/r) = y を x について解く必要があって、解けなくて困った。(ちなみに Wolfram Alpha でも解けなかった)
結局、Asymptote には Newton 法の実装が入っているので、それを使ってなんとか描けた。
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);
asymptote-1.76 を入れたら、アニメーションの問題は直っていた。
buildcycle というのを見つけて、使ってみると輪郭線をつけてもこれで描けた。
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));
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.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);
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
こだわりが感じられる。
buildcycle は Asy - Contours Domaines のページが詳しいような気がする
そういう気がするのだが、フランス語なのがきつい
半透明で、上が円、下が六角形円な柱
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));
ブリリアントカットな赤いやつを作ってみた (Culet は作らなかったので、57面である)
なお、視点を設定する方法はよくわかっていないので、
% asy -f pdf -V brilliant.asy
で起動した acroread で対話的に動かして、スクリーンショットをとって画像を得た。
以下を参考にした
なお、ブリリアントカットをちゃんと理解した結果、Ruby のロゴのやつはブリリアントカットではないということがわかった。Star Facet と Pavilion Facet がなくなっている
... 検索したら [ruby-talk:142211] を見つけた。simplified というのはわかった上でそうやっているようだ。
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);
大阪中之島の三井ビルのやつは、Table が 8角でなく 6角なのをはじめとして、さらに (ロゴ以上に) 簡略化されているようだ
画像検索すると、Ruby Quiz のロゴは上部はちゃんとブリリアントカットになっている気がする。下部は簡略化されているが。
ブリリアントカットの形を決定するパラメータは、ダイヤモンドの鑑定書で定義されているようだ
というか、鑑定書には形を測定した結果が数値で書いてあるので、その数値から形を作ることができる (完全に軸対称になっているとか、数値に現れない部分がすべて理想的と仮定すれば)
鑑定書にも発行元によっていろいろ種類があってどんなパラメータが書いてあるかは微妙に異なるようだが、 GIA の形式でパラメータを指定するようにしてみた
まぁ、length という名前のくせに百分率なのは気にいらないが。
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));
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以上なので,最初の一つだけが使われます
gnuplot を長年使っていることもあるのだろうが、比較すると、カッコが必要なのはどうもひっかかる。
入力していて、気分はすでに引数の中身に向いているのに、カッコの入力を強いられる、という感じ。
ピタゴラスの定理 (三平方の定理) の証明のアニメを描いてみる
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; } } }
<URL:http://www.zusaku.com/anitry.html> にはいろいろなアニメがある
ふと、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))
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
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());
gnuplot で等高線を描くのは簡単でないと前から思っていたが、GNU R より長くなっている。等高線の機能は splot のおまけみたいなかんじなので、余計な部分を削る記述が多い。もし、等高線を描く専用のコマンドが用意されるなら、"set contour", "unset surface", "set view 0,0", "unset ztics" の 4つは指定する必要はなくて、2行で済むだろう。
そうか、bmi=w/h^2 を h=sqrt(w/bmi) と解いて普通にグラフを描けば、等高線を描く必要はないか。
gnuplot:
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.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.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));
とくに意味はないが、とあるロボット の BMI を計算してみよう。
% ruby -e 'p 550.0*1000/57**2' 169.28285626346567
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 で、データファイルに '-' を指定するとデータを別ファイルにせずに埋め込むことができる。
ファイル名を示さなくていいので、日記に書くには便利である。
パラメータを与えるとグラフを表示するアプリケーションを考えよう。
具体的には、体重と身長を引数で与えると、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 でしか動かない。
ひとはなぜエスケープを忘れるのか。
さて、日記のシステムに、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 についてエスケープの規則が定義されているかどうか知らなければ、やはり探さないかもしれない。また、試す方法を知らなければエスケープをよく理解できないかもしれない。そして、動いてしまって、そのままにしてしまうと、セキュリティホールが残るかもしれない。
Asymptote みたいなものは他にどういうものがあるかと思って、「作図ツール」で検索したら、教育用のが出てくる。
それはそれで興味深いが、探しているのはそういうのじゃないので、さらに探していくと、wikipedia: List of vector graphics markup languages が意図に近いリストのようだ。
2D のやつをひとつひとつ見ていくと、以下が近いかんじである。
どちらもあまりそそられない。
(やはりというかなんというか) 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" になっちゃうからである。
そういや、GNU Octave があったよな、と思って調べると、グラフを描くには gnuplot を使っているのか。
なんとなく π をモンテカルロで。
数を増やしていくとゆっくりとπに収束していく感じがしないでもない。
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)
Low-discrepancy sequence を使って準モンテカルロにすると収束が速くなるというので、試してみる
LDS は Debian package になっているものでは r-cran-foptions が提供しているようで、それの runif.sobol を使った
たしかにこの場合あからさまに収束が良い
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)
GNU R は、ベクトル単位で処理をすると、速いという。
まぁプリミティブが大きくなれば、インタプリタオーバーヘッドが相対的に減るから、それはそうだろうなとは思うわけであるが、ちゃんとした説明を探してみる。
そうすると、「Rの基礎とプログラミング技法」という本が見つかった。すばらしいことに「効率的なプログラミング」という章がある。
そして、なんともすばらしいことに、Google ブックスで読める。
が、しかし、ちょうどいいところで切れている。なかなか。
「Rの基礎とプログラミング技法」を買ってきた。
ふむ。GNU R はあたりまえのように日本語が通ってすばらしい。
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 からとってきた。身長はともかく、体重まで設定されているキャラクターはそんなに多くない?
wikipedia には、「ハヤテのごとく!」のキャラクターのデータがたくさん載っていたのでプロットしてみた。
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, "ヒムロ")
あー、低体重が多いですな。
cvs.m17n.org を明日置き換える。
14:00 頃の予定。
IP アドレスが変わるので、DNS の変更が行き渡るまではアクセスできないかも。
Python Issue 5753: CVE-2008-5983 python: untrusted python modules search path に vim を調べてわかったことをコメントしてみた。
cvs.m17n.org の置き換え完了
リポジトリを比較してみるとなんかちゃんとコピーされていないのがある。
うぅむ。rsync を使ったのだが、そういうことってあるのかなぁ。使い方を間違えた?
ともかく、変なところは手動でコピーした。
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.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")
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
net/http の速度ネタが ruby-core に出ていたので、思い立って測ってみる。
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 相手で通信速度が速いせいだろうが、その限界まではまだけっこうありそうな感じ
「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]