コードクローン分析ツールGeminiを 用いたコードクローン分析手法 大阪大学 大学院情報科学研究科 肥後 芳樹([email protected]) 楠本 真二([email protected]) 井上 克郎([email protected]) Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University 背景 コードクローンとは ソースコード中に存在する一致または類似したコード片 コピーアンドペーストなどのさまざまな理由により生成される copy-and-paste copy-andpaste ソフトウェアの保守を困難にする あるコード片にバグがあると,そのコードクローン全てについて修 正の検討を行う必要がある 機能を追加する場合も同様のことがいえる Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University コードクローンに対するこれまでの取り組み コードクローンに対する支援ツールの開発 検出ツール: CCFinder[1] 分析ツール: Gemini[2] CCFinder/Geminiパッケージとして国内外の個人・組織に配布 研究機関での利用 企業での試用・商用ソフトウェアの開発プロセスへの導入 配布先からのフィードバック バグ報告,新機能の提案 分析手順に関する問い合わせ Geminiを用いたコードクローン分析方法を提案する [1] T. Kamiya, S. Kusumoto, and K. Inoue, “CCFinder: A multi-linguistic token-based code clone detection system for large scale source code”, IEEE Transactions on Software Engineering, 28(7):654-670, 2002. [2] Y. Ueda, T. Kamiya, S. Kusumoto and K. Inoue, “Gemini: Maintenance Support Environment Based on Code Clone Analysis”, Proc. Of the 8th IEEE International Symposium on Software Metrics, 67-76, 2002. Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University コードクローンを用いた分析の目的 設計とコードの一貫性確認 設計情報で重複している部分はソースコードでも重複しており,それ以 外の部分には重複をしている部分がないかを確認する 信頼性の改善 長期間保守をされているシステムのソースコードには多くのコードクローン が存在する可能性が高い 新たな保守作業の際に,保守対象のコード片に対するコードクローンを 調査することで,変更漏れを防ぐことが可能となる 保守性の改善 複数のバージョンのソースコードが与えられたときに,バージョン間でのコー ドクローンの遷移を調査し,保守作業の効率化を計る 繰り返し修正が加えられているコードクローンは集約する 安定しているコードクローンにはリファクタリングは不要 Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University クローンペアとクローンセット クローンペア: 互いに一致・類似しているコード片の対 クローンセット: 互いに一致・類似しているコード片の集合 C1 クローンペア (C1, C4) クローンセット {C1, C4, C5} C2 (C1, C5) {C2, C3} C3 (C2, C3) C4 (C4, C5) C5 Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University コードクローン検出ツール CCFinder 概要: ソースコードをトークン単位で直接比較することにより コードクローンを検出 名前空間の正規化 ユーザ定義名の置き換え テーブル初期化部分の取り除き モジュールの区切りの認識 解析結果はテキスト形式で出力 数百万行規模でも実用的な時間で解析可能 Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University コードクローン検出ツール CCFinder 検出プロセス: Source files static throws {{{ String 1. static static foo() throws RESyntaxException { {{ $$ $$ (( (( )) ))throws $void void foofoo() throws$$RESyntaxException RESyntaxException String aaa { static RESyntaxException String 1. void throws RESyntaxException static void $ $$foo throws ]{{] {${$ "123,400" , [[ [][] String $String $$ = new $[] { ]]] === a[] new $[] 2. [[String a[] = new String { "123,400", "123,400", "abc", "orange "orange 100" 100" }; }; 2. new "abc", [String $String "abc" , "orange 100" } ; org . apache . regexp ; } 3. org.apache.regexp.RE org.apache.regexp.RE pat == new new org.apache.regexp.RE("[0-9,]+"); org.apache.regexp.RE("[0-9,]+"); } ; 3. pat $$ === new $$ pat RE pat RE new 4. .int int sum 0; org . apache . regexp 4. sum ==new 0; . RE )) ;;; int $$ ==== $0$00 $$ sum $$ $$ ((( "[0-9,]+" RE int sum sum 5. for for (int"[0-9,]+" i == 0; 0; ii) << a.length; a.length; ++i) 5. (int i ++i) ;; for $$ i$$i === 0$0$ ;;; i$$i <<<< int for (( int 6. a$ ifif. (pat.match(a[i])) (pat.match(a[i])) 6. ;++ $$ ii)) ))if $$ ;; ++ length ; ++ ++ pat pat $ . length if ifif(( ((($$ pat 7. .. match sum += Sample.parseNumber(pat.getParen(0)); 7. sum += Sample.parseNumber(pat.getParen(0)); $$ (( (( $$ aa [[ [[ $$ ii ]] ]] )) )) )) ))) $$sum sum sum . match 8. System.out.println("sum " ++ sum); sum); 8. += System.out.println("sum "getParen += Sample ((( 000 (( $$ .. $$ (( ((pat $$ .. $.$. parseNumber parseNumber pat$$ .= . getParen pat .= getParen += 9. }} )) )) ;; System (( $$ ((( "sum .. .$$. println $$ .. .$$. out System out println "sum===""" 9. println "sum static String $$ $$goo }}} static ))) ;;; goo(String $$ void sum static void void goo String 10. static static void goo(String []((a) a)((( $$throws throws RESyntaxException {{ +++ sum goo String 10. [] RESyntaxException static {{ $$ $$ = $$RE("[0-9,]+"); throws RESyntaxException RE exp exp === [[[ exp ]]] )))= RESyntaxException RE exp 11. a$a$RE RE exp =throws newRESyntaxException throws = {{{ RE 11. new RE("[0-9,]+"); new RE = $$ )) ;;)) $$;; $$int $$ (( "[0-9,]+" int sum sum new =sum$$=== 000 12. new int sum"[0-9,]+" 0; 12. int sum == 0; $$ i$$i === 0$0$ ;;; i$$i <<<< for int for ((( int for (int 13. ;;;for for 0; ii << a.length; a.length; ++i) ++i) 13. (int ii == 0; $ ( $$ ii)) ))if $$ ;; ++ if ( exp length ; ++ ++ if ( exp a$a$ ... length ;++ ( exp if ( $ 14. . match (exp.match(a[i])) 14. ifif (exp.match(a[i])) ] $ [ $ ( $ ( a [ i ] ( a [ i ] sum sum . $ ( $ [ $ ] )) )) )) ))) $$sum 15. += sum += parseNumber(exp.getParen(0)); 15. sum += parseNumber(exp.getParen(0)); (( .. $$ getParen $$ (( ( $$exp.. ((. $$exp += getParen ()) 0)) )(( )00 )) )) parseNumber exp getParen $$$ ... parseNumber += parseNumber 16. ;;;System.out.println("sum System.out.println("sum ==="""""+++++sum sum); 16. sum); $$ = (( $$ ((++ "sum .. .$$. println $$ .. .$$. out = System out println "sum sum System "sum sum 17. }}))) ;;; }}} 17. 字句解析 字句解析 トークン列 トークン列 変換処理 変換処理 変換後トークン列 変換後トークン列 検出処理 検出処理 クローン情報 クローン情報 出力整形処理 出力整形処理 クローンペア位置情報 Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University コードクローン分析ツール Gemini 概要: CCFinderの解析結果(テキストファイル)を読み込み,コード クローン情報を視覚的に表示 クローン散布図(スキャタープロット図) メトリクスグラフ ファイルリスト 重要でないコードクローンのフィルタリング Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University コードクローン分析ツール Gemini クローン散布図: 原点は左上隅 はその水平方向のトークンと垂 直方向のトークンが等しいことを意 味する 常に対角線が引かれる クローンペアは線分として出現する 対角線に対して線対称となる a b c a b c a d e c a b c a b c a d e c 水平・垂直方向にソースコード中 のトークンを出現順に配置 a, b, c, ... : tokens : matched position Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University コードクローン分析ツール Gemini メトリクスグラフ(概要) メトリクスを用いてクローンセットを定量的に特徴づける 多次元並行座標表現を用いている 各メトリクスにつき1つの座標軸が存在する 各クローンセットにつき1つの折れ線がメトリクス値に基づいて描画される S1 S1 S2 S2 RAD LEN RNR POP DFL RAD LEN RNR POP DFL ユーザは各メトリクスの上限・下限を変更することでクローンセットの選 択・選択解除を行う 全てのメトリクスが上限と下限の間にあるクローンセットが選択状態になる 選択状態にあるクローンセットのソースコードは簡単に閲覧可能 Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University コードクローン分析ツール Gemini メトリクスグラフ(用いているメトリクス): LEN(S): クローンセット S 内に含まれるコード片のトークン 数の平均値を表す POP(S): S に含まれるコード片の数を表す RAD(S): S 内のコード片がファイルシステム上でどの程度 分散しているかを表す DFL(S): S に含まれるコード片に共通するロジックを実装す るサブルーチンを作り,各コード片をそのサブルーチン呼び出 しに置き換えた場合の減少が予測されるトークン数を表す 作成したサブルーチン サブルーチンの呼び出し Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University コードクローン分析ツール Gemini ファイルリスト: 対象ファイルの一覧を表示 各ファイルは以下のメトリクスと共に表示される ファイル F の行数を表す NOT(F): F のトークン数を表す NOC(F): F に含まれている重複コードの数を表す ROC(F): F がどの程度重複化しているかを表す NOF(F): F がコードクローンを共有しているファイル数を表す NOL(F): 行の並び替えが可能 ファイルを各メトリクス値の昇順・降順にソーティング クローン散布図と連動 Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University コードクローン分析ツール Gemini 重要でないコードクローンのフィルタリング: CCFinderの検出するコードクローンはトークンの列であり,重要でない コードクローンを多数検出してしまう switch文の各caseエントリ 連続したimport文,printf文, フィルタリングメトリクス RNR(S) クローンセット scanf文 など S に含まれるコード片の非繰り返し度を表す 例 トークン列 <x a b c a b c* a* b* c* y> CCFinder は以下の2つのコード片をコードクローンとして検出 x a b c a b c*<F1> a* b* c* y x a b c a b c* a* b* c*<F2> y F1はコード片の長さが6トークン,そのうち5トークンが非繰り返し F2はコード片の長さが6トークン,そのうち2トークンが非繰り返し RNR(S1) = (5 + 2)/(6 + 6) = 7/12 = 0.583 Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University 各ビューの特徴 クローン散布図: コードクローンの分布状態を俯瞰的に知ることができる 以下の部分が目立ちやすい ある程度の領域内にコードクローンが密集している部分 繰り返し同じパターンが出現している部分 ファイルよりも大きな単位での類似部分を知ることができる クローン散布図において目立つ部分は,必ずしもその部分に存在するコードクローン が特徴的であることを示しているわけではない 目立つ部分に存在するコードクローンは一種類ではなく,複数の種類のコードク ローンが混在している場合がある 目立ちやすさとコードクローンの位置が関係している 要素数の多いクローンセットであっても,そのコード片が複数のファイル内に散在 している場合は,クローン散布図上ではそれらは離れた位置に描画される Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University 各ビューの特徴 メトリクスグラフ,ファイルリスト: メトリクスグラフ 定量的に特徴的なコードクローンを見つけることができる コードクローンの位置に影響されることはない メトリクスRAD(S)を用いて,クローンセットに含まれるコード片がファイルシ ステム上でどの程度散らばっているかを知ることができる ファイルリスト 定量的に特徴的なファイルを見つけることができる メトリクスNOF(F)を用いると多くのファイルとコードクローンを共有している ファイルを見つけることができる 設計が悪い? 保守のボトルネック? 横断的関心事? Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University 提案する分析法 概要: Gemini を用いた効果的と思われる分析法を提案する 大まかな把握 STEP2A: トークン数の多いクローンセットの特定 STEP2B: 要素数の多いクローンセットの特定 STEP2C: 多くのファイルとクローンを共有しているファイルの特 定 (STEP2A)~(STEP2C)は順序不同 STEP1: Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University 効果的な分析法 STEP1(大まかな把握): 新規でコードクローン分析を行う場合は,まずクローン散布図を用いて コードクローンの分布状態を大まかに把握するとよい クローン散布図では,マウスカーソル位置の水平・垂直方向のファイル のパスがリアルタイムで表示される 目立つ部分にマウスカーソルを移動させるだけで,その部分がどのファイル なのかを知ることができる 以下の2つの部分が目立ちやすい部分である 一定の領域内にコードクローンが密集している部分 同じようなパターンが繰り返し出現している部分 メトリクス RNR(S) の値が0.5未満のコードクローンは青色,0.5以上 のコードクローンは黒色で描画 Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University 提案する分析法 STEP2A(要素数の多いクローンセット): 要素が多いということは,その機能がソフトウェアの多くの箇所で実装さ れていることを表している ソフトウェアの象徴的な処理部分であるとも考えられる その部分にバグが検出された場合,多くの箇所に同様の修正を加えなけ ればならない リファクタリングの対象とすべき? 要素数の多いクローンセットの特定にはメトリクスグラフを用いる 要素数を表すメトリクスは POP(S) メトリクス RNR(S) も同時に用いた方が望ましい 繰り返し部分は要素数の多いクローンセットになりがち 選択状態にあるクローンセットのソースコードは簡単に閲覧可能 Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University 提案する分析法 STEP2B(トークン数の多いクローンセット): トークン数の多いコードクローンはコピーアンドペーストにより生成された ものではないかと思われる ペースト後の変数名やメソッド名の修正漏れがバグに繋がる 修正漏れのチェックを行うのは効果的な予防保守 トークン数の多いクローンセットの特定にはメトリクスグラフを用いる トークン数を表すメトリクスはLEN(S) メトリクス RNR(S) も同時に用いた方が望ましい 選択状態にあるクローンセットのソースコードは簡単に閲覧可能 Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University 提案する分析法 STEP2C(多くのファイルとクローンを共有しているファイル): 根本的な問題を表している可能性がある 設計が悪いことを暗示 プログラミング言語に適切な抽象化機構が存在しない 横断的関心事 多くのファイルとコードクローンを共有しているファイルの特定に はファイルリストを用いる ファイルリストには,対象ファイルの一覧が表示される メトリクス NOF(F) の値でソーティングを行う Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University Gemini を用いた実験 目的 提案した分析方法が有効であるかを調査する 対象 Geminiのソースコード Java言語で記述 ファイル数: 126 総行数: 26,000 ・・・ UI層 メトリクスグラフ クローン散布図 ファイルリスト ソースコードビュー CCFinderの出力ファイル読み込み 検出対象: 30トークン以上 ビジネス層 ・ ・ ・ 5830個のクローンペア 512個のクローンセット メトリクス計算 データ層 クローンペアデータ クローンセットデータ ファイルデータ Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University Gemini を用いた実験 STEP1: クローン散布図での分析(全体) 右図は対象ソースコード全体を 表したクローン散布図 A, B, Cの部分が特徴的 C の部分は非常に多くの コードクローンが存在する Bの部分は特定の出現パター ンが繰り返されている A A, B 格子の色 灰色: ファイルの区切り 黒色: ディレクトリの区切り Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University C Gemini を用いた実験 STEP1: クローン散布図での分析(Aの部分) クローンの場所:クローンペアのデータを格 納するファイル(クラス) a1 a2 ファイル a1 は1つのファイル内に存在する クローンペア情報を表すデータクラス ファイル a2 は複数のファイルに存在する クローンペア情報を表すデータクラス ファイル a3 は対象コード全体に存在する クローンペア情報を表すデータクラス a3 n/m クローンが実装している機能:クローンペア の情報をクローン散布図に書き込むメソッ ド コードクローンの量に応じて異なる粒度で a3 n/m m 描画 m m C a2 m C Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University C a1 Gemini を用いた実験 STEP1:クローン散布図での分析(Bの部分): クローンの場所: Tableビューの実装部分 1つのディレクトリに含まれるJavaファイル が1つのTableビューを作成している 実体となるクラス モデルを表すクラス 行の並び替え機能を実装するクラス(2つ) 見た目(色,セル幅など)を制御するクラス ポップアップメニューを構成するクラス クローンが実装している機能: ファイル全体が 重複 クローンになっている理由: GeminiにはTableビューとして実装されて いるビューが複数存在する 対象ソースコードのTableビュー クローンセットのTableビュー 1つのクローンセットに含まれるコード片の テーブルビュー コピーアンドペーストによる開発 Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University Gemini を用いた実験 STEP1:クローン散布図での分析(Cの部分) クローンの場所:クローン散布図を実装して いるファイル c1 クローンが実装している機能: c1: マウスイベントの処理メソッド 呼び出されるメソッドの定義部分 c2 c2: クローン描画の位置計算 ソフトウェア内の位置からクローン散布 図上での位置を計算部分 クローンになっている理由: クローン散布図はマウスからイベントを 受け取り,インタラクティブに処理を行う 選択,拡大表示などの機能の存在 現在のマウスカーソルの位置から水平・ 垂直方向のファイルを計算し,ファイル 名を表示 Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University Gemini を用いた実験 STEP2:メトリクスグラフを用いた分析(1) 予め RNR(S) を用いて,その値が0.5未満のクローンセットは除いてある トークン数の多いコードクローンと同形のコード片が多いコードクローンを調査 最もトークン数の多いコードクローン(568トークン,97行) クローンの場所: クローン散布図を実装しているファイル(RAD = 0) クローンが実装している機能: マウスドラッグの開始部分から現在位置までを対 角線とする長方形を描く部分 クローンになっている理由: クローン散布図を実装しているファイル(クラス)には,マウスによりドラッグ部分を拡大 表示する機能と,選択をする機能が存在する ユーザにドラッグしている部分を伝えるために開始部分から現在位置までを対角線と する長方形を描く実装 拡大表示時と選択時で,描かれる長方形が塗りつぶされるか否かが異なる それぞれの機能は1つのメソッドとして実装 コピーアンドペーストにより作成 Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University Gemini を用いた実験 STEP3:メトリクスを用いた分析(2) 最も同形のコード片の数が多いコードクローン(17個)(1) クローンの場所: クローン散布図を実装しているファイル(RAD = 0) クローンが実装している機能: 対象システム内の位置から,クローン散布図上で の位置を求める計算部分のコードクローン クローンになっている理由: クローン散布図にはさまざまな機能があり,随所でデータ変換を行う必要がある クローン散布図による分析(C)と同じコードクローン 最も同形のコード片の数が多いコードクローン(17個)(2) クローンの場所: Tableビューの行の並び替え機能を実装しているファイル(RAD= 4) クローンが実装している機能: 行の並び替えを行っているメソッドの一部 クローンになっている理由: Gemini には複数のTableビューが存在 クローン散布図による分析(B)のコードクローンの一部 Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University Geminiを用いた実験 STEP4:ファイルリストを用いた分析 メトリクスNOC(F)(Fに含まれるコードクローンの数), ROC(F)(Fの重複度)の高いファ イル内に含まれるコードクローンは前述のクローンと同じものであった クローンペアデータを実装しているファイル クローン散布図を実装しているファイル Tableビューを実装しているファイル メトリクスNOF(F)(Fがコードクローンを共有しているファイルの数)の高いファイルに含 まれるコードクローン コードクローンの場所: GUIを実装しているファイル Tableビュー クローン散布図 メトリクスグラフ ソースコードビュー コードクローンが実装している機能: Swingの定型的な処理 スクロールバーを生成している部分 リスナーを登録している部分 マウスの右ボタンがクリックされた時に,ポップアップメニューを表示する部分 Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University Geminiを用いた実験 各ビューで目立つコードクローン クローン散布図 メトリクスグラフ (LEN(S)) 用 メトリクスグラフ (POP(S)) い た ビ ファイルリスト ュ (NOC(S)) ー ファイルリスト (ROC(S)) ファイルリスト (NOF(S)) クローンペアデータ クローン散布図パネル Tableビュー Swing定型処理 見つかったコードクローンの場所 Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University まとめ Geminiのビューの特徴をまとめた クローン散布図 メトリクスグラフ ファイルリスト 効果的と思われる分析方法の提案を行った Geminiのソースコードの対して実験を行った 設計情報に含まれるもの・含まれないもの,プログラミング言 語に依存したものなど,さまざまなコードクローンが検出された Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University メトリクスRNR(S)について トークン列 <x a b c a b c a b c y> を考える 繰り返しは <x a b c a b c* a* b* c* y> と判定 なぜ <x a b c a* b* c* a* b* c* y> ではないのか? 前者の方がどちらかというと適切であると思われるから 理論的な裏づけがあるわけではない 繰り返し部分をコードクローンとして検出する場合 1つ目のクローンコードはできるだけ非繰り返しとしたい 2つ目以降のクローンコードはできるだけ繰り返しとしたい Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University メトリクスRNR(S)について [a, b, c]がクローンコードである場合 <x a b c a b c* a* b* c* y>は <x a b c a b c* a* b* c* y> (非繰り返し度 = 3/3) <x a b c a b c* a* b* c* y> (非繰り返し度 = 1/3) <x a b c a b c* a* b* c* y> (非繰り返し度 = 0/3) <x a b c a* b* c* a* b* c* y>は <x a b c a* b* c* a* b* c* y> (非繰り返し度 = 3/3) <x a b c a* b* c* a* b* c* y> (非繰り返し度 = 0/3) <x a b c a* b* c* a* b* c* y> (非繰り返し度 = 0/3) Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University メトリクスRNR(S)について [b, c, a]がクローンコードである場合 <x a b c a b c* a* b* c* y>は <x a b c a b c* a* b* c* y> (非繰り返し度 = 3/3) <x a b c a b c* a* b* c* y> (非繰り返し度 = 1/3) <x a b c a* b* c* a* b* c* y>は <x a b c a* b* c* a* b* c* y> (非繰り返し度 = 2/3) <x a b c a* b* c* a* b* c* y> (非繰り返し度 = 0/3) Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University メトリクスRNR(S)について [a, b, c, a, b, c]がクローンコードである場合 <x a b c a b c* a* b* c* y>は <x a b c a b c* a* b* c* y> (非繰り返し度 = 5/6) <x a b c a b c* a* b* c* y> (非繰り返し度 = 2/6) <x a b c a* b* c* a* b* c* y>は <x a b c a* b* c* a* b* c* y> (非繰り返し度 = 3/6) <x a b c a* b* c* a* b* c* y> (非繰り返し度 = 0/6) Software Engineering Laboratory, Department of Computer Science, Graduate School of Information Science and Technology, Osaka University
© Copyright 2024 ExpyDoc