<!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>
      <issn pub-type="ppub">1613-0073</issn>
    </journal-meta>
    <article-meta>
      <title-group>
        <article-title>A note on some interesting test results for the Rabin-Karp string matching algorithm</article-title>
      </title-group>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>Tatiana Jajcayová</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
          <xref ref-type="aff" rid="aff1">1</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Zuzana Majeríková</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
          <xref ref-type="aff" rid="aff1">1</xref>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          <institution>Department of Applied Informatics, Comenius University</institution>
          ,
          <addr-line>Bratislava</addr-line>
          ,
          <country country="SK">Slovakia</country>
        </aff>
        <aff id="aff1">
          <label>1</label>
          <institution>The Rabin-Karp algorithm</institution>
        </aff>
      </contrib-group>
      <pub-date>
        <year>2018</year>
      </pub-date>
      <volume>2203</volume>
      <fpage>181</fpage>
      <lpage>187</lpage>
      <abstract>
        <p>While analyzing and testing some of the well known string matching algorithms, we came across rather interesting phenomenon in tests results for the Rabin-Karp algorithm. Testing which moduli work best in the algorithm, we realized that on some texts some moduli perform much worse then others. This caught our attention, and we continued testing. In this paper, we summarize tests using different moduli on the same text, tests run on different English texts (fiction, scientific, law, newspaper), and tests run on different languages and alphabets (English, Slovak, French, German and Russian). We include analysis of the obtained results and state some hypotheses. We start with a brief review of the Rabin-Karp algorithm and its computational complexity. This string matching algorithm is based on the use of elementary numbertheoretic notions such as the equivalence of two numbers modulo a third number. Rabin and Karp [5] proposed the algorithm to improve performance of string matching algorithms in practice. This algorithm generalizes to other algorithms for related problems, such as two dimensional pattern matching. To simplify the explanations, it will be convenient to assume for a moment that characters are decimal digits, so we interpret the characters of strings as both digits and also graphical symbols. Thus, a string of length k can be represented as a decimal number. For instatnce, a string s = “12345” of length 5 corresponds to a decimal number 12 345. In general case, we assume to have an alphabet Σ which consists of characters that are digits from the number system over the base b = |Σ|. Let us have a pattern P[1...m] and text T [1...n]. The decimal value of pattern P will be denoted as p. Similarly, the decimal value of every substring of a text T of length m starting at a position s will be denoted as ts. We say that pattern P occurs in text T if and only if one can find at least one ts that has the same decimal value as p, i.e. ts = p and T [s + 1...s + m] = P[1...m], s = 0, 1, . . . , n − m. In that case we call s a valid shift. We can compute decimal value of p in time Θ(m) by using the Horner's Rule: p = P[m] + 10(P[m − 1] + 10(P[m − 2] + 10(P[m − 3] + . . .</p>
      </abstract>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>-</title>
      <p>Similarly, again by the Horner’s Rule, the value t0 can
be computed in Θ(m).</p>
      <p>For every s, the value ts+1 can be then computed from
the previous value ts:</p>
      <p>ts+1 = 10(ts − 10m−1T [s + 1]) + T [s + m + 1].</p>
      <p>
        For example, to compute the value t1 from t0 for our text
T = “12345” from the previous paragraph and pattern P of
length m = 3, we use the value t0 which is 123. In this
computation s = 0. A character at the position T[s+1] is
“1”, and its numerical value is 1, a character at position
T[s+m+1] is “4” and its value is 4. The computation is as
follows:
t1 = 10(t0 − 103−1T [0 + 1]) + T [0 + 3 + 1]
t1 = 10(123 − 102T [1]) + T [
        <xref ref-type="bibr" rid="ref3">4</xref>
        ]
t1 = 10(123 − 100) + 4
      </p>
      <p>t1 = 234</p>
      <p>We see that by computing ts − 10m−1T [s + 1], we
remove the highest order digit from value ts. By subsequent
multiplication of the remainder of the value by 10, we shift
the number to the left. 10 is used because we work with
the decimal system. In the general case, where base b is
|Σ|, we would have to shift by b. By adding T [s + m + 1]
we add the low-order digit and we get the final value of
ts+1. (Figure 1)</p>
      <p>If the constant 10m−1 is precomputed, then for each
