Skip to content

Commit ba64072

Browse files
committed
Fix math tags
1 parent 960ac2d commit ba64072

File tree

69 files changed

+1710
-1327
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+1710
-1327
lines changed

pretext/Advanced/DictionariesRevisited.ptx

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@
5454
set of keys and a hash function, we could place the keys in a collection
5555
that allowed us to search and retrieve the associated data value. Our
5656
analysis showed that this technique could potentially yield an
57-
<math>O(1)</math> search. However, performance degraded due to issues such as
57+
<m>O(1)</m> search. However, performance degraded due to issues such as
5858
table size, collisions, and collision resolution strategy.</p>
5959
<p>In Chapter&#xA0;<url href="#trees" visual="#trees">[trees]</url> we considered a binary search tree as a
6060
way to store such a collection. In this case the keys were placed in the
61-
tree such that searching could be done in <math>O(\log n)</math>. However,
61+
tree such that searching could be done in <m>O(\log n)</m>. However,
6262
this was only true if the tree was balanced; that is, the left and the
6363
right subtrees were all of similar size. Unfortunately, depending on the
6464
order of insertion, the keys could end up being skewed to the right or
@@ -411,39 +411,39 @@
411411
<subsubsection xml:id="advanced_analysis-of-a-skip-list">
412412
<title>Analysis of a Skip List</title>
413413
<p>If we had simply stored the key-value pairs in an ordered linked list,
414-
we know that the search method would be <math>O(n)</math>. Can we expect
414+
we know that the search method would be <m>O(n)</m>. Can we expect
415415
better performance from the skip list? Recall that the skip list is a
416416
probabilistic data structure. This means that the analysis will be
417417
dependent upon the probability of some event, in this case, the flip of
418418
a coin. Although a rigorous analysis of this structure is beyond the
419419
scope of this text, we can make a strong informal argument.</p>
420-
<p>Assume that we are building a skip list for <math>n</math> keys. We know that
420+
<p>Assume that we are building a skip list for <m>n</m> keys. We know that
421421
each tower starts off with a height of 1. As we add data nodes to the
422422
tower, assuming the probability of getting heads is
423-
<math>\frac{1}{2}</math>, we can say that <math>\frac{n}{2}</math> of the keys
424-
have towers of height 2. As we flip the coin again, <math>\frac{n}{4}</math>
423+
<m>\frac{1}{2}</m>, we can say that <m>\frac{n}{2}</m> of the keys
424+
have towers of height 2. As we flip the coin again, <m>\frac{n}{4}</m>
425425
of the keys have a tower of height 3. This corresponds to the
426426
probability of flipping two heads in a row. Continuing this argument
427-
shows <math>\frac{n}{8}</math> keys have a tower of height 4 and so on. This
427+
shows <m>\frac{n}{8}</m> keys have a tower of height 4 and so on. This
428428
means that we expect the height of the tallest tower to be
429-
<math>\log_{2}(n) + 1</math>. Using our Big-O notation, we would say that
430-
the height of the skip list is <math>O(\log (n))</math>.</p>
429+
<m>\log_{2}(n) + 1</m>. Using our Big-O notation, we would say that
430+
the height of the skip list is <m>O(\log (n))</m>.</p>
431431
<p>To analyze the <c>search</c> method, recall that there are two scans that
432432
need to be considered as we look for a given key. The first is the down
433433
direction. The previous result suggests that in the worst case we will
434-
expect to consider <math>O(\log (n))</math> levels to find a key. In
434+
expect to consider <m>O(\log (n))</m> levels to find a key. In
435435
addition, we need to include the number of forward links that need to be
436436
scanned on each level. We drop down a level when one of two events
437437
occurs. Either we find a data node with a key that is greater than the
438438
key we are looking for or we find the end of a level. If we are
439439
currently looking at some data node, the probability that one of those
440-
two events will happen in the next link is <math>\frac{1}{2}</math>. This
440+
two events will happen in the next link is <m>\frac{1}{2}</m>. This
441441
means that after looking at two links, we would expect to drop to the next
442442
lower level (we expect to get heads after two coin flips). In any case,
443443
the number of nodes that we need to look at on any given level is
444-
constant. The entire result then becomes <math>O(\log (n))</math>. Since
444+
constant. The entire result then becomes <m>O(\log (n))</m>. Since
445445
inserting a new node is dominated by searching for its location, the
446-
<c>insert</c> operation will also have <math>O(\log(n))</math> performance.</p>
446+
<c>insert</c> operation will also have <m>O(\log(n))</m> performance.</p>
447447
</subsubsection>
448448
</subsection>
449449
</section>

