Mercurial > hg > Papers > 2017 > tatsuki-master
view differential.tex @ 13:7acd7d5afeb6
commit
author | tatsuki |
---|---|
date | Tue, 07 Feb 2017 18:50:35 +0900 |
parents | 498b8f4175f9 |
children | 33d8077a5d45 |
line wrap: on
line source
\chapter{Differential Jungle Tree} Jungleの木の変更の手間は形によって異なる。 特に線形の木は、変更の手間がO(n)となってしまう。 線形の木をO(1)で変更するために、Jungleは、ルートノードを追加していくPushPopの機能を持つ。 しかし、PushPopはルートノードを追加していくため、図\ref{fig:pushpop}のようにノードの並びが逆順になってしまう。 Logなどの正順の木でなければデータを表現できない場合、木の編集時 PushPop を使用できない。 \begin{figure}[htpb] \begin{center} \includegraphics[scale=0.3]{figures/PushPopDemerit.pdf} \caption{PushPopの問題点} \label{fig:pushpop} \end{center} \end{figure} その問題を解決するために、木の編集の手間をO(1)で、正順の木を構築できるDifferential Jungle Treeの実装を行った。 Differential Jungle Treeは、木のバージョンごとに、自身の木の最後尾を表す末尾のノードを保持する。 \section{Differential Tree Context} Jungleの木はTreeContextというオブジェクトに自身の木の情報を保持している(表\ref{TreeContext})。 \newpage \begin{table}[htb] \begin{center} \caption{TreeContextが保持している値} \begin{tabular}{|l|} \hline {\tt } 自身のルートノード\\ \hline {\tt } 1つ前のversionのTreeContext\\ \hline {\tt } 編集のログ\\ \hline {\tt } 木のuuid \\ \hline {\tt } 木の名前 \\ \hline {\tt } 木のversion \\ \hline {\tt } 木の検索に使うTraverser \\ \hline \end{tabular} \label{TreeContext} \end{center} \end{table} Differential Jungle Treeでは、現在の版の木構造の末尾ノード保持することが可能な Differential Tree Context 作成した。 \section{Differential Jungle Treeの作成} Differential Jungle Treeを作成するためにJungleに、{\tt createNewDifferentialTree(String treeName) }を実装した。 これは、第一引数String {\tt treeName}で受け取った名前の Differential Tree を作成する。 その際、名前が重複した場合木の生成に失敗する。 ソースコード\ref{newDifferentialTree}に新しいDifferential Jungle Treeを作成するサンプルコードを記載する。 \begin{lstlisting}[frame=lrbt,numbers=left,label=newDifferentialTree,caption=Differential Jungle Treeの生成] Jungle jungle = new DefaultJungle(null, "hogehoge", new DefaultTraverser()); // jungleの作成 String treeName = "difTree"; //treeNameの設定 JungleTree tree = jungle.createNewDifferenceTree(treeName]); //Differential Treeの作成 \end{lstlisting} Jungle では、{\tt TreeMap<String,Jungle Tree>} を用いて Jungle Tree を管理している。 Differential Jungle Tree と Default Jungle Tree は、同じ TreeMap に保持されるため、別々の木に同じ名前をつけることはできない(ソースコード\ref{src:nameFail})。 \begin{lstlisting}[frame=lrbt,numbers=left,label=src:nameFail,caption=名前の重複] Jungle jungle = new DefaultJungle(null, "hogehoge", new DefaultTraverser()); // jungleの作成 String treeName = "treeName"; //treeNameの設定 JungleTree defaultTree = jungle.createNewTree(treeName) //Default Treeの作成 JungleTree dfTree = jungle.createNewDifferenceTree(treeName); //Differential Treeの作成 \end{lstlisting} ソースコード\ref{src:nameFail}では、4行目で Differentail Jungle Tree の名前が、3行目で生成した Default Jungle Tree の名前と重複するため、木の生成に失敗する。 \newpage \section{末尾ノードを使用した木の編集} Differential Jungle Treeの木の編集は、Differential Jungle Tree Editorを使用して行う。 %Differential Jungle Tree Editorは、Jungle Tree Editor インターフェースを実装しているため、使い方はDefault Jungle Tree Editorと同じである。 Default Jungle Tree との、木の編集時の処理の違いは、Default Jungle Tree の Editorは、木の複製を行い、過去の木を保持するのに対して、Differential Jungle TreeのEditor は、自身が保持している Sub Tree に対して破壊的に編集を行う。 そして、Commitを行う際に、構築したSub Treeを末尾ノードにAppendする。 そうすることで、木の複製を行う必要がないため、木の変更の手間はO(1)で行える。 また、Differential TreeはSub Treeに対する変更しか行えないため、一度Commitした木に対して変更は行えない。 図\ref{fig:EditDifTree}にDifferential Jungle Treeの編集の流れを記述する。 \begin{figure}[htpb] \begin{center} \includegraphics[scale=0.28]{figures/EditDifferencialTree.pdf} \caption{末尾ノードを使用した木の編集} \label{fig:EditDifTree} \end{center} \end{figure} \begin{enumerate} \item 木から{\tt getJungleTreeEditor}でEditorを取得する。(このとき取得するEditorはSub Treeを持つ)。 \item SubTreeに対して{\tt addNewChild(<-1,0>)}を実行し、ノードの追加を行う。 \item Commitを行い、Treeの末尾ノードにSub TreeをAppendする。 \end{enumerate} Sub Tree に最後に追加したノードが、新しい木の末尾ノードとなる。 また、Differential TreeのIndexのアップデートは、Commit 時に Sub Treeの中身をIndexに追加するだけで良い。 \section{Differential Jungle Treeの整合性} Differential Jungle Treeに対する変更が競合した場合、先にCommitを行った方の変更が適応される。 末尾ノードへのAppendは、破壊的な変更であるため、Commit成功後に行う。 そうすることで、編集が競合した際の整合性を保っている。 また、Differential Jungle Treeは、木を破壊的に変更するため、過去の木を取得し変更を加えた場合、末尾ノードに複数のSub TreeがAppendされてしまい、木の整合性が崩れてしまう。 その問題を解決するため、末尾ノードは1つしか子ノードを持つことができない。 ノードのAppend時、末尾ノードが子ノードを持っていた場合、過去に木に対する変更と判断し、木の Commit は失敗する。 \begin{comment} ソースコード\ref{src:Append}にSub TreeのAppend部分のコードを記述する。 \begin{lstlisting}[frame=lrbt,label=src:Append,caption=Sub TreeのAppend部分のコード,numbers=left] Either<Error, TreeNode> appendSubTree(TreeNode subTreeRoot) { TreeNode appendedNode = treeContext.getEndNode(); TreeNodeChildren children = appendedNode.getChildren(); if (children.size() != 0) return DefaultEither.newA(APPEND_FAILD); return children.addNewChildAt(0, subTreeRoot); } \end{lstlisting} ソースコード\ref{src:Append}の解説を行う。 \begin{enumerate} \item 関数{\tt appendSubTree}でSub TreeのAppendを行う。引数にSub Treeのルートを持つ。 \item Differential Treeから末尾ノードを取得する。 \item 末尾ノードからChildrenを取得する。 \item 末尾ノードにSub TreeがすでにAppendされているか(子供を持っているか)を調べる。 \item 他のSub TreeがAppendされている(今編集を行っているのが過去の木)場合、木のAppendは失敗するため、エラーを返す。 \item そうでない場合、Sub Treeを末尾ノードにAppendする。 \end{enumerate} このように、末尾ノードが複数の子を持つことを禁止することで、過去の木を取得した際の木の整合性を保証している。 \end{comment} \section{Differential Jungle Treeの検索} Differential Treeは、木を破壊的に編集する。 そのため、過去の木に対して、Indexを使わずに全探索を行った場合、その版の木には無いはずのノードが取得できてしまう。 そこで、その版の木が持つ末尾ノード以下のSub Treeを検索対象から除外する検索を持つ、Differential Interface Traverser を実装した。 Indexを使用した検索を行う場合、各版に対応したIndexがあるため、Default Treeと検索のアルゴリズムは変わらない。 これらの実装により Differential Jungle Tree は木構造の構築・検索を行う。