s = 1, 2, . . . , n − m, the computation of the value ts is done
in constant time. Thus the computation of all the
remaining values t1, t2, t3, . . ., tn−m is done in Θ(n − m). That
means, that by comparing value of p with every value of
ts, we can get all valid shifts in time Θ(m) + Θ(n − m + 1).</p>
      <p>A problem may occur, when value p and values ts
are too large. Some mathematical operations with large
numbers may take a long time, and the assumption that
they take only constant time may be unreasonable. One
possible remedy for this is, what Rabin-Karp algorithm
does: instead of comparing the original values, it
computes values p and ts modulo some suitable modulus q, and
then compare these new modulated numbers. The
modulated numbers are not bigger than q − 1. Computation of
p (mod q) takes again time Θ(m) and computation of all
ts (mod q) values together takes Θ(n − m + 1).</p>
      <p>The modulus q is usually chosen to be a prime such that
the value b · q fits within a computer word. (b is the base,
the number of characters in the alphabet Σ). According to
this, the previous equation for computing ts + 1 changes
to:
ts+1 ≡ (b(ts − T [s + 1]h) + T [S + m + 1])
(mod q),
where
h ≡ dm−1</p>
      <p>(mod q)</p>
      <p>It is clear that if p 6≡ ts (mod q) then P does not start
at position s in T . So if this happens, we know that s is not
a valid shift. On the other hand, it is possible that p ≡ ts
(mod q), and still the pattern P does not start at s. That
means that to complete this algorithm, we must not only
compare the modulated values and find a match, but also
test further to see if the substring T [s + 1...s + m] is the
same as the pattern P. This additional but indispensable
comparison takes another Θ(m) time. The simple
graphical example of the Rabin-Karp algorithm and modulation
of the values of ts is shown in Figure 2.</p>
      <p>In our version of the Rabin-Karp algorithm the
preprocessing time takes Θ(n). The processing time takes
Θ((n − m + 1)m) in the worst case, and only Θ(n + 1) in
the best case of running. The worst case occurs when all
characters of pattern P and all characters of text T are the
same unique symbol. For example, if we have a pattern
P=“aaa” and a text T=“aaaaaaaaa”, then algorithm
considers every possible shift as valid and behaves as the naive
string matching algorithm.
2</p>
    </sec>
    <sec id="sec-2">
      <title>Implementation</title>
      <p>In this section we sketch how we implemented the
RabinKarp algorithm. The particulars of the implementation can
become interesting when discussing the test results in the
last section of the paper.</p>
      <p>We have chosen Java as the programming language.
Java is an object-oriented language, and its biggest
advantage is its platform independence, which means that
the Java code can be run without modifying at any
platform that supports Java. As a development tool we chose
Eclipse Java Oxygen with a WindowBuilder component.
WindowBuilder is designed to create Java GUI
applications in an easy way.
2.1</p>
      <sec id="sec-2-1">
        <title>Implementation of the Main Application</title>
        <p>We study and test Rabin-Karp algorithm in a context of
other string matching algorithms. To organize the testing
of the implemented algorithms, we needed to create the
main application with Graphical User Interface. This
application is build to work with all the studied algorithms
and to manage the input texts, patterns and all of the
output results. The main components that we need in our
application:
• Input pattern - text input field, where the user can
write or paste the pattern that he wants to find in the
text Input text
• Input text - text input field, where the user can write
or paste the text where he wants to find all the
occurrences of the pattern from the Input pattern
• Load text from file - button, that allows the user to
load text from a file to theInput text
• Algorithm - selector, where the user can choose
which algorithm he wants to test
• Modulo - number input field, where the user can
choose the modulo that will be used in the
RabinKarp algorithm
• Output text - output text field, where the text is
rewritten from the Input text, but with highlighted
occurrences of the pattern from Input pattern
• Additional console logs - check field, if it is checked
it means that in the Console there will be written
some additional logs for the given algorithm
alongside with the proccessing and preprocessing time
• Console - after running an algorithm, in the console
there is shown it’s processing and preprocessing time
and when the Additional console logs is checked
there are some additional logs for every algorithm
• Run - button that runs the program, where with a
selected Algorithm, search in Input text for an Input
pattern
A class diagram is shown in Figure 3.</p>
        <p>The application consists of the following classes that
