Googleクラスルーム
GeoGebraGeoGebra Classroom

zipで関数とグラフ

1.関数に式は必要か?

このワークシートはMath by Codeの一部です。 関数は集合Xの要素xから集合Yの要素yへの対応づけだ。 対応がつけばよいだけなのに、対応を式に表すことができると考えてしまいがちだ。 f :: X→Y f (x) = expr(x) 中学数学で学んだ1次関数、2次関数のイメージが強いためか、 関数というと、y=xの式という、計算操作のイメージがつきまつ。 しかし、結果としてのグラフイメージで関数を俯瞰してみよう。 すると、関数はXとYの直積空間(X-Y座標平面)の要素の点(x,y)のあつまり、部分集合という風にとらえることもできる。 y=2xという関数は、この関数を満たす点と考えると、順序対、タプル(x,y)のリスト と考えることもできるね。 連続量に近いイメージがほしければ、xの範囲を細かく区切ると良い。 #[IN]julia #============================ F=[(x,2*x) for x in 1:10] G=[(x,2*x) for x in 1:0.001:10] #============================ [OUT] 10-element Vector{Tuple{Int64, Int64}}: (1, 2) (2, 4) (3, 6) (4, 8) (5, 10) (6, 12) (7, 14) (8, 16) (9, 18) (10, 20) [OUT] 91-element Vector{Tuple{Float64, Float64}}: (1.0, 2.0) (1.1, 2.2) (1.2, 2.4) (1.3, 2.6) (1.4, 2.8) (1.5, 3.0) (1.6, 3.2) (1.7, 3.4) (1.8, 3.6) (1.9, 3.8) (2.0, 4.0) (2.1, 4.2) (2.2, 4.4) ⋮ (8.9, 17.8) (9.0, 18.0) (9.1, 18.2) (9.2, 18.4) (9.3, 18.6) (9.4, 18.8) (9.5, 19.0) (9.6, 19.2) (9.7, 19.4) (9.8, 19.6) (9.9, 19.8) (10.0, 20.0) すると、1対1にこだわらなければ、xの剰余を対応させたり、 xの値と無関係に乱数を作ってzipで順序対(タプル)を作ったりと 関数は自由だ。 zipを使うと、関数も作れるし、グラフもすぐかけるね。 #[IN]julia #============================ H=[(x,x % 3) for x in 1:10] #============================ [OUT] 10-element Vector{Tuple{Int64, Int64}}: (1, 1) (2, 2) (3, 0) (4, 1) (5, 2) (6, 0) (7, 1) (8, 2) (9, 0) (10, 1) #[IN]julia #============================ xs=Vector(1:10) ys=rand(10) z=[(x,y) for (x,y) in zip(xs,ys)] #============================ [OUT] 10-element Vector{Tuple{Int64, Float64}}: (1, 0.20169081026514768) (2, 0.17422295843712776) (3, 0.25178803264424066) (4, 0.5264239612886585) (5, 0.4820281573212978) (6, 0.23582173409057716) (7, 0.06452661349364275) (8, 0.6707651637338825) (9, 0.3189198173371426) (10, 0.4016041332227487)

関数と順序対

mod関数 の視覚化

2.暗号解読は逆関数?

<シーザー暗号とは> シーザー暗号[Cipher]というものがある。 これって、ルールは単純で、 文字xに対して、文字コードy=f(x)を対応させる。 f(x)は数値だから、それに定数sを足す。 そして、文字コードsに対する文字をf-1(x)で求めたものをzとしよう。 これが暗号化関数Cだ。 これを、入力した文字列Xの文字xすべて対してzを求めて出力したものが文字列Zとなる。 つまり、暗号化はC :: X→Zとかけるね。 とうことは暗号解読はその逆関数C-1 ::Z→Xとかくことができるはずだ。 <暗号化と復号化を比べると> それでは、暗号を作る関数Cと暗号を解読(復号)する逆関数C-1を作ってみようか?。 しかし、この発想には無駄がある。 暗号化のときに、文字コードを+sしているとしたら、 復号化のときは、文字コードをーsすればよいだけだ。 だったら、暗号と復号の両方に使える関数Ciを作った方がよいことがわかるね。 シフト数をshift 、入力文字をxとすると コード化::Char→Int   x -> y = codepoint(x) シフト:: Int →Int y -> z = y + shift デコード化:: Int→Char z -> d=Char(z) この3ステップを合成した関数がCiになるね。 <実装しよう> #julia #============================ Int(codepoint('A')) #============================ [OUT] 65 #============================ Char(65) #============================ [OUT] 'A': このように、コード化とデコード化はできることがわかる。 英数字、つまり、アスキー文字に限った暗号だとすると、 コード番号にshiftを加算してずらそう。 ただ、たすのではなく、Aが0番になるようにして、 からshiftをたして、それでも65を超えた番号は 振り出しのAから順にぐるぐる回るようにしたい。 #julia #============================ Ci(shift::Int, x::Char)::Char = Char((Int(codepoint(x)) - 65 + shift) % 65 + 65) Ci(0,'A'),Ci(1,'A'),Ci(2,'A'),Ci(3,'A') #============================ [OUT] ('A', 'B', 'C', 'D') では、もっと先の文字も含めて、暗号と復号がうまくいくことを確認しよう。 #julia #============================ Target = "ABCDE PQRSTU abcde,.xyz"; println(Target) Ciphered=join([Ci(5,x) for x in Target] ) println(Ciphered) Recovered=join([Ci(-5,x) for x in Ciphered] ) println(Recovered) #============================ [OUT] ABCDE PQRSTU abcde,.xyz FGHIJ%UVWXYZ%fghij13}~ ABCDE PQRSTU abcde,.xyz #julia #============================ Target = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG"; println(Target) Ciphered=join([Ci(5,x) for x in Target] ) println(Ciphered) Recovered=join([Ci(-5,x) for x in Ciphered] ) println(Recovered) #============================ [OUT] THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG YMJ%VZNHP%GWT\S%KT]%OZRUX%T[JW%YMJ%QF_^%ITL THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG