tag:crieit.net,2005:https://crieit.net/tags/%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0/feed
「アルゴリズム」の記事 - Crieit
Crieitでタグ「アルゴリズム」に投稿された最近の記事
2021-07-14T15:39:56+09:00
https://crieit.net/tags/%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0/feed
tag:crieit.net,2005:PublicArticle/17515
2021-07-14T15:39:56+09:00
2021-07-14T15:39:56+09:00
https://crieit.net/posts/LAN-WPA-WPA2-WPA3
【ネットワーク】無線LANの認証機能(WPA・WPA2・WPA3)と暗号化アルゴリズム
<p>ワイヤレスでの認証規格に、WPA、WPA2、 WPA3がある</p>
<p>この記事書くのにヤクの毛大量に刈ってきましたが、まだ間違っているかもなので間違いみっけたらコメントくれると助かります</p>
<h1 id="それぞれの規格一覧"><a href="#%E3%81%9D%E3%82%8C%E3%81%9E%E3%82%8C%E3%81%AE%E8%A6%8F%E6%A0%BC%E4%B8%80%E8%A6%A7">それぞれの規格一覧</a></h1>
<p><a href="https://crieit.now.sh/upload_images/8433f144cd60ab84b23d7834aaa6f25960e95d8c41ab8.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/8433f144cd60ab84b23d7834aaa6f25960e95d8c41ab8.png?mw=700" alt="image" /></a></p>
<h2 id="暗号化方式とは"><a href="#%E6%9A%97%E5%8F%B7%E5%8C%96%E6%96%B9%E5%BC%8F%E3%81%A8%E3%81%AF">暗号化方式とは</a></h2>
<h5 id="TKIP"><a href="#TKIP">TKIP</a></h5>
<p>RC4で暗号化し、Michaelで安全性を検証している</p>
<h5 id="CCMP"><a href="#CCMP">CCMP</a></h5>
<p>AESアルゴリズムをもとに暗号化をする方式</p>
<h5 id="GCMP"><a href="#GCMP">GCMP</a></h5>
<p>WPA3用。新種すぎてなかなか情報が得られず。(2017年にWPA2に脆弱性が見つかったらしいよ)</p>
<h2 id="暗号化アルゴリズム(めちゃ数学です)"><a href="#%E6%9A%97%E5%8F%B7%E5%8C%96%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%EF%BC%88%E3%82%81%E3%81%A1%E3%82%83%E6%95%B0%E5%AD%A6%E3%81%A7%E3%81%99%EF%BC%89">暗号化アルゴリズム(めちゃ数学です)</a></h2>
<h5 id="RC4"><a href="#RC4">RC4</a></h5>
<p>共通鍵暗号方式で、WEPやWPA、SSL/TLSなどに使われている</p>
<p>データを1ビットずつ暗号化していく<strong>ストリーム暗号</strong>で、<br />
疑似乱数を生成して、平文との排他的論理和を計算し、それを暗号文としている。</p>
<p>暗号化した時と同じ疑似乱数を使ってもう一度排他的論理和を計算すると、平文に戻るという仕組みです。<br />
擬似乱数を共通鍵として持っておけば、複合化できます。</p>
<p>排他的論理和を2回繰り返すと元に戻るという数学チックなやり方を使っていますね</p>
<h5 id="AES"><a href="#AES">AES</a></h5>
<p>無線LANやファイルの暗号化で使われている。</p>
<p><strong>Advanced Encryption Standard</strong>の略<br />
RC4とは対照的に、一定量のデータをまとめて暗号化する<strong>ブロック暗号</strong>を利用しています。<br />
AESで使う4 種類の変換は、「SubBytes」「ShiftRows」「MixColumns」「AddRoundKey」<br />
これを基本的にこの順番で、何回か繰り返して作られています。</p>
<h6 id="SubBytes"><a href="#SubBytes">SubBytes</a></h6>
<ol>
<li><p>8ビットの情報をガロア体GF(28)の逆数に変換<br />
最初の4ビットがX, 後半4ビットがYになります。<br />
<a href="https://crieit.now.sh/upload_images/fef47aea7e6009d8c040e4b1a1a121e460eada947f9c1.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/fef47aea7e6009d8c040e4b1a1a121e460eada947f9c1.png?mw=700" alt="スクリーンショット 2021-07-11 20.48.28.png" /></a><br />
GF(28)の逆数変換テーブル</p></li>
<li><p>その結果をもとに、行列変換をします。</p></li>
</ol>
<p><a href="https://crieit.now.sh/upload_images/dc0b31bc7bf1241dd6b3cc7e671dda9b60eadc34a6a16.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/dc0b31bc7bf1241dd6b3cc7e671dda9b60eadc34a6a16.png?mw=700" alt="スクリーンショット 2021-07-11 20.55.28.png" /></a></p>
<p>a0からa7までに、逆数変換した後の値を入れて、行列変換します。</p>
<h6 id="ShiftRows"><a href="#ShiftRows">ShiftRows</a></h6>
<p>その名の通り、列を並べ替えていきます。</p>
<p>4×4の行列を、行ごとで一つずつシフト</p>
<p><a href="https://crieit.now.sh/upload_images/2da2a1210ecce69718ddeb021008d2e260eae10711b1d.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/2da2a1210ecce69718ddeb021008d2e260eae10711b1d.png?mw=700" alt="スクリーンショット 2021-07-11 21.16.03.png" /></a></p>
<h6 id="MixColums"><a href="#MixColums">MixColums</a></h6>
<p>行列を、列ごとに掛け算していきます。<br />
行列は、<a href="https://crieit.now.sh/upload_images/8396bd9aad7141bdd503b24f158fb1db60eae2a11ad9c.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/8396bd9aad7141bdd503b24f158fb1db60eae2a11ad9c.png?mw=700" alt="スクリーンショット 2021-07-11 21.22.53.png" /></a><br />
で求められます</p>
<h6 id="AddRoundKey"><a href="#AddRoundKey">AddRoundKey</a></h6>
<p>Key Scheduleから作成された行列との排他的論理和をとります。至って単純。</p>
<p>アルゴリズムの参考サイト<br />
<a target="_blank" rel="nofollow noopener" href="http://www.ihpc.se.ritsumei.ac.jp/hpc/papers/b05/umehara.pdf">http://www.ihpc.se.ritsumei.ac.jp/hpc/papers/b05/umehara.pdf</a><br />
<a target="_blank" rel="nofollow noopener" href="https://www.cqpub.co.jp/DWM/contest/2004/specification2004.pdf">https://www.cqpub.co.jp/DWM/contest/2004/specification2004.pdf</a><br />
その他諸々</p>
<h2 id="認証方式について"><a href="#%E8%AA%8D%E8%A8%BC%E6%96%B9%E5%BC%8F%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6">認証方式について</a></h2>
<h4 id="WPAパーソナル"><a href="#WPA%E3%83%91%E3%83%BC%E3%82%BD%E3%83%8A%E3%83%AB">WPAパーソナル</a></h4>
<p>認証サーバを使わないモード</p>
<h5 id="PSK"><a href="#PSK">PSK</a></h5>
<p>Pre-Shared Keyの略。意味は、「共有パスワードキー」<br />
まー従来使われていたやつ。</p>
<h5 id="SAE"><a href="#SAE">SAE</a></h5>
<p>Simultaneous Authentication of Equalsの略。<br />
クライアント役とサーバ役が時と場合によりコロコロ入れ替わる。<br />
認証パスワードが予測できない。<br />
鍵交換に4ウェイハンドシェイクするらしい(4ウェイって初めて聞いた笑)</p>
<h4 id="WPAエンタープライズ"><a href="#WPA%E3%82%A8%E3%83%B3%E3%82%BF%E3%83%BC%E3%83%97%E3%83%A9%E3%82%A4%E3%82%BA">WPAエンタープライズ</a></h4>
<p>認証サーバを使用するモード。<br />
企業で使われる</p>
<h5 id="IEEE 802.1X/EAP"><a href="#IEEE+802.1X%2FEAP">IEEE 802.1X/EAP</a></h5>
<p>WEPにはない認証方式を作るためにできた。<br />
サプリカント、認証装置、認証サーバを用いる。<a href="https://crieit.now.sh/upload_images/4f2fb798ce8ede0f416577ce9af4f98660eaf318e1571.png" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/4f2fb798ce8ede0f416577ce9af4f98660eaf318e1571.png?mw=700" alt="スクリーンショット 2021-07-11 22.33.08.png" /></a></p>
<p>認証方式に、MD5とか。TLSとか。よく聞いたとこあるようなやつが使われている。</p>
skyms
tag:crieit.net,2005:PublicArticle/16685
2021-02-14T18:24:50+09:00
2021-02-14T18:50:36+09:00
https://crieit.net/posts/Ruby-SA-IS-suffix-array-induced-sorting
Rubyで素朴なSA-IS(suffix array induced sorting)を書いてみた
<p><a target="_blank" rel="nofollow noopener" href="https://memo88.hatenablog.com/entry/20160303/1457007566">FM-index</a> と同様に、ほぼ最適化をしていない素朴な実装を作ってみました。</p>
<p>元の論文の実装は空間効率まで考慮して書かれていてすごい! ……のですが、まずはそれ以外の部分の仕組みを理解したかったので、以下のコードではそこらへんも無視しています。</p>
<p>(※ <a target="_blank" rel="nofollow noopener" href="https://memo88.hatenablog.com/entry/20160317/1458224137">2016-03-17 に書いた記事</a>のクロスポストです)</p>
<h1 id="コード"><a href="#%E3%82%B3%E3%83%BC%E3%83%89">コード</a></h1>
<pre><code class="ruby">require "minitest/autorun"
SENTINEL = "$"
TYPE_L = "L"
TYPE_S = "S"
NAME_CHARS = [
"a","b","c","d","e","f","g","h","i","j",
"k","l","m","n","o","p","q","r","s","t",
"u","v","w","x","y","z"
]
def _assert(exp)
raise "must not happen" if exp == false
end
# from <= i <= to
def _each_up(from, to)
( from.upto(to) ).each {|i| yield(i) }
end
# from >= i >= to
def _each_down(from, to)
( from.downto(to) ).each {|i| yield(i) }
end
class Buckets
def initialize(s_cs)
@ary = []
@freq_map = make_freq_map(s_cs)
@sorted_uniq_chars = @freq_map.keys().sort()
clear(s_cs.length())
end
def clear(length)
_each_up(0, length - 1) {|i|
@ary[i] = nil
}
end
def make_freq_map(s_cs)
uniq_cs = s_cs.uniq()
# 初期化
freq_map = {}
uniq_cs.each {|c| freq_map[c] = 0 }
s_cs.each {|c| freq_map[c] += 1 }
return freq_map
end
def first_pos(c)
i = 0
found = false
@sorted_uniq_chars.each {|iter_c|
if (iter_c == c)
found = true
break
end
i += num_bucket_elements(iter_c)
}
return i
end
def num_bucket_elements(c)
return @freq_map[c]
end
def add_l(c, si)
# バケツの先頭・末尾
bia = first_pos(c)
biz = bia + num_bucket_elements(c) - 1
i = nil
# 線形走査。遅い。
_each_up(bia, biz) {|bi|
if @ary[bi] != nil
next
end
i = bi
break
}
_assert( i != nil )
@ary[i] = si
end
def add_s(c, si)
# バケツの先頭・末尾
bia = first_pos(c)
biz = bia + num_bucket_elements(c) - 1
i = nil
# 線形走査。遅い。
_each_down(biz, bia) {|bi|
if @ary[bi] != nil
next
end
i = bi
break
}
_assert( i != nil )
@ary[i] = si
end
def num_chars()
return @ary.length()
end
def get(i)
return @ary[i]
end
def set(i, value)
@ary[i] = value
end
def to_array()
return @ary
end
end
def make_types(s_cs)
types = []
types[s_cs.length() - 1] = TYPE_S # sentinel は S
prev_type = TYPE_S
prev_c = SENTINEL
_each_down(s_cs.length() - 2, 0) {|si|
c = s_cs[si]
if (c < prev_c)
type = TYPE_S
elsif (c > prev_c)
type = TYPE_L
else
type = prev_type
end
types[si] = type
prev_c = c
prev_type = type
}
return types
end
def extract_lms_positions(types)
sis = []
prev_type = TYPE_S # sentinel
_each_down(types.length() - 2, 0) {|si|
type = types[si]
if (type == TYPE_L && prev_type == TYPE_S)
sis.unshift(si + 1)
end
prev_type = type
}
return sis
end
def add_lms_to_bkts(bkts, s_cs, lms_sis)
lms_sis.each {|lms_si|
c = s_cs[lms_si]
bkts.add_s(c, lms_si)
}
return bkts
end
def induce_l(bkts, s_cs, types)
# 上から
_each_up(0, bkts.num_chars() - 1) {|bi|
si = bkts.get(bi)
next if si == nil
next if si == 0
next if types[si - 1] != TYPE_L
prev_c = s_cs[si - 1]
bkts.add_l(prev_c, si - 1)
}
return bkts
end
def induce_s(bkts, s_cs, types)
# 下から
_each_down(bkts.num_chars() - 1, 0) {|bi|
si = bkts.get(bi)
next if si == nil
next if si == 0
next if types[si - 1] != TYPE_S
prev_c = s_cs[si - 1]
bkts.add_s(prev_c, si - 1)
}
return bkts
end
def is_lms(lms_sis, si)
return lms_sis.include?(si)
end
def induced_sort(bkts, s_cs, types, lms_sis)
bkts = induce_l(bkts, s_cs, types)
# sentinel 以外の LMS を除去
_each_up(1, bkts.num_chars() - 1) {|bi|
si = bkts.get(bi)
bkts.set(bi, nil) if is_lms(lms_sis, si)
}
bkts = induce_s(bkts, s_cs, types)
return bkts
end
def is_same_substring(s_cs, ai, bi, lms_sis)
i = 0
is_same = true
while true
if s_cs[ai + i] != s_cs[bi + i]
is_same = false
break
end
if i >= 2
# 元論文ではタイプ(L/S)による判別も行なっている
a_is_lms = is_lms(lms_sis, ai + i)
b_is_lms = is_lms(lms_sis, bi + i)
if (a_is_lms && b_is_lms)
break
elsif (! a_is_lms && b_is_lms)
is_same = false
break
elsif (a_is_lms && ! b_is_lms)
is_same = false
break
else
# both are not LMS
end
end
i += 1
_assert(i < s_cs.length())
end
return is_same
end
def get_name(i)
name = NAME_CHARS[i]
if (name == nil)
raise "names (LMS-substring) is too many"
end
return name
end
def to_names(s_cs, lms_sis, sorted_lms_sis_temp)
is_unique = true
# name index
ni = 0
names = []
# 1個目
names.unshift(get_name(ni))
ni += 1
# 2個目以降
_each_up(0, sorted_lms_sis_temp.length() - 2) {|ai|
sia = sorted_lms_sis_temp[ai]
sib = sorted_lms_sis_temp[ai + 1]
if (is_same_substring(s_cs, sia, sib, lms_sis))
is_unique = false
else
ni += 1
end
names.unshift(get_name(ni))
}
return [names, is_unique]
end
def sa_is(s_cs)
bkts = Buckets.new(s_cs)
types = make_types(s_cs)
lms_sis = extract_lms_positions(types)
# --------------------------------
# induced sort 1回目
# LMS-substring をソートするのが目的
bkts = add_lms_to_bkts(bkts, s_cs, lms_sis)
bkts = induced_sort(bkts, s_cs, types, lms_sis)
# この時点で LMS-substring がソートされた状態になる
# (ただし、重複した LMS-substring 同士の順序は未確定)
# --------------------------------
# LMS-substring のソート
# LMS だけを抜き出す
sorted_lms_sis_temp = []
_each_up(0, bkts.num_chars() - 1) {|bi|
si = bkts.get(bi)
if (is_lms(lms_sis, si))
sorted_lms_sis_temp << si
end
}
names, is_unique = to_names(s_cs, lms_sis, sorted_lms_sis_temp)
sorted_lms_sis = nil
if (is_unique)
sorted_lms_sis = sorted_lms_sis_temp
else
ret = sa_is(names)
sorted_lms_sis = []
ret.each {|i|
sorted_lms_sis.unshift(lms_sis[i])
}
end
# --------------------------------
# induced sort 2回目
# 1回目のソートは LMS-substring のソート結果を得るのが目的だったので
# 一旦空にして良い。
bkts.clear(s_cs.length())
bkts = add_lms_to_bkts(bkts, s_cs, sorted_lms_sis)
bkts = induced_sort(bkts, s_cs, types, sorted_lms_sis)
return bkts.to_array()
end
class SaIsTest < Minitest::Test
def test_make_lms_sis_1
# 0 1
assert_equal([1], extract_lms_positions(["L","S"]))
end
def test_make_lms_sis_2
# 0 1 2
assert_equal([2], extract_lms_positions(["S","L","S"]))
end
def test_make_lms_sis_3
# 0 1 2 3
assert_equal [2], extract_lms_positions(["S","L","S","S"])
end
def test_make_lms_sis_4
# 0 1 2 3 4 5
assert_equal([2, 5], extract_lms_positions(["S","L","S","L","L","S"]))
end
def test_is_same_substring_1
# 0 1 2 3 4 5 6 7
# L S L S L S L S
t_cs = ["b","a","b","a","b","a","b","$"]
lms_sis = [1,3,5,7]
assert_equal true, is_same_substring(t_cs, 1, 3, lms_sis)
end
def test_is_same_substring_2
# 0 1 2 3 4 5 6 7
# L S L S L S L S
s_cs = ["b","a","c","a","b","a","b","$"]
lms_sis = [1,3,5,7]
assert_equal false, is_same_substring(s_cs, 1, 3, lms_sis)
end
def test_sa_is_bbaaddaaddaaccaa
# 0 1
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
# L L S S L L S S L L S S L L L L S
s_cs = ["b","b","a","a","d","d","a","a","d","d","a","a","c","c","a","a", SENTINEL]
assert_equal(
[16 ,15 ,14 ,10 ,6 ,2 ,11 ,7 ,3 ,1 ,0 ,13 ,12 ,9 ,5 ,8 ,4],
sa_is(s_cs)
)
end
def test_sa_is_eaefaegaefaag
# 0 1
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3
# L S S L S S L S S L S S L S
s_cs = ["e","a","e","f","a","e","g","a","e","f","a","a","g", SENTINEL]
assert_equal(
[13,10,7,1,4,11,0,8,2,5,9,3,12,6],
sa_is(s_cs)
)
end
def test_sa_is_mississippi
# 0 1
# 0 1 2 3 4 5 6 7 8 9 0 1
# L S L L S L L S L L L S
s_cs = ["m","i","s","s","i","s","s","i","p","p","i", SENTINEL]
assert_equal(
[11,10,7,4,1,0,9,8,6,3,5,2],
sa_is(s_cs)
)
end
def test_sa_is_abracadabra
# 0 1
# 0 1 2 3 4 5 6 7 8 9 0 1
# S S L S L S L S S L L S
s_cs = ["a","b","r","a","c","a","d","a","b","r","a", SENTINEL]
assert_equal(
[11,10,7,0,3,5,8,1,4,6,9,2],
sa_is(s_cs)
)
end
end
</code></pre>
<p>(追記 2021-02-14) Ruby 3.0.0 向けに minitest まわりを微修正しました。</p>
<h1 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h1>
<ul>
<li>2018-01-30 <a target="_blank" rel="nofollow noopener" href="https://mametter.hatenablog.com/entry/20180130/p1">SA-IS 法のメモ - まめめも</a>
<ul>
<li>Ruby による実装</li>
</ul></li>
</ul>
sonota486
tag:crieit.net,2005:PublicArticle/16678
2021-02-08T18:51:49+09:00
2021-02-08T18:55:50+09:00
https://crieit.net/posts/Ruby-FM-index
Rubyで素朴なFM-indexを書いてみた
<p>BWT、検索処理の最適化・高速化は行なっていません(SA-IS、ウェーブレット行列などは使っていません)。 BWT から検索まで全体の流れが見渡せる最小限の実装にしました。 せっかくなので Ruby に馴染みのない方が見ても読みやすいと思われる書き方にしています(returnやメソッド呼び出しの括弧を省略しない、など)。</p>
<p>(※ <a target="_blank" rel="nofollow noopener" href="https://memo88.hatenablog.com/entry/20160303/1457007566">2016-03-03 に書いた記事</a>のクロスポストです)</p>
<h1 id="参考にしたもの"><a href="#%E5%8F%82%E8%80%83%E3%81%AB%E3%81%97%E3%81%9F%E3%82%82%E3%81%AE">参考にしたもの</a></h1>
<ul>
<li><a target="_blank" rel="nofollow noopener" href="http://www.langmead-lab.org/teaching-materials/">Teaching Materials</a> - ここに置いてある「Burrows-Wheeler Transform and FM Index」というタイトルの PDF(ジョンズ・ホプキンス大学 Ben Langmead さんの講義資料)</li>
</ul>
<p>最初の取っ掛かりとして分りやすかったのがこれ。要点を押さえた簡潔な図と Python コードを眺めてるだけでだいぶ分かった気になれます。</p>
<hr />
<ul>
<li><a target="_blank" rel="nofollow noopener" href="https://github.com/erukiti/cerebrums">erukiti/cerebrums: 文章・情報共有ソフト</a></li>
</ul>
<p>もっと具体的なところについては実装を見た方が早いということで <a target="_blank" rel="nofollow noopener" href="http://qiita.com/erukiti/items/f11f448d3f4d73fbc1f9">ハクビシンにもわかる全文検索</a> の erukiti さんの実装を参考にさせてもらいました。CoffeeScript 製。</p>
<h1 id="コード"><a href="#%E3%82%B3%E3%83%BC%E3%83%89">コード</a></h1>
<pre><code>- range
- (a..b) => [a, b] b is included
- (a...b) => [a, b) b is not included
- a.downto(b) => [a, a-1, ... b+1, b]
- method { |x| ... } => in JavaScript: method((x)=>{ ... })
</code></pre>
<pre><code class="ruby">require "minitest/autorun"
SENTINEL = "$"
def to_bwm(t)
tt = t + SENTINEL + t
rows = (0..t.length).map { |i|
tt[i..(i + t.length)]
}
return rows.sort
end
# Burrows-Wheeler transform
def bwt(t)
bwm = to_bwm(t)
return bwm.map { |cs| cs[-1] }.join("")
end
def rank_less_than(cs, c)
return cs.count { |_c| _c < c }
end
def rank(cs, c, i)
return (0...i).count { |j| cs[j] == c }
end
# LF mapping
def map_lf(cs, c, i)
return rank_less_than(cs, c) + rank(cs, c, i)
end
# String before c
def backward_chars(bwt_t, c, s, e)
bwt_cs = bwt_t.split("") # to array of chars
cb = c # T(i)
ca = nil # T(i-1)
result = ""
while true
s = map_lf(bwt_cs, cb, s)
e = map_lf(bwt_cs, cb, e)
# assert e - s == 1
ca = bwt_t[s]
if (ca == SENTINEL)
break
end
result += ca
cb = ca
end
return result.reverse
end
def reverse(bwt_t)
# sentinel は F列では必ず 0 行目のみに存在する
# sentinel is always at F[0]
s = 0 # start
e = 1 # end
return backward_chars(bwt_t, SENTINEL, s, e)
end
def search_internal(bwt_t, q)
bwt_cs = bwt_t.split("") # to array of chars
s = 0
e = bwt_t.length
(q.length - 1).downto(0).each { |i|
s = map_lf(bwt_cs, q[i], s)
e = map_lf(bwt_cs, q[i], e)
if (s >= e)
return nil
end
}
return [s, e]
end
def search(bwt_t, q)
s, e = search_internal(bwt_t, q)
return s == nil ? 0 : (e - s)
end
class FmIndexTest < Minitest::Test
def setup
t = "abaaba"
@bwt_t = bwt(t)
end
def test_bwt
assert_equal("abba$aa", @bwt_t)
end
# 1文字の検索
def test_one_char
s, e = search_internal(@bwt_t, "a")
assert_equal(1, s)
assert_equal(5, e)
# 出現回数
num_hits = search(@bwt_t, "a")
assert_equal(4, num_hits)
end
# 2回出現する
def test_2_hits
s, e = search_internal(@bwt_t, "aba")
assert_equal(3, s)
assert_equal(5, e)
assert_equal(2, search(@bwt_t, "aba"))
end
# 1回出現する
def test_one_hit
s, e = search_internal(@bwt_t, "aaba")
assert_equal(2, s)
assert_equal(3, e)
assert_equal(1, search(@bwt_t, "aaba"))
end
# 存在しない組み合わせ
def non_existent_combination
s, e = search_internal(@bwt_t, "baba")
assert_equal(nil, s)
assert_equal(nil, e)
assert_equal(0, search(@bwt_t, "baba"))
end
# 存在しない文字
def non_existent_char
s, e = search_internal(@bwt_t, "x")
assert_equal(nil, s)
assert_equal(nil, e)
assert_equal(0, search(@bwt_t, "x"))
end
def test_reverse
bwt_t = bwt("mississippi")
assert_equal("ipssm$pissii", bwt_t)
assert_equal("mississippi", reverse(bwt_t))
end
end
</code></pre>
<ul>
<li>(追記 2021-02-08) Ruby 3.0.0 向けに minitest まわりを微修正しました。</li>
</ul>
sonota486
tag:crieit.net,2005:PublicArticle/16451
2020-12-31T12:00:55+09:00
2020-12-31T12:03:07+09:00
https://crieit.net/posts/UMAP
UMAPに関して書いてみました
<p>拙文ながら、高次元データ可視化の手法、UMAPとt-SNEに関して書いてみたので、紹介。</p>
<ul>
<li><p>UMAPの仕組み ─ 低次元化の理屈を理解してみる<br />
<a target="_blank" rel="nofollow noopener" href="https://kntty.hateblo.jp/entry/2020/12/14/070022">https://kntty.hateblo.jp/entry/2020/12/14/070022</a></p></li>
<li><p>t-SNEやUMAPで、裾の広い分布を使う理由(混雑問題)<br />
<a target="_blank" rel="nofollow noopener" href="https://kntty.hateblo.jp/entry/2020/12/31/092334">https://kntty.hateblo.jp/entry/2020/12/31/092334</a></p></li>
</ul>
knttylap
tag:crieit.net,2005:PublicArticle/15188
2019-07-02T13:00:13+09:00
2019-07-03T11:45:10+09:00
https://crieit.net/posts/c81cf757cf261b0453084bb2451b8a6f
ビジネスデータ分析を支える技術
<p>ビジネスデータ分析を支える技術について簡単に解説したいと思います。データ分析は割と広い世界になっていて、使われる技術は色々とあります。まず下記の図を見てください。</p>
<p><a href="https://crieit.now.sh/upload_images/d49c72d087511c590d1aeeccc7f5c4895d1acdf9f3a6b.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/d49c72d087511c590d1aeeccc7f5c4895d1acdf9f3a6b.jpg?mw=700" alt="Data Analysis Process.jpg" /></a></p>
<p>データ分析システムをフルに作ろうとすると、だいたいこの図のようなフローになると思います。左から右へ流れて行きます。まず、一番左のグループです。データが生成される場所ですね。<br />
データは形式により大きく3つに分かれます。</p>
<pre><code> 構造化データ
非構造化データ
半構造化データ
</code></pre>
<p>ここで必要な技術は何でしょう? データ理解です。これが実は案外難しい。習うより慣れろではないですが、経験がものを言うエリアです。分析をするプロセスに持ち込むデータの量、形式、質などを期待されるアウトプットを考えて、整理し、必要なら加工していかなけばならないのですね。欠損が無いか、もしあればどう補うのか。センサーデータなどのの場合は、採用するかどうかの基準値を決めなければなりません。非構造化データの場合も、どのデータを使うのかの基準値が必要になります。分析に使用するアルゴリズムによっては、必要とするデータ量が決まっているものもあります。後工程のことを考えつつ、データを理解し、必要なアクションを取って行くスキルが求められます。ここを安易に通過すると、期待する分析結果が得られないリスクがあります。</p>
<p>次に、データをためるDWH(データウエアハウス)とData Lake(データレイク)。構造化データ(典型的な構造化データは、RDBMS)はDWHにため込むことになります。ほとんどがCloud DWHになります。半構造化データと非構造化データは、Data Lakeに保存しておきます。従って、DWHとData Lakeの技術スキルが必要とされます。</p>
<p>次が、分析プロセス。データが保存されているDWHやData Lakeから分析に必要なデータを抽出して持っていく必要があるわけです。Data Martを作る場合もあります。レガシーシステムですとETLの知識が必要でしたがCloudでは、もう少し簡単になっています。DWHから分析に必要なデータを抽出する為には、SQLがわかっていなければなりません。Cloud Data Lakeの場合は、データカタログという機能が用意されており、抽出が容易になっています。</p>
<p>分析プロセスについては、下図を見て下さい。</p>
<p><a href="https://crieit.now.sh/upload_images/6b64021e020be575d571e445986395495d1ad53473b69.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/6b64021e020be575d571e445986395495d1ad53473b69.jpg?mw=700" alt="datanalysisprocessfigure.jpg" /></a></p>
<p>分析プロセスで必要なスキルは、どのようなものでしょうか?<br />
ここでは、データは使える状態になっているので、分析に使うアルゴリズムを決めます。データと期待されているアウトプットを考えて、アルゴリズムを決めるスキルが必要です。</p>
<p>処理プロセスとしては最後になる、データビジュアライゼーションです。具体的には、Microsoft Power BIやTableauといったセルフサービスBIのスキルですね。最近は、第二世代も出てきていますので、この分野の知識とスキルも大切です。</p>
<p>ビジュアライゼーションされた分析結果を読み取り、意思決定を支援できる知見を得ることがビジネスデータ分析の目的です。この知見発見というのが、ビジネスデータ分析の最大の難所です。ドメイン知識も必要ですし、おのれの知識や経験を総動員して考えなければなりません。クライアントやビジネスパートナーと知見発見ミーティングを持つ必要もありますが、それでもたたき台はコンサルタントが作成する必要があります。頑張りどころですし、ここで評価も決まってきます。</p>
Masao Kato