work as follows:
Main is the main class that runs the application. Its
purpose is to initialize the contents of the frame of GUI
window. When users run the application, the Main class gets
the value of the input text, the input pattern, the input
modulo and the selected algorithm. The class passes all this
values to class StringMatching and calls the function run
of the class StringMatching. After the run is completed,
the class fills the output text and console with the results
of running.</p>
        <p>TextHolder is the class that stores the text and the
pattern that the application got on input. It also generates the
alphabet and the base based on the given text and pattern.
OpenFile is the class that allows the user to load a text
from a file with aJFileChooser.</p>
        <p>Algorithm is an interface for implemented algorithms.
Every algorithm needs to have implemented functions
getTimeOfPreprocessing, getTimeOfProcessing,
getOccurrences, getOtherConsoleLogs and run(text, pattern,
alphabet, base, modulo).</p>
      </sec>
      <sec id="sec-2-2">
        <title>NaiveMatching, RabinKarpMatching, FiniteAu</title>
        <p>tomataMatching,
OptimalizedFiniteAutomataMatching, KnuthMorrisPrattMatching are the classes
where the implemented algorithms that we used are.
StringMatching is the class that gets the selected
algorithm, input text, input pattern and modulo. First, it
processes the text and the pattern with TextHolder and gets
the alphabet and the base generated from the text. Then, it
creates a new instance of the selected algorithm and calls
it’s function run.</p>
        <p>The review of the implemented application and it’s GUI
is shown in Figure 4, where a simple running of the
program with the naive string matching algorithm with pattern
“the” and text of the book “The Project Gutenberg EBook
of The Adventures of Sherlock Holmes by Sir Arthur
Conan Doyle” is demonstrated.
For the Rabin-Karp string matching procedure, after it
receives the input text, the pattern, the value of d that
represents the radix − d notation that is uses in its matching
and modulo, we need to initialize the value of the
highorder digit position of an m-digit window. This is shown
in Listing 1 on line 1. After that the preprocessing of this
algorithm follows. We need to compute the value of p and
the value of the first substringt0 of the text with length of
the pattern. Implementation of this is shown in Listing 1
on lines 3 − 6, where the pattern_hash is our value of p
and sub_text_hash represents the value of t0. As a default,
these variables were preset to value 0.</p>
        <p>Listing 1: Calculation of Hashed Values of Value h, p and t0
1 i n t h = ( i n t ) Math . pow ( base , p a t t e r n _ l e n g t h −1) % modulo ;
2
3 for ( i n t i =0; i &lt; p a t t e r n _ l e n g t h ; i ++) {
4 p a t t e r n _ h a s h = ( base∗p a t t e r n _ h a s h + p a t t e r n . charAt ( i ) ) % modulo ;
5 sub_text_hash = ( base∗sub_text_hash + t e x t . charAt ( i ) ) % modulo ;
6 }</p>
        <p>How the processing is implemented can seen in
Listing 2. It starts by iterating through all possible shifts s
in the text. On line 3 there is a check whether value p
matches value of ts at shift s where the loop is executed.
If so, then the character by character comparison between
pattern P and substring of text T [s + 1...s + m] follows. If
these two strings are equal, we add shift to the array of
all of the occurrences, where we store all shifts in which
we have found a positive match. The check on line 9 will
be true on every ts, except the last one tn−m. That is
because the main loop will execute one more time and in
that case we need to compute the value of upcoming ts+1.
This computation is implemented on line 10. In the case
that the value of ts+1 is smaller that 0, we add q to this
value on lines 13 − 15.</p>
        <p>Listing 2: Processing of the Rabin-Karp String Matching Algorithm
1 for ( i n t s =0; s &lt;( t e x t _ l e n g t h − p a t t e r n _ l e n g t h ) ; s ++) {
2
3 i f ( p a t t e r n _ h a s h == sub_text_hash ) {
4 S t r i n g t e x t _ s u b s t r i n g = t e x t . s u b s t r i n g ( s , ( s + p a t t e r n _ l e n g t h ) ) ;
5 i f ( Objects . equals ( p a t t e r n , t e x t _ s u b s t r i n g ) )
6 o c c u r r e n c e s . add ( s ) ;
7 }
8
9 i f ( s &lt; ( t e x t _ l e n g t h − p a t t e r n _ l e n g t h ) ) {
1101 sub_text_hash = ( base ∗( s utebx_tte. xcht_ahr Aasth( s−+ ptaet xtet r.nc_hlaernAgt t(hs))∗) h%) +modulo ;
12
13 i f ( sub_text_hash &lt; 0)
14 sub_text_hash = ( sub_text_hash + modulo ) ;
15 }
16 }
3</p>
      </sec>
    </sec>
    <sec id="sec-3">
      <title>Testing moduli in the Rabin-Karp algorithm</title>
      <p>While testing a performance of the implemented string
