<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>Identifying change patterns in software history</article-title>
      </title-group>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>Jason Dagit</string-name>
          <email>dagitj@gmail.com</email>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Matthew Sottile</string-name>
          <email>mjsottile@gmail.com</email>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          <institution>Galois, Inc</institution>
          ,
          <addr-line>Portland, OR</addr-line>
          ,
          <country country="US">USA</country>
        </aff>
      </contrib-group>
      <pub-date>
        <year>2013</year>
      </pub-date>
      <volume>1008</volume>
      <abstract>
        <p>Traditional algorithms for detecting di erences in source code focus on di erences between lines. As such, little can be learned about abstract changes that occur over time within a project. Structural di erencing on the program's abstract syntax tree reveals changes at the syntactic level within code, which allows us to further process the di erences to understand their meaning. We propose that grouping of changes by some metric of similarity, followed by pattern extraction via antiuni cation will allow us to identify patterns of change within a software project from the sequence of changes contained within a Version Control System (VCS). Tree similarity metrics such as a tree edit distance can be used to group changes in order to identify groupings that may represent a single class of change (e.g., adding a parameter to a function call). By applying antiuni cation within each group we are able to generalize from families of concrete changes to patterns of structural change. Studying patterns of change at the structural level, instead of line-by-line, allows us to gain insight into the evolution of software.</p>
      </abstract>
      <kwd-group>
        <kwd>version control</kwd>
        <kwd>structural di erencing</kwd>
        <kwd>antiuni cation</kwd>
        <kwd>software evolution</kwd>
      </kwd-group>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>1. INTRODUCTION</title>
      <p>Version control systems (VCS's) track the evolution of
software over time in the form of a sequence of changes to
the plain text representation of the code. We would like to be
able to characterize the changes to les in a software project
according to the type of change that they represent. The
ability to map these changes to the syntax of the language,
instead of its raw text representation, will allow them to
be understood in terms of the language constructs
themselves. Doing so will allow us to identify patterns of changes
at the abstract syntax level, separate from syntax neutral
changes to the text such as layout variations. As a result,
the interpretation of changes is made unambiguous given the
de nition of the abstract syntax of the language.</p>
      <p>Finding common patterns for the changes to a source le
gives us the ability to understand, at a higher level, what
sorts of revisions are happening. Detecting simple changes,
such as semaphore handling changes in system-level software,
we may think to use a textual search tool, such as grep, to
search the source code for functions related to semaphores.
Such tools are unable to easily identify more complex patterns
though that have no single textual representation, such as
instances of semaphore handling calls being made within
conditionals where the format of the conditional can vary.
Structure aware searching would be necessary in this case, as
treating the program as raw text ignores important syntactic
structure.</p>
      <p>In an even more complicated situation, a programmer may
be faced with a code base that they are unfamiliar with. In
this case, the programmer may not know a-priori what kinds
of structures are important to look for related to a certain
kind of change. Here, we would like to use the di erences
that are recorded in the VCS during the period of time when
the change of interest was being performed to discover the
structural patterns that represent the high level structure of
the changes. In this way, our goal is to not provide simply
a sophisticated search tool, but to provide a method for
identifying patterns of code changes over a period of time.</p>
      <p>Our contributions towards this goal presented in this paper
are:</p>
      <p>We show that structural di erencing algorithms that
operate on the abstract syntax tree (AST) of a language
can be used to map text di erences stored in a VCS to
a form where the syntactic meaning of changes can be
reasoned about.</p>
      <p>We show that the antiuni cation algorithm that seeks
the \least general generalization" of a set of trees can
be used to map changes considered to be su ciently
similar to a meaningful generalized change pattern.
We show that a thresholded tree similarity metric
derived from a tree edit distance score provides a useful
grouping mechanism to de ne the notion of \su ciently
similar".</p>
      <p>In this paper, we brie y describe the building blocks of
our work and show preliminary results of this methodology
as applied to version control repositories for open source
projects available online. The projects studied in this paper
are ANTLR1 and Clojure2, both written in Java.
1.1</p>
    </sec>
    <sec id="sec-2">
      <title>Motivation</title>
      <p>We would like to be able to take existing software projects
and use the history stored in the VCS to answer questions
which may be important to software developers, software
project managers, language designers, and static analysis
tools.</p>
      <p>Language designers may want to know whether speci c
syntactic constructs would make the language more
productive for users. Taking an example from Java, we might
consider the addition of the for-each loop construct. This
feature could be partially justi ed by doing an analysis of
existing source code to determine that most for-loops iterate
over an entire collection. To strengthen this argument, it
would be insightful to know what is the impact of
maintaining the code without for-each. For example, if refactoring
the code commonly leads to editing the bounds to match
the collection used, then the argument in favor of adding
for-each is strengthened, as now it helps to prevent a class of
bugs where programmers forget to update the bounds. We
demonstrate the detection of loop patterns within ANTLR
in Section 3.2.</p>
      <p>Software developers joining a new project or team are
expected to learn the source code that they will be working
with. We would like to provide these programmers with
tools that aid them in this task by allowing them to see
what types of changes other team members have made in
the past. Software developers may also want to compare
the changes that happen in response to related bugs, hoping
to nd opportunities to improve software quality, either by
searching for buggy patterns in the source code or making a
tool to detect the pattern in new code. We demonstrate the
detection of generic patterns within the Clojure compiler in
Section 3.3.</p>
      <p>We believe there are many uses for this approach beyond
the ones demonstrated in this paper. Consider a problem
that has been faced by many projects in the last decade|the
challenge of migrating to utilize multicore processors. A
manager who is leading a large software project may want
to answer important questions to help inform future
development: what sorts of constructs were removed or added?
This can reveal patterns of code that were thread unsafe in
the pre-multicore code that developers (especially those not
participating in the multicore port) should be made aware
of in the future. It can also reveal repeated patterns that
were added, indicating potential refactorings that may be
desirable to apply in order to reduce the proliferation of code
clones within the project.
1.2</p>
    </sec>
    <sec id="sec-3">
      <title>Related work</title>
      <p>
        The use of version control repositories as a source of data to
study changes to code over time is not new, but our approach
to the problem is novel. Neamtiu [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ] uses a similar approach
of analyzing the abstract syntax tree of code in successive
program versions, but focuses on detecting change
occurrences only instead of going a step further and attempting to
identify any common patterns of change that can be found.
Other groups have focused on identifying patterns based on
common refactorings that can be identi ed in the code [
        <xref ref-type="bibr" rid="ref10">10</xref>
        ],
1https://github.com/antlr/antlr4
      </p>
      <sec id="sec-3-1">
        <title>2https://github.com/clojure/clojure</title>
        <p>
          and seek to infer simple abstract rules that encapsulate the
changes that they detect [
          <xref ref-type="bibr" rid="ref3">3</xref>
          ]. For example, one such rule
could indicate that for all calls that match a certain pattern,
an additional argument should be added to their argument
list.
        </p>
        <p>
          This goal of generating abstract rules is similar to our goal
of inferring generic patterns in terms via antiuni cation [
          <xref ref-type="bibr" rid="ref5 ref6">6,
5</xref>
          ]. What di ers with our approach is that we presuppose
no knowledge of the underlying language beyond the
structure provided by the language parser and its mapping to
an annotated term (or, aterm) [
          <xref ref-type="bibr" rid="ref9">9</xref>
          ] format. As such, it is
challenging to build rules that give an interpretation to the
program abstract syntax, such as \append an argument to
the function call", since we do not provide a mapping from
the concept of \function call" to a pattern of AST nodes. By
instead emitting templates in terms of the language AST in
aterm form, we are able to keep the tool as language-neutral
as possible.
2.
        </p>
      </sec>
    </sec>
    <sec id="sec-4">
      <title>METHODOLOGY</title>
      <p>We propose the tool work ow illustrated in Figure 1 for
studying software evolution via VCS data. First, each version
of all source les in the project are reconstituted from the
di erences stored within the VCS such that each version
of a le can be parsed by an appropriate language front
end. Each front-end is con gured to map the parsed code to
an aterm that represents a standardized serialization of the
AST. Mapping languages to a common aterm format allows
the downstream portions of our work ow to be
languageagnostic to a large degree, with minimal language-speci c
parameterization.</p>
      <p>
        Once we have code in an aterm format, we can then apply
a structural di erencing algorithm between adjacent versions
of each source le (e.g., version n of le f is compared
to version n + 1 of le f ). The result of this is a forest
of trees that represent the portions of the AST of le f
that changed between versions at the structural level. These
changes can either be code insertions, deletions, or mutations.
Our di erencing is based on the work of Yang [
        <xref ref-type="bibr" rid="ref11">11</xref>
        ] whose
algorithm was designed for computing di erences between
source code versions. Yang's goal was to improve the visual
presentation of di erences in textual di tools, and our use
of their algorithm to provide input to further tree analysis
algorithms is novel.
      </p>
      <p>After reducing the sequence of di erences stored in the
VCS, we have a large forest of trees each representing a
change that occurred over the evolution of the software. At
this point, we seek to relate each of these trees via a tree
similarity metric. This is achieved by using Yang's algorithm
a second time, but in this case we ignore the sequence of
edit operations that it produces and simply consume the
quantitative similarity metric that it produces as a rough
estimate of how closely related two trees are. A threshold
parameter is de ned in which two trees with a similarity
above the threshold are considered to be part of the same
group of di erence tress.</p>
      <p>
        Finally, once the set of di erences are grouped into groups
of trees that are similar up to the threshold, we perform
antiuni cation on the entire group to distill all members to a
representative code pattern for the group. Antiuni cation of
a set of terms yields the least general generalization of those
terms, which is how we de ne our notion of a code pattern.
The antiuni cation algorithm as described by Bulychev [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ]
a.c
b.c
source code
version history
a.c
v1
a.c
v2
compare sequential
versions of each file
treediff
tree similarity
      </p>
      <p>forest of
diff subtrees
group by similarity
antiunify</p>
      <p>P1
antiunify</p>
      <p>
        P2
antiunify to obtain
patterns
as part of the clonedigger project3 was used, which itself is
an implementation of the classical antiuni cation algorithm
described by both Reynolds [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ] and Plotkin [
        <xref ref-type="bibr" rid="ref5">5</xref>
        ].
      </p>
      <p>In the following sections, we describe the steps above in
greater detail.
2.1</p>
    </sec>
    <sec id="sec-5">
      <title>Parsing and aterm generation</title>
      <p>One of the most challenging aspects of performing this kind
of study on arbitrary software packages is the availability of
robust language parsing tools. In the absence of a common
intermediate representation or abstract syntax representation
for popular languages, we adopted a standardized
serialization format in the form of annotated terms. Generation of
aterms was achieved via language-speci c parsers. In this
work, we used the language-java parser available as an
open source library accessible via the Haskell programming
language.</p>
      <p>The structure of aterms is given by this simple syntax:
hatermi
::= `AAppl' hstringi haterm-list i
j `AList' haterm-list i
j `AInt' hint i
haterm-list i ::= hatermi haterm-list i</p>
      <p>j</p>
      <p>This structure is su cient for us to encode typical abstract
syntax trees if we allow ourselves to use the string label of the</p>
      <sec id="sec-5-1">
        <title>3http://clonedigger.sourceforge.net</title>
        <p>AAppl portion of the aterm. This is most easily illustrated
with an example. Suppose that we have the Java AST for
the statement i++;. In a textual form, this portion of the
AST would be represented by:</p>
        <sec id="sec-5-1-1">
          <title>ExpStmt (PostIncrement (ExpName (Name [Ident "i"])))</title>
          <p>The translation to aterm would give us:</p>
        </sec>
        <sec id="sec-5-1-2">
          <title>AAppl "ExpStmt"</title>
          <p>[AAppl "PostIncrement"
[AAppl "ExpName"
[AAppl "Name"
[AList</p>
          <p>[AAppl "Ident" [AAppl "\"i\"" []]]]]]]</p>
          <p>Notice that for strings, such as identi er names, we place
double quotes around the string inside the label portion
of the aterm. Implementations of aterms often provide a
representation that allows for nodes to be shared within the
tree. While this is a useful optimization for saving space,
we chose to use the simpler unshared representation in our
prototype due to the clearer expression of the tree analysis
algorithms over the unshared form of the structure.
2.2</p>
        </sec>
      </sec>
    </sec>
    <sec id="sec-6">
      <title>Structural differencing</title>
      <p>
        One of the classical algorithms studied in computer science
is that of string similarity and the concept of string edit
distance as a measure of the minimal number of operations
necessary to mutate one string or sequence into another. A
more complex problem is to de ne a similar sequence of
operations to change a non-linear structure like a tree from
one into another. This problem of computing a structural
edit distance has been studied since the 1970s and has yielded
tree di erencing algorithms analogous to string di erencing
algorithms commonly used in text analysis. Many modern
e orts in this area are based on the initial work of Selkow [
        <xref ref-type="bibr" rid="ref7">7</xref>
        ]
and Tai [
        <xref ref-type="bibr" rid="ref8">8</xref>
        ]. Interest in such analysis of tree-structured
data increased with the proliferation of structured document
formats used on the Internet such as XML, HTML and SGML
(a noteworthy example from this body of work is found in
Chawathe [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ]).
      </p>
      <p>
        Our work is based on Yang's source di erencing
technique [
        <xref ref-type="bibr" rid="ref11">11</xref>
        ]. In this algorithm two trees to be compared are
mapped to two trees of edit operations in which nodes from
the original trees are annotated with edit operations (keep or
delete). These can be applied to turn each tree into the other.
On their own the edit trees are not su cient to identify the
paired subtrees that represent regions where change occurred.
This requires an additional step of processing the edit trees
to form a single tree in which the edit trees have been woven
together.
2.3
      </p>
    </sec>
    <sec id="sec-7">
      <title>Identifying structural changes via edit tree weaving</title>
      <p>Ideally, we would like to obtain from the tree di erencing
algorithm what can be thought of as the two trees overlaid
on each other such that the common structure from the root
towards the children is clear, and points where subtrees di er
are explicitly identi ed. The details on how this algorithm
was implemented are not critical to this paper | instead, we
will focus on what the woven trees contain. In the discussion
that follows, we adopt the convention that the arguments to
the binary tree di erencing function are referred to as the
left and right trees.</p>
      <p>Changes that occur between the trees are represented by
three change types. If the di erence between two trees is the
insertion of a subtree in the right tree, then the woven tree
will contain a left-hole. Similarly, deletion of a subtree from
the left such that it is not present in the right tree will result
in a right-hole. If a subtree was determined to be changed,
then the woven tree will contain a mismatch point that refers
to the both the right and left subtrees that di er. All other
points in the tree that match are joined with a match point
that contains the corresponding common node to both trees.</p>
      <p>Given two edit trees that have been woven together into
a tree with explicit holes and mismatches, we can extract
the subtrees that correspond to the three types of changes
above. Match points also play an important role in extracting
changes by retaining the common context that was present
in both trees where the change occurred. If we extract only
the subtree rooted at the point where the change occurred,
the rest of the analysis will be missing the context where
the change took place. This information is necessary when
constructing understandable patterns.</p>
      <p>For example, while it may be true that a code fragment
such as i++ is where the change occurred, it is most useful
to know whether or not that fragment occurred within an
expression, a for-loop, or as a standalone statement. As such,
we have chosen for the work presented here to extract the
subtree along with the closest enclosing statement. For example,
if the subtree was the expression i++; within the statement
if(i &lt; 100) i++; we would extract the if-statement with
the expression.</p>
      <p>This is achieved by including the subtree rooted at the
nearest ancestor (which must be a matching point in the
woven edit trees) to a change representing an appropriate
abstract syntax element. In the future, we would like to
explore other ways of extracting context, such as looking at
the closest enclosing expression, function (when it exists),
or class. This information should also be parameterizable
to support di erences in important AST nodes that varies
between languages.
2.4</p>
    </sec>
    <sec id="sec-8">
      <title>Tree similarity metric and grouping</title>
      <p>Given two trees t1 and t2, we would like to de ne a
similarity metric such that d(t1; t2) 2 [0; 1], where a similarity of
1 means that the trees are identical, and 0 represents
maximal dissimilarity. In Yang's algorithm, a similarity score
is provided for comparing ta and tb. This metric is order
dependent, forcing the maximal score to be the size of the
left tree (ta), even if tb is larger. If the trees are identical,
the score will be exactly jtaj, the number of nodes in ta. If
they di er, it will be strictly less than jtaj. As such, it would
be possible to de ne our distance function to be d(ta;tb) ,
jtaj
but this operator is not symmetric, since it is easy to nd
instances such that d(tb;ta) 6= d(ta;tb) when the trees are very
jtbj jtaj
di erent. Instead, we de ne (ta; tb) to be the function
(ta; tb) :=
min(d(ta; tb); d(tb; ta))</p>
      <p>max(jtaj; jtbj)
where the min and max functions force the calculation to
be symmetric.</p>
      <p>Once we have the set of changes that were detected from
the VCS history, we can generate a forest of trees t1; ; tn
obtained from the holes and mismatch points in the woven
edit trees. We then compute the n2 distances between all
pairs to generate a distance matrix D where Dij = (ti; tj).
Given a threshold value , we can produce a boolean matrix
D0 where Di0j = (ti; tj) &gt; . An example matrix is shown
in Figure 2 for changes observed in the VCS for ANTLR
where = 0:9. Note that for large numbers of changes, a
sparse representation of the boolean matrix can be computed
for a given without requiring the full dense distance matrix
to be created. The sparsity of the matrix is dependent both
on the types of changes present and the value of chosen.</p>
      <p>In our implementation, we create multiple distance
matrices such that each represents only related changes of a
certain type from the woven tree (left and right holes, and
mismatches). The matrix as de ned above is simply the
element-wise boolean or of these three matrices. Capturing
this information is important as it allows us to further re ne
our view of the code evolution to distinguish code changes
from the insertion or removal of code that occurs over time.
For example, when code is being developed and grown, we
expect to see a number of code insertions. Similarly, when a
mass refactoring occurs to simplify code, we would expect to
see a set of code deletions. When a more subtle re nement
occurs, such as transposition of code arguments or the
addition of a conditional to re ne control ow, we would expect
to see mismatches where the tree changes.
2.5</p>
    </sec>
    <sec id="sec-9">
      <title>Antiunification and template generation</title>
      <p>Once we have groups of related code snippets in the form
of related subtrees, we can seek patterns that relate changes.
For example, say we have a function call foo() where each
invocation of the function uses the same parameters (e.g,
foo(x,y), where x and y are always the same). If we
add a new parameter at the end of each call where the
variable passed in di ers each time (e.g., foo(x,y,a) and
foo(x,y,b)), we would like to abstract out this change as
foo(x,y, ), where each instance of the change replaces
with whatever concrete variable is used at that point. The
antiuni cation algorithm is built for this purpose { given two
addi-ons  
dele-ons  
modifica-ons  
0  
0.2  
0.4   0.6  </p>
      <p>Threshold  
trees, it seeks the least-general generalization of the pair and
produces a triplet representing the generalized tree with a
metavariable introduced where the two di er, as well as a
substitution set that allows the metavariable to be replaced
with the appropriate concrete subtree necessary to
reconstitute the two trees that were antiuni ed. Multiple distinct
metavariables ( 1, , n) are used when multiple
independent points are necessary to represent a generalized set of
trees.</p>
    </sec>
    <sec id="sec-10">
      <title>EXPERIMENTAL RESULTS</title>
      <p>We tested the methodology outlined in Section 2 on the
publicly available git repositories for two popular open source
projects, the ANTLR parser generator and the Clojure
language implementation. Both are implemented in Java, and
one (ANTLR) is composed of a mixture of hand-written and
automatically generated code.
3.1</p>
    </sec>
    <sec id="sec-11">
      <title>Threshold sensitivity</title>
      <p>The rst experiment that we performed was to investigate
the e ect of similarity threshold to the number of groups
identi ed, as well as the degree of generality present in the tree
that results from all members of each group being antiuni ed
together. Our prediction was that at the lowest threshold
( = 0:0), when all trees are considered to be similar, their
antiuni cation will yield the most general pattern. This is
what was observed, in which the antiuni cation result is a
tree composed of a single metavariable node. Similarly, at
the highest threshold ( = 1:0), the only groupings that will
be present will be single tree sets, or sets containing
identical trees for instances of identical changes that occurred
in di erent places. This is precisely what we observed, with
the antiuni ed trees containing no meta-variables since
antiuni cation of a set of identical elements is the element
itself.
3.2</p>
    </sec>
    <sec id="sec-12">
      <title>Group counts</title>
      <p>We show the number of groups (broken down by type:
addition, deletion, or modi cation) as a function of threshold
of similarity ( ). Figure 3 shows the number of groups for
the Clojure history and Figure 4 shows the number of groups
for the ANTLR history. In both cases, we only consider a
small portion of the full history of the VCS.</p>
      <p>At the maximum = 1:0, the total number of changes is
less than the number of trees we started with, because some
}
}
}
0  
changes end up being identical. As we can see, as increases,
we see more groupings of changes due to changes that were
considered similar under a lower threshold being considered
dissimilar under the more restrictive threshold. Increases in
the group count represent large groups splitting into one or
more smaller groups.</p>
      <p>As an example, at = 0:15, a single pattern for for-loops
is identi ed:
for (
=
;
&lt;
;</p>
      <p>) {</p>
      <p>As the threshold is increased to = 0:25, in addition to
generic for-loops, a cohort of changes are identi ed to a more
speci c instance of the for-loop where the loop counter is
initialized to zero:
for (
= 0 ;
&lt;
;</p>
      <p>) {</p>
      <p>Increasing to = 0:35, the pattern for the conditional
becomes more speci c and we see what appears to be a
template for using the eld of an object (e.g., args.length)
as the loop termination criterion:
for (
= 0 ;
&lt;
.</p>
      <p>;</p>
      <p>) {</p>
      <p>Similar templates emerge for code patterns such as method
invocations, printing the concatenation of two strings, and
other common activities.
3.3</p>
    </sec>
    <sec id="sec-13">
      <title>Pattern identification</title>
      <p>Using a portion of the Clojure history, we varied from
0 to 1 with an increment size of 0.01 as shown in Figure 3.
Looking at just the number of deletions, we examined the
point where the number of deletions goes from 4 to 5 as the
threshold changes from 0.35 to 0.36.</p>
      <p>The following code, presented in standard style of uni ed
di , shows a loop and the lines that were removed. This
example comes from a class named PersistentArrayMap:
public Object kvreduce(IFn f, Object init){
for(int i=0;i &lt; array.length;i+=2){
init = f.invoke(init, array[i], array[i+1]);
if(RT.isReduced(init))</p>
      <p>return ((IDeref)init).deref();</p>
      <p>Given the low threshold, this deletion was considered to be
similar to the following example from PersistentHashMap.
Note that whitespace in most languages is syntactically
neutral and curly braces are optional for single statement
conditional or loop bodies. As a result, the parser used in
this work gives the same AST for if (exp) { stmt; } and
if (exp) stmt;. Such changes are intermingled with
syntactically meaningful changes in the uni ed di format. To
clarify the speci c di erence that our tool considers to
actually be di erent, we have added a \&gt;" pre x to the
appropriate lines of the uni ed di .
public Object kvreduce(IFn f, Object init){
for(INode node : array){</p>
      <p>if(node != null){
for(INode node : array)
{
if(node != null)
init = node.kvreduce(f,init);
if(RT.isReduced(init))</p>
      <p>return ((IDeref)init).deref();
}
}
}
return init;
+
+
+
&gt;&gt;+
}</p>
      <p>In both cases, our tool identi ed for-loops where the same
lines are removed. In fact, the code for both of these is very
similar perhaps owing to Java's HashMap and ArrayMap
classes being very similar in terms of interface. Furthermore,
it did this at the statement level, eg., we did not need to
consider the similarities of the le names or the method names.
The jump in group count as increased corresponds to the
di erences in the for-loops that contain the change falling
below the necessary threshold of similarity for grouping.</p>
    </sec>
    <sec id="sec-14">
      <title>CONCLUSIONS AND FUTURE WORK</title>
      <p>We have shown that patterns of change over the lifetime
of a project can be obtained through analysis of its version
control history. The use of tree di erencing and tree
similarity measures, as well as the antiuni cation algorithm for
computing generalized patterns, allows this large volume of
di erence data to be distilled into a compact form in which
changes can be studied at the level of the base language
syntax. Analysis of the size and count of groups of similar
changes as a function of a similarity threshold provides a
disciplined way to identify generalizations of changes identi ed
by the tool.</p>
      <p>Our work has been performed using a generic, language
neutral term representation allowing the same techniques
to be applied to other languages given appropriate parsing
infrastructure and a mapping from language-speci c abstract
syntax forms to the generic annotated term form. Minimal
parameterization of the tool is necessary to then consume
these terms, with language-speci c parameters largely
focused on speci c nodes within the term that correspond to
semantically useful subtree roots for providing context to
tree di erences.</p>
      <p>In Section 3.1, we showed that our approach can highlight
the evolution of code structurally. In fact, our example of
the for-loop precisely supports the hypothetical language
designer argument laid out in Section 1.1.</p>
      <p>In Section 3.3, we were able to nd related changes in
di erent les that happened as part of the same commit.
Not only were we able to remove noise compared to
linebased di , but we were also looking at the Clojure source
for the rst time and able to see an important relationship
between the internals of the classes in those two les. As
programmers who are completely new to the Clojure source
we were able to gain valuable insight.</p>
      <p>Our experiment relied on a simple replay of the history
of a software project. There are other meaningful ways to
generate the set of les to analyze. One such example would
be to correlate code changes to bug xes and bug reports
and then push those changes through our work ow to nd
patterns. As mentioned in Section 1.1 this may provide a
support to quality assurance practices.</p>
      <p>In Section 2.3 we explored one way to extract context.
Many di erent heuristics would be suitable here. Studying
the trade-o s of di erent heuristics would allow us to ne
tune our approach depending on the application and what
we wanted to learn about the source code.
4.1</p>
    </sec>
    <sec id="sec-15">
      <title>Acknowledgments</title>
      <p>This work was supported in part by the US Department
of Energy O ce of Science, Advanced Scienti c Computing
Research contract no. DE-SC0004968. Additional support
was provided by Galois, Inc.
5.</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          [1]
          <string-name>
            <given-names>P.</given-names>
            <surname>Bulychev</surname>
          </string-name>
          and
          <string-name>
            <given-names>M.</given-names>
            <surname>Minea</surname>
          </string-name>
          .
          <article-title>Duplicate code detection using anti-uni cation</article-title>
          .
          <source>In Proc. Spring Young Researchers Colloquium on Software Engineering</source>
          ,
          <year>2008</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          [2]
          <string-name>
            <given-names>S. S.</given-names>
            <surname>Chawathe</surname>
          </string-name>
          ,
          <string-name>
            <given-names>A.</given-names>
            <surname>Rajaraman</surname>
          </string-name>
          ,
          <string-name>
            <given-names>H.</given-names>
            <surname>Garcia-Molina</surname>
          </string-name>
          ,
          <article-title>and</article-title>
          <string-name>
            <given-names>J.</given-names>
            <surname>Widom</surname>
          </string-name>
          .
          <article-title>Change detection in hierarchically structured information</article-title>
          .
          <source>In Proceedings of the 1996 ACM SIGMOD international conference on Management of data</source>
          ,
          <year>1996</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          [3]
          <string-name>
            <given-names>M.</given-names>
            <surname>Kim</surname>
          </string-name>
          ,
          <string-name>
            <given-names>D.</given-names>
            <surname>Notkin</surname>
          </string-name>
          , and
          <string-name>
            <given-names>D.</given-names>
            <surname>Grossman</surname>
          </string-name>
          .
          <article-title>Automatic inference of structural changes for matching across program versions</article-title>
          .
          <source>In Proceedings of the 29th international conference on Software Engineering (ICSE'07)</source>
          ,
          <year>2007</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          [4]
          <string-name>
            <given-names>I.</given-names>
            <surname>Neamtiu</surname>
          </string-name>
          ,
          <string-name>
            <given-names>J. S.</given-names>
            <surname>Foster</surname>
          </string-name>
          , and
          <string-name>
            <given-names>M.</given-names>
            <surname>Hicks</surname>
          </string-name>
          .
          <article-title>Understanding Source Code Evolution Using Abstract Syntax Tree Matching</article-title>
          .
          <source>In Proceedings of the 2005 international workshop on Mining software repositories (MSR'05)</source>
          ,
          <year>2005</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          [5]
          <string-name>
            <given-names>G. D.</given-names>
            <surname>Plotkin</surname>
          </string-name>
          .
          <source>A Note on Inductive Generalization. Machine Intelligence</source>
          ,
          <volume>5</volume>
          :
          <fpage>153</fpage>
          {
          <fpage>163</fpage>
          ,
          <year>1970</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          [6]
          <string-name>
            <given-names>J. C.</given-names>
            <surname>Reynolds</surname>
          </string-name>
          .
          <article-title>Transformational systems and the algebraic structure of atomic formulas</article-title>
          .
          <source>Machine Intelligence</source>
          ,
          <volume>5</volume>
          :
          <fpage>135</fpage>
          {
          <fpage>151</fpage>
          ,
          <year>1970</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          [7]
          <string-name>
            <given-names>S. M.</given-names>
            <surname>Selkow</surname>
          </string-name>
          .
          <article-title>The tree-to-tree editing problem</article-title>
          .
          <source>Information Processing Letters</source>
          ,
          <volume>6</volume>
          (
          <issue>6</issue>
          ):
          <volume>184</volume>
          {
          <fpage>186</fpage>
          ,
          <year>December 1977</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          [8]
          <string-name>
            <given-names>K.-C.</given-names>
            <surname>Tai</surname>
          </string-name>
          .
          <article-title>The tree-to-tree correction problem</article-title>
          .
          <source>Journal of the ACM</source>
          ,
          <volume>26</volume>
          (
          <issue>3</issue>
          ):
          <volume>422</volume>
          {
          <fpage>433</fpage>
          ,
          <year>July 1979</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          [9]
          <string-name>
            <surname>M. van den Brand</surname>
          </string-name>
          , H. de Jong, P. Klint, and
          <string-name>
            <given-names>P.</given-names>
            <surname>Olivier</surname>
          </string-name>
          .
          <article-title>E cient annotated terms</article-title>
          .
          <source>Software{Practice and Experience</source>
          ,
          <volume>30</volume>
          :
          <fpage>259</fpage>
          {
          <fpage>291</fpage>
          ,
          <year>2000</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          [10]
          <string-name>
            <surname>P.</surname>
          </string-name>
          <article-title>Wei gerber and S. Diehl. Identifying refactorings from source-code changes</article-title>
          .
          <source>In Proceedings of the 21st IEEE/ACM International Conference on Automated Software Engineering (ASE'06)</source>
          ,
          <year>2006</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>
          [11]
          <string-name>
            <given-names>W.</given-names>
            <surname>Yang</surname>
          </string-name>
          .
          <article-title>Identifying syntactic di erences between two programs</article-title>
          .
          <source>Software{Practice and Experience</source>
          ,
          <volume>21</volume>
          (
          <issue>7</issue>
          ):
          <volume>739</volume>
          {
          <fpage>755</fpage>
          ,
          <year>July 1991</year>
          .
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>