pretext/Advanced/GraphsRevisited.ptx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,18 @@
9797
Line&#xA0;<url href="#lst_simplematcher:line_patternended" visual="#lst_simplematcher:line_patternended">[lst_simplematcher:line_patternended]</url>
9898
checks to see if every character in the pattern has been processed. If
9999
so, a match has been found and we return its starting index.</p>
100-
<p>If we assume that the length of the text is <math>n</math> characters and the
101-
length of the pattern is <math>m</math> characters, then it is easy to see
102-
that the complexity of this approach is <math>O(nm)</math>. For each of the
103-
<math>n</math> characters we may have to compare against almost all <math>m</math>
104-
of the pattern characters. This is not so bad if the size of <math>n</math>
105-
and <math>m</math> are small. However, if we are considering thousands (or
100+
<p>If we assume that the length of the text is <m>n</m> characters and the
101+
length of the pattern is <m>m</m> characters, then it is easy to see
102+
that the complexity of this approach is <m>O(nm)</m>. For each of the
103+
<m>n</m> characters we may have to compare against almost all <m>m</m>
104+
of the pattern characters. This is not so bad if the size of <m>n</m>
105+
and <m>m</m> are small. However, if we are considering thousands (or
106106
perhaps millions) of characters in our text in addition a large
107107
pattern, it will be necessary to look for a better approach.</p>
108108
</subsection>
109109
<subsection xml:id="advanced_using-graphs-finite-state-automata">
110110
<title>Using Graphs: Finite State Automata</title>
111-
<p>It is possible to create an <math>O(n)</math> pattern matcher if we are
111+
<p>It is possible to create an <m>O(n)</m> pattern matcher if we are
112112
willing to do some preprocessing with the pattern. One approach is to
113113
build what is known as a <term>deterministic finite automaton</term>, or <term>DFA</term>,
114114
that represents the pattern as a graph. Each vertex of the <term>DFA graph</term>
@@ -154,7 +154,7 @@
154154
<image source="Advanced/Figures/steptable.png" width="50%" alt="A Trace of the DFA Pattern Matcher" height="2.75in"/>
155155
</figure>
156156
<p>Since every character from the text is used once as input to the DFA
157-
graph, the complexity of this approach is <math>O(n)</math>. However, we need
157+
graph, the complexity of this approach is <m>O(n)</m>. However, we need
158158
to take into account the preprocessing step that builds the DFA. There
159159
are many well-known algorithms for producing a DFA graph from a pattern.
160160
Unfortunately, all of them are quite complex mostly due to the fact that
@@ -261,8 +261,8 @@
261261
The method begins by augmenting the pattern so that the indices on the
262262
characters match the vertex labels in the KMP graph. Since the initial
263263
state is state 0, we have used the <c>'0'</c> symbol as a placeholder. Now the
264-
characters 1 to <math>m</math> in the augmented pattern correspond directly
265-
with the states 1 to <math>m</math> in the graph.</p>
264+
characters 1 to <m>m</m> in the augmented pattern correspond directly
265+
with the states 1 to <m>m</m> in the graph.</p>
266266
<p>Line&#xA0;<url href="#lst_mismatchedlinks:line_initdict" visual="#lst_mismatchedlinks:line_initdict">[lst_mismatchedlinks:line_initdict]</url>
267267
creates the first dictionary entry, which is always a transition from
268268
vertex 1 back to the initial state where a new character is
@@ -288,7 +288,7 @@
288288
<image source="Advanced/Figures/steptable2.png" width="50%" alt="A Trace of the KMP Pattern Matcher" height="3in"/>
289289
</figure>
290290
<p>As with the DFA graph from the previous section, KMP pattern matching is
291-
<math>O(n)</math> since we process each character of the text string.
291+
<m>O(n)</m> since we process each character of the text string.
292292
However, the KMP graph is much easier to construct and requires much
293293
less storage as there are only two transitions from every vertex.</p>
294294
</subsection>

pretext/Advanced/PythonListsRevisited.ptx

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222
array. The array only supports two operations: indexing and assignment
2323
to an array index.</p>
2424
<p>The best way to think about an array is that it is one continuous block
25-
of bytes in the computer's memory. This block is divided up into <math>n</math>-byte
26-
chunks where <math>n</math> is based on the data type that is stored in the array.
25+
of bytes in the computer's memory. This block is divided up into <m>n</m>-byte
26+
chunks where <m>n</m> is based on the data type that is stored in the array.
2727
Figure&#xA0;<url href="#fig_array" visual="#fig_array">1</url> illustrates the idea of an array that is sized
2828
to hold six floating point values.</p>
2929
<figure align="" xml:id="fig-array">
@@ -42,8 +42,8 @@
4242
<p>For example, suppose that our array starts at location <c>0x000040</c>,
4343
which is 64 in decimal. To calculate the location of the object at
4444
position 4 in the array we simply do the arithmetic:
45-
<math>64 + 4 \cdot 8 = 96</math>. Clearly this kind of calculation is
46-
<math>O(1)</math>. Of course this comes with some risks. First, since
45+
<m>64 + 4 \cdot 8 = 96</m>. Clearly this kind of calculation is
46+
<m>O(1)</m>. Of course this comes with some risks. First, since
4747
the size of an array is fixed, one cannot just add things on to the end of
4848
the array indefinitely without some serious consequences. Second, in
4949
some languages, like C, the bounds of the array are not even checked, so
@@ -77,20 +77,20 @@
7777
<p>
7878
<ul>
7979
<li>
80-
<p>Accessing an itema at a specific location is <math>O(1)</math>.</p>
80+
<p>Accessing an itema at a specific location is <m>O(1)</m>.</p>
8181
</li>
8282
<li>
83-
<p>Appending to the list is <math>O(1)</math> on average, but <math>O(n)</math> in
83+
<p>Appending to the list is <m>O(1)</m> on average, but <m>O(n)</m> in
8484
the worst case.</p>
8585
</li>
8686
<li>
87-
<p>Popping from the end of the list is <math>O(1)</math>.</p>
87+
<p>Popping from the end of the list is <m>O(1)</m>.</p>
8888
</li>
8989
<li>
90-
<p>Deleting an item from the list is <math>O(n)</math>.</p>
90+
<p>Deleting an item from the list is <m>O(n)</m>.</p>
9191
</li>
9292
<li>
93-
<p>Inserting an item into an arbitrary position is <math>O(n)</math>.</p>
93+
<p>Inserting an item into an arbitrary position is <m>O(n)</m>.</p>
9494
</li>
9595
</ul>
9696
</p>
@@ -142,13 +142,13 @@
142142
the new value is added to the list at <c>last_index</c>, and <c>last_index</c>
143143
is incremented by one.</p>
144144
<p>The <c>resize</c> method calculates a new size for the array using
145-
<math>2 ^ {size\_exponent}</math>. There are many methods that could be used
145+
<m>2 ^ {size\_exponent}</m>. There are many methods that could be used
146146
for resizing the array. Some implementations double the size of the
147147
array every time as we do here, some use a multiplier of 1.5, and some
148148
use powers of two. Python uses a multiplier of 1.125 plus a constant.
149149
The Python developers designed this strategy as a good tradeoff for
150150
computers of varying CPU and memory speeds. The Python strategy leads to
151-
a sequence of array sizes of <math>0, 4, 8, 16, 24, 32, 40, 52, 64, 76\ldots</math> .
151+
a sequence of array sizes of <m>0, 4, 8, 16, 24, 32, 40, 52, 64, 76\ldots</m> .
152152
Doubling the array size leads to a bit more wasted space at any
153153
one time, but is much easier to analyze. Once a new array has been
154154
allocated, the values from the old list must be copied into the new
@@ -161,45 +161,45 @@
161161
that in Python objects that are no longer referenced are automatically
162162
cleaned up by the garbage collection algorithm.</p>
163163
<p>Before we move on let's analyze why this strategy gives us an average
164-
<math>O(1)</math> performance for <c>append</c>. The key is to notice that most
165-
of the time the cost to append an item <math>c_i</math> is 1. The only time
164+
<m>O(1)</m> performance for <c>append</c>. The key is to notice that most
165+
of the time the cost to append an item <m>c_i</m> is 1. The only time
166166
that the operation is more expensive is when <c>last_index</c> is a power
167167
of 2. When <c>last_index</c> is a power of 2 then the cost to append an
168-
item is <math>O(last\_index)</math>. We can summarize the cost to insert the
169-
<math>i_{th}</math> item as follows:</p>
170-
<math_block docname="Advanced/PythonListsRevisited" label="True" nowrap="False" number="True" xml:space="preserve">c_i =
168+
item is <m>O(last\_index)</m>. We can summarize the cost to insert the
169+
<m>i_{th}</m> item as follows:</p>
170+
<math_block docname="Advanced/PythonListsRevisited" nowrap="False" number="True" xml:space="preserve">c_i =
171171
\begin{cases}
172172
i \text{ if } i \text{ is a power of 2} \\
173173
1 \text{ otherwise}
174174
\end{cases}</math_block>
175175
<p>Since the expensive cost of copying <c>last_index</c> items occurs
176176
relatively infrequently we spread the cost out, or <em>amortize</em>, the
177177
cost of insertion over all of the appends. When we do this the cost of
178-
any one insertion averages out to <math>O(1)</math>. For example, consider
178+
any one insertion averages out to <m>O(1)</m>. For example, consider
179179
the case where you have already appended four items. Each of these four
180180
appends costs you just one operation to store in the array that was
181181
already allocated to hold four items. When the fifth item is added a new
182182
array of size 8 is allocated and the four old items are copied. But now
183183
you have room in the array for four additional low cost appends.
184184
Mathematically we can show this as follows:</p>
185-
<math_block docname="Advanced/PythonListsRevisited" label="True" nowrap="False" number="True" xml:space="preserve">\begin{aligned}
185+
<math_block docname="Advanced/PythonListsRevisited" nowrap="False" number="True" xml:space="preserve">\begin{aligned}
186186
cost_{total} &amp;= n + \sum_{j=0}^{\log_2{n}}{2^j} \\
187187
&amp;= n + 2n \\
188188
&amp;= 3n\end{aligned}</math_block>
189189
<p>The summation in the previous equation may not be obvious to you, so
190-
let's think about that a bit more. The sum goes from zero to <math>\log_2{n}</math>.
190+
let's think about that a bit more. The sum goes from zero to <m>\log_2{n}</m>.
191191
The upper bound on the summation tells us how many times we
192-
need to double the size of the array. The term <math>2^j</math> accounts for
192+
need to double the size of the array. The term <m>2^j</m> accounts for
193193
the copies that we need to do when the array is doubled. Since the total
194-
cost to append n items is <math>3n</math>, the cost for a single item is
195-
<math>3n/n = 3</math>. Because the cost is a constant we say that it is
196-
<math>O(1)</math>. This kind of analysis is called <term>amortized analysis</term> and
194+
cost to append n items is <m>3n</m>, the cost for a single item is
195+
<m>3n/n = 3</m>. Because the cost is a constant we say that it is
196+
<m>O(1)</m>. This kind of analysis is called <term>amortized analysis</term> and
197197
is very useful in analyzing more advanced algorithms.</p>
198198
<p>Next, let us turn to the index operators.
199199
Listing&#xA0;<url href="#lst_arrindex" visual="#lst_arrindex">[lst_arrindex]</url> shows our Python
200200
implementation for index and assignment to an array location. Recall
201201
that we discussed above that the calculation required to find the memory
202-
location of the <math>i_{th}</math> item in an array is a simple <math>O(1)</math>
202+
location of the <m>i_{th}</m> item in an array is a simple <m>O(1)</m>
203203
arithmetic expression. Even languages like C hide that calculation
204204
behind a nice array index operator, so in this case the C and the Python
205205
look very much the same. In fact, in Python it is very difficult to get
@@ -245,10 +245,10 @@ def __setitem__(self, idx, val):
245245
self.my_array[i + 1] = self.my_array[i]
246246
self.last_index += 1
247247
self.my_array[idx] = val</pre>
248-
<p>The performance of the insert is <math>O(n)</math> since in the worst case we
248+
<p>The performance of the insert is <m>O(n)</m> since in the worst case we
249249
want to insert something at index 0 and we have to shift the entire
250250
array forward by one. On average we will only need to shift half of the
251-
array, but this is still <math>O(n)</math>. You may want to go back to
251+
array, but this is still <m>O(n)</m>. You may want to go back to
252252
Chapter&#xA0;<url href="#basicds" visual="#basicds">[basicds]</url> and remind yourself how all of these
253253
list operations are done using nodes and references. Neither
254254
implementation is right or wrong; they just have different performance

0 commit comments

Comments
 (0)