matching algorithms, we were interested whether a choice
of the modulus q in the Rabin-Karp algorithm affects the
performance of the algorithm. Recall that for the given
base b = |Σ|, the modulus q is usually chosen to be a prime
number such that the value b · q fits within a computer
word. In this section we summarize results of our testing
of moduli in the Rabin-Karp algorithm.</p>
      <p>We had some preconceived ideas how the test results
should look like. These expectations were met while
testing some of the texts, for an example see Figure 5. The
sample text in Figure 5 is an English text. It is an artificial
text in the sense that it was generated in an online random
text generator, with even some further random changes and
additions. The text is 400 000 characters long.</p>
      <p>A suprise came when we tested the Rabin-Karp
algorithm on The adventures of Sherlock Holmes by Sir Arthur
Conan Doyle. The text was obtained from The Project
Gutenberg. Release Date: March, 1999 [EBook #1661]
[Most recently updated: November 29, 2002], Edition: 12,
Language: English, Character set encoding: ASCII.</p>
      <p>The text was again about 500 000 characters long, and
we tested with different patterns and different lengths of
patterns. As we see in Figure 6, modulus q = 13 performed
significantly worse than the other moduli.</p>
      <p>This caught our attention. We tested the same text for
the second time, now with the moduli ordered in the
descending order (see Figure 7) to make sure that a
possible error is not caused in the program (language Java can
sometimes slow down the performance of the program
because of the Garbage Collector). Since we got the two
graphs that are exactly mirror images of each other, we
see that the garbage collecting in Java is not the reason for
the unexpected behavior.</p>
      <p>Our first hypothesis was that the natural language has
different characteristics than randomly generated texts. So
we continue testing on many different types of English
texts and patterns. In Figure 8, we see the results of the
testing on a law text The Common Law, by Oliver Wendell
Holmes, Jr., and in Figure 9 on a scientific text from the
book Ancient And Modern Physics by Thomas E.
Willson. (Both these text were again obtained from the Project
Gutenberg.) As we see the charts for all these texts are
different. To definitely show that our first hypothesis does
not hold, in Figure 10 is yet another randomly generated
English text that has q = 13 behaving as it is in the fiction
in Figure 6.</p>
      <p>Our another guess was that the performance depending
on moduli may somehow be related to the language or
to the alphabet of the text. Therefore we tested on other
languages, including German (Figure 11), and other
languages using other alphabets, including Russian (Figures
12 and 13.) We see that we can get all types of behavior.</p>
      <p>We were also interested what is happening in Slovak
language. Below you see the results of three tests. The
first one, Figure 14, is on a randomly generated Slovak
text, the second one, Figure 15, is on the original Slovak
fiction, Adam Šangala by Ladislav Nádaši-Jégé, and the
third one, Figure 16, is on the Slovak translation of French
Molier’s Lakomec (L’Avare).</p>
      <p>Here it seems that q = 13 is again behaving worse that
other moduli. (Why?) Just to make a comparison, we also
include the results of the testing on the original French
text. As we see below, Figure 17, modulus q = 13 is not
different from others, while q = 7 and in some extend its
multiples are now the moduli with the worst performance.</p>
      <p>We were hoping that by systematically running tests on
different types of texts, on different languages and
alphabets, with different patterns to search for, we would be able
to understand the relationship between the computational
time and the modulus for Rabin-Karp algorithm. At this
moment we see that this tests are not sufficient to explain
this relationship, and that other, more involved (probably
statistical) methods would be needed to completely
understand the phenomenon.</p>
    </sec>
    <sec id="sec-4">
      <title>Acknowlegment</title>
      <p>The first author acknowledges the support by
VEGA 1/0039/17 and VEGA 1/0719/18</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          [2]
          <string-name>
            <given-names>Nimisha</given-names>
            <surname>Singla</surname>
          </string-name>
          , Deepak Garg,
          <year>January 2012</year>
          ,
          <article-title>String Matching Algorithms and their Applicability in various Applicationsl</article-title>
          ,
          <source>International Journal of Soft Computing and Engineering</source>
          (IJSCE) ISSN:
          <fpage>2231</fpage>
          -
          <lpage>2307</lpage>
          , Volume-I, Issue-6, January 2012
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          [3]
          <string-name>
            <surname>Thomas</surname>
            <given-names>H.</given-names>
          </string-name>
          <string-name>
            <surname>Cormen</surname>
          </string-name>
          , Charles E. Leiserson, Ronald L. Rivest, Clifford Stein,
          <year>2009</year>
          , Introduction to Algorithms: Third Edition, Massachusetts Institute of Technology, Cambridge, Massachusetts 02142 &lt;http://mitpress.mit.edu&gt;
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          [4]
          <string-name>
            <surname>Alfred</surname>
            <given-names>V.</given-names>
          </string-name>
          <string-name>
            <surname>Aho</surname>
            , John E. Hopcroft, and
            <given-names>Jeffrey D.</given-names>
          </string-name>
          <string-name>
            <surname>Ullman</surname>
          </string-name>
          ,
          <article-title>The Design and Analysis of Computer Algorithms</article-title>
          , AddisonWesley,
          <year>1974</year>
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          [5]
          <string-name>
            <surname>Richard</surname>
            <given-names>M.</given-names>
          </string-name>
          <string-name>
            <surname>Karp</surname>
          </string-name>
          and
          <string-name>
            <surname>Michael O. Rabin</surname>
          </string-name>
          ,
          <article-title>Efficient randomized pattern-matching algorithms</article-title>
          ,
          <source>IBM Journal of Research and Development</source>
          ,
          <volume>31</volume>
          (
          <issue>2</issue>
          ):
          <fpage>249</fpage>
          -
          <lpage>260</lpage>
          ,
          <year>1987</year>
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          [6]
          <string-name>
            <surname>Donald</surname>
            <given-names>E.</given-names>
          </string-name>
          <string-name>
            <surname>Knuth</surname>
          </string-name>
          ,
          <string-name>
            <surname>James H. Morris</surname>
          </string-name>
          , Jr., and
          <string-name>
            <surname>Vaughan R. Pratt</surname>
          </string-name>
          ,
          <article-title>Fast pattern matching in strings</article-title>
          ,
          <source>SIAM Journal on Computing</source>
          ,
          <volume>6</volume>
          (
          <issue>2</issue>
          ):
          <fpage>323</fpage>
          -
          <lpage>350</lpage>
          ,
          <year>1977</year>
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          [7]
          <string-name>
            <surname>Edward</surname>
            <given-names>M.</given-names>
          </string-name>
          <string-name>
            <surname>Reingold</surname>
            ,
            <given-names>Kenneth J.</given-names>
          </string-name>
          <string-name>
            <surname>Urban</surname>
          </string-name>
          , and David Gries,
          <article-title>KM-P string matching revisited</article-title>
          ,
          <source>Information Processing Letters</source>
          ,
          <volume>64</volume>
          (
          <issue>5</issue>
          ):
          <fpage>217</fpage>
          -
          <lpage>223</lpage>
          ,
          <year>1997</year>
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          [8]
          <string-name>
            <given-names>Zvi</given-names>
            <surname>Galil</surname>
          </string-name>
          and
          <string-name>
            <given-names>Joel</given-names>
            <surname>Seiferas</surname>
          </string-name>
          ,
          <article-title>Time-space-optimal string matching</article-title>
          ,
          <source>Journal of Computer and System Sciences</source>
          ,
          <volume>26</volume>
          (
          <issue>3</issue>
          ):
          <fpage>280</fpage>
          -
          <lpage>294</lpage>
          ,
          <year>1983</year>
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          [9]
          <string-name>
            <surname>Vidya</surname>
            <given-names>SaiKrishna</given-names>
          </string-name>
          , Prof.
          <source>Akhtar Rasool and Dr. Nilay Khare</source>
          ,
          <article-title>String Matching and its Applications in Diversified Fields</article-title>
          , IJCSI
          <source>International Journal of Computer Science Issues</source>
          , Vol.
          <volume>9</volume>
          ,
          <string-name>
            <surname>Issue</surname>
            <given-names>1</given-names>
          </string-name>
          , No 1,
          <string-name>
            <surname>January</surname>
            <given-names>2012</given-names>
          </string-name